Sync the uplcom(4) driver with FreeBSD.
[dragonfly.git] / usr.bin / mkcsmapper / yacc.y
1 /*      $NetBSD: src/usr.bin/mkcsmapper/yacc.y,v 1.5 2004/01/05 19:20:10 itojun Exp $   */
2 /*      $DragonFly: src/usr.bin/mkcsmapper/yacc.y,v 1.1 2005/03/11 20:17:11 joerg Exp $ */
3
4 %{
5 /*-
6  * Copyright (c)2003 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 zone_t           src_zone;
63 static u_int32_t        colmask, rowmask;
64 static u_int32_t        dst_invalid, dst_ilseq, oob_mode, dst_unit_bits;
65 static void             (*putfunc)(void *, size_t, u_int32_t) = 0;
66
67 static u_int32_t        src_next;
68 static int              next_valid;
69
70 static u_int32_t        done_flag = 0;
71 #define DF_TYPE                 0x00000001
72 #define DF_NAME                 0x00000002
73 #define DF_SRC_ZONE             0x00000004
74 #define DF_DST_INVALID          0x00000008
75 #define DF_DST_ILSEQ            0x00000010
76 #define DF_DST_UNIT_BITS        0x00000020
77 #define DF_OOB_MODE             0x00000040
78
79 static void     dump_file(void);
80 static void     setup_map(void);
81 static void     set_type(int);
82 static void     set_name(char *);
83 static void     set_src_zone(const zone_t *);
84 static void     set_dst_invalid(u_int32_t);
85 static void     set_dst_ilseq(u_int32_t);
86 static void     set_dst_unit_bits(u_int32_t);
87 static void     set_oob_mode(u_int32_t);
88 static void     calc_next(void);
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 %}
95
96 %union {
97         u_int32_t       i_value;
98         char            *s_value;
99         zone_t          z_value;
100         linear_zone_t   lz_value;
101 }
102
103 %token                  R_TYPE R_NAME R_SRC_ZONE R_DST_UNIT_BITS
104 %token                  R_DST_INVALID R_DST_ILSEQ
105 %token                  R_BEGIN_MAP R_END_MAP R_INVALID R_ROWCOL
106 %token                  R_ILSEQ R_OOB_MODE
107 %token                  R_LN
108 %token <i_value>        L_IMM
109 %token <s_value>        L_STRING
110
111 %type <z_value>         zone
112 %type <lz_value>        src
113 %type <i_value>         dst types oob_mode_sel
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 src_zone        : R_SRC_ZONE zone { set_src_zone(&$2); }
134 zone            : L_IMM '-' L_IMM {
135                         $$.row_begin = $$.row_end = 0;
136                         $$.col_begin = $1; $$.col_end = $3;
137                         $$.col_bits = 32;
138                 }
139                 | L_IMM '-' L_IMM '/' L_IMM '-' L_IMM '/' L_IMM {
140                         $$.row_begin = $1; $$.row_end = $3;
141                         $$.col_begin = $5; $$.col_end = $7;
142                         $$.col_bits = $9;
143                 }
144
145 dst_invalid     : R_DST_INVALID L_IMM { set_dst_invalid($2); }
146 dst_ilseq       : R_DST_ILSEQ L_IMM { set_dst_ilseq($2); }
147 dst_unit_bits   : R_DST_UNIT_BITS L_IMM { set_dst_unit_bits($2); }
148 oob_mode        : R_OOB_MODE oob_mode_sel { set_oob_mode($2); }
149
150 oob_mode_sel    : R_INVALID { $$ = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL; }
151                 | R_ILSEQ { $$ = _CITRUS_MAPPER_STD_OOB_ILSEQ; }
152
153 mapping         : begin_map map_elems R_END_MAP
154 begin_map       : R_BEGIN_MAP lns { setup_map(); }
155
156 map_elems       : /* empty */
157                 | map_elems map_elem lns
158
159 map_elem        : src '=' dst
160                 { store(&$1, $3, 0); }
161                 | src '=' L_IMM '-'
162                 { store(&$1, $3, 1); }
163 dst             : L_IMM
164                 {
165                         $$ = $1;
166                 }
167                 | R_INVALID
168                 {
169                         $$ = dst_invalid;
170                 }
171                 | R_ILSEQ
172                 {
173                         $$ = dst_ilseq;
174                 }
175
176 src             : /* empty */
177                 {
178                         if (!next_valid) {
179                                 yyerror("cannot omit src");
180                         }
181                         $$.begin = $$.end = src_next;
182                         calc_next();
183                 }
184                 | L_IMM
185                 {
186                         if (check_src($1, $1)) {
187                                 yyerror("illegal zone");
188                         }
189                         $$.begin = $$.end = $1;
190                         src_next = $1;
191                         calc_next();
192                 }
193                 | L_IMM '-' L_IMM
194                 {
195                         if (check_src($1, $3)) {
196                                 yyerror("illegal zone");
197                         }
198                         $$.begin = $1; $$.end = $3;
199                         src_next = $3;
200                         calc_next();
201                 }
202                 | '-' L_IMM
203                 {
204                         if (!next_valid) {
205                                 yyerror("cannot omit src");
206                         }
207                         if (check_src(src_next, $2)) {
208                                 yyerror("illegal zone");
209                         }
210                         $$.begin = src_next; $$.end = $2;
211                         src_next = $2;
212                         calc_next();
213                 }
214 lns             : R_LN
215                 | lns R_LN
216
217 %%
218
219 static void
220 warning(const char *s)
221 {
222         fprintf(stderr, "%s in %d\n", s, line_number);
223 }
224
225 int
226 yyerror(const char *s)
227 {
228         warning(s);
229         exit(1);
230 }
231
232 void
233 put8(void *ptr, size_t ofs, u_int32_t val)
234 {
235         *((u_int8_t *)ptr + ofs) = val;
236 }
237
238 void
239 put16(void *ptr, size_t ofs, u_int32_t val)
240 {
241         u_int16_t oval = htons(val);
242         memcpy((u_int16_t *)ptr + ofs, &oval, 2);
243 }
244
245 void
246 put32(void *ptr, size_t ofs, u_int32_t val)
247 {
248         u_int32_t oval = htonl(val);
249         memcpy((u_int32_t *)ptr + ofs, &oval, 4);
250 }
251
252 static void
253 alloc_table(void)
254 {
255         size_t i;
256         u_int32_t val = 0;
257
258         table_size =
259             (src_zone.row_end-src_zone.row_begin + 1) *
260             (src_zone.col_end-src_zone.col_begin + 1);
261         table = malloc(table_size*dst_unit_bits / 8);
262         if (!table) {
263                 perror("malloc");
264                 exit(1);
265         }
266
267         switch (oob_mode) {
268         case _CITRUS_MAPPER_STD_OOB_NONIDENTICAL:
269                 val = dst_invalid;
270                 break;
271         case _CITRUS_MAPPER_STD_OOB_ILSEQ:
272                 val = dst_ilseq;
273                 break;
274         default:
275                 ;
276         }
277         for (i = 0; i < table_size; i++)
278                 (*putfunc)(table, i, val);
279 }
280
281 static void
282 setup_map(void)
283 {
284
285         if ((done_flag & DF_SRC_ZONE)==0) {
286                 fprintf(stderr, "SRC_ZONE is mandatory.\n");
287                 exit(1);
288         }
289         if ((done_flag & DF_DST_UNIT_BITS)==0) {
290                 fprintf(stderr, "DST_UNIT_BITS is mandatory.\n");
291                 exit(1);
292         }
293
294         if ((done_flag & DF_DST_INVALID) == 0)
295                 dst_invalid = 0xFFFFFFFF;
296         if ((done_flag & DF_DST_ILSEQ) == 0)
297                 dst_ilseq = 0xFFFFFFFE;
298         if ((done_flag & DF_OOB_MODE) == 0)
299                 oob_mode = _CITRUS_MAPPER_STD_OOB_NONIDENTICAL;
300
301         alloc_table();
302 }
303
304 static void
305 create_rowcol_info(struct _region *r)
306 {
307         void *ptr;
308         size_t ofs;
309
310         ofs = 0;
311         ptr = malloc(_CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE);
312         if (ptr==NULL)
313                 err(EXIT_FAILURE, "malloc");
314
315         put32(ptr, ofs, src_zone.col_bits); ofs++;
316         put32(ptr, ofs, dst_invalid); ofs++;
317         put32(ptr, ofs, src_zone.row_begin); ofs++;
318         put32(ptr, ofs, src_zone.row_end); ofs++;
319         put32(ptr, ofs, src_zone.col_begin); ofs++;
320         put32(ptr, ofs, src_zone.col_end); ofs++;
321         put32(ptr, ofs, dst_unit_bits); ofs++;
322         put32(ptr, ofs, 0); /* pad */
323
324         _region_init(r, ptr, _CITRUS_MAPPER_STD_ROWCOL_INFO_SIZE);
325 }
326
327 static void
328 create_rowcol_ext_ilseq_info(struct _region *r)
329 {
330         void *ptr;
331         size_t ofs;
332
333         ofs = 0;
334         ptr = malloc(_CITRUS_MAPPER_STD_ROWCOL_EXT_ILSEQ_SIZE);
335         if (ptr==NULL)
336                 err(EXIT_FAILURE, "malloc");
337
338         put32(ptr, ofs, oob_mode); ofs++;
339         put32(ptr, ofs, dst_ilseq); ofs++;
340
341         _region_init(r, ptr, _CITRUS_MAPPER_STD_ROWCOL_EXT_ILSEQ_SIZE);
342 }
343
344 #define CHKERR(ret, func, a)                                            \
345 do {                                                                    \
346         ret = func a;                                                   \
347         if (ret)                                                        \
348                 errx(EXIT_FAILURE, "%s: %s", #func, strerror(ret));     \
349 } while (/*CONSTCOND*/0)
350
351 static void
352 dump_file(void)
353 {
354         FILE *fp;
355         int ret;
356         struct _db_factory *df;
357         struct _region data;
358         void *serialized;
359         size_t size;
360
361         /*
362          * build database
363          */
364         CHKERR(ret, _db_factory_create, (&df, _db_hash_std, NULL));
365
366         /* store type */
367         CHKERR(ret, _db_factory_addstr_by_s,
368                (df, _CITRUS_MAPPER_STD_SYM_TYPE,
369                 _CITRUS_MAPPER_STD_TYPE_ROWCOL));
370
371         /* store info */
372         create_rowcol_info(&data);
373         CHKERR(ret, _db_factory_add_by_s,
374                (df, _CITRUS_MAPPER_STD_SYM_INFO, &data, 1));
375
376         /* ilseq extension */
377         create_rowcol_ext_ilseq_info(&data);
378         CHKERR(ret, _db_factory_add_by_s,
379                (df, _CITRUS_MAPPER_STD_SYM_ROWCOL_EXT_ILSEQ, &data, 1));
380
381         /* store table */
382         _region_init(&data, table, table_size*dst_unit_bits/8);
383         CHKERR(ret, _db_factory_add_by_s,
384                (df, _CITRUS_MAPPER_STD_SYM_TABLE, &data, 1));
385
386         /*
387          * dump database to file
388          */
389         if (output)
390                 fp = fopen(output, "wb");
391         else
392                 fp = stdout;
393
394         if (fp == NULL) {
395                 perror("fopen");
396                 exit(1);
397         }
398
399         /* dump database body */
400         size = _db_factory_calc_size(df);
401         serialized = malloc(size);
402         _region_init(&data, serialized, size);
403         CHKERR(ret, _db_factory_serialize,
404                (df, _CITRUS_MAPPER_STD_MAGIC, &data));
405         if (fwrite(serialized, size, 1, fp) != 1)
406                 err(EXIT_FAILURE, "fwrite");
407
408         fclose(fp);
409 }
410
411 static void
412 /*ARGSUSED*/
413 set_type(int type)
414 {
415
416         if (done_flag & DF_TYPE) {
417                 warning("TYPE is duplicated. ignored this one");
418                 return;
419         }
420
421         map_type = type;
422
423         done_flag |= DF_TYPE;
424 }
425 static void
426 /*ARGSUSED*/
427 set_name(char *str)
428 {
429
430         if (done_flag & DF_NAME) {
431                 warning("NAME is duplicated. ignored this one");
432                 return;
433         }
434
435         map_name = str;
436
437         done_flag |= DF_NAME;
438 }
439 static void
440 set_src_zone(const zone_t *zone)
441 {
442
443         if (done_flag & DF_SRC_ZONE) {
444                 warning("SRC_ZONE is duplicated. ignored this one");
445                 return;
446         }
447
448         /* sanity check */
449         if (zone->col_bits < 1 || zone->col_bits > 32) {
450                 goto bad;
451         }
452
453         if (zone->col_bits != 32)
454                 colmask = (1 << zone->col_bits )- 1;
455         else
456                 colmask = ~0;
457         rowmask = ~colmask;
458         if (zone->col_begin > zone->col_end ||
459             zone->row_begin > zone->row_end ||
460             (zone->col_begin & rowmask) != 0 ||
461             (zone->col_end & rowmask) != 0 ||
462             ((zone->row_begin << zone->col_bits) & colmask) != 0 ||
463             ((zone->row_end << zone->col_bits) & colmask) != 0) {
464 bad:
465                 yyerror("Illegal argument for SRC_ZONE");
466         }
467
468         src_zone = *zone;
469
470         done_flag |= DF_SRC_ZONE;
471
472         return;
473 }
474 static void
475 set_dst_invalid(u_int32_t val)
476 {
477
478         if (done_flag & DF_DST_INVALID) {
479                 warning("DST_INVALID is duplicated. ignored this one");
480                 return;
481         }
482
483         dst_invalid = val;
484
485         done_flag |= DF_DST_INVALID;
486 }
487 static void
488 set_dst_ilseq(u_int32_t val)
489 {
490
491         if (done_flag & DF_DST_ILSEQ) {
492                 warning("DST_ILSEQ is duplicated. ignored this one");
493                 return;
494         }
495
496         dst_ilseq = val;
497
498         done_flag |= DF_DST_ILSEQ;
499 }
500 static void
501 set_oob_mode(u_int32_t val)
502 {
503
504         if (done_flag & DF_OOB_MODE) {
505                 warning("OOB_MODE is duplicated. ignored this one");
506                 return;
507         }
508
509         oob_mode = val;
510
511         done_flag |= DF_OOB_MODE;
512 }
513 static void
514 set_dst_unit_bits(u_int32_t val)
515 {
516
517         if (done_flag & DF_DST_UNIT_BITS) {
518                 warning("DST_UNIT_BITS is duplicated. ignored this one");
519                 return;
520         }
521
522         switch (val) {
523         case 8:
524                 putfunc = &put8;
525                 dst_unit_bits = val;
526                 break;
527         case 16:
528                 putfunc = &put16;
529                 dst_unit_bits = val;
530                 break;
531         case 32:
532                 putfunc = &put32;
533                 dst_unit_bits = val;
534                 break;
535         default:
536                 yyerror("Illegal argument for DST_UNIT_BITS");
537         }
538         done_flag |= DF_DST_UNIT_BITS;
539 }
540 static void
541 calc_next(void)
542 {
543         src_next++;
544         if (check_src(src_next, src_next))
545                 next_valid = 0;
546         else
547                 next_valid = 1;
548 }
549 static int
550 check_src(u_int32_t begin, u_int32_t end)
551 {
552         u_int32_t b_row = 0, e_row = 0, b_col, e_col;
553
554         b_col = begin & colmask;
555         e_col = end & colmask;
556         if (src_zone.col_bits != 32) {
557                 b_row = begin >> src_zone.col_bits;
558                 e_row = end >> src_zone.col_bits;
559         }
560
561         if (b_row != e_row ||
562             b_row < src_zone.row_begin ||
563             b_row > src_zone.row_end ||
564             e_row < src_zone.row_begin ||
565             e_row > src_zone.row_end ||
566             b_col < src_zone.col_begin ||
567             b_col > src_zone.col_end ||
568             e_col < src_zone.col_begin ||
569             e_col > src_zone.col_end ||
570             b_col>e_col) {
571                 return (-1);
572         }
573         return (0);
574 }
575 static void
576 store(const linear_zone_t *lz, u_int32_t dst, int inc)
577 {
578         u_int32_t row=0, col, ofs, i;
579
580         if (src_zone.col_bits != 32)
581                 row = lz->begin >> src_zone.col_bits;
582         col = lz->begin & colmask;
583         ofs = (row-src_zone.row_begin) *
584             (src_zone.col_end-src_zone.col_begin + 1) +
585             (col-src_zone.col_begin);
586         for (i = lz->end - lz->begin + 1; i > 0; i--) {
587                 (*putfunc)(table, ofs++, dst);
588                 if (inc)
589                         dst++;
590         }
591 }
592
593 static void
594 do_mkdb(FILE *in)
595 {
596         int ret;
597         FILE *out;
598
599         /* dump DB to file */
600         if (output)
601                 out = fopen(output, "wb");
602         else
603                 out = stdout;
604
605         if (out==NULL)
606                 err(EXIT_FAILURE, "fopen");
607
608         ret = _lookup_factory_convert(out, in);
609         fclose(out);
610         if (ret && output)
611                 unlink(output); /* dump failure */
612 }
613
614 static void
615 do_mkpv(FILE *in)
616 {
617         int ret;
618         FILE *out;
619
620         /* dump pivot to file */
621         if (output)
622                 out = fopen(output, "wb");
623         else
624                 out = stdout;
625
626         if (out==NULL)
627                 err(EXIT_FAILURE, "fopen");
628
629         ret = _pivot_factory_convert(out, in);
630         fclose(out);
631         if (ret && output)
632                 unlink(output); /* dump failure */
633         if (ret)
634                 errx(EXIT_FAILURE, "%s\n", strerror(ret));
635 }
636
637 static void
638 usage(void)
639 {
640         warnx("usage: \n"
641               "\t%s [-d] [-o outfile] [infile]\n"
642               "\t%s -m [-d] [-o outfile] [infile]\n"
643               "\t%s -p [-d] [-o outfile] [infile]\n",
644               getprogname(), getprogname(), getprogname());
645         exit(1);
646 }
647
648 int
649 main(int argc, char **argv)
650 {
651         int ch;
652         FILE *in = NULL;
653         int mkdb = 0, mkpv = 0;
654
655         while ((ch = getopt(argc, argv, "do:mp")) != EOF) {
656                 switch (ch) {
657                 case 'd':
658                         debug=1;
659                         break;
660                 case 'o':
661                         output = strdup(optarg);
662                         break;
663                 case 'm':
664                         mkdb = 1;
665                         break;
666                 case 'p':
667                         mkpv = 1;
668                         break;
669                 default:
670                         usage();
671                 }
672         }
673
674         argc-=optind;
675         argv+=optind;
676         switch (argc) {
677         case 0:
678                 in = stdin;
679                 break;
680         case 1:
681                 in = fopen(argv[0], "r");
682                 if (!in)
683                         err(EXIT_FAILURE, argv[0]);
684                 break;
685         default:
686                 usage();
687         }
688
689         if (mkdb)
690                 do_mkdb(in);
691         else if (mkpv)
692                 do_mkpv(in);
693         else {
694                 yyin = in;
695                 yyparse();
696         }
697
698         return (0);
699 }