comparison main.c @ 4:ee9a66b87c70

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