style: compare return value of getopt() against -1 rather than EOF
[dragonfly.git] / usr.bin / mkcsmapper / yacc.y
1 /*      $NetBSD: yacc.y,v 1.7 2006/09/09 14:35:17 tnozaki Exp $ */
2 /*      $DragonFly: src/usr.bin/mkcsmapper/yacc.y,v 1.3 2008/07/10 18:29:51 swildner Exp $      */
3
4 %{
5 /*-
6  * Copyright (c)2003, 2006 Citrus Project,
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 #include <sys/types.h>
32 #include <assert.h>
33 #include <err.h>
34 #include <errno.h>
35 #include <limits.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #include <netinet/in.h>
42
43 #include "ldef.h"
44
45 #include "citrus_namespace.h"
46 #include "citrus_types.h"
47 #include "citrus_mapper_std_file.h"
48 #include "citrus_region.h"
49 #include "citrus_db_factory.h"
50 #include "citrus_db_hash.h"
51 #include "citrus_lookup_factory.h"
52 #include "citrus_pivot_factory.h"
53
54 extern FILE *   yyin;
55
56 int                     debug = 0;
57 static char             *output = NULL;
58 static void             *table = NULL;
59 static size_t           table_size;
60 static char             *map_name;
61 static int              map_type;
62 static u_int32_t        dst_invalid, dst_ilseq, oob_mode, dst_unit_bits;
63 static void             (*putfunc)(void *, size_t, u_int32_t) = 0;
64
65 static u_int32_t        src_next;
66
67 static u_int32_t        done_flag = 0;
68 #define DF_TYPE                 0x00000001
69 #define DF_NAME                 0x00000002
70 #define DF_SRC_ZONE             0x00000004
71 #define DF_DST_INVALID          0x00000008
72 #define DF_DST_ILSEQ            0x00000010
73 #define DF_DST_UNIT_BITS        0x00000020
74 #define DF_OOB_MODE             0x00000040
75
76 static linear_zone_t    rowcol[_CITRUS_MAPPER_STD_ROWCOL_MAX];
77 static size_t           rowcol_len = 0;
78 static u_int32_t        rowcol_bits = 0, rowcol_mask = 0;
79
80 static void     dump_file(void);
81 static void     setup_map(void);
82 static void     set_type(int);
83 static void     set_name(char *);
84 static void     set_src_zone(u_int32_t);
85 static void     set_dst_invalid(u_int32_t);
86 static void     set_dst_ilseq(u_int32_t);
87 static void     set_dst_unit_bits(u_int32_t);
88 static void     set_oob_mode(u_int32_t);
89 static int      check_src(u_int32_t, u_int32_t);
90 static void     store(const linear_zone_t *, u_int32_t, int);
91 static void     put8(void *, size_t, u_int32_t);
92 static void     put16(void *, size_t, u_int32_t);
93 static void     put32(void *, size_t, u_int32_t);
94 static void     set_range(u_int32_t, u_int32_t);
95 static void     set_src(linear_zone_t *, u_int32_t, u_int32_t);
96 %}
97
98 %union {
99         u_int32_t       i_value;
100         char            *s_value;
101         linear_zone_t   lz_value;
102 }
103
104 %token                  R_TYPE R_NAME R_SRC_ZONE R_DST_UNIT_BITS
105 %token                  R_DST_INVALID R_DST_ILSEQ
106 %token                  R_BEGIN_MAP R_END_MAP R_INVALID R_ROWCOL
107 %token                  R_ILSEQ R_OOB_MODE
108 %token                  R_LN
109 %token <i_value>        L_IMM
110 %token <s_value>        L_STRING
111
112 %type <lz_value>        src
113 %type <i_value>         dst types oob_mode_sel zone
114
115 %%
116
117 file            : property mapping lns
118                 { dump_file(); }
119
120 property        : /* empty */
121                 | property R_LN
122                 | property name
123                 | property type
124                 | property src_zone
125                 | property dst_invalid
126                 | property dst_ilseq
127                 | property dst_unit_bits
128                 | property oob_mode
129
130 name            : R_NAME L_STRING { set_name($2); $2 = NULL; }
131 type            : R_TYPE types { set_type($2); }
132 types           : R_ROWCOL { $$ = R_ROWCOL; }
133 range           : L_IMM '-' L_IMM { set_range($1, $3); }
134
135 ranges          : /* empty */
136                 | ranges range '/'
137
138 src_zone        : R_SRC_ZONE zone { set_src_zone($2); }
139 zone            : range {
140                         $$ = 32;
141                 }
142                 | range '/' range '/' ranges L_IMM {
143                         $$ = $6;
144                 }
145
146 dst_invalid     : R_DST_INVALID L_IMM { set_dst_invalid($2); }
147 dst_ilseq       : R_DST_ILSEQ L_IMM { set_dst_ilseq($2); }
148 dst_unit_bits   : R_DST_UNIT_BITS L_IMM { set_dst_unit_bits($2); }
149 oob_mode        : R_OOB_MODE oob_mode_sel { set_oob_mode($2); }
150
151 oob_mode_sel    : R_INVALID { $$ = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL; }
152                 | R_ILSEQ { $$ = _CITRUS_MAPPER_STD_OOB_ILSEQ; }
153
154 mapping         : begin_map map_elems R_END_MAP
155 begin_map       : R_BEGIN_MAP lns { setup_map(); }
156
157 map_elems       : /* empty */
158                 | map_elems map_elem lns
159
160 map_elem        : src '=' dst
161                 { store(&$1, $3, 0); }
162                 | src '=' L_IMM '-'
163                 { store(&$1, $3, 1); }
164 dst             : L_IMM
165                 {
166                         $$ = $1;
167                 }
168                 | R_INVALID
169                 {
170                         $$ = dst_invalid;
171                 }
172                 | R_ILSEQ
173                 {
174                         $$ = dst_ilseq;
175                 }
176
177 src             : /* empty */
178                 {
179                         set_src(&$$, src_next, src_next);
180                 }
181                 | L_IMM
182                 {
183                         set_src(&$$, $1, $1);
184                 }
185                 | L_IMM '-' L_IMM
186                 {
187                         set_src(&$$, $1, $3);
188                 }
189                 | '-' L_IMM
190                 {
191                         set_src(&$$, src_next, $2);
192                 }
193 lns             : R_LN
194                 | lns R_LN
195
196 %%
197
198 static void
199 warning(const char *s)
200 {
201         fprintf(stderr, "%s in %d\n", s, line_number);
202 }
203
204 int
205 yyerror(const char *s)
206 {
207         warning(s);
208         exit(1);
209 }
210
211 void
212 put8(void *ptr, size_t ofs, u_int32_t val)
213 {
214         *((u_int8_t *)ptr + ofs) = val;
215 }
216
217 void
218 put16(void *ptr, size_t ofs, u_int32_t val)
219 {
220         u_int16_t oval = htons(val);
221         memcpy((u_int16_t *)ptr + ofs, &oval, 2);
222 }
223
224 void
225 put32(void *ptr, size_t ofs, u_int32_t val)
226 {
227         u_int32_t oval = htonl(val);
228         memcpy((u_int32_t *)ptr + ofs, &oval, 4);
229 }
230
231 static void
232 alloc_table(void)
233 {
234         size_t i;
235         u_int32_t val = 0;
236         linear_zone_t *p;
237
238         i = rowcol_len;
239         p = &rowcol[--i];
240         table_size = p->width;
241         while (i > 0) {
242                 p = &rowcol[--i];
243                 table_size *= p->width;
244         }
245         table = (void *)malloc(table_size * dst_unit_bits / 8);
246         if (table == NULL) {
247                 perror("malloc");
248                 exit(1);
249         }
250
251         switch (oob_mode) {
252         case _CITRUS_MAPPER_STD_OOB_NONIDENTICAL:
253                 val = dst_invalid;
254                 break;
255         case _CITRUS_MAPPER_STD_OOB_ILSEQ:
256                 val = dst_ilseq;
257                 break;
258         default:
259                 ;
260         }
261         for (i = 0; i < table_size; i++)
262                 (*putfunc)(table, i, val);
263 }
264
265 static void
266 setup_map(void)
267 {
268
269         if ((done_flag & DF_SRC_ZONE)==0) {
270                 fprintf(stderr, "SRC_ZONE is mandatory.\n");
271                 exit(1);
272         }
273         if ((done_flag & DF_DST_UNIT_BITS)==0) {
274                 fprintf(stderr, "DST_UNIT_BITS is mandatory.\n");
275                 exit(1);
276         }
277
278         if ((done_flag & DF_DST_INVALID) == 0)
279                 dst_invalid = 0xFFFFFFFF;
280         if ((done_flag & DF_DST_ILSEQ) == 0)
281                 dst_ilseq = 0xFFFFFFFE;
282         if ((done_flag & DF_OOB_MODE) == 0)
283                 oob_mode = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL;
284
285         alloc_table();
286 }
287
288 static void
289 create_rowcol_info(struct _region *r)
290 {
291         void *ptr;
292         size_t ofs, i, len;
293
294         ofs = 0;
295         ptr = malloc(_CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE);
296         if (ptr == NULL)
297                 err(EXIT_FAILURE, "malloc");
298         put32(ptr, ofs, rowcol_bits); ofs++;
299         put32(ptr, ofs, dst_invalid); ofs++;
300
301         /* XXX: keep backward compatibility */
302         switch (rowcol_len) {
303         case 1:
304                 put32(ptr, ofs, 0); ofs++;
305                 put32(ptr, ofs, 0); ofs++;
306         /*FALLTHROUGH*/
307         case 2:
308                 len = 0;
309                 break;
310         default:
311                 len = rowcol_len;
312         }
313         for (i = 0; i < rowcol_len; ++i) {
314                 put32(ptr, ofs, rowcol[i].begin); ofs++;
315                 put32(ptr, ofs, rowcol[i].end); ofs++;
316         }
317         put32(ptr, ofs, dst_unit_bits); ofs++;
318         put32(ptr, ofs, len); ofs++;
319
320         _region_init(r, ptr, ofs * 4);
321 }
322
323
324 static void
325 create_rowcol_ext_ilseq_info(struct _region *r)
326 {
327         void *ptr;
328         size_t ofs;
329
330         ofs = 0;
331         ptr = malloc(_CITRUS_MAPPER_STD_ROWCOL_EXT_ILSEQ_SIZE);
332         if (ptr==NULL)
333                 err(EXIT_FAILURE, "malloc");
334
335         put32(ptr, ofs, oob_mode); ofs++;
336         put32(ptr, ofs, dst_ilseq); ofs++;
337
338         _region_init(r, ptr, _CITRUS_MAPPER_STD_ROWCOL_EXT_ILSEQ_SIZE);
339 }
340
341 #define CHKERR(ret, func, a)                                            \
342 do {                                                                    \
343         ret = func a;                                                   \
344         if (ret)                                                        \
345                 errx(EXIT_FAILURE, "%s: %s", #func, strerror(ret));     \
346 } while (/*CONSTCOND*/0)
347
348 static void
349 dump_file(void)
350 {
351         FILE *fp;
352         int ret;
353         struct _db_factory *df;
354         struct _region data;
355         void *serialized;
356         size_t size;
357
358         /*
359          * build database
360          */
361         CHKERR(ret, _db_factory_create, (&df, _db_hash_std, NULL));
362
363         /* store type */
364         CHKERR(ret, _db_factory_addstr_by_s,
365                (df, _CITRUS_MAPPER_STD_SYM_TYPE,
366                 _CITRUS_MAPPER_STD_TYPE_ROWCOL));
367
368         /* store info */
369         create_rowcol_info(&data);
370         CHKERR(ret, _db_factory_add_by_s,
371                (df, _CITRUS_MAPPER_STD_SYM_INFO, &data, 1));
372
373         /* ilseq extension */
374         create_rowcol_ext_ilseq_info(&data);
375         CHKERR(ret, _db_factory_add_by_s,
376                (df, _CITRUS_MAPPER_STD_SYM_ROWCOL_EXT_ILSEQ, &data, 1));
377
378         /* store table */
379         _region_init(&data, table, table_size*dst_unit_bits/8);
380         CHKERR(ret, _db_factory_add_by_s,
381                (df, _CITRUS_MAPPER_STD_SYM_TABLE, &data, 1));
382
383         /*
384          * dump database to file
385          */
386         if (output)
387                 fp = fopen(output, "wb");
388         else
389                 fp = stdout;
390
391         if (fp == NULL) {
392                 perror("fopen");
393                 exit(1);
394         }
395
396         /* dump database body */
397         size = _db_factory_calc_size(df);
398         serialized = malloc(size);
399         _region_init(&data, serialized, size);
400         CHKERR(ret, _db_factory_serialize,
401                (df, _CITRUS_MAPPER_STD_MAGIC, &data));
402         if (fwrite(serialized, size, 1, fp) != 1)
403                 err(EXIT_FAILURE, "fwrite");
404
405         fclose(fp);
406 }
407
408 static void
409 /*ARGSUSED*/
410 set_type(int type)
411 {
412
413         if (done_flag & DF_TYPE) {
414                 warning("TYPE is duplicated. ignored this one");
415                 return;
416         }
417
418         map_type = type;
419
420         done_flag |= DF_TYPE;
421 }
422 static void
423 /*ARGSUSED*/
424 set_name(char *str)
425 {
426
427         if (done_flag & DF_NAME) {
428                 warning("NAME is duplicated. ignored this one");
429                 return;
430         }
431
432         map_name = str;
433
434         done_flag |= DF_NAME;
435 }
436 static void
437 set_src_zone(u_int32_t val)
438 {
439         size_t i;
440         linear_zone_t *p;
441
442         if (done_flag & DF_SRC_ZONE) {
443                 warning("SRC_ZONE is duplicated. ignored this one");
444                 return;
445         }
446         rowcol_bits = val;
447
448         /* sanity check */
449         switch (rowcol_bits) {
450         case 8: case 16: case 32:
451                 if (rowcol_len <= 32 / rowcol_bits)
452                         break;
453         /*FALLTHROUGH*/
454         default: 
455                 goto bad;
456         }
457         rowcol_mask = 1 << (rowcol_bits - 1);
458         rowcol_mask |= rowcol_mask - 1;
459         for (i = 0; i < rowcol_len; ++i) {
460                 p = &rowcol[i];
461                 _DIAGASSERT(p->begin <= p->end);
462                 if (p->end > rowcol_mask)
463                         goto bad;
464         }
465         done_flag |= DF_SRC_ZONE;
466         return;
467
468 bad:
469         yyerror("Illegal argument for SRC_ZONE");
470 }
471 static void
472 set_dst_invalid(u_int32_t val)
473 {
474
475         if (done_flag & DF_DST_INVALID) {
476                 warning("DST_INVALID is duplicated. ignored this one");
477                 return;
478         }
479
480         dst_invalid = val;
481
482         done_flag |= DF_DST_INVALID;
483 }
484 static void
485 set_dst_ilseq(u_int32_t val)
486 {
487
488         if (done_flag & DF_DST_ILSEQ) {
489                 warning("DST_ILSEQ is duplicated. ignored this one");
490                 return;
491         }
492
493         dst_ilseq = val;
494
495         done_flag |= DF_DST_ILSEQ;
496 }
497 static void
498 set_oob_mode(u_int32_t val)
499 {
500
501         if (done_flag & DF_OOB_MODE) {
502                 warning("OOB_MODE is duplicated. ignored this one");
503                 return;
504         }
505
506         oob_mode = val;
507
508         done_flag |= DF_OOB_MODE;
509 }
510 static void
511 set_dst_unit_bits(u_int32_t val)
512 {
513
514         if (done_flag & DF_DST_UNIT_BITS) {
515                 warning("DST_UNIT_BITS is duplicated. ignored this one");
516                 return;
517         }
518
519         switch (val) {
520         case 8:
521                 putfunc = &put8;
522                 dst_unit_bits = val;
523                 break;
524         case 16:
525                 putfunc = &put16;
526                 dst_unit_bits = val;
527                 break;
528         case 32:
529                 putfunc = &put32;
530                 dst_unit_bits = val;
531                 break;
532         default:
533                 yyerror("Illegal argument for DST_UNIT_BITS");
534         }
535         done_flag |= DF_DST_UNIT_BITS;
536 }
537 static int
538 check_src(u_int32_t begin, u_int32_t end)
539 {
540         size_t i;
541         linear_zone_t *p;
542         u_int32_t m, n;
543
544         if (begin > end)
545                 return 1;
546         if (begin < end) {
547                 m = begin & ~rowcol_mask;
548                 n = end & ~rowcol_mask;
549                 if (m != n)
550                         return 1;
551         }
552         for (i = rowcol_len * rowcol_bits, p = &rowcol[0]; i > 0; ++p) {
553                 i -= rowcol_bits;
554                 m = (begin >> i) & rowcol_mask;
555                 if (m < p->begin || m > p->end)
556                         return 1;
557         }
558         if (begin < end) {
559                 n = end & rowcol_mask;
560                 _DIAGASSERT(p > rowcol);
561                 --p;
562                 if (n < p->begin || n > p->end)
563                         return 1;
564         }
565         return 0;
566 }
567 static void
568 store(const linear_zone_t *lz, u_int32_t dst, int inc)
569 {
570         size_t i, ofs;
571         linear_zone_t *p;
572         u_int32_t n;
573
574         ofs = 0;
575         for (i = rowcol_len * rowcol_bits, p = &rowcol[0]; i > 0; ++p) {
576                 i -= rowcol_bits;
577                 n = ((lz->begin >> i) & rowcol_mask) - p->begin;
578                 ofs = (ofs * p->width) + n;
579         }
580         n = lz->width;
581         while (n-- > 0) {
582                 (*putfunc)(table, ofs++, dst);
583                 if (inc)
584                         dst++;
585         }
586 }
587 static void
588 set_range(u_int32_t begin, u_int32_t end)
589 {
590         linear_zone_t *p;
591
592         if (rowcol_len >= _CITRUS_MAPPER_STD_ROWCOL_MAX)
593                 goto bad;
594         p = &rowcol[rowcol_len++];
595
596         if (begin > end)
597                 goto bad;
598         p->begin = begin, p->end = end;
599         p->width = end - begin + 1;
600
601         return;
602
603 bad:
604         yyerror("Illegal argument for SRC_ZONE");
605 }
606 static void
607 set_src(linear_zone_t *lz, u_int32_t begin, u_int32_t end)
608 {
609         _DIAGASSERT(lz != NULL);
610
611         if (check_src(begin, end) != 0)
612                 yyerror("illegal zone");
613
614         lz->begin = begin, lz->end = end;
615         lz->width = end - begin + 1;
616
617         src_next = end + 1;
618 }
619
620 static void
621 do_mkdb(FILE *in)
622 {
623         int ret;
624         FILE *out;
625
626         /* dump DB to file */
627         if (output)
628                 out = fopen(output, "wb");
629         else
630                 out = stdout;
631
632         if (out==NULL)
633                 err(EXIT_FAILURE, "fopen");
634
635         ret = _lookup_factory_convert(out, in);
636         fclose(out);
637         if (ret && output)
638                 unlink(output); /* dump failure */
639 }
640
641 static void
642 do_mkpv(FILE *in)
643 {
644         int ret;
645         FILE *out;
646
647         /* dump pivot to file */
648         if (output)
649                 out = fopen(output, "wb");
650         else
651                 out = stdout;
652
653         if (out==NULL)
654                 err(EXIT_FAILURE, "fopen");
655
656         ret = _pivot_factory_convert(out, in);
657         fclose(out);
658         if (ret && output)
659                 unlink(output); /* dump failure */
660         if (ret)
661                 errx(EXIT_FAILURE, "%s\n", strerror(ret));
662 }
663
664 static void
665 usage(void)
666 {
667         warnx("usage: \n"
668               "\t%s [-d] [-o outfile] [infile]\n"
669               "\t%s -m [-d] [-o outfile] [infile]\n"
670               "\t%s -p [-d] [-o outfile] [infile]\n",
671               getprogname(), getprogname(), getprogname());
672         exit(1);
673 }
674
675 int
676 main(int argc, char **argv)
677 {
678         int ch;
679         FILE *in = NULL;
680         int mkdb = 0, mkpv = 0;
681
682         while ((ch = getopt(argc, argv, "do:mp")) != -1) {
683                 switch (ch) {
684                 case 'd':
685                         debug=1;
686                         break;
687                 case 'o':
688                         output = strdup(optarg);
689                         break;
690                 case 'm':
691                         mkdb = 1;
692                         break;
693                 case 'p':
694                         mkpv = 1;
695                         break;
696                 default:
697                         usage();
698                 }
699         }
700
701         argc-=optind;
702         argv+=optind;
703         switch (argc) {
704         case 0:
705                 in = stdin;
706                 break;
707         case 1:
708                 in = fopen(argv[0], "r");
709                 if (!in)
710                         err(EXIT_FAILURE, argv[0]);
711                 break;
712         default:
713                 usage();
714         }
715
716         if (mkdb)
717                 do_mkdb(in);
718         else if (mkpv)
719                 do_mkpv(in);
720         else {
721                 yyin = in;
722                 yyparse();
723         }
724
725         return (0);
726 }