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 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_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 80struct warns warns = { 81 .endiflabels = true, 82 .nestcomment = false, 83 .undef = false, 84 .unused = false, 85}; 86 87//////////////////////////////////////////////////////////// 88// commandline macros 89 90struct commandline_macro { 91 struct place where; 92 struct place where2; 93 const char *macro; 94 const char *expansion; 95}; 96 97static struct array commandline_macros; 98 99static 100void 101commandline_macros_init(void) 102{ 103 array_init(&commandline_macros); 104} 105 106static 107void 108commandline_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 123static 124void 125commandline_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 139static 140void 141commandline_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 166static 167void 168commandline_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 177static 178void 179apply_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 198static 199void 200apply_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 208static 209void 210apply_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 218static 219void 220apply_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 258struct commandline_file { 259 struct place where; 260 char *name; 261 bool suppress_output; 262}; 263 264static struct array commandline_files; 265 266static 267void 268commandline_files_init(void) 269{ 270 array_init(&commandline_files); 271} 272 273static 274void 275commandline_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 292static 293void 294commandline_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 305static 306void 307commandline_addfile_output(const struct place *p, char *name) 308{ 309 commandline_addfile(p, name, false); 310} 311 312static 313void 314commandline_addfile_nooutput(const struct place *p, char *name) 315{ 316 commandline_addfile(p, name, true); 317} 318 319static 320void 321read_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 347static struct stringarray incpath_quote; 348static struct stringarray incpath_user; 349static struct stringarray incpath_system; 350static struct stringarray incpath_late; 351static const char *sysroot; 352 353static 354void 355incpath_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 363static 364void 365incpath_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 378static 379void 380commandline_isysroot(const struct place *p, char *dir) 381{ 382 (void)p; 383 sysroot = dir; 384} 385 386static 387void 388commandline_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 397static 398void 399commandline_addincpath_quote(const struct place *p, char *dir) 400{ 401 (void)p; 402 commandline_addincpath(&incpath_quote, dir); 403} 404 405static 406void 407commandline_addincpath_user(const struct place *p, char *dir) 408{ 409 (void)p; 410 commandline_addincpath(&incpath_user, dir); 411} 412 413static 414void 415commandline_addincpath_system(const struct place *p, char *dir) 416{ 417 (void)p; 418 commandline_addincpath(&incpath_system, dir); 419} 420 421static 422void 423commandline_addincpath_late(const struct place *p, char *dir) 424{ 425 (void)p; 426 commandline_addincpath(&incpath_late, dir); 427} 428 429static 430void 431loadincludepath(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 491static const char *commandline_prefix; 492 493static 494void 495commandline_setprefix(const struct place *p, char *prefix) 496{ 497 (void)p; 498 commandline_prefix = prefix; 499} 500 501static 502void 503commandline_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 516static 517void 518commandline_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 531static 532void 533commandline_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 544static 545void 546commandline_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 560DEAD static 561void 562commandline_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 571static 572void 573commandline_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 604static 605void 606commandline_dD(void) 607{ 608 mode.do_macrolist = true; 609 mode.macrolist_include_stddef = false; 610 mode.macrolist_include_expansions = true; 611} 612 613static 614void 615commandline_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 623static 624void 625commandline_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 636static 637void 638commandline_dI(void) 639{ 640 mode.do_trace = true; 641 mode.trace_namesonly = false; 642 mode.trace_indented = false; 643} 644 645static 646void 647commandline_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 658static 659void 660commandline_setdependtarget(const struct place *p, char *str) 661{ 662 (void)p; 663 mode.depend_target = str; 664 mode.depend_quote_target = false; 665} 666 667static 668void 669commandline_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 676static 677void 678commandline_setdependoutput(const struct place *p, char *str) 679{ 680 (void)p; 681 mode.depend_file = str; 682} 683 684static 685void 686commandline_M(void) 687{ 688 mode.do_depend = true; 689 mode.depend_report_system = true; 690 mode.do_output = false; 691} 692 693static 694void 695commandline_MM(void) 696{ 697 mode.do_depend = true; 698 mode.depend_report_system = false; 699 mode.do_output = false; 700} 701 702static 703void 704commandline_MD(void) 705{ 706 mode.do_depend = true; 707 mode.depend_report_system = true; 708} 709 710static 711void 712commandline_MMD(void) 713{ 714 mode.do_depend = true; 715 mode.depend_report_system = false; 716} 717 718static 719void 720commandline_wall(void) 721{ 722 warns.nestcomment = true; 723 warns.undef = true; 724 warns.unused = true; 725} 726 727static 728void 729commandline_wnoall(void) 730{ 731 warns.nestcomment = false; 732 warns.undef = false; 733 warns.unused = false; 734} 735 736static 737void 738commandline_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 749struct ignore_option { 750 const char *string; 751}; 752 753struct flag_option { 754 const char *string; 755 bool *flag; 756 bool setto; 757}; 758 759struct act_option { 760 const char *string; 761 void (*func)(void); 762}; 763 764struct prefix_option { 765 const char *string; 766 void (*func)(const struct place *, char *); 767}; 768 769struct arg_option { 770 const char *string; 771 void (*func)(const struct place *, char *); 772}; 773 774static const struct ignore_option ignore_options[] = { 775 { "m32" }, 776 { "traditional" }, 777}; 778static const unsigned num_ignore_options = HOWMANY(ignore_options); 779 780static 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}; 802static const unsigned num_flag_options = HOWMANY(flag_options); 803 804static 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}; 818static const unsigned num_act_options = HOWMANY(act_options); 819 820static 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}; 827static const unsigned num_prefix_options = HOWMANY(prefix_options); 828 829static 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}; 846static const unsigned num_arg_options = HOWMANY(arg_options); 847 848static 849bool 850check_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 867static 868bool 869check_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 887static 888bool 889check_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 907static 908bool 909check_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 928static 929bool 930check_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 954DEAD PF(2, 3) static 955void 956usage(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 987static struct stringarray freestrings; 988 989static 990void 991init(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 1005static 1006void 1007cleanup(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 1029void 1030die(void) 1031{ 1032 cleanup(); 1033 exit(EXIT_FAILURE); 1034} 1035 1036void 1037freestringlater(char *s) 1038{ 1039 stringarray_add(&freestrings, s, NULL); 1040} 1041 1042//////////////////////////////////////////////////////////// 1043// main 1044 1045int 1046main(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