strings: fix crash bug parsing foo = bar ?: baz
[smatch.git] / options.c
blob6ee4d878a473639bf1f53c61a524da1d6e0ac021
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 <ctype.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
20 #ifndef __GNUC__
21 # define __GNUC__ 2
22 # define __GNUC_MINOR__ 95
23 # define __GNUC_PATCHLEVEL__ 0
24 #endif
26 enum flag_type {
27 FLAG_OFF,
28 FLAG_ON,
29 FLAG_FORCE_OFF
32 int die_if_error = 0;
33 int do_output = 1;
34 int gcc_major = __GNUC__;
35 int gcc_minor = __GNUC_MINOR__;
36 int gcc_patchlevel = __GNUC_PATCHLEVEL__;
37 int has_error = 0;
38 int optimize_level;
39 int optimize_size;
40 int preprocess_only;
41 int preprocessing;
42 int verbose;
44 #define CMDLINE_INCLUDE 20
45 int cmdline_include_nr = 0;
46 char *cmdline_include[CMDLINE_INCLUDE];
48 const char *base_filename;
49 const char *diag_prefix = "";
50 const char *gcc_base_dir = GCC_BASE;
51 const char *multiarch_dir = MULTIARCH_TRIPLET;
52 const char *outfile = NULL;
54 enum standard standard = STANDARD_GNU89;
56 int arch_big_endian = ARCH_BIG_ENDIAN;
57 int arch_cmodel = CMODEL_UNKNOWN;
58 int arch_fp_abi = FP_ABI_NATIVE;
59 int arch_m64 = ARCH_M64_DEFAULT;
60 int arch_msize_long = 0;
61 int arch_os = OS_NATIVE;
63 int dbg_compound = 0;
64 int dbg_dead = 0;
65 int dbg_domtree = 0;
66 int dbg_entry = 0;
67 int dbg_ir = 0;
68 int dbg_postorder = 0;
70 int dump_macro_defs = 0;
71 int dump_macros_only = 0;
73 int dissect_show_all_symbols = 0;
75 unsigned long fdump_ir;
76 int fhosted = 1;
77 unsigned int fmax_errors = 100;
78 unsigned int fmax_warnings = 100;
79 int fmem_report = 0;
80 unsigned long long fmemcpy_max_count = 100000;
81 unsigned long fpasses = ~0UL;
82 int fpic = 0;
83 int fpie = 0;
84 int fshort_wchar = 0;
85 int funsigned_bitfields = 0;
86 int funsigned_char = 0;
88 int Waddress = 0;
89 int Waddress_space = 1;
90 int Wbitwise = 1;
91 int Wbitwise_pointer = 0;
92 int Wcast_from_as = 0;
93 int Wcast_to_as = 0;
94 int Wcast_truncate = 1;
95 int Wconstant_suffix = 0;
96 int Wconstexpr_not_const = 0;
97 int Wcontext = 1;
98 int Wdecl = 1;
99 int Wdeclarationafterstatement = -1;
100 int Wdefault_bitfield_sign = 0;
101 int Wdesignated_init = 1;
102 int Wdo_while = 0;
103 int Wenum_mismatch = 1;
104 int Wexternal_function_has_definition = 1;
105 int Wflexible_array_array = 1;
106 int Wflexible_array_nested = 0;
107 int Wflexible_array_sizeof = 0;
108 int Wflexible_array_union = 0;
109 int Wimplicit_int = 1;
110 int Winit_cstring = 0;
111 int Wint_to_pointer_cast = 1;
112 int Wmemcpy_max_count = 1;
113 int Wnewline_eof = 1;
114 int Wnon_pointer_null = 1;
115 int Wold_initializer = 1;
116 int Wold_style_definition = 1;
117 int Wone_bit_signed_bitfield = 1;
118 int Woverride_init = 1;
119 int Woverride_init_all = 0;
120 int Woverride_init_whole_range = 0;
121 int Wparen_string = 0;
122 int Wpast_deep_designator = 0;
123 int Wpedantic = 0;
124 int Wpointer_arith = 0;
125 int Wpointer_to_int_cast = 1;
126 int Wptr_subtraction_blows = 0;
127 int Wreturn_void = 0;
128 int Wshadow = 0;
129 int Wshift_count_negative = 1;
130 int Wshift_count_overflow = 1;
131 int Wsizeof_bool = 0;
132 int Wsparse_error = FLAG_FORCE_OFF;
133 int Wstrict_prototypes = 1;
134 int Wtautological_compare = 0;
135 int Wtransparent_union = 0;
136 int Wtypesign = 0;
137 int Wundef = 0;
138 int Wuninitialized = 1;
139 int Wunion_cast = 0;
140 int Wuniversal_initializer = 0;
141 int Wunknown_attribute = 0;
142 int Wvla = 1;
144 ////////////////////////////////////////////////////////////////////////////////
145 // Helpers for option parsing
147 static const char *match_option(const char *arg, const char *prefix)
149 unsigned int n = strlen(prefix);
150 if (strncmp(arg, prefix, n) == 0)
151 return arg + n;
152 return NULL;
156 struct val_map {
157 const char *name;
158 int val;
161 static int handle_subopt_val(const char *opt, const char *arg, const struct val_map *map, int *flag)
163 const char *name;
165 if (*arg++ != '=')
166 die("missing argument for option '%s'", opt);
167 for (;(name = map->name); map++) {
168 if (strcmp(name, arg) == 0 || strcmp(name, "*") == 0) {
169 *flag = map->val;
170 return 1;
172 if (strcmp(name, "?") == 0)
173 die("invalid argument '%s' in option '%s'", arg, opt);
175 return 0;
179 struct mask_map {
180 const char *name;
181 unsigned long mask;
184 static int apply_mask(unsigned long *val, const char *str, unsigned len, const struct mask_map *map, int neg)
186 const char *name;
188 for (;(name = map->name); map++) {
189 if (!strncmp(name, str, len) && !name[len]) {
190 if (neg == 0)
191 *val |= map->mask;
192 else
193 *val &= ~map->mask;
194 return 0;
197 return 1;
200 static int handle_suboption_mask(const char *arg, const char *opt, const struct mask_map *map, unsigned long *flag)
202 if (*opt == '\0') {
203 apply_mask(flag, "", 0, map, 0);
204 return 1;
206 if (*opt++ != '=')
207 return 0;
208 while (1) {
209 unsigned int len = strcspn(opt, ",+");
210 int neg = 0;
211 if (len == 0)
212 goto end;
213 if (!strncmp(opt, "no-", 3)) {
214 opt += 3;
215 len -= 3;
216 neg = 1;
218 if (apply_mask(flag, opt, len, map, neg))
219 die("error: wrong option '%.*s' for \'%s\'", len, opt, arg);
221 end:
222 opt += len;
223 if (*opt++ == '\0')
224 break;
226 return 1;
230 #define OPT_INVERSE 1
231 #define OPT_VAL 2
232 struct flag {
233 const char *name;
234 int *flag;
235 int (*fun)(const char *arg, const char *opt, const struct flag *, int options);
236 unsigned long mask;
237 int val;
240 static int handle_switches(const char *ori, const char *opt, const struct flag *flags)
242 const char *arg = opt;
243 int val = 1;
245 // Prefixe "no-" mean to turn flag off.
246 if (strncmp(arg, "no-", 3) == 0) {
247 arg += 3;
248 val = 0;
251 for (; flags->name; flags++) {
252 const char *opt = match_option(arg, flags->name);
253 int rc;
255 if (!opt)
256 continue;
258 if (flags->fun) {
259 int options = 0;
260 if (!val)
261 options |= OPT_INVERSE;
262 if ((rc = flags->fun(ori, opt, flags, options)))
263 return rc;
266 // boolean flag
267 if (opt[0] == '\0' && flags->flag) {
268 if (flags->mask & OPT_VAL)
269 val = flags->val;
270 if (flags->mask & OPT_INVERSE)
271 val = !val;
272 *flags->flag = val;
273 return 1;
277 // not handled
278 return 0;
281 static char **handle_onoff_switch(char *arg, char **next, const struct flag flags[])
283 int flag = FLAG_ON;
284 char *p = arg + 1;
285 unsigned i;
287 // Prefixes "no" and "no-" mean to turn warning off.
288 if (p[0] == 'n' && p[1] == 'o') {
289 p += 2;
290 if (p[0] == '-')
291 p++;
292 flag = FLAG_FORCE_OFF;
295 for (i = 0; flags[i].name; i++) {
296 if (!strcmp(p,flags[i].name)) {
297 *flags[i].flag = flag;
298 return next;
302 // Unknown.
303 return NULL;
306 static void handle_onoff_switch_finalize(const struct flag flags[])
308 unsigned i;
310 for (i = 0; flags[i].name; i++) {
311 if (*flags[i].flag == FLAG_FORCE_OFF)
312 *flags[i].flag = FLAG_OFF;
316 static int handle_switch_setval(const char *arg, const char *opt, const struct flag *flag, int options)
318 *(flag->flag) = flag->mask;
319 return 1;
323 #define OPTNUM_ZERO_IS_INF 1
324 #define OPTNUM_UNLIMITED 2
326 #define OPT_NUMERIC(NAME, TYPE, FUNCTION) \
327 static int opt_##NAME(const char *arg, const char *opt, TYPE *ptr, int flag) \
329 char *end; \
330 TYPE val; \
332 val = FUNCTION(opt, &end, 0); \
333 if (*end != '\0' || end == opt) { \
334 if ((flag & OPTNUM_UNLIMITED) && !strcmp(opt, "unlimited")) \
335 val = ~val; \
336 else \
337 die("error: wrong argument to \'%s\'", arg); \
339 if ((flag & OPTNUM_ZERO_IS_INF) && val == 0) \
340 val = ~val; \
341 *ptr = val; \
342 return 1; \
345 OPT_NUMERIC(ullong, unsigned long long, strtoull)
346 OPT_NUMERIC(uint, unsigned int, strtoul)
348 ////////////////////////////////////////////////////////////////////////////////
349 // Option parsing
351 static char **handle_switch_a(char *arg, char **next)
353 if (!strcmp(arg, "ansi"))
354 standard = STANDARD_C89;
356 return next;
359 static char **handle_switch_D(char *arg, char **next)
361 const char *name = arg + 1;
362 const char *value = "1";
364 if (!*name) {
365 arg = *++next;
366 if (!arg)
367 die("argument to `-D' is missing");
368 name = arg;
371 for (;;arg++) {
372 char c;
373 c = *arg;
374 if (!c)
375 break;
376 if (c == '=') {
377 *arg = '\0';
378 value = arg + 1;
379 break;
382 add_pre_buffer("#define %s %s\n", name, value);
383 return next;
386 static char **handle_switch_d(char *arg, char **next)
388 char *arg_char = arg + 1;
391 * -d<CHARS>, where <CHARS> is a sequence of characters, not preceded
392 * by a space. If you specify characters whose behaviour conflicts,
393 * the result is undefined.
395 while (*arg_char) {
396 switch (*arg_char) {
397 case 'M': /* dump just the macro definitions */
398 dump_macros_only = 1;
399 dump_macro_defs = 0;
400 break;
401 case 'D': /* like 'M', but also output pre-processed text */
402 dump_macro_defs = 1;
403 dump_macros_only = 0;
404 break;
405 case 'N': /* like 'D', but only output macro names not bodies */
406 break;
407 case 'I': /* like 'D', but also output #include directives */
408 break;
409 case 'U': /* like 'D', but only output expanded macros */
410 break;
412 arg_char++;
414 return next;
417 static char **handle_switch_E(char *arg, char **next)
419 if (arg[1] == '\0')
420 preprocess_only = 1;
421 return next;
424 static int handle_ftabstop(const char *arg, const char *opt, const struct flag *flag, int options)
426 unsigned long val;
427 char *end;
429 if (*opt == '\0')
430 die("error: missing argument to \"%s\"", arg);
432 /* we silently ignore silly values */
433 val = strtoul(opt, &end, 10);
434 if (*end == '\0' && 1 <= val && val <= 100)
435 tabstop = val;
437 return 1;
440 static int handle_fpasses(const char *arg, const char *opt, const struct flag *flag, int options)
442 unsigned long mask;
444 mask = flag->mask;
445 if (*opt == '\0') {
446 if (options & OPT_INVERSE)
447 fpasses &= ~mask;
448 else
449 fpasses |= mask;
450 return 1;
452 if (options & OPT_INVERSE)
453 return 0;
454 if (!strcmp(opt, "-enable")) {
455 fpasses |= mask;
456 return 1;
458 if (!strcmp(opt, "-disable")) {
459 fpasses &= ~mask;
460 return 1;
462 if (!strcmp(opt, "=last")) {
463 // clear everything above
464 mask |= mask - 1;
465 fpasses &= mask;
466 return 1;
468 return 0;
471 static int handle_fdiagnostic_prefix(const char *arg, const char *opt, const struct flag *flag, int options)
473 switch (*opt) {
474 case '\0':
475 diag_prefix = "sparse: ";
476 return 1;
477 case '=':
478 diag_prefix = xasprintf("%s: ", opt+1);
479 return 1;
480 default:
481 return 0;
485 static int handle_fdump_ir(const char *arg, const char *opt, const struct flag *flag, int options)
487 static const struct mask_map dump_ir_options[] = {
488 { "", PASS_LINEARIZE },
489 { "linearize", PASS_LINEARIZE },
490 { "mem2reg", PASS_MEM2REG },
491 { "final", PASS_FINAL },
492 { },
495 return handle_suboption_mask(arg, opt, dump_ir_options, &fdump_ir);
498 static int handle_fmemcpy_max_count(const char *arg, const char *opt, const struct flag *flag, int options)
500 opt_ullong(arg, opt, &fmemcpy_max_count, OPTNUM_ZERO_IS_INF|OPTNUM_UNLIMITED);
501 return 1;
504 static int handle_fmax_errors(const char *arg, const char *opt, const struct flag *flag, int options)
506 opt_uint(arg, opt, &fmax_errors, OPTNUM_UNLIMITED);
507 return 1;
510 static int handle_fmax_warnings(const char *arg, const char *opt, const struct flag *flag, int options)
512 opt_uint(arg, opt, &fmax_warnings, OPTNUM_UNLIMITED);
513 return 1;
516 static struct flag fflags[] = {
517 { "diagnostic-prefix", NULL, handle_fdiagnostic_prefix },
518 { "dump-ir", NULL, handle_fdump_ir },
519 { "freestanding", &fhosted, NULL, OPT_INVERSE },
520 { "hosted", &fhosted },
521 { "linearize", NULL, handle_fpasses, PASS_LINEARIZE },
522 { "max-errors=", NULL, handle_fmax_errors },
523 { "max-warnings=", NULL, handle_fmax_warnings },
524 { "mem-report", &fmem_report },
525 { "memcpy-max-count=", NULL, handle_fmemcpy_max_count },
526 { "tabstop=", NULL, handle_ftabstop },
527 { "mem2reg", NULL, handle_fpasses, PASS_MEM2REG },
528 { "optim", NULL, handle_fpasses, PASS_OPTIM },
529 { "pic", &fpic, handle_switch_setval, 1 },
530 { "PIC", &fpic, handle_switch_setval, 2 },
531 { "pie", &fpie, handle_switch_setval, 1 },
532 { "PIE", &fpie, handle_switch_setval, 2 },
533 { "signed-bitfields", &funsigned_bitfields, NULL, OPT_INVERSE },
534 { "unsigned-bitfields", &funsigned_bitfields, NULL, },
535 { "signed-char", &funsigned_char, NULL, OPT_INVERSE },
536 { "short-wchar", &fshort_wchar },
537 { "unsigned-char", &funsigned_char, NULL, },
538 { },
541 static char **handle_switch_f(char *arg, char **next)
543 if (handle_switches(arg-1, arg+1, fflags))
544 return next;
546 return next;
549 static char **handle_switch_G(char *arg, char **next)
551 if (!strcmp(arg, "G") && *next)
552 return next + 1; // "-G 0"
553 else
554 return next; // "-G0" or (bogus) terminal "-G"
557 static char **handle_base_dir(char *arg, char **next)
559 gcc_base_dir = *++next;
560 if (!gcc_base_dir)
561 die("missing argument for -gcc-base-dir option");
562 return next;
565 static char **handle_switch_g(char *arg, char **next)
567 if (!strcmp(arg, "gcc-base-dir"))
568 return handle_base_dir(arg, next);
570 return next;
573 static char **handle_switch_I(char *arg, char **next)
575 char *path = arg+1;
577 switch (arg[1]) {
578 case '-':
579 add_pre_buffer("#split_include\n");
580 break;
582 case '\0': /* Plain "-I" */
583 path = *++next;
584 if (!path)
585 die("missing argument for -I option");
586 /* Fall through */
587 default:
588 add_pre_buffer("#add_include \"%s/\"\n", path);
590 return next;
593 static void add_cmdline_include(char *filename)
595 if (cmdline_include_nr >= CMDLINE_INCLUDE)
596 die("too many include files for %s\n", filename);
597 cmdline_include[cmdline_include_nr++] = filename;
600 static char **handle_switch_i(char *arg, char **next)
602 if (*next && !strcmp(arg, "include"))
603 add_cmdline_include(*++next);
604 else if (*next && !strcmp(arg, "imacros"))
605 add_cmdline_include(*++next);
606 else if (*next && !strcmp(arg, "isystem")) {
607 char *path = *++next;
608 if (!path)
609 die("missing argument for -isystem option");
610 add_pre_buffer("#add_isystem \"%s/\"\n", path);
611 } else if (*next && !strcmp(arg, "idirafter")) {
612 char *path = *++next;
613 if (!path)
614 die("missing argument for -idirafter option");
615 add_pre_buffer("#add_dirafter \"%s/\"\n", path);
617 return next;
620 static char **handle_switch_M(char *arg, char **next)
622 if (!strcmp(arg, "MF") || !strcmp(arg,"MQ") || !strcmp(arg,"MT")) {
623 if (!*next)
624 die("missing argument for -%s option", arg);
625 return next + 1;
627 return next;
630 static int handle_march(const char *opt, const char *arg, const struct flag *flag, int options)
632 if (arch_target->parse_march)
633 arch_target->parse_march(arg);
634 return 1;
637 static int handle_mcmodel(const char *opt, const char *arg, const struct flag *flag, int options)
639 static const struct val_map cmodels[] = {
640 { "kernel", CMODEL_KERNEL },
641 { "large", CMODEL_LARGE },
642 { "medany", CMODEL_MEDANY },
643 { "medium", CMODEL_MEDIUM },
644 { "medlow", CMODEL_MEDLOW },
645 { "small", CMODEL_SMALL },
646 { "tiny", CMODEL_TINY },
647 { },
649 return handle_subopt_val(opt, arg, cmodels, flag->flag);
652 static int handle_mfloat_abi(const char *opt, const char *arg, const struct flag *flag, int options) {
653 static const struct val_map fp_abis[] = {
654 { "hard", FP_ABI_HARD },
655 { "soft", FP_ABI_SOFT },
656 { "softfp", FP_ABI_HYBRID },
657 { "?" },
659 return handle_subopt_val(opt, arg, fp_abis, flag->flag);
662 static char **handle_multiarch_dir(char *arg, char **next)
664 multiarch_dir = *++next;
665 if (!multiarch_dir)
666 die("missing argument for -multiarch-dir option");
667 return next;
670 static const struct flag mflags[] = {
671 { "64", &arch_m64, NULL, OPT_VAL, ARCH_LP64 },
672 { "32", &arch_m64, NULL, OPT_VAL, ARCH_LP32 },
673 { "31", &arch_m64, NULL, OPT_VAL, ARCH_LP32 },
674 { "16", &arch_m64, NULL, OPT_VAL, ARCH_LP32 },
675 { "x32",&arch_m64, NULL, OPT_VAL, ARCH_X32 },
676 { "size-llp64", &arch_m64, NULL, OPT_VAL, ARCH_LLP64 },
677 { "size-long", &arch_msize_long },
678 { "arch=", NULL, handle_march },
679 { "big-endian", &arch_big_endian, NULL },
680 { "little-endian", &arch_big_endian, NULL, OPT_INVERSE },
681 { "cmodel", &arch_cmodel, handle_mcmodel },
682 { "float-abi", &arch_fp_abi, handle_mfloat_abi },
683 { "hard-float", &arch_fp_abi, NULL, OPT_VAL, FP_ABI_HARD },
684 { "soft-float", &arch_fp_abi, NULL, OPT_VAL, FP_ABI_SOFT },
688 static char **handle_switch_m(char *arg, char **next)
690 if (!strcmp(arg, "meabi") && next[1] && next[1][0] != '-') {
691 // clang has such an option with syntax: -meabi <arg>
692 // It's used by the kernel for armv7.
693 // GCC has the same option but with no argument.
694 // Parse it here to consume the possible argument.
695 static const char *valid[] = { "gnu", "4", "5", "default", NULL };
696 int i;
697 for (i = 0; valid[i]; i++) {
698 if (!strcmp(next[1], valid[i]))
699 return ++next;
703 if (!strcmp(arg, "multiarch-dir")) {
704 return handle_multiarch_dir(arg, next);
705 } else {
706 handle_switches(arg-1, arg+1, mflags);
709 return next;
712 static char **handle_nostdinc(char *arg, char **next)
714 add_pre_buffer("#nostdinc\n");
715 return next;
718 static char **handle_switch_n(char *arg, char **next)
720 if (!strcmp(arg, "nostdinc"))
721 return handle_nostdinc(arg, next);
723 return next;
726 static char **handle_switch_O(char *arg, char **next)
728 int level = 1;
729 if (arg[1] >= '0' && arg[1] <= '9')
730 level = arg[1] - '0';
731 optimize_level = level;
732 optimize_size = arg[1] == 's';
733 return next;
736 static char **handle_switch_o(char *arg, char **next)
738 if (!strcmp(arg, "o")) { // "-o foo"
739 if (!*++next)
740 die("argument to '-o' is missing");
741 outfile = *next;
743 // else "-ofoo"
745 return next;
748 static const struct flag pflags[] = {
749 { "pedantic", &Wpedantic, NULL, OPT_VAL, FLAG_ON },
753 static char **handle_switch_p(char *arg, char **next)
755 handle_switches(arg-1, arg, pflags);
756 return next;
759 static char **handle_switch_s(const char *arg, char **next)
761 if ((arg = match_option(arg, "std="))) {
762 if (!strcmp(arg, "c89") ||
763 !strcmp(arg, "iso9899:1990"))
764 standard = STANDARD_C89;
766 else if (!strcmp(arg, "iso9899:199409"))
767 standard = STANDARD_C94;
769 else if (!strcmp(arg, "c99") ||
770 !strcmp(arg, "c9x") ||
771 !strcmp(arg, "iso9899:1999") ||
772 !strcmp(arg, "iso9899:199x"))
773 standard = STANDARD_C99;
775 else if (!strcmp(arg, "gnu89"))
776 standard = STANDARD_GNU89;
778 else if (!strcmp(arg, "gnu99") || !strcmp(arg, "gnu9x"))
779 standard = STANDARD_GNU99;
781 else if (!strcmp(arg, "c11") ||
782 !strcmp(arg, "c1x") ||
783 !strcmp(arg, "iso9899:2011"))
784 standard = STANDARD_C11;
786 else if (!strcmp(arg, "gnu11"))
787 standard = STANDARD_GNU11;
789 else if (!strcmp(arg, "c17") ||
790 !strcmp(arg, "c18") ||
791 !strcmp(arg, "iso9899:2017") ||
792 !strcmp(arg, "iso9899:2018"))
793 standard = STANDARD_C17;
794 else if (!strcmp(arg, "gnu17") ||
795 !strcmp(arg, "gnu18"))
796 standard = STANDARD_GNU17;
798 else
799 die("Unsupported C dialect");
802 return next;
805 static char **handle_switch_U(char *arg, char **next)
807 const char *name = arg + 1;
809 if (*name == '\0') {
810 name = *++next;
811 if (!name)
812 die("argument to `-U' is missing");
814 add_pre_buffer("#undef %s\n", name);
815 return next;
818 static struct flag debugs[] = {
819 { "compound", &dbg_compound},
820 { "dead", &dbg_dead},
821 { "domtree", &dbg_domtree},
822 { "entry", &dbg_entry},
823 { "ir", &dbg_ir},
824 { "postorder", &dbg_postorder},
828 static char **handle_switch_v(char *arg, char **next)
830 char ** ret = handle_onoff_switch(arg, next, debugs);
831 if (ret)
832 return ret;
834 // Unknown.
835 do {
836 verbose++;
837 } while (*++arg == 'v');
838 return next;
841 static void handle_switch_v_finalize(void)
843 handle_onoff_switch_finalize(debugs);
846 static const struct flag warnings[] = {
847 { "address", &Waddress },
848 { "address-space", &Waddress_space },
849 { "bitwise", &Wbitwise },
850 { "bitwise-pointer", &Wbitwise_pointer},
851 { "cast-from-as", &Wcast_from_as },
852 { "cast-to-as", &Wcast_to_as },
853 { "cast-truncate", &Wcast_truncate },
854 { "constant-suffix", &Wconstant_suffix },
855 { "constexpr-not-const", &Wconstexpr_not_const},
856 { "context", &Wcontext },
857 { "decl", &Wdecl },
858 { "declaration-after-statement", &Wdeclarationafterstatement },
859 { "default-bitfield-sign", &Wdefault_bitfield_sign },
860 { "designated-init", &Wdesignated_init },
861 { "do-while", &Wdo_while },
862 { "enum-mismatch", &Wenum_mismatch },
863 { "external-function-has-definition", &Wexternal_function_has_definition },
864 { "flexible-array-array", &Wflexible_array_array },
865 { "flexible-array-nested", &Wflexible_array_nested },
866 { "flexible-array-sizeof", &Wflexible_array_sizeof },
867 { "flexible-array-union", &Wflexible_array_union },
868 { "implicit-int", &Wimplicit_int },
869 { "init-cstring", &Winit_cstring },
870 { "int-to-pointer-cast", &Wint_to_pointer_cast },
871 { "memcpy-max-count", &Wmemcpy_max_count },
872 { "non-pointer-null", &Wnon_pointer_null },
873 { "newline-eof", &Wnewline_eof },
874 { "old-initializer", &Wold_initializer },
875 { "old-style-definition", &Wold_style_definition },
876 { "one-bit-signed-bitfield", &Wone_bit_signed_bitfield },
877 { "override-init", &Woverride_init },
878 { "override-init-all", &Woverride_init_all },
879 { "paren-string", &Wparen_string },
880 { "past-deep-designator", &Wpast_deep_designator },
881 { "pedantic", &Wpedantic },
882 { "pointer-to-int-cast", &Wpointer_to_int_cast },
883 { "ptr-subtraction-blows", &Wptr_subtraction_blows },
884 { "return-void", &Wreturn_void },
885 { "shadow", &Wshadow },
886 { "shift-count-negative", &Wshift_count_negative },
887 { "shift-count-overflow", &Wshift_count_overflow },
888 { "sizeof-bool", &Wsizeof_bool },
889 { "strict-prototypes", &Wstrict_prototypes },
890 { "pointer-arith", &Wpointer_arith },
891 { "sparse-error", &Wsparse_error },
892 { "tautological-compare", &Wtautological_compare },
893 { "transparent-union", &Wtransparent_union },
894 { "typesign", &Wtypesign },
895 { "undef", &Wundef },
896 { "uninitialized", &Wuninitialized },
897 { "union-cast", &Wunion_cast },
898 { "universal-initializer", &Wuniversal_initializer },
899 { "unknown-attribute", &Wunknown_attribute },
900 { "vla", &Wvla },
904 static char **handle_switch_W(char *arg, char **next)
906 char ** ret = handle_onoff_switch(arg, next, warnings);
907 if (ret)
908 return ret;
910 if (!strcmp(arg, "Wsparse-all")) {
911 int i;
912 for (i = 0; warnings[i].name; i++) {
913 if (*warnings[i].flag != FLAG_FORCE_OFF)
914 *warnings[i].flag = FLAG_ON;
918 // Unknown.
919 return next;
922 static void handle_switch_W_finalize(void)
924 handle_onoff_switch_finalize(warnings);
926 /* default Wdeclarationafterstatement based on the C dialect */
927 if (-1 == Wdeclarationafterstatement) {
928 switch (standard) {
929 case STANDARD_C89:
930 case STANDARD_C94:
931 Wdeclarationafterstatement = 1;
932 break;
933 default:
934 Wdeclarationafterstatement = 0;
935 break;
940 static char **handle_switch_x(char *arg, char **next)
942 if (!*++next)
943 die("missing argument for -x option");
944 return next;
948 static char **handle_arch(char *arg, char **next)
950 enum machine mach;
952 if (*arg++ != '=')
953 die("missing argument for --arch option");
955 mach = target_parse(arg);
956 if (mach != MACH_UNKNOWN)
957 target_config(mach);
959 return next;
962 static char **handle_param(char *arg, char **next)
964 char *value = NULL;
966 /* For now just skip any '--param=*' or '--param *' */
967 if (*arg == '\0') {
968 value = *++next;
969 } else if (isspace((unsigned char)*arg) || *arg == '=') {
970 value = ++arg;
973 if (!value)
974 die("missing argument for --param option");
976 if (!strcmp(value, "dissect-show-all-symbols"))
977 dissect_show_all_symbols = 1;
979 return next;
982 static char **handle_os(char *arg, char **next)
984 if (*arg++ != '=')
985 die("missing argument for --os option");
987 target_os(arg);
989 return next;
992 static char **handle_version(char *arg, char **next)
994 printf("%s\n", sparse_version);
995 exit(0);
998 struct switches {
999 const char *name;
1000 char **(*fn)(char *, char **);
1001 unsigned int prefix:1;
1004 static char **handle_long_options(char *arg, char **next)
1006 static struct switches cmd[] = {
1007 { "arch", handle_arch, 1 },
1008 { "os", handle_os, 1 },
1009 { "param", handle_param, 1 },
1010 { "version", handle_version },
1011 { NULL, NULL }
1013 struct switches *s = cmd;
1015 while (s->name) {
1016 int optlen = strlen(s->name);
1017 if (!strncmp(s->name, arg, optlen + !s->prefix))
1018 return s->fn(arg + optlen, next);
1019 s++;
1021 return next;
1024 char **handle_switch(char *arg, char **next)
1026 switch (*arg) {
1027 case 'a': return handle_switch_a(arg, next);
1028 case 'D': return handle_switch_D(arg, next);
1029 case 'd': return handle_switch_d(arg, next);
1030 case 'E': return handle_switch_E(arg, next);
1031 case 'f': return handle_switch_f(arg, next);
1032 case 'g': return handle_switch_g(arg, next);
1033 case 'G': return handle_switch_G(arg, next);
1034 case 'I': return handle_switch_I(arg, next);
1035 case 'i': return handle_switch_i(arg, next);
1036 case 'M': return handle_switch_M(arg, next);
1037 case 'm': return handle_switch_m(arg, next);
1038 case 'n': return handle_switch_n(arg, next);
1039 case 'o': return handle_switch_o(arg, next);
1040 case 'O': return handle_switch_O(arg, next);
1041 case 'p': return handle_switch_p(arg, next);
1042 case 's': return handle_switch_s(arg, next);
1043 case 'U': return handle_switch_U(arg, next);
1044 case 'v': return handle_switch_v(arg, next);
1045 case 'W': return handle_switch_W(arg, next);
1046 case 'x': return handle_switch_x(arg, next);
1047 case '-': return handle_long_options(arg + 1, next);
1048 default:
1049 break;
1053 * Ignore unknown command line options:
1054 * they're probably gcc switches
1056 return next;
1059 void handle_switch_finalize(void)
1061 handle_switch_v_finalize();
1062 handle_switch_W_finalize();