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