math: array parameters can be NULL
[smatch.git] / options.c
blob9f05bdf9cf4fa3f25efdba33e5da2d64ebf595fa
1 // SPDX-License-Identifier: MIT
2 /*
3 * 'sparse' library helper routines.
5 * Copyright (C) 2003 Transmeta Corp.
6 * 2003-2004 Linus Torvalds
7 * 2017-2020 Luc Van Oostenryck
8 */
10 #include "options.h"
11 #include "lib.h"
12 #include "machine.h"
13 #include "target.h"
14 #include "version.h"
15 #include <ctype.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
21 #ifndef __GNUC__
22 # define __GNUC__ 2
23 # define __GNUC_MINOR__ 95
24 # define __GNUC_PATCHLEVEL__ 0
25 #endif
27 enum flag_type {
28 FLAG_OFF,
29 FLAG_ON,
30 FLAG_FORCE_OFF
33 int die_if_error = 0;
34 int do_output = 1;
35 int gcc_major = __GNUC__;
36 int gcc_minor = __GNUC_MINOR__;
37 int gcc_patchlevel = __GNUC_PATCHLEVEL__;
38 int has_error = 0;
39 int optimize_level;
40 int optimize_size;
41 int preprocess_only;
42 int preprocessing;
43 int verbose;
45 #define CMDLINE_INCLUDE 20
46 int cmdline_include_nr = 0;
47 char *cmdline_include[CMDLINE_INCLUDE];
49 const char *base_filename;
50 const char *diag_prefix = "";
51 const char *gcc_base_dir = GCC_BASE;
52 const char *multiarch_dir = MULTIARCH_TRIPLET;
53 const char *outfile = NULL;
55 enum standard standard = STANDARD_GNU89;
57 int arch_big_endian = ARCH_BIG_ENDIAN;
58 int arch_cmodel = CMODEL_UNKNOWN;
59 int arch_fp_abi = FP_ABI_NATIVE;
60 int arch_m64 = ARCH_M64_DEFAULT;
61 int arch_msize_long = 0;
62 int arch_os = OS_NATIVE;
64 int dbg_compound = 0;
65 int dbg_dead = 0;
66 int dbg_domtree = 0;
67 int dbg_entry = 0;
68 int dbg_ir = 0;
69 int dbg_postorder = 0;
71 int dump_macro_defs = 0;
72 int dump_macros_only = 0;
74 unsigned long fdump_ir;
75 int fhosted = 1;
76 unsigned int fmax_warnings = 100;
77 int fmem_report = 0;
78 unsigned long long fmemcpy_max_count = 100000;
79 unsigned long fpasses = ~0UL;
80 int fpic = 0;
81 int fpie = 0;
82 int fshort_wchar = 0;
83 int funsigned_char = 0;
85 int Waddress = 0;
86 int Waddress_space = 1;
87 int Wbitwise = 1;
88 int Wbitwise_pointer = 0;
89 int Wcast_from_as = 0;
90 int Wcast_to_as = 0;
91 int Wcast_truncate = 1;
92 int Wconstant_suffix = 0;
93 int Wconstexpr_not_const = 0;
94 int Wcontext = 1;
95 int Wdecl = 1;
96 int Wdeclarationafterstatement = -1;
97 int Wdefault_bitfield_sign = 0;
98 int Wdesignated_init = 1;
99 int Wdo_while = 0;
100 int Wenum_mismatch = 1;
101 int Wexternal_function_has_definition = 1;
102 int Wimplicit_int = 1;
103 int Winit_cstring = 0;
104 int Wint_to_pointer_cast = 1;
105 int Wmemcpy_max_count = 1;
106 int Wnewline_eof = 1;
107 int Wnon_pointer_null = 1;
108 int Wold_initializer = 1;
109 int Wold_style_definition = 1;
110 int Wone_bit_signed_bitfield = 1;
111 int Woverride_init = 1;
112 int Woverride_init_all = 0;
113 int Woverride_init_whole_range = 0;
114 int Wparen_string = 0;
115 int Wpedantic = 0;
116 int Wpointer_arith = 0;
117 int Wpointer_to_int_cast = 1;
118 int Wptr_subtraction_blows = 0;
119 int Wreturn_void = 0;
120 int Wshadow = 0;
121 int Wshift_count_negative = 1;
122 int Wshift_count_overflow = 1;
123 int Wsizeof_bool = 0;
124 int Wsparse_error = FLAG_FORCE_OFF;
125 int Wstrict_prototypes = 1;
126 int Wtautological_compare = 0;
127 int Wtransparent_union = 0;
128 int Wtypesign = 0;
129 int Wundef = 0;
130 int Wuninitialized = 1;
131 int Wuniversal_initializer = 0;
132 int Wunknown_attribute = 0;
133 int Wvla = 1;
135 ////////////////////////////////////////////////////////////////////////////////
136 // Helpers for option parsing
138 static const char *match_option(const char *arg, const char *prefix)
140 unsigned int n = strlen(prefix);
141 if (strncmp(arg, prefix, n) == 0)
142 return arg + n;
143 return NULL;
147 struct val_map {
148 const char *name;
149 int val;
152 static int handle_subopt_val(const char *opt, const char *arg, const struct val_map *map, int *flag)
154 const char *name;
156 if (*arg++ != '=')
157 die("missing argument for option '%s'", opt);
158 for (;(name = map->name); map++) {
159 if (strcmp(name, arg) == 0 || strcmp(name, "*") == 0) {
160 *flag = map->val;
161 return 1;
163 if (strcmp(name, "?") == 0)
164 die("invalid argument '%s' in option '%s'", arg, opt);
166 return 0;
170 struct mask_map {
171 const char *name;
172 unsigned long mask;
175 static int apply_mask(unsigned long *val, const char *str, unsigned len, const struct mask_map *map, int neg)
177 const char *name;
179 for (;(name = map->name); map++) {
180 if (!strncmp(name, str, len) && !name[len]) {
181 if (neg == 0)
182 *val |= map->mask;
183 else
184 *val &= ~map->mask;
185 return 0;
188 return 1;
191 static int handle_suboption_mask(const char *arg, const char *opt, const struct mask_map *map, unsigned long *flag)
193 if (*opt == '\0') {
194 apply_mask(flag, "", 0, map, 0);
195 return 1;
197 if (*opt++ != '=')
198 return 0;
199 while (1) {
200 unsigned int len = strcspn(opt, ",+");
201 int neg = 0;
202 if (len == 0)
203 goto end;
204 if (!strncmp(opt, "no-", 3)) {
205 opt += 3;
206 len -= 3;
207 neg = 1;
209 if (apply_mask(flag, opt, len, map, neg))
210 die("error: wrong option '%.*s' for \'%s\'", len, opt, arg);
212 end:
213 opt += len;
214 if (*opt++ == '\0')
215 break;
217 return 1;
221 #define OPT_INVERSE 1
222 #define OPT_VAL 2
223 struct flag {
224 const char *name;
225 int *flag;
226 int (*fun)(const char *arg, const char *opt, const struct flag *, int options);
227 unsigned long mask;
228 int val;
231 static int handle_switches(const char *ori, const char *opt, const struct flag *flags)
233 const char *arg = opt;
234 int val = 1;
236 // Prefixe "no-" mean to turn flag off.
237 if (strncmp(arg, "no-", 3) == 0) {
238 arg += 3;
239 val = 0;
242 for (; flags->name; flags++) {
243 const char *opt = match_option(arg, flags->name);
244 int rc;
246 if (!opt)
247 continue;
249 if (flags->fun) {
250 int options = 0;
251 if (!val)
252 options |= OPT_INVERSE;
253 if ((rc = flags->fun(ori, opt, flags, options)))
254 return rc;
257 // boolean flag
258 if (opt[0] == '\0' && flags->flag) {
259 if (flags->mask & OPT_VAL)
260 val = flags->val;
261 if (flags->mask & OPT_INVERSE)
262 val = !val;
263 *flags->flag = val;
264 return 1;
268 // not handled
269 return 0;
272 static char **handle_onoff_switch(char *arg, char **next, const struct flag flags[])
274 int flag = FLAG_ON;
275 char *p = arg + 1;
276 unsigned i;
278 // Prefixes "no" and "no-" mean to turn warning off.
279 if (p[0] == 'n' && p[1] == 'o') {
280 p += 2;
281 if (p[0] == '-')
282 p++;
283 flag = FLAG_FORCE_OFF;
286 for (i = 0; flags[i].name; i++) {
287 if (!strcmp(p,flags[i].name)) {
288 *flags[i].flag = flag;
289 return next;
293 // Unknown.
294 return NULL;
297 static void handle_onoff_switch_finalize(const struct flag flags[])
299 unsigned i;
301 for (i = 0; flags[i].name; i++) {
302 if (*flags[i].flag == FLAG_FORCE_OFF)
303 *flags[i].flag = FLAG_OFF;
307 static int handle_switch_setval(const char *arg, const char *opt, const struct flag *flag, int options)
309 *(flag->flag) = flag->mask;
310 return 1;
314 #define OPTNUM_ZERO_IS_INF 1
315 #define OPTNUM_UNLIMITED 2
317 #define OPT_NUMERIC(NAME, TYPE, FUNCTION) \
318 static int opt_##NAME(const char *arg, const char *opt, TYPE *ptr, int flag) \
320 char *end; \
321 TYPE val; \
323 val = FUNCTION(opt, &end, 0); \
324 if (*end != '\0' || end == opt) { \
325 if ((flag & OPTNUM_UNLIMITED) && !strcmp(opt, "unlimited")) \
326 val = ~val; \
327 else \
328 die("error: wrong argument to \'%s\'", arg); \
330 if ((flag & OPTNUM_ZERO_IS_INF) && val == 0) \
331 val = ~val; \
332 *ptr = val; \
333 return 1; \
336 OPT_NUMERIC(ullong, unsigned long long, strtoull)
337 OPT_NUMERIC(uint, unsigned int, strtoul)
339 ////////////////////////////////////////////////////////////////////////////////
340 // Option parsing
342 static char **handle_switch_a(char *arg, char **next)
344 if (!strcmp(arg, "ansi"))
345 standard = STANDARD_C89;
347 return next;
350 static char **handle_switch_D(char *arg, char **next)
352 const char *name = arg + 1;
353 const char *value = "1";
355 if (!*name) {
356 arg = *++next;
357 if (!arg)
358 die("argument to `-D' is missing");
359 name = arg;
362 for (;;arg++) {
363 char c;
364 c = *arg;
365 if (!c)
366 break;
367 if (c == '=') {
368 *arg = '\0';
369 value = arg + 1;
370 break;
373 add_pre_buffer("#define %s %s\n", name, value);
374 return next;
377 static char **handle_switch_d(char *arg, char **next)
379 char *arg_char = arg + 1;
382 * -d<CHARS>, where <CHARS> is a sequence of characters, not preceded
383 * by a space. If you specify characters whose behaviour conflicts,
384 * the result is undefined.
386 while (*arg_char) {
387 switch (*arg_char) {
388 case 'M': /* dump just the macro definitions */
389 dump_macros_only = 1;
390 dump_macro_defs = 0;
391 break;
392 case 'D': /* like 'M', but also output pre-processed text */
393 dump_macro_defs = 1;
394 dump_macros_only = 0;
395 break;
396 case 'N': /* like 'D', but only output macro names not bodies */
397 break;
398 case 'I': /* like 'D', but also output #include directives */
399 break;
400 case 'U': /* like 'D', but only output expanded macros */
401 break;
403 arg_char++;
405 return next;
408 static char **handle_switch_E(char *arg, char **next)
410 if (arg[1] == '\0')
411 preprocess_only = 1;
412 return next;
415 static int handle_ftabstop(const char *arg, const char *opt, const struct flag *flag, int options)
417 unsigned long val;
418 char *end;
420 if (*opt == '\0')
421 die("error: missing argument to \"%s\"", arg);
423 /* we silently ignore silly values */
424 val = strtoul(opt, &end, 10);
425 if (*end == '\0' && 1 <= val && val <= 100)
426 tabstop = val;
428 return 1;
431 static int handle_fpasses(const char *arg, const char *opt, const struct flag *flag, int options)
433 unsigned long mask;
435 mask = flag->mask;
436 if (*opt == '\0') {
437 if (options & OPT_INVERSE)
438 fpasses &= ~mask;
439 else
440 fpasses |= mask;
441 return 1;
443 if (options & OPT_INVERSE)
444 return 0;
445 if (!strcmp(opt, "-enable")) {
446 fpasses |= mask;
447 return 1;
449 if (!strcmp(opt, "-disable")) {
450 fpasses &= ~mask;
451 return 1;
453 if (!strcmp(opt, "=last")) {
454 // clear everything above
455 mask |= mask - 1;
456 fpasses &= mask;
457 return 1;
459 return 0;
462 static int handle_fdiagnostic_prefix(const char *arg, const char *opt, const struct flag *flag, int options)
464 switch (*opt) {
465 case '\0':
466 diag_prefix = "sparse: ";
467 return 1;
468 case '=':
469 diag_prefix = xasprintf("%s: ", opt+1);
470 return 1;
471 default:
472 return 0;
476 static int handle_fdump_ir(const char *arg, const char *opt, const struct flag *flag, int options)
478 static const struct mask_map dump_ir_options[] = {
479 { "", PASS_LINEARIZE },
480 { "linearize", PASS_LINEARIZE },
481 { "mem2reg", PASS_MEM2REG },
482 { "final", PASS_FINAL },
483 { },
486 return handle_suboption_mask(arg, opt, dump_ir_options, &fdump_ir);
489 static int handle_fmemcpy_max_count(const char *arg, const char *opt, const struct flag *flag, int options)
491 opt_ullong(arg, opt, &fmemcpy_max_count, OPTNUM_ZERO_IS_INF|OPTNUM_UNLIMITED);
492 return 1;
495 static int handle_fmax_warnings(const char *arg, const char *opt, const struct flag *flag, int options)
497 opt_uint(arg, opt, &fmax_warnings, OPTNUM_UNLIMITED);
498 return 1;
501 static struct flag fflags[] = {
502 { "diagnostic-prefix", NULL, handle_fdiagnostic_prefix },
503 { "dump-ir", NULL, handle_fdump_ir },
504 { "freestanding", &fhosted, NULL, OPT_INVERSE },
505 { "hosted", &fhosted },
506 { "linearize", NULL, handle_fpasses, PASS_LINEARIZE },
507 { "max-warnings=", NULL, handle_fmax_warnings },
508 { "mem-report", &fmem_report },
509 { "memcpy-max-count=", NULL, handle_fmemcpy_max_count },
510 { "tabstop=", NULL, handle_ftabstop },
511 { "mem2reg", NULL, handle_fpasses, PASS_MEM2REG },
512 { "optim", NULL, handle_fpasses, PASS_OPTIM },
513 { "pic", &fpic, handle_switch_setval, 1 },
514 { "PIC", &fpic, handle_switch_setval, 2 },
515 { "pie", &fpie, handle_switch_setval, 1 },
516 { "PIE", &fpie, handle_switch_setval, 2 },
517 { "signed-char", &funsigned_char, NULL, OPT_INVERSE },
518 { "short-wchar", &fshort_wchar },
519 { "unsigned-char", &funsigned_char, NULL, },
520 { },
523 static char **handle_switch_f(char *arg, char **next)
525 if (handle_switches(arg-1, arg+1, fflags))
526 return next;
528 return next;
531 static char **handle_switch_G(char *arg, char **next)
533 if (!strcmp(arg, "G") && *next)
534 return next + 1; // "-G 0"
535 else
536 return next; // "-G0" or (bogus) terminal "-G"
539 static char **handle_base_dir(char *arg, char **next)
541 gcc_base_dir = *++next;
542 if (!gcc_base_dir)
543 die("missing argument for -gcc-base-dir option");
544 return next;
547 static char **handle_switch_g(char *arg, char **next)
549 if (!strcmp(arg, "gcc-base-dir"))
550 return handle_base_dir(arg, next);
552 return next;
555 static char **handle_switch_I(char *arg, char **next)
557 char *path = arg+1;
559 switch (arg[1]) {
560 case '-':
561 add_pre_buffer("#split_include\n");
562 break;
564 case '\0': /* Plain "-I" */
565 path = *++next;
566 if (!path)
567 die("missing argument for -I option");
568 /* Fall through */
569 default:
570 add_pre_buffer("#add_include \"%s/\"\n", path);
572 return next;
575 static void add_cmdline_include(char *filename)
577 if (cmdline_include_nr >= CMDLINE_INCLUDE)
578 die("too many include files for %s\n", filename);
579 cmdline_include[cmdline_include_nr++] = filename;
582 static char **handle_switch_i(char *arg, char **next)
584 if (*next && !strcmp(arg, "include"))
585 add_cmdline_include(*++next);
586 else if (*next && !strcmp(arg, "imacros"))
587 add_cmdline_include(*++next);
588 else if (*next && !strcmp(arg, "isystem")) {
589 char *path = *++next;
590 if (!path)
591 die("missing argument for -isystem option");
592 add_pre_buffer("#add_isystem \"%s/\"\n", path);
593 } else if (*next && !strcmp(arg, "idirafter")) {
594 char *path = *++next;
595 if (!path)
596 die("missing argument for -idirafter option");
597 add_pre_buffer("#add_dirafter \"%s/\"\n", path);
599 return next;
602 static char **handle_switch_M(char *arg, char **next)
604 if (!strcmp(arg, "MF") || !strcmp(arg,"MQ") || !strcmp(arg,"MT")) {
605 if (!*next)
606 die("missing argument for -%s option", arg);
607 return next + 1;
609 return next;
612 static int handle_mcmodel(const char *opt, const char *arg, const struct flag *flag, int options)
614 static const struct val_map cmodels[] = {
615 { "kernel", CMODEL_KERNEL },
616 { "large", CMODEL_LARGE },
617 { "medany", CMODEL_MEDANY },
618 { "medium", CMODEL_MEDIUM },
619 { "medlow", CMODEL_MEDLOW },
620 { "small", CMODEL_SMALL },
621 { "tiny", CMODEL_TINY },
622 { },
624 return handle_subopt_val(opt, arg, cmodels, flag->flag);
627 static int handle_mfloat_abi(const char *opt, const char *arg, const struct flag *flag, int options) {
628 static const struct val_map fp_abis[] = {
629 { "hard", FP_ABI_HARD },
630 { "soft", FP_ABI_SOFT },
631 { "softfp", FP_ABI_HYBRID },
632 { "?" },
634 return handle_subopt_val(opt, arg, fp_abis, flag->flag);
637 static char **handle_multiarch_dir(char *arg, char **next)
639 multiarch_dir = *++next;
640 if (!multiarch_dir)
641 die("missing argument for -multiarch-dir option");
642 return next;
645 static const struct flag mflags[] = {
646 { "64", &arch_m64, NULL, OPT_VAL, ARCH_LP64 },
647 { "32", &arch_m64, NULL, OPT_VAL, ARCH_LP32 },
648 { "31", &arch_m64, NULL, OPT_VAL, ARCH_LP32 },
649 { "16", &arch_m64, NULL, OPT_VAL, ARCH_LP32 },
650 { "x32",&arch_m64, NULL, OPT_VAL, ARCH_X32 },
651 { "size-llp64", &arch_m64, NULL, OPT_VAL, ARCH_LLP64 },
652 { "size-long", &arch_msize_long },
653 { "big-endian", &arch_big_endian, NULL },
654 { "little-endian", &arch_big_endian, NULL, OPT_INVERSE },
655 { "cmodel", &arch_cmodel, handle_mcmodel },
656 { "float-abi", &arch_fp_abi, handle_mfloat_abi },
657 { "hard-float", &arch_fp_abi, NULL, OPT_VAL, FP_ABI_HARD },
658 { "soft-float", &arch_fp_abi, NULL, OPT_VAL, FP_ABI_SOFT },
662 static char **handle_switch_m(char *arg, char **next)
664 if (!strcmp(arg, "multiarch-dir")) {
665 return handle_multiarch_dir(arg, next);
666 } else {
667 handle_switches(arg-1, arg+1, mflags);
670 return next;
673 static char **handle_nostdinc(char *arg, char **next)
675 add_pre_buffer("#nostdinc\n");
676 return next;
679 static char **handle_switch_n(char *arg, char **next)
681 if (!strcmp(arg, "nostdinc"))
682 return handle_nostdinc(arg, next);
684 return next;
687 static char **handle_switch_O(char *arg, char **next)
689 int level = 1;
690 if (arg[1] >= '0' && arg[1] <= '9')
691 level = arg[1] - '0';
692 optimize_level = level;
693 optimize_size = arg[1] == 's';
694 return next;
697 static char **handle_switch_o(char *arg, char **next)
699 if (!strcmp(arg, "o")) { // "-o foo"
700 if (!*++next)
701 die("argument to '-o' is missing");
702 outfile = *next;
704 // else "-ofoo"
706 return next;
709 static const struct flag pflags[] = {
710 { "pedantic", &Wpedantic, NULL, OPT_VAL, FLAG_ON },
714 static char **handle_switch_p(char *arg, char **next)
716 handle_switches(arg-1, arg, pflags);
717 return next;
720 static char **handle_switch_s(const char *arg, char **next)
722 if ((arg = match_option(arg, "std="))) {
723 if (!strcmp(arg, "c89") ||
724 !strcmp(arg, "iso9899:1990"))
725 standard = STANDARD_C89;
727 else if (!strcmp(arg, "iso9899:199409"))
728 standard = STANDARD_C94;
730 else if (!strcmp(arg, "c99") ||
731 !strcmp(arg, "c9x") ||
732 !strcmp(arg, "iso9899:1999") ||
733 !strcmp(arg, "iso9899:199x"))
734 standard = STANDARD_C99;
736 else if (!strcmp(arg, "gnu89"))
737 standard = STANDARD_GNU89;
739 else if (!strcmp(arg, "gnu99") || !strcmp(arg, "gnu9x"))
740 standard = STANDARD_GNU99;
742 else if (!strcmp(arg, "c11") ||
743 !strcmp(arg, "c1x") ||
744 !strcmp(arg, "iso9899:2011"))
745 standard = STANDARD_C11;
747 else if (!strcmp(arg, "gnu11"))
748 standard = STANDARD_GNU11;
750 else if (!strcmp(arg, "c17") ||
751 !strcmp(arg, "c18") ||
752 !strcmp(arg, "iso9899:2017") ||
753 !strcmp(arg, "iso9899:2018"))
754 standard = STANDARD_C17;
755 else if (!strcmp(arg, "gnu17") ||
756 !strcmp(arg, "gnu18"))
757 standard = STANDARD_GNU17;
759 else
760 die("Unsupported C dialect");
763 return next;
766 static char **handle_switch_U(char *arg, char **next)
768 const char *name = arg + 1;
769 add_pre_buffer("#undef %s\n", name);
770 return next;
773 static struct flag debugs[] = {
774 { "compound", &dbg_compound},
775 { "dead", &dbg_dead},
776 { "domtree", &dbg_domtree},
777 { "entry", &dbg_entry},
778 { "ir", &dbg_ir},
779 { "postorder", &dbg_postorder},
783 static char **handle_switch_v(char *arg, char **next)
785 char ** ret = handle_onoff_switch(arg, next, debugs);
786 if (ret)
787 return ret;
789 // Unknown.
790 do {
791 verbose++;
792 } while (*++arg == 'v');
793 return next;
796 static void handle_switch_v_finalize(void)
798 handle_onoff_switch_finalize(debugs);
801 static const struct flag warnings[] = {
802 { "address", &Waddress },
803 { "address-space", &Waddress_space },
804 { "bitwise", &Wbitwise },
805 { "bitwise-pointer", &Wbitwise_pointer},
806 { "cast-from-as", &Wcast_from_as },
807 { "cast-to-as", &Wcast_to_as },
808 { "cast-truncate", &Wcast_truncate },
809 { "constant-suffix", &Wconstant_suffix },
810 { "constexpr-not-const", &Wconstexpr_not_const},
811 { "context", &Wcontext },
812 { "decl", &Wdecl },
813 { "declaration-after-statement", &Wdeclarationafterstatement },
814 { "default-bitfield-sign", &Wdefault_bitfield_sign },
815 { "designated-init", &Wdesignated_init },
816 { "do-while", &Wdo_while },
817 { "enum-mismatch", &Wenum_mismatch },
818 { "external-function-has-definition", &Wexternal_function_has_definition },
819 { "implicit-int", &Wimplicit_int },
820 { "init-cstring", &Winit_cstring },
821 { "int-to-pointer-cast", &Wint_to_pointer_cast },
822 { "memcpy-max-count", &Wmemcpy_max_count },
823 { "non-pointer-null", &Wnon_pointer_null },
824 { "newline-eof", &Wnewline_eof },
825 { "old-initializer", &Wold_initializer },
826 { "old-style-definition", &Wold_style_definition },
827 { "one-bit-signed-bitfield", &Wone_bit_signed_bitfield },
828 { "override-init", &Woverride_init },
829 { "override-init-all", &Woverride_init_all },
830 { "paren-string", &Wparen_string },
831 { "pedantic", &Wpedantic },
832 { "pointer-to-int-cast", &Wpointer_to_int_cast },
833 { "ptr-subtraction-blows", &Wptr_subtraction_blows },
834 { "return-void", &Wreturn_void },
835 { "shadow", &Wshadow },
836 { "shift-count-negative", &Wshift_count_negative },
837 { "shift-count-overflow", &Wshift_count_overflow },
838 { "sizeof-bool", &Wsizeof_bool },
839 { "strict-prototypes", &Wstrict_prototypes },
840 { "pointer-arith", &Wpointer_arith },
841 { "sparse-error", &Wsparse_error },
842 { "tautological-compare", &Wtautological_compare },
843 { "transparent-union", &Wtransparent_union },
844 { "typesign", &Wtypesign },
845 { "undef", &Wundef },
846 { "uninitialized", &Wuninitialized },
847 { "universal-initializer", &Wuniversal_initializer },
848 { "unknown-attribute", &Wunknown_attribute },
849 { "vla", &Wvla },
853 static char **handle_switch_W(char *arg, char **next)
855 char ** ret = handle_onoff_switch(arg, next, warnings);
856 if (ret)
857 return ret;
859 if (!strcmp(arg, "Wsparse-all")) {
860 int i;
861 for (i = 0; warnings[i].name; i++) {
862 if (*warnings[i].flag != FLAG_FORCE_OFF)
863 *warnings[i].flag = FLAG_ON;
867 // Unknown.
868 return next;
871 static void handle_switch_W_finalize(void)
873 handle_onoff_switch_finalize(warnings);
875 /* default Wdeclarationafterstatement based on the C dialect */
876 if (-1 == Wdeclarationafterstatement) {
877 switch (standard) {
878 case STANDARD_C89:
879 case STANDARD_C94:
880 Wdeclarationafterstatement = 1;
881 break;
882 default:
883 Wdeclarationafterstatement = 0;
884 break;
889 static char **handle_switch_x(char *arg, char **next)
891 if (!*++next)
892 die("missing argument for -x option");
893 return next;
897 static char **handle_arch(char *arg, char **next)
899 enum machine mach;
901 if (*arg++ != '=')
902 die("missing argument for --arch option");
904 mach = target_parse(arg);
905 if (mach != MACH_UNKNOWN)
906 target_config(mach);
908 return next;
911 static char **handle_param(char *arg, char **next)
913 char *value = NULL;
915 /* For now just skip any '--param=*' or '--param *' */
916 if (*arg == '\0') {
917 value = *++next;
918 } else if (isspace((unsigned char)*arg) || *arg == '=') {
919 value = ++arg;
922 if (!value)
923 die("missing argument for --param option");
925 return next;
928 static char **handle_version(char *arg, char **next)
930 printf("%s\n", SPARSE_VERSION);
931 exit(0);
934 struct switches {
935 const char *name;
936 char **(*fn)(char *, char **);
937 unsigned int prefix:1;
940 static char **handle_long_options(char *arg, char **next)
942 static struct switches cmd[] = {
943 { "arch", handle_arch, 1 },
944 { "param", handle_param, 1 },
945 { "version", handle_version },
946 { NULL, NULL }
948 struct switches *s = cmd;
950 while (s->name) {
951 int optlen = strlen(s->name);
952 if (!strncmp(s->name, arg, optlen + !s->prefix))
953 return s->fn(arg + optlen, next);
954 s++;
956 return next;
959 char **handle_switch(char *arg, char **next)
961 switch (*arg) {
962 case 'a': return handle_switch_a(arg, next);
963 case 'D': return handle_switch_D(arg, next);
964 case 'd': return handle_switch_d(arg, next);
965 case 'E': return handle_switch_E(arg, next);
966 case 'f': return handle_switch_f(arg, next);
967 case 'g': return handle_switch_g(arg, next);
968 case 'G': return handle_switch_G(arg, next);
969 case 'I': return handle_switch_I(arg, next);
970 case 'i': return handle_switch_i(arg, next);
971 case 'M': return handle_switch_M(arg, next);
972 case 'm': return handle_switch_m(arg, next);
973 case 'n': return handle_switch_n(arg, next);
974 case 'o': return handle_switch_o(arg, next);
975 case 'O': return handle_switch_O(arg, next);
976 case 'p': return handle_switch_p(arg, next);
977 case 's': return handle_switch_s(arg, next);
978 case 'U': return handle_switch_U(arg, next);
979 case 'v': return handle_switch_v(arg, next);
980 case 'W': return handle_switch_W(arg, next);
981 case 'x': return handle_switch_x(arg, next);
982 case '-': return handle_long_options(arg + 1, next);
983 default:
984 break;
988 * Ignore unknown command line options:
989 * they're probably gcc switches
991 return next;
994 void handle_switch_finalize(void)
996 handle_switch_v_finalize();
997 handle_switch_W_finalize();