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