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