1 /*- 2 * Copyright (c) 2010 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by David A. Holland. 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 * POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <stdio.h> 31 #include <stdarg.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <string.h> 35 #include <errno.h> 36 37 #include "bool.h" 38 #include "version.h" 39 #include "config.h" 40 #include "utils.h" 41 #include "array.h" 42 #include "mode.h" 43 #include "place.h" 44 #include "files.h" 45 #include "directive.h" 46 #include "macro.h" 47 48 struct mode mode = { 49 .werror = false, 50 51 .input_allow_dollars = false, 52 .input_tabstop = 8, 53 54 .do_stdinc = true, 55 .do_stddef = true, 56 57 .do_output = true, 58 .output_linenumbers = true, 59 .output_cheaplinenumbers = false, 60 .output_retain_comments = false, 61 .output_file = NULL, 62 63 .do_depend = false, 64 .depend_report_system = false, 65 .depend_assume_generated = false, 66 .depend_issue_fakerules = false, 67 .depend_quote_target = true, 68 .depend_target = NULL, 69 .depend_file = NULL, 70 71 .do_macrolist = false, 72 .macrolist_include_stddef = false, 73 .macrolist_include_expansions = false, 74 75 .do_trace = false, 76 .trace_namesonly = false, 77 .trace_indented = false, 78 }; 79 80 struct warns warns = { 81 .endiflabels = true, 82 .nestcomment = false, 83 .undef = false, 84 .unused = false, 85 }; 86 87 //////////////////////////////////////////////////////////// 88 // commandline macros 89 90 struct commandline_macro { 91 struct place where; 92 struct place where2; 93 const char *macro; 94 const char *expansion; 95 }; 96 97 static struct array commandline_macros; 98 99 static 100 void 101 commandline_macros_init(void) 102 { 103 array_init(&commandline_macros); 104 } 105 106 static 107 void 108 commandline_macros_cleanup(void) 109 { 110 unsigned i, num; 111 struct commandline_macro *cm; 112 113 num = array_num(&commandline_macros); 114 for (i=0; i<num; i++) { 115 cm = array_get(&commandline_macros, i); 116 dofree(cm, sizeof(*cm)); 117 } 118 array_setsize(&commandline_macros, 0); 119 120 array_cleanup(&commandline_macros); 121 } 122 123 static 124 void 125 commandline_macro_add(const struct place *p, const char *macro, 126 const struct place *p2, const char *expansion) 127 { 128 struct commandline_macro *cm; 129 130 cm = domalloc(sizeof(*cm)); 131 cm->where = *p; 132 cm->where2 = *p2; 133 cm->macro = macro; 134 cm->expansion = expansion; 135 136 array_add(&commandline_macros, cm, NULL); 137 } 138 139 static 140 void 141 commandline_def(const struct place *p, char *str) 142 { 143 struct place p2; 144 char *val; 145 146 if (*str == '\0') { 147 complain(NULL, "-D: macro name expected"); 148 die(); 149 } 150 151 val = strchr(str, '='); 152 if (val != NULL) { 153 *val = '\0'; 154 val++; 155 } 156 157 if (val) { 158 p2 = *p; 159 place_addcolumns(&p2, strlen(str)); 160 } else { 161 place_setbuiltin(&p2, 1); 162 } 163 commandline_macro_add(p, str, &p2, val ? val : "1"); 164 } 165 166 static 167 void 168 commandline_undef(const struct place *p, char *str) 169 { 170 if (*str == '\0') { 171 complain(NULL, "-U: macro name expected"); 172 die(); 173 } 174 commandline_macro_add(p, str, p, NULL); 175 } 176 177 static 178 void 179 apply_commandline_macros(void) 180 { 181 struct commandline_macro *cm; 182 unsigned i, num; 183 184 num = array_num(&commandline_macros); 185 for (i=0; i<num; i++) { 186 cm = array_get(&commandline_macros, i); 187 if (cm->expansion != NULL) { 188 macro_define_plain(&cm->where, cm->macro, 189 &cm->where2, cm->expansion); 190 } else { 191 macro_undef(cm->macro); 192 } 193 dofree(cm, sizeof(*cm)); 194 } 195 array_setsize(&commandline_macros, 0); 196 } 197 198 static 199 void 200 apply_magic_macro(unsigned num, const char *name) 201 { 202 struct place p; 203 204 place_setbuiltin(&p, num); 205 macro_define_magic(&p, name); 206 } 207 208 static 209 void 210 apply_builtin_macro(unsigned num, const char *name, const char *val) 211 { 212 struct place p; 213 214 place_setbuiltin(&p, num); 215 macro_define_plain(&p, name, &p, val); 216 } 217 218 static 219 void 220 apply_builtin_macros(void) 221 { 222 unsigned n = 1; 223 224 apply_magic_macro(n++, "__FILE__"); 225 apply_magic_macro(n++, "__LINE__"); 226 227 #ifdef CONFIG_OS 228 apply_builtin_macro(n++, CONFIG_OS, "1"); 229 #endif 230 #ifdef CONFIG_OS_2 231 apply_builtin_macro(n++, CONFIG_OS_2, "1"); 232 #endif 233 234 #ifdef CONFIG_CPU 235 apply_builtin_macro(n++, CONFIG_CPU, "1"); 236 #endif 237 #ifdef CONFIG_CPU_2 238 apply_builtin_macro(n++, CONFIG_CPU_2, "1"); 239 #endif 240 241 #ifdef CONFIG_SIZE 242 apply_builtin_macro(n++, CONFIG_SIZE, "1"); 243 #endif 244 #ifdef CONFIG_BINFMT 245 apply_builtin_macro(n++, CONFIG_BINFMT, "1"); 246 #endif 247 248 #ifdef CONFIG_COMPILER 249 apply_builtin_macro(n++, CONFIG_COMPILER, VERSION_MAJOR); 250 apply_builtin_macro(n++, CONFIG_COMPILER_MINOR, VERSION_MINOR); 251 apply_builtin_macro(n++, "__VERSION__", VERSION_LONG); 252 #endif 253 } 254 255 //////////////////////////////////////////////////////////// 256 // extra included files 257 258 struct commandline_file { 259 struct place where; 260 char *name; 261 bool suppress_output; 262 }; 263 264 static struct array commandline_files; 265 266 static 267 void 268 commandline_files_init(void) 269 { 270 array_init(&commandline_files); 271 } 272 273 static 274 void 275 commandline_files_cleanup(void) 276 { 277 unsigned i, num; 278 struct commandline_file *cf; 279 280 num = array_num(&commandline_files); 281 for (i=0; i<num; i++) { 282 cf = array_get(&commandline_files, i); 283 if (cf != NULL) { 284 dofree(cf, sizeof(*cf)); 285 } 286 } 287 array_setsize(&commandline_files, 0); 288 289 array_cleanup(&commandline_files); 290 } 291 292 static 293 void 294 commandline_addfile(const struct place *p, char *name, bool suppress_output) 295 { 296 struct commandline_file *cf; 297 298 cf = domalloc(sizeof(*cf)); 299 cf->where = *p; 300 cf->name = name; 301 cf->suppress_output = suppress_output; 302 array_add(&commandline_files, cf, NULL); 303 } 304 305 static 306 void 307 commandline_addfile_output(const struct place *p, char *name) 308 { 309 commandline_addfile(p, name, false); 310 } 311 312 static 313 void 314 commandline_addfile_nooutput(const struct place *p, char *name) 315 { 316 commandline_addfile(p, name, true); 317 } 318 319 static 320 void 321 read_commandline_files(void) 322 { 323 struct commandline_file *cf; 324 unsigned i, num; 325 bool save = false; 326 327 num = array_num(&commandline_files); 328 for (i=0; i<num; i++) { 329 cf = array_get(&commandline_files, i); 330 array_set(&commandline_files, i, NULL); 331 if (cf->suppress_output) { 332 save = mode.do_output; 333 mode.do_output = false; 334 file_readquote(&cf->where, cf->name); 335 mode.do_output = save; 336 } else { 337 file_readquote(&cf->where, cf->name); 338 } 339 dofree(cf, sizeof(*cf)); 340 } 341 array_setsize(&commandline_files, 0); 342 } 343 344 //////////////////////////////////////////////////////////// 345 // include path accumulation 346 347 static struct stringarray incpath_quote; 348 static struct stringarray incpath_user; 349 static struct stringarray incpath_system; 350 static struct stringarray incpath_late; 351 static const char *sysroot; 352 353 static 354 void 355 incpath_init(void) 356 { 357 stringarray_init(&incpath_quote); 358 stringarray_init(&incpath_user); 359 stringarray_init(&incpath_system); 360 stringarray_init(&incpath_late); 361 } 362 363 static 364 void 365 incpath_cleanup(void) 366 { 367 stringarray_setsize(&incpath_quote, 0); 368 stringarray_setsize(&incpath_user, 0); 369 stringarray_setsize(&incpath_system, 0); 370 stringarray_setsize(&incpath_late, 0); 371 372 stringarray_cleanup(&incpath_quote); 373 stringarray_cleanup(&incpath_user); 374 stringarray_cleanup(&incpath_system); 375 stringarray_cleanup(&incpath_late); 376 } 377 378 static 379 void 380 commandline_isysroot(const struct place *p, char *dir) 381 { 382 (void)p; 383 sysroot = dir; 384 } 385 386 static 387 void 388 commandline_addincpath(struct stringarray *arr, char *s) 389 { 390 if (*s == '\0') { 391 complain(NULL, "Empty include directory"); 392 die(); 393 } 394 stringarray_add(arr, s, NULL); 395 } 396 397 static 398 void 399 commandline_addincpath_quote(const struct place *p, char *dir) 400 { 401 (void)p; 402 commandline_addincpath(&incpath_quote, dir); 403 } 404 405 static 406 void 407 commandline_addincpath_user(const struct place *p, char *dir) 408 { 409 (void)p; 410 commandline_addincpath(&incpath_user, dir); 411 } 412 413 static 414 void 415 commandline_addincpath_system(const struct place *p, char *dir) 416 { 417 (void)p; 418 commandline_addincpath(&incpath_system, dir); 419 } 420 421 static 422 void 423 commandline_addincpath_late(const struct place *p, char *dir) 424 { 425 (void)p; 426 commandline_addincpath(&incpath_late, dir); 427 } 428 429 static 430 void 431 loadincludepath(void) 432 { 433 unsigned i, num; 434 const char *dir; 435 char *t; 436 437 num = stringarray_num(&incpath_quote); 438 for (i=0; i<num; i++) { 439 dir = stringarray_get(&incpath_quote, i); 440 files_addquotepath(dir, false); 441 } 442 files_addquotepath(NULL, false); 443 444 num = stringarray_num(&incpath_user); 445 for (i=0; i<num; i++) { 446 dir = stringarray_get(&incpath_user, i); 447 files_addquotepath(dir, false); 448 files_addbracketpath(dir, false); 449 } 450 451 if (mode.do_stdinc) { 452 if (sysroot != NULL) { 453 t = dostrdup3(sysroot, "/", CONFIG_LOCALINCLUDE); 454 freestringlater(t); 455 dir = t; 456 } else { 457 dir = CONFIG_LOCALINCLUDE; 458 } 459 files_addquotepath(dir, true); 460 files_addbracketpath(dir, true); 461 462 if (sysroot != NULL) { 463 t = dostrdup3(sysroot, "/", CONFIG_SYSTEMINCLUDE); 464 freestringlater(t); 465 dir = t; 466 } else { 467 dir = CONFIG_SYSTEMINCLUDE; 468 } 469 files_addquotepath(dir, true); 470 files_addbracketpath(dir, true); 471 } 472 473 num = stringarray_num(&incpath_system); 474 for (i=0; i<num; i++) { 475 dir = stringarray_get(&incpath_system, i); 476 files_addquotepath(dir, true); 477 files_addbracketpath(dir, true); 478 } 479 480 num = stringarray_num(&incpath_late); 481 for (i=0; i<num; i++) { 482 dir = stringarray_get(&incpath_late, i); 483 files_addquotepath(dir, false); 484 files_addbracketpath(dir, false); 485 } 486 } 487 488 //////////////////////////////////////////////////////////// 489 // silly commandline stuff 490 491 static const char *commandline_prefix; 492 493 static 494 void 495 commandline_setprefix(const struct place *p, char *prefix) 496 { 497 (void)p; 498 commandline_prefix = prefix; 499 } 500 501 static 502 void 503 commandline_addincpath_user_withprefix(const struct place *p, char *dir) 504 { 505 char *s; 506 507 if (commandline_prefix == NULL) { 508 complain(NULL, "-iprefix needed"); 509 die(); 510 } 511 s = dostrdup3(commandline_prefix, "/", dir); 512 freestringlater(s); 513 commandline_addincpath_user(p, s); 514 } 515 516 static 517 void 518 commandline_addincpath_late_withprefix(const struct place *p, char *dir) 519 { 520 char *s; 521 522 if (commandline_prefix == NULL) { 523 complain(NULL, "-iprefix needed"); 524 die(); 525 } 526 s = dostrdup3(commandline_prefix, "/", dir); 527 freestringlater(s); 528 commandline_addincpath_late(p, s); 529 } 530 531 static 532 void 533 commandline_setstd(const struct place *p, char *std) 534 { 535 (void)p; 536 537 if (!strcmp(std, "krc")) { 538 return; 539 } 540 complain(NULL, "Standard %s not supported by this preprocessor", std); 541 die(); 542 } 543 544 static 545 void 546 commandline_setlang(const struct place *p, char *lang) 547 { 548 (void)p; 549 550 if (!strcmp(lang, "c") || !strcmp(lang, "assembler-with-cpp")) { 551 return; 552 } 553 complain(NULL, "Language %s not supported by this preprocessor", lang); 554 die(); 555 } 556 557 //////////////////////////////////////////////////////////// 558 // complex modes 559 560 DEAD static 561 void 562 commandline_iremap(const struct place *p, char *str) 563 { 564 (void)p; 565 /* XXX */ 566 (void)str; 567 complain(NULL, "-iremap not supported"); 568 die(); 569 } 570 571 static 572 void 573 commandline_tabstop(const struct place *p, char *s) 574 { 575 char *t; 576 unsigned long val; 577 578 (void)p; 579 580 t = strchr(s, '='); 581 if (t == NULL) { 582 /* should not happen */ 583 complain(NULL, "Invalid tabstop"); 584 die(); 585 } 586 t++; 587 errno = 0; 588 val = strtoul(t, &t, 10); 589 if (errno || *t != '\0') { 590 complain(NULL, "Invalid tabstop"); 591 die(); 592 } 593 if (val > 64) { 594 complain(NULL, "Preposterously large tabstop"); 595 die(); 596 } 597 mode.input_tabstop = val; 598 } 599 600 /* 601 * macrolist 602 */ 603 604 static 605 void 606 commandline_dD(void) 607 { 608 mode.do_macrolist = true; 609 mode.macrolist_include_stddef = false; 610 mode.macrolist_include_expansions = true; 611 } 612 613 static 614 void 615 commandline_dM(void) 616 { 617 mode.do_macrolist = true; 618 mode.macrolist_include_stddef = true; 619 mode.macrolist_include_expansions = true; 620 mode.do_output = false; 621 } 622 623 static 624 void 625 commandline_dN(void) 626 { 627 mode.do_macrolist = true; 628 mode.macrolist_include_stddef = false; 629 mode.macrolist_include_expansions = false; 630 } 631 632 /* 633 * include trace 634 */ 635 636 static 637 void 638 commandline_dI(void) 639 { 640 mode.do_trace = true; 641 mode.trace_namesonly = false; 642 mode.trace_indented = false; 643 } 644 645 static 646 void 647 commandline_H(void) 648 { 649 mode.do_trace = true; 650 mode.trace_namesonly = true; 651 mode.trace_indented = true; 652 } 653 654 /* 655 * depend 656 */ 657 658 static 659 void 660 commandline_setdependtarget(const struct place *p, char *str) 661 { 662 (void)p; 663 mode.depend_target = str; 664 mode.depend_quote_target = false; 665 } 666 667 static 668 void 669 commandline_setdependtarget_quoted(const struct place *p, char *str) 670 { 671 (void)p; 672 mode.depend_target = str; 673 mode.depend_quote_target = true; 674 } 675 676 static 677 void 678 commandline_setdependoutput(const struct place *p, char *str) 679 { 680 (void)p; 681 mode.depend_file = str; 682 } 683 684 static 685 void 686 commandline_M(void) 687 { 688 mode.do_depend = true; 689 mode.depend_report_system = true; 690 mode.do_output = false; 691 } 692 693 static 694 void 695 commandline_MM(void) 696 { 697 mode.do_depend = true; 698 mode.depend_report_system = false; 699 mode.do_output = false; 700 } 701 702 static 703 void 704 commandline_MD(void) 705 { 706 mode.do_depend = true; 707 mode.depend_report_system = true; 708 } 709 710 static 711 void 712 commandline_MMD(void) 713 { 714 mode.do_depend = true; 715 mode.depend_report_system = false; 716 } 717 718 static 719 void 720 commandline_wall(void) 721 { 722 warns.nestcomment = true; 723 warns.undef = true; 724 warns.unused = true; 725 } 726 727 static 728 void 729 commandline_wnoall(void) 730 { 731 warns.nestcomment = false; 732 warns.undef = false; 733 warns.unused = false; 734 } 735 736 static 737 void 738 commandline_wnone(void) 739 { 740 warns.nestcomment = false; 741 warns.endiflabels = false; 742 warns.undef = false; 743 warns.unused = false; 744 } 745 746 //////////////////////////////////////////////////////////// 747 // options 748 749 struct ignore_option { 750 const char *string; 751 }; 752 753 struct flag_option { 754 const char *string; 755 bool *flag; 756 bool setto; 757 }; 758 759 struct act_option { 760 const char *string; 761 void (*func)(void); 762 }; 763 764 struct prefix_option { 765 const char *string; 766 void (*func)(const struct place *, char *); 767 }; 768 769 struct arg_option { 770 const char *string; 771 void (*func)(const struct place *, char *); 772 }; 773 774 static const struct ignore_option ignore_options[] = { 775 { "m32" }, 776 { "traditional" }, 777 }; 778 static const unsigned num_ignore_options = HOWMANY(ignore_options); 779 780 static const struct flag_option flag_options[] = { 781 { "C", &mode.output_retain_comments, true }, 782 { "CC", &mode.output_retain_comments, true }, 783 { "MG", &mode.depend_assume_generated, true }, 784 { "MP", &mode.depend_issue_fakerules, true }, 785 { "P", &mode.output_linenumbers, false }, 786 { "Wcomment", &warns.nestcomment, true }, 787 { "Wendif-labels", &warns.endiflabels, true }, 788 { "Werror", &mode.werror, true }, 789 { "Wno-comment", &warns.nestcomment, false }, 790 { "Wno-endif-labels", &warns.endiflabels, false }, 791 { "Wno-error", &mode.werror, false }, 792 { "Wno-undef", &warns.undef, false }, 793 { "Wno-unused-macros", &warns.unused, false }, 794 { "Wundef", &warns.undef, true }, 795 { "Wunused-macros", &warns.unused, true }, 796 { "fdollars-in-identifiers", &mode.input_allow_dollars, true }, 797 { "fno-dollars-in-identifiers", &mode.input_allow_dollars, false }, 798 { "nostdinc", &mode.do_stdinc, false }, 799 { "p", &mode.output_cheaplinenumbers, true }, 800 { "undef", &mode.do_stddef, false }, 801 }; 802 static const unsigned num_flag_options = HOWMANY(flag_options); 803 804 static const struct act_option act_options[] = { 805 { "H", commandline_H }, 806 { "M", commandline_M }, 807 { "MD", commandline_MD }, 808 { "MM", commandline_MM }, 809 { "MMD", commandline_MMD }, 810 { "Wall", commandline_wall }, 811 { "Wno-all", commandline_wnoall }, 812 { "dD", commandline_dD }, 813 { "dI", commandline_dI }, 814 { "dM", commandline_dM }, 815 { "dN", commandline_dN }, 816 { "w", commandline_wnone }, 817 }; 818 static const unsigned num_act_options = HOWMANY(act_options); 819 820 static const struct prefix_option prefix_options[] = { 821 { "D", commandline_def }, 822 { "I", commandline_addincpath_user }, 823 { "U", commandline_undef }, 824 { "ftabstop=", commandline_tabstop }, 825 { "std=", commandline_setstd }, 826 }; 827 static const unsigned num_prefix_options = HOWMANY(prefix_options); 828 829 static const struct arg_option arg_options[] = { 830 { "MF", commandline_setdependoutput }, 831 { "MQ", commandline_setdependtarget_quoted }, 832 { "MT", commandline_setdependtarget }, 833 { "debuglog", debuglog_open }, 834 { "idirafter", commandline_addincpath_late }, 835 { "imacros", commandline_addfile_nooutput }, 836 { "include", commandline_addfile_output }, 837 { "iprefix", commandline_setprefix }, 838 { "iquote", commandline_addincpath_quote }, 839 { "iremap", commandline_iremap }, 840 { "isysroot", commandline_isysroot }, 841 { "isystem", commandline_addincpath_system }, 842 { "iwithprefix", commandline_addincpath_late_withprefix }, 843 { "iwithprefixbefore", commandline_addincpath_user_withprefix }, 844 { "x", commandline_setlang }, 845 }; 846 static const unsigned num_arg_options = HOWMANY(arg_options); 847 848 static 849 bool 850 check_ignore_option(const char *opt) 851 { 852 unsigned i; 853 int r; 854 855 for (i=0; i<num_ignore_options; i++) { 856 r = strcmp(opt, ignore_options[i].string); 857 if (r == 0) { 858 return true; 859 } 860 if (r < 0) { 861 break; 862 } 863 } 864 return false; 865 } 866 867 static 868 bool 869 check_flag_option(const char *opt) 870 { 871 unsigned i; 872 int r; 873 874 for (i=0; i<num_flag_options; i++) { 875 r = strcmp(opt, flag_options[i].string); 876 if (r == 0) { 877 *flag_options[i].flag = flag_options[i].setto; 878 return true; 879 } 880 if (r < 0) { 881 break; 882 } 883 } 884 return false; 885 } 886 887 static 888 bool 889 check_act_option(const char *opt) 890 { 891 unsigned i; 892 int r; 893 894 for (i=0; i<num_act_options; i++) { 895 r = strcmp(opt, act_options[i].string); 896 if (r == 0) { 897 act_options[i].func(); 898 return true; 899 } 900 if (r < 0) { 901 break; 902 } 903 } 904 return false; 905 } 906 907 static 908 bool 909 check_prefix_option(const struct place *p, char *opt) 910 { 911 unsigned i, len; 912 int r; 913 914 for (i=0; i<num_prefix_options; i++) { 915 len = strlen(prefix_options[i].string); 916 r = strncmp(opt, prefix_options[i].string, len); 917 if (r == 0) { 918 prefix_options[i].func(p, opt + len); 919 return true; 920 } 921 if (r < 0) { 922 break; 923 } 924 } 925 return false; 926 } 927 928 static 929 bool 930 check_arg_option(const char *opt, const struct place *argplace, char *arg) 931 { 932 unsigned i; 933 int r; 934 935 for (i=0; i<num_arg_options; i++) { 936 r = strcmp(opt, arg_options[i].string); 937 if (r == 0) { 938 if (arg == NULL) { 939 complain(NULL, 940 "Option -%s requires an argument", 941 opt); 942 die(); 943 } 944 arg_options[i].func(argplace, arg); 945 return true; 946 } 947 if (r < 0) { 948 break; 949 } 950 } 951 return false; 952 } 953 954 DEAD PF(2, 3) static 955 void 956 usage(const char *progname, const char *fmt, ...) 957 { 958 va_list ap; 959 960 fprintf(stderr, "%s: ", progname); 961 va_start(ap, fmt); 962 vfprintf(stderr, fmt, ap); 963 va_end(ap); 964 fprintf(stderr, "\n"); 965 966 fprintf(stderr, "usage: %s [options] [infile [outfile]]\n", progname); 967 fprintf(stderr, "Common options:\n"); 968 fprintf(stderr, " -C Retain comments\n"); 969 fprintf(stderr, " -Dmacro[=def] Predefine macro\n"); 970 fprintf(stderr, " -Idir Add to include path\n"); 971 fprintf(stderr, " -M Issue depend info\n"); 972 fprintf(stderr, " -MD Issue depend info and output\n"); 973 fprintf(stderr, " -MM -M w/o system headers\n"); 974 fprintf(stderr, " -MMD -MD w/o system headers\n"); 975 fprintf(stderr, " -nostdinc Drop default include path\n"); 976 fprintf(stderr, " -Umacro Undefine macro\n"); 977 fprintf(stderr, " -undef Undefine everything\n"); 978 fprintf(stderr, " -Wall Enable all warnings\n"); 979 fprintf(stderr, " -Werror Make warnings into errors\n"); 980 fprintf(stderr, " -w Disable all warnings\n"); 981 die(); 982 } 983 984 //////////////////////////////////////////////////////////// 985 // exit and cleanup 986 987 static struct stringarray freestrings; 988 989 static 990 void 991 init(void) 992 { 993 stringarray_init(&freestrings); 994 995 incpath_init(); 996 commandline_macros_init(); 997 commandline_files_init(); 998 999 place_init(); 1000 files_init(); 1001 directive_init(); 1002 macros_init(); 1003 } 1004 1005 static 1006 void 1007 cleanup(void) 1008 { 1009 unsigned i, num; 1010 1011 macros_cleanup(); 1012 directive_cleanup(); 1013 files_cleanup(); 1014 place_cleanup(); 1015 1016 commandline_files_cleanup(); 1017 commandline_macros_cleanup(); 1018 incpath_cleanup(); 1019 debuglog_close(); 1020 1021 num = stringarray_num(&freestrings); 1022 for (i=0; i<num; i++) { 1023 dostrfree(stringarray_get(&freestrings, i)); 1024 } 1025 stringarray_setsize(&freestrings, 0); 1026 stringarray_cleanup(&freestrings); 1027 } 1028 1029 void 1030 die(void) 1031 { 1032 cleanup(); 1033 exit(EXIT_FAILURE); 1034 } 1035 1036 void 1037 freestringlater(char *s) 1038 { 1039 stringarray_add(&freestrings, s, NULL); 1040 } 1041 1042 //////////////////////////////////////////////////////////// 1043 // main 1044 1045 int 1046 main(int argc, char *argv[]) 1047 { 1048 const char *progname; 1049 const char *inputfile = NULL; 1050 const char *outputfile = NULL; 1051 struct place cmdplace; 1052 int i; 1053 1054 progname = strrchr(argv[0], '/'); 1055 progname = progname == NULL ? argv[0] : progname + 1; 1056 complain_init(progname); 1057 1058 if (pledge("stdio rpath wpath cpath", NULL) == -1) { 1059 fprintf(stderr, "%s: pledge: %s", progname, strerror(errno)); 1060 exit(1); 1061 } 1062 1063 init(); 1064 1065 for (i=1; i<argc; i++) { 1066 if (argv[i][0] != '-' || argv[i][1] == 0) { 1067 break; 1068 } 1069 place_setcommandline(&cmdplace, i, 1); 1070 if (check_ignore_option(argv[i]+1)) { 1071 continue; 1072 } 1073 if (check_flag_option(argv[i]+1)) { 1074 continue; 1075 } 1076 if (check_act_option(argv[i]+1)) { 1077 continue; 1078 } 1079 if (check_prefix_option(&cmdplace, argv[i]+1)) { 1080 continue; 1081 } 1082 place_setcommandline(&cmdplace, i+1, 1); 1083 if (check_arg_option(argv[i]+1, &cmdplace, argv[i+1])) { 1084 i++; 1085 continue; 1086 } 1087 usage(progname, "Invalid option %s", argv[i]); 1088 } 1089 if (i < argc) { 1090 inputfile = argv[i++]; 1091 if (!strcmp(inputfile, "-")) { 1092 inputfile = NULL; 1093 } 1094 } 1095 if (i < argc) { 1096 outputfile = argv[i++]; 1097 if (!strcmp(outputfile, "-")) { 1098 outputfile = NULL; 1099 } 1100 } 1101 if (i < argc) { 1102 usage(progname, "Extra non-option argument %s", argv[i]); 1103 } 1104 1105 mode.output_file = outputfile; 1106 1107 loadincludepath(); 1108 apply_builtin_macros(); 1109 apply_commandline_macros(); 1110 read_commandline_files(); 1111 place_setnowhere(&cmdplace); 1112 file_readabsolute(&cmdplace, inputfile); 1113 1114 cleanup(); 1115 if (complain_failed()) { 1116 return EXIT_FAILURE; 1117 } 1118 return EXIT_SUCCESS; 1119 } 1120