GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: libexec/tradcpp/main.c Lines: 0 333 0.0 %
Date: 2017-11-07 Branches: 0 118 0.0 %

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