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