1 %{ 2 /* 3 * Copyright (c) 2004-2006 Kungliga Tekniska H�gskolan 4 * (Royal Institute of Technology, Stockholm, Sweden). 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 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 * 3. Neither the name of the Institute nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #ifdef HAVE_CONFIG_H 36 #include <config.h> 37 RCSID("$Id: slc-gram.y 20767 2007-06-01 11:24:52Z lha $"); 38 #endif 39 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <err.h> 43 #include <ctype.h> 44 #include <limits.h> 45 #include <getarg.h> 46 #include <vers.h> 47 #include <roken.h> 48 49 #include "slc.h" 50 extern FILE *yyin; 51 extern struct assignment *assignment; 52 %} 53 54 %union { 55 char *string; 56 struct assignment *assignment; 57 } 58 59 %token <string> LITERAL 60 %token <string> STRING 61 %type <assignment> assignment assignments 62 63 %start start 64 65 %% 66 67 start : assignments 68 { 69 assignment = $1; 70 } 71 ; 72 73 assignments : assignment assignments 74 { 75 $1->next = $2; 76 $$ = $1; 77 } 78 | assignment 79 ; 80 81 assignment : LITERAL '=' STRING 82 { 83 $$ = malloc(sizeof(*$$)); 84 $$->name = $1; 85 $$->type = a_value; 86 $$->lineno = lineno; 87 $$->u.value = $3; 88 $$->next = NULL; 89 } 90 | LITERAL '=' '{' assignments '}' 91 { 92 $$ = malloc(sizeof(*$$)); 93 $$->name = $1; 94 $$->type = a_assignment; 95 $$->lineno = lineno; 96 $$->u.assignment = $4; 97 $$->next = NULL; 98 } 99 ; 100 101 %% 102 char *filename; 103 FILE *cfile, *hfile; 104 int error_flag; 105 struct assignment *assignment; 106 107 108 static void 109 ex(struct assignment *a, const char *fmt, ...) 110 { 111 va_list ap; 112 fprintf(stderr, "%s:%d: ", a->name, a->lineno); 113 va_start(ap, fmt); 114 vfprintf(stderr, fmt, ap); 115 va_end(ap); 116 fprintf(stderr, "\n"); 117 } 118 119 120 121 static int 122 check_option(struct assignment *as) 123 { 124 struct assignment *a; 125 int seen_long = 0; 126 int seen_short = 0; 127 int seen_type = 0; 128 int seen_argument = 0; 129 int seen_help = 0; 130 int seen_default = 0; 131 int ret = 0; 132 133 for(a = as; a != NULL; a = a->next) { 134 if(strcmp(a->name, "long") == 0) 135 seen_long++; 136 else if(strcmp(a->name, "short") == 0) 137 seen_short++; 138 else if(strcmp(a->name, "type") == 0) 139 seen_type++; 140 else if(strcmp(a->name, "argument") == 0) 141 seen_argument++; 142 else if(strcmp(a->name, "help") == 0) 143 seen_help++; 144 else if(strcmp(a->name, "default") == 0) 145 seen_default++; 146 else { 147 ex(a, "unknown name"); 148 ret++; 149 } 150 } 151 if(seen_long == 0 && seen_short == 0) { 152 ex(as, "neither long nor short option"); 153 ret++; 154 } 155 if(seen_long > 1) { 156 ex(as, "multiple long options"); 157 ret++; 158 } 159 if(seen_short > 1) { 160 ex(as, "multiple short options"); 161 ret++; 162 } 163 if(seen_type > 1) { 164 ex(as, "multiple types"); 165 ret++; 166 } 167 if(seen_argument > 1) { 168 ex(as, "multiple arguments"); 169 ret++; 170 } 171 if(seen_help > 1) { 172 ex(as, "multiple help strings"); 173 ret++; 174 } 175 if(seen_default > 1) { 176 ex(as, "multiple default values"); 177 ret++; 178 } 179 return ret; 180 } 181 182 static int 183 check_command(struct assignment *as) 184 { 185 struct assignment *a; 186 int seen_name = 0; 187 int seen_function = 0; 188 int seen_help = 0; 189 int seen_argument = 0; 190 int seen_minargs = 0; 191 int seen_maxargs = 0; 192 int ret = 0; 193 for(a = as; a != NULL; a = a->next) { 194 if(strcmp(a->name, "name") == 0) 195 seen_name++; 196 else if(strcmp(a->name, "function") == 0) { 197 seen_function++; 198 } else if(strcmp(a->name, "option") == 0) 199 ret += check_option(a->u.assignment); 200 else if(strcmp(a->name, "help") == 0) { 201 seen_help++; 202 } else if(strcmp(a->name, "argument") == 0) { 203 seen_argument++; 204 } else if(strcmp(a->name, "min_args") == 0) { 205 seen_minargs++; 206 } else if(strcmp(a->name, "max_args") == 0) { 207 seen_maxargs++; 208 } else { 209 ex(a, "unknown name"); 210 ret++; 211 } 212 } 213 if(seen_name == 0) { 214 ex(as, "no command name"); 215 ret++; 216 } 217 if(seen_function > 1) { 218 ex(as, "multiple function names"); 219 ret++; 220 } 221 if(seen_help > 1) { 222 ex(as, "multiple help strings"); 223 ret++; 224 } 225 if(seen_argument > 1) { 226 ex(as, "multiple argument strings"); 227 ret++; 228 } 229 if(seen_minargs > 1) { 230 ex(as, "multiple min_args strings"); 231 ret++; 232 } 233 if(seen_maxargs > 1) { 234 ex(as, "multiple max_args strings"); 235 ret++; 236 } 237 238 return ret; 239 } 240 241 static int 242 check(struct assignment *as) 243 { 244 struct assignment *a; 245 int ret = 0; 246 for(a = as; a != NULL; a = a->next) { 247 if(strcmp(a->name, "command")) { 248 fprintf(stderr, "unknown type %s line %d\n", a->name, a->lineno); 249 ret++; 250 continue; 251 } 252 if(a->type != a_assignment) { 253 fprintf(stderr, "bad command definition %s line %d\n", a->name, a->lineno); 254 ret++; 255 continue; 256 } 257 ret += check_command(a->u.assignment); 258 } 259 return ret; 260 } 261 262 static struct assignment * 263 find_next(struct assignment *as, const char *name) 264 { 265 for(as = as->next; as != NULL; as = as->next) { 266 if(strcmp(as->name, name) == 0) 267 return as; 268 } 269 return NULL; 270 } 271 272 static struct assignment * 273 find(struct assignment *as, const char *name) 274 { 275 for(; as != NULL; as = as->next) { 276 if(strcmp(as->name, name) == 0) 277 return as; 278 } 279 return NULL; 280 } 281 282 static void 283 space(FILE *f, int level) 284 { 285 fprintf(f, "%*.*s", level * 4, level * 4, " "); 286 } 287 288 static void 289 cprint(int level, const char *fmt, ...) 290 { 291 va_list ap; 292 va_start(ap, fmt); 293 space(cfile, level); 294 vfprintf(cfile, fmt, ap); 295 va_end(ap); 296 } 297 298 static void 299 hprint(int level, const char *fmt, ...) 300 { 301 va_list ap; 302 va_start(ap, fmt); 303 space(hfile, level); 304 vfprintf(hfile, fmt, ap); 305 va_end(ap); 306 } 307 308 static void gen_name(char *str); 309 310 static void 311 gen_command(struct assignment *as) 312 { 313 struct assignment *a, *b; 314 char *f; 315 a = find(as, "name"); 316 f = strdup(a->u.value); 317 gen_name(f); 318 cprint(1, " { "); 319 fprintf(cfile, "\"%s\", ", a->u.value); 320 fprintf(cfile, "%s_wrap, ", f); 321 b = find(as, "argument"); 322 if(b) 323 fprintf(cfile, "\"%s %s\", ", a->u.value, b->u.value); 324 else 325 fprintf(cfile, "\"%s\", ", a->u.value); 326 b = find(as, "help"); 327 if(b) 328 fprintf(cfile, "\"%s\"", b->u.value); 329 else 330 fprintf(cfile, "NULL"); 331 fprintf(cfile, " },\n"); 332 for(a = a->next; a != NULL; a = a->next) 333 if(strcmp(a->name, "name") == 0) 334 cprint(1, " { \"%s\" },\n", a->u.value); 335 cprint(0, "\n"); 336 } 337 338 static void 339 gen_name(char *str) 340 { 341 char *p; 342 for(p = str; *p != '\0'; p++) 343 if(!isalnum((unsigned char)*p)) 344 *p = '_'; 345 } 346 347 static char * 348 make_name(struct assignment *as) 349 { 350 struct assignment *lopt; 351 struct assignment *type; 352 char *s; 353 354 lopt = find(as, "long"); 355 if(lopt == NULL) 356 lopt = find(as, "name"); 357 if(lopt == NULL) 358 return NULL; 359 360 type = find(as, "type"); 361 if(strcmp(type->u.value, "-flag") == 0) 362 asprintf(&s, "%s_flag", lopt->u.value); 363 else 364 asprintf(&s, "%s_%s", lopt->u.value, type->u.value); 365 gen_name(s); 366 return s; 367 } 368 369 370 static void defval_int(const char *name, struct assignment *defval) 371 { 372 if(defval != NULL) 373 cprint(1, "opt.%s = %s;\n", name, defval->u.value); 374 else 375 cprint(1, "opt.%s = 0;\n", name); 376 } 377 static void defval_string(const char *name, struct assignment *defval) 378 { 379 if(defval != NULL) 380 cprint(1, "opt.%s = \"%s\";\n", name, defval->u.value); 381 else 382 cprint(1, "opt.%s = NULL;\n", name); 383 } 384 static void defval_strings(const char *name, struct assignment *defval) 385 { 386 cprint(1, "opt.%s.num_strings = 0;\n", name); 387 cprint(1, "opt.%s.strings = NULL;\n", name); 388 } 389 390 static void free_strings(const char *name) 391 { 392 cprint(1, "free_getarg_strings (&opt.%s);\n", name); 393 } 394 395 struct type_handler { 396 const char *typename; 397 const char *c_type; 398 const char *getarg_type; 399 void (*defval)(const char*, struct assignment*); 400 void (*free)(const char*); 401 } type_handlers[] = { 402 { "integer", 403 "int", 404 "arg_integer", 405 defval_int, 406 NULL 407 }, 408 { "string", 409 "char*", 410 "arg_string", 411 defval_string, 412 NULL 413 }, 414 { "strings", 415 "struct getarg_strings", 416 "arg_strings", 417 defval_strings, 418 free_strings 419 }, 420 { "flag", 421 "int", 422 "arg_flag", 423 defval_int, 424 NULL 425 }, 426 { "-flag", 427 "int", 428 "arg_negative_flag", 429 defval_int, 430 NULL 431 }, 432 { NULL } 433 }; 434 435 static struct type_handler *find_handler(struct assignment *type) 436 { 437 struct type_handler *th; 438 for(th = type_handlers; th->typename != NULL; th++) 439 if(strcmp(type->u.value, th->typename) == 0) 440 return th; 441 ex(type, "unknown type \"%s\"", type->u.value); 442 exit(1); 443 } 444 445 static void 446 gen_options(struct assignment *opt1, const char *name) 447 { 448 struct assignment *tmp; 449 450 hprint(0, "struct %s_options {\n", name); 451 452 for(tmp = opt1; 453 tmp != NULL; 454 tmp = find_next(tmp, "option")) { 455 struct assignment *type; 456 struct type_handler *th; 457 char *s; 458 459 s = make_name(tmp->u.assignment); 460 type = find(tmp->u.assignment, "type"); 461 th = find_handler(type); 462 hprint(1, "%s %s;\n", th->c_type, s); 463 free(s); 464 } 465 hprint(0, "};\n"); 466 } 467 468 static void 469 gen_wrapper(struct assignment *as) 470 { 471 struct assignment *name; 472 struct assignment *arg; 473 struct assignment *opt1; 474 struct assignment *function; 475 struct assignment *tmp; 476 char *n, *f; 477 int nargs = 0; 478 479 name = find(as, "name"); 480 n = strdup(name->u.value); 481 gen_name(n); 482 arg = find(as, "argument"); 483 opt1 = find(as, "option"); 484 function = find(as, "function"); 485 if(function) 486 f = function->u.value; 487 else 488 f = n; 489 490 491 if(opt1 != NULL) { 492 gen_options(opt1, n); 493 hprint(0, "int %s(struct %s_options*, int, char **);\n", f, n); 494 } else { 495 hprint(0, "int %s(void*, int, char **);\n", f); 496 } 497 498 fprintf(cfile, "static int\n"); 499 fprintf(cfile, "%s_wrap(int argc, char **argv)\n", n); 500 fprintf(cfile, "{\n"); 501 if(opt1 != NULL) 502 cprint(1, "struct %s_options opt;\n", n); 503 cprint(1, "int ret;\n"); 504 cprint(1, "int optidx = 0;\n"); 505 cprint(1, "struct getargs args[] = {\n"); 506 for(tmp = find(as, "option"); 507 tmp != NULL; 508 tmp = find_next(tmp, "option")) { 509 struct assignment *type = find(tmp->u.assignment, "type"); 510 struct assignment *lopt = find(tmp->u.assignment, "long"); 511 struct assignment *sopt = find(tmp->u.assignment, "short"); 512 struct assignment *aarg = find(tmp->u.assignment, "argument"); 513 struct assignment *help = find(tmp->u.assignment, "help"); 514 515 struct type_handler *th; 516 517 cprint(2, "{ "); 518 if(lopt) 519 fprintf(cfile, "\"%s\", ", lopt->u.value); 520 else 521 fprintf(cfile, "NULL, "); 522 if(sopt) 523 fprintf(cfile, "'%c', ", *sopt->u.value); 524 else 525 fprintf(cfile, "0, "); 526 th = find_handler(type); 527 fprintf(cfile, "%s, ", th->getarg_type); 528 fprintf(cfile, "NULL, "); 529 if(help) 530 fprintf(cfile, "\"%s\", ", help->u.value); 531 else 532 fprintf(cfile, "NULL, "); 533 if(aarg) 534 fprintf(cfile, "\"%s\"", aarg->u.value); 535 else 536 fprintf(cfile, "NULL"); 537 fprintf(cfile, " },\n"); 538 } 539 cprint(2, "{ \"help\", 'h', arg_flag, NULL, NULL, NULL }\n"); 540 cprint(1, "};\n"); 541 cprint(1, "int help_flag = 0;\n"); 542 543 for(tmp = find(as, "option"); 544 tmp != NULL; 545 tmp = find_next(tmp, "option")) { 546 char *s; 547 struct assignment *type = find(tmp->u.assignment, "type"); 548 549 struct assignment *defval = find(tmp->u.assignment, "default"); 550 551 struct type_handler *th; 552 553 s = make_name(tmp->u.assignment); 554 th = find_handler(type); 555 (*th->defval)(s, defval); 556 free(s); 557 } 558 559 for(tmp = find(as, "option"); 560 tmp != NULL; 561 tmp = find_next(tmp, "option")) { 562 char *s; 563 s = make_name(tmp->u.assignment); 564 cprint(1, "args[%d].value = &opt.%s;\n", nargs++, s); 565 free(s); 566 } 567 cprint(1, "args[%d].value = &help_flag;\n", nargs++); 568 cprint(1, "if(getarg(args, %d, argc, argv, &optidx))\n", nargs); 569 cprint(2, "goto usage;\n"); 570 571 { 572 int min_args = -1; 573 int max_args = -1; 574 char *end; 575 if(arg == NULL) { 576 max_args = 0; 577 } else { 578 if((tmp = find(as, "min_args")) != NULL) { 579 min_args = strtol(tmp->u.value, &end, 0); 580 if(*end != '\0') { 581 ex(tmp, "min_args is not numeric"); 582 exit(1); 583 } 584 if(min_args < 0) { 585 ex(tmp, "min_args must be non-negative"); 586 exit(1); 587 } 588 } 589 if((tmp = find(as, "max_args")) != NULL) { 590 max_args = strtol(tmp->u.value, &end, 0); 591 if(*end != '\0') { 592 ex(tmp, "max_args is not numeric"); 593 exit(1); 594 } 595 if(max_args < 0) { 596 ex(tmp, "max_args must be non-negative"); 597 exit(1); 598 } 599 } 600 } 601 if(min_args != -1 || max_args != -1) { 602 if(min_args == max_args) { 603 cprint(1, "if(argc - optidx != %d) {\n", 604 min_args); 605 cprint(2, "fprintf(stderr, \"Need exactly %u parameters (%%u given).\\n\\n\", argc - optidx);\n", min_args); 606 cprint(2, "goto usage;\n"); 607 cprint(1, "}\n"); 608 } else { 609 if(max_args != -1) { 610 cprint(1, "if(argc - optidx > %d) {\n", max_args); 611 cprint(2, "fprintf(stderr, \"Arguments given (%%u) are more than expected (%u).\\n\\n\", argc - optidx);\n", max_args); 612 cprint(2, "goto usage;\n"); 613 cprint(1, "}\n"); 614 } 615 if(min_args != -1) { 616 cprint(1, "if(argc - optidx < %d) {\n", min_args); 617 cprint(2, "fprintf(stderr, \"Arguments given (%%u) are less than expected (%u).\\n\\n\", argc - optidx);\n", min_args); 618 cprint(2, "goto usage;\n"); 619 cprint(1, "}\n"); 620 } 621 } 622 } 623 } 624 625 cprint(1, "if(help_flag)\n"); 626 cprint(2, "goto usage;\n"); 627 628 cprint(1, "ret = %s(%s, argc - optidx, argv + optidx);\n", 629 f, opt1 ? "&opt": "NULL"); 630 631 /* free allocated data */ 632 for(tmp = find(as, "option"); 633 tmp != NULL; 634 tmp = find_next(tmp, "option")) { 635 char *s; 636 struct assignment *type = find(tmp->u.assignment, "type"); 637 struct type_handler *th; 638 th = find_handler(type); 639 if(th->free == NULL) 640 continue; 641 s = make_name(tmp->u.assignment); 642 (*th->free)(s); 643 free(s); 644 } 645 cprint(1, "return ret;\n"); 646 647 cprint(0, "usage:\n"); 648 cprint(1, "arg_printusage (args, %d, \"%s\", \"%s\");\n", nargs, 649 name->u.value, arg ? arg->u.value : ""); 650 /* free allocated data */ 651 for(tmp = find(as, "option"); 652 tmp != NULL; 653 tmp = find_next(tmp, "option")) { 654 char *s; 655 struct assignment *type = find(tmp->u.assignment, "type"); 656 struct type_handler *th; 657 th = find_handler(type); 658 if(th->free == NULL) 659 continue; 660 s = make_name(tmp->u.assignment); 661 (*th->free)(s); 662 free(s); 663 } 664 cprint(1, "return 0;\n"); 665 cprint(0, "}\n"); 666 cprint(0, "\n"); 667 } 668 669 char cname[PATH_MAX]; 670 char hname[PATH_MAX]; 671 672 static void 673 gen(struct assignment *as) 674 { 675 struct assignment *a; 676 cprint(0, "#include <stdio.h>\n"); 677 cprint(0, "#include <getarg.h>\n"); 678 cprint(0, "#include <sl.h>\n"); 679 cprint(0, "#include \"%s\"\n\n", hname); 680 681 hprint(0, "#include <stdio.h>\n"); 682 hprint(0, "#include <sl.h>\n"); 683 hprint(0, "\n"); 684 685 686 for(a = as; a != NULL; a = a->next) 687 gen_wrapper(a->u.assignment); 688 689 cprint(0, "SL_cmd commands[] = {\n"); 690 for(a = as; a != NULL; a = a->next) 691 gen_command(a->u.assignment); 692 cprint(1, "{ NULL }\n"); 693 cprint(0, "};\n"); 694 695 hprint(0, "extern SL_cmd commands[];\n"); 696 } 697 698 int version_flag; 699 int help_flag; 700 struct getargs args[] = { 701 { "version", 0, arg_flag, &version_flag }, 702 { "help", 0, arg_flag, &help_flag } 703 }; 704 int num_args = sizeof(args) / sizeof(args[0]); 705 706 static void 707 usage(int code) 708 { 709 arg_printusage(args, num_args, NULL, "command-table"); 710 exit(code); 711 } 712 713 int 714 main(int argc, char **argv) 715 { 716 char *p; 717 718 int optidx = 0; 719 720 setprogname(argv[0]); 721 if(getarg(args, num_args, argc, argv, &optidx)) 722 usage(1); 723 if(help_flag) 724 usage(0); 725 if(version_flag) { 726 print_version(NULL); 727 exit(0); 728 } 729 730 if(argc == optidx) 731 usage(1); 732 733 filename = argv[optidx]; 734 yyin = fopen(filename, "r"); 735 if(yyin == NULL) 736 err(1, "%s", filename); 737 p = strrchr(filename, '/'); 738 if(p) 739 strlcpy(cname, p + 1, sizeof(cname)); 740 else 741 strlcpy(cname, filename, sizeof(cname)); 742 p = strrchr(cname, '.'); 743 if(p) 744 *p = '\0'; 745 strlcpy(hname, cname, sizeof(hname)); 746 strlcat(cname, ".c", sizeof(cname)); 747 strlcat(hname, ".h", sizeof(hname)); 748 yyparse(); 749 if(error_flag) 750 exit(1); 751 if(check(assignment) == 0) { 752 cfile = fopen(cname, "w"); 753 if(cfile == NULL) 754 err(1, "%s", cname); 755 hfile = fopen(hname, "w"); 756 if(hfile == NULL) 757 err(1, "%s", hname); 758 gen(assignment); 759 fclose(cfile); 760 fclose(hfile); 761 } 762 fclose(yyin); 763 return 0; 764 } 765