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