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
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_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
79 struct warns warns = {
80 .endiflabels = true,
81 .nestcomment = false,
82 .undef = false,
83 .unused = false,
84 };
85
86 ////////////////////////////////////////////////////////////
87 // commandline macros
88
89 struct commandline_macro {
90 struct place where;
91 struct place where2;
92 const char *macro;
93 const char *expansion;
94 };
95
96 static struct array commandline_macros;
97
98 static
99 void
commandline_macros_init(void)100 commandline_macros_init(void)
101 {
102 array_init(&commandline_macros);
103 }
104
105 static
106 void
commandline_macros_cleanup(void)107 commandline_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
122 static
123 void
commandline_macro_add(const struct place * p,const char * macro,const struct place * p2,const char * expansion)124 commandline_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
138 static
139 void
commandline_def(const struct place * p,char * str)140 commandline_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
165 static
166 void
commandline_undef(const struct place * p,char * str)167 commandline_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
176 static
177 void
apply_commandline_macros(void)178 apply_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
197 static
198 void
apply_magic_macro(unsigned num,const char * name)199 apply_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
207 static
208 void
apply_builtin_macro(unsigned num,const char * name,const char * val)209 apply_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
217 static
218 void
apply_builtin_macros(void)219 apply_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
257 struct commandline_file {
258 struct place where;
259 char *name;
260 bool suppress_output;
261 };
262
263 static struct array commandline_files;
264
265 static
266 void
commandline_files_init(void)267 commandline_files_init(void)
268 {
269 array_init(&commandline_files);
270 }
271
272 static
273 void
commandline_files_cleanup(void)274 commandline_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
291 static
292 void
commandline_addfile(const struct place * p,char * name,bool suppress_output)293 commandline_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
304 static
305 void
commandline_addfile_output(const struct place * p,char * name)306 commandline_addfile_output(const struct place *p, char *name)
307 {
308 commandline_addfile(p, name, false);
309 }
310
311 static
312 void
commandline_addfile_nooutput(const struct place * p,char * name)313 commandline_addfile_nooutput(const struct place *p, char *name)
314 {
315 commandline_addfile(p, name, true);
316 }
317
318 static
319 void
read_commandline_files(void)320 read_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
346 static struct stringarray incpath_quote;
347 static struct stringarray incpath_user;
348 static struct stringarray incpath_system;
349 static struct stringarray incpath_late;
350 static const char *sysroot;
351
352 static
353 void
incpath_init(void)354 incpath_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
362 static
363 void
incpath_cleanup(void)364 incpath_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
377 static
378 void
commandline_isysroot(const struct place * p,char * dir)379 commandline_isysroot(const struct place *p, char *dir)
380 {
381 (void)p;
382 sysroot = dir;
383 }
384
385 static
386 void
commandline_addincpath(struct stringarray * arr,char * s)387 commandline_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
396 static
397 void
commandline_addincpath_quote(const struct place * p,char * dir)398 commandline_addincpath_quote(const struct place *p, char *dir)
399 {
400 (void)p;
401 commandline_addincpath(&incpath_quote, dir);
402 }
403
404 static
405 void
commandline_addincpath_user(const struct place * p,char * dir)406 commandline_addincpath_user(const struct place *p, char *dir)
407 {
408 (void)p;
409 commandline_addincpath(&incpath_user, dir);
410 }
411
412 static
413 void
commandline_addincpath_system(const struct place * p,char * dir)414 commandline_addincpath_system(const struct place *p, char *dir)
415 {
416 (void)p;
417 commandline_addincpath(&incpath_system, dir);
418 }
419
420 static
421 void
commandline_addincpath_late(const struct place * p,char * dir)422 commandline_addincpath_late(const struct place *p, char *dir)
423 {
424 (void)p;
425 commandline_addincpath(&incpath_late, dir);
426 }
427
428 static
429 void
loadincludepath(void)430 loadincludepath(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
490 static const char *commandline_prefix;
491
492 static
493 void
commandline_setprefix(const struct place * p,char * prefix)494 commandline_setprefix(const struct place *p, char *prefix)
495 {
496 (void)p;
497 commandline_prefix = prefix;
498 }
499
500 static
501 void
commandline_addincpath_user_withprefix(const struct place * p,char * dir)502 commandline_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
515 static
516 void
commandline_addincpath_late_withprefix(const struct place * p,char * dir)517 commandline_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
530 static
531 void
commandline_setstd(const struct place * p,char * std)532 commandline_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
543 static
544 void
commandline_setlang(const struct place * p,char * lang)545 commandline_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
559 DEAD static
560 void
commandline_iremap(const struct place * p,char * str)561 commandline_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
570 static
571 void
commandline_tabstop(const struct place * p,char * s)572 commandline_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
603 static
604 void
commandline_dD(void)605 commandline_dD(void)
606 {
607 mode.do_macrolist = true;
608 mode.macrolist_include_stddef = false;
609 mode.macrolist_include_expansions = true;
610 }
611
612 static
613 void
commandline_dM(void)614 commandline_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
622 static
623 void
commandline_dN(void)624 commandline_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
635 static
636 void
commandline_dI(void)637 commandline_dI(void)
638 {
639 mode.do_trace = true;
640 mode.trace_namesonly = false;
641 mode.trace_indented = false;
642 }
643
644 static
645 void
commandline_H(void)646 commandline_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
657 static
658 void
commandline_setdependtarget(const struct place * p,char * str)659 commandline_setdependtarget(const struct place *p, char *str)
660 {
661 (void)p;
662 mode.depend_target = str;
663 mode.depend_quote_target = false;
664 }
665
666 static
667 void
commandline_setdependtarget_quoted(const struct place * p,char * str)668 commandline_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
675 static
676 void
commandline_setdependoutput(const struct place * p,char * str)677 commandline_setdependoutput(const struct place *p, char *str)
678 {
679 (void)p;
680 mode.depend_file = str;
681 }
682
683 static
684 void
commandline_M(void)685 commandline_M(void)
686 {
687 mode.do_depend = true;
688 mode.depend_report_system = true;
689 mode.do_output = false;
690 }
691
692 static
693 void
commandline_MM(void)694 commandline_MM(void)
695 {
696 mode.do_depend = true;
697 mode.depend_report_system = false;
698 mode.do_output = false;
699 }
700
701 static
702 void
commandline_MD(void)703 commandline_MD(void)
704 {
705 mode.do_depend = true;
706 mode.depend_report_system = true;
707 }
708
709 static
710 void
commandline_MMD(void)711 commandline_MMD(void)
712 {
713 mode.do_depend = true;
714 mode.depend_report_system = false;
715 }
716
717 static
718 void
commandline_wall(void)719 commandline_wall(void)
720 {
721 warns.nestcomment = true;
722 warns.undef = true;
723 warns.unused = true;
724 }
725
726 static
727 void
commandline_wnoall(void)728 commandline_wnoall(void)
729 {
730 warns.nestcomment = false;
731 warns.undef = false;
732 warns.unused = false;
733 }
734
735 static
736 void
commandline_wnone(void)737 commandline_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
748 struct ignore_option {
749 const char *string;
750 };
751
752 struct flag_option {
753 const char *string;
754 bool *flag;
755 bool setto;
756 };
757
758 struct act_option {
759 const char *string;
760 void (*func)(void);
761 };
762
763 struct prefix_option {
764 const char *string;
765 void (*func)(const struct place *, char *);
766 };
767
768 struct arg_option {
769 const char *string;
770 void (*func)(const struct place *, char *);
771 };
772
773 static const struct ignore_option ignore_options[] = {
774 { "m32" },
775 { "traditional" },
776 };
777 static const unsigned num_ignore_options = HOWMANY(ignore_options);
778
779 static 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 };
801 static const unsigned num_flag_options = HOWMANY(flag_options);
802
803 static 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 };
817 static const unsigned num_act_options = HOWMANY(act_options);
818
819 static 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 };
826 static const unsigned num_prefix_options = HOWMANY(prefix_options);
827
828 static 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 };
845 static const unsigned num_arg_options = HOWMANY(arg_options);
846
847 static
848 bool
check_ignore_option(const char * opt)849 check_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
866 static
867 bool
check_flag_option(const char * opt)868 check_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
886 static
887 bool
check_act_option(const char * opt)888 check_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
906 static
907 bool
check_prefix_option(const struct place * p,char * opt)908 check_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
927 static
928 bool
check_arg_option(const char * opt,const struct place * argplace,char * arg)929 check_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
953 DEAD PF(2, 3) static
954 void
usage(const char * progname,const char * fmt,...)955 usage(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
986 static struct stringarray freestrings;
987
988 static
989 void
init(void)990 init(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
1004 static
1005 void
cleanup(void)1006 cleanup(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
1028 void
die(void)1029 die(void)
1030 {
1031 cleanup();
1032 exit(EXIT_FAILURE);
1033 }
1034
1035 void
freestringlater(char * s)1036 freestringlater(char *s)
1037 {
1038 stringarray_add(&freestrings, s, NULL);
1039 }
1040
1041 ////////////////////////////////////////////////////////////
1042 // main
1043
1044 int
main(int argc,char * argv[])1045 main(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