/* Command line option handling. Copyright (C) 2006, 2007, 2008, 2010 Free Software Foundation, Inc. This file is part of GCC. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "intl.h" #include "coretypes.h" #include "opts.h" #include "options.h" #include "diagnostic.h" #include "tm.h" /* For SWITCH_TAKES_ARG, WORD_SWITCH_TAKES_ARG and TARGET_OPTION_TRANSLATE_TABLE. */ static void prune_options (struct cl_decoded_option **, unsigned int *); /* Perform a binary search to find which option the command-line INPUT matches. Returns its index in the option array, and OPT_SPECIAL_unknown on failure. This routine is quite subtle. A normal binary search is not good enough because some options can be suffixed with an argument, and multiple sub-matches can occur, e.g. input of "-pedantic" matching the initial substring of "-pedantic-errors". A more complicated example is -gstabs. It should match "-g" with an argument of "stabs". Suppose, however, that the number and list of switches are such that the binary search tests "-gen-decls" before having tested "-g". This doesn't match, and as "-gen-decls" is less than "-gstabs", it will become the lower bound of the binary search range, and "-g" will never be seen. To resolve this issue, 'optc-gen.awk' makes "-gen-decls" point, via the back_chain member, to "-g" so that failed searches that end between "-gen-decls" and the lexicographically subsequent switch know to go back and see if "-g" causes a match (which it does in this example). This search is done in such a way that the longest match for the front end in question wins. If there is no match for the current front end, the longest match for a different front end is returned (or N_OPTS if none) and the caller emits an error message. */ size_t find_opt (const char *input, int lang_mask) { size_t mn, mn_orig, mx, md, opt_len; size_t match_wrong_lang; int comp; mn = 0; mx = cl_options_count; /* Find mn such this lexicographical inequality holds: cl_options[mn] <= input < cl_options[mn + 1]. */ while (mx - mn > 1) { md = (mn + mx) / 2; opt_len = cl_options[md].opt_len; comp = strncmp (input, cl_options[md].opt_text + 1, opt_len); if (comp < 0) mx = md; else mn = md; } mn_orig = mn; /* This is the switch that is the best match but for a different front end, or OPT_SPECIAL_unknown if there is no match at all. */ match_wrong_lang = OPT_SPECIAL_unknown; /* Backtrace the chain of possible matches, returning the longest one, if any, that fits best. With current GCC switches, this loop executes at most twice. */ do { const struct cl_option *opt = &cl_options[mn]; /* Is the input either an exact match or a prefix that takes a joined argument? */ if (!strncmp (input, opt->opt_text + 1, opt->opt_len) && (input[opt->opt_len] == '\0' || (opt->flags & CL_JOINED))) { /* If language is OK, return it. */ if (opt->flags & lang_mask) return mn; /* If we haven't remembered a prior match, remember this one. Any prior match is necessarily better. */ if (match_wrong_lang == OPT_SPECIAL_unknown) match_wrong_lang = mn; } /* Try the next possibility. This is cl_options_count if there are no more. */ mn = opt->back_chain; } while (mn != cl_options_count); if (match_wrong_lang == OPT_SPECIAL_unknown && input[0] == '-') { /* Long options, starting "--", may be abbreviated if the abbreviation is unambiguous. This only applies to options not taking a joined argument, and abbreviations of "--option" are permitted even if there is a variant "--option=". */ size_t mnc = mn_orig + 1; size_t cmp_len = strlen (input); while (mnc < cl_options_count && strncmp (input, cl_options[mnc].opt_text + 1, cmp_len) == 0) { /* Option matching this abbreviation. OK if it is the first match and that does not take a joined argument, or the second match, taking a joined argument and with only '=' added to the first match; otherwise considered ambiguous. */ if (mnc == mn_orig + 1 && !(cl_options[mnc].flags & CL_JOINED)) match_wrong_lang = mnc; else if (mnc == mn_orig + 2 && match_wrong_lang == mn_orig + 1 && (cl_options[mnc].flags & CL_JOINED) && (cl_options[mnc].opt_len == cl_options[mn_orig + 1].opt_len + 1) && strncmp (cl_options[mnc].opt_text + 1, cl_options[mn_orig + 1].opt_text + 1, cl_options[mn_orig + 1].opt_len) == 0) ; /* OK, as long as there are no more matches. */ else return OPT_SPECIAL_unknown; mnc++; } } /* Return the best wrong match, or OPT_SPECIAL_unknown if none. */ return match_wrong_lang; } /* If ARG is a non-negative integer made up solely of digits, return its value, otherwise return -1. */ int integral_argument (const char *arg) { const char *p = arg; while (*p && ISDIGIT (*p)) p++; if (*p == '\0') return atoi (arg); return -1; } /* Return whether OPTION is OK for the language given by LANG_MASK. */ static bool option_ok_for_language (const struct cl_option *option, unsigned int lang_mask) { if (!(option->flags & lang_mask)) return false; else if ((option->flags & CL_TARGET) && (option->flags & (CL_LANG_ALL | CL_DRIVER)) && !(option->flags & (lang_mask & ~CL_COMMON & ~CL_TARGET))) /* Complain for target flag language mismatches if any languages are specified. */ return false; return true; } /* Fill in the canonical option part of *DECODED with an option described by OPT_INDEX, ARG and VALUE. */ static void generate_canonical_option (size_t opt_index, const char *arg, int value, struct cl_decoded_option *decoded) { const struct cl_option *option = &cl_options[opt_index]; const char *opt_text = option->opt_text; if (value == 0 && !(option->flags & CL_REJECT_NEGATIVE) && (opt_text[1] == 'W' || opt_text[1] == 'f' || opt_text[1] == 'm')) { char *t = XNEWVEC (char, option->opt_len + 5); t[0] = '-'; t[1] = opt_text[1]; t[2] = 'n'; t[3] = 'o'; t[4] = '-'; memcpy (t + 5, opt_text + 2, option->opt_len); opt_text = t; } decoded->canonical_option[2] = NULL; decoded->canonical_option[3] = NULL; if (arg) { if ((option->flags & CL_SEPARATE) && !(option->flags & CL_SEPARATE_ALIAS)) { decoded->canonical_option[0] = opt_text; decoded->canonical_option[1] = arg; decoded->canonical_option_num_elements = 2; } else { gcc_assert (option->flags & CL_JOINED); decoded->canonical_option[0] = concat (opt_text, arg, NULL); decoded->canonical_option[1] = NULL; decoded->canonical_option_num_elements = 1; } } else { decoded->canonical_option[0] = opt_text; decoded->canonical_option[1] = NULL; decoded->canonical_option_num_elements = 1; } } /* Structure describing mappings from options on the command line to options to look up with find_opt. */ struct option_map { /* Prefix of the option on the command line. */ const char *opt0; /* If two argv elements are considered to be merged into one option, prefix for the second element, otherwise NULL. */ const char *opt1; /* The new prefix to map to. */ const char *new_prefix; /* Whether at least one character is needed following opt1 or opt0 for this mapping to be used. (--optimize= is valid for -O, but --warn- is not valid for -W.) */ bool another_char_needed; /* Whether the original option is a negated form of the option resulting from this map. */ bool negated; }; static const struct option_map option_map[] = { { "-Wno-", NULL, "-W", false, true }, { "-fno-", NULL, "-f", false, true }, { "-mno-", NULL, "-m", false, true }, { "--debug=", NULL, "-g", false, false }, { "--machine-", NULL, "-m", true, false }, { "--machine-no-", NULL, "-m", false, true }, { "--machine=", NULL, "-m", false, false }, { "--machine=no-", NULL, "-m", false, true }, { "--machine", "", "-m", false, false }, { "--machine", "no-", "-m", false, true }, { "--optimize=", NULL, "-O", false, false }, { "--std=", NULL, "-std=", false, false }, { "--std", "", "-std=", false, false }, { "--warn-", NULL, "-W", true, false }, { "--warn-no-", NULL, "-W", false, true }, { "--", NULL, "-f", true, false }, { "--no-", NULL, "-f", false, true } }; /* Decode the switch beginning at ARGV for the language indicated by LANG_MASK (including CL_COMMON and CL_TARGET if applicable), into the structure *DECODED. Returns the number of switches consumed. */ static unsigned int decode_cmdline_option (const char **argv, unsigned int lang_mask, struct cl_decoded_option *decoded) { size_t opt_index; const char *arg = 0; int value = 1; unsigned int result = 1, i, extra_args; int adjust_len = 0; size_t total_len; char *p; const struct cl_option *option; int errors = 0; const char *warn_message = NULL; bool separate_arg_flag; bool joined_arg_flag; bool have_separate_arg = false; extra_args = 0; opt_index = find_opt (argv[0] + 1, lang_mask); i = 0; while (opt_index == OPT_SPECIAL_unknown && i < ARRAY_SIZE (option_map)) { const char *opt0 = option_map[i].opt0; const char *opt1 = option_map[i].opt1; const char *new_prefix = option_map[i].new_prefix; bool another_char_needed = option_map[i].another_char_needed; size_t opt0_len = strlen (opt0); size_t opt1_len = (opt1 == NULL ? 0 : strlen (opt1)); size_t optn_len = (opt1 == NULL ? opt0_len : opt1_len); size_t new_prefix_len = strlen (new_prefix); extra_args = (opt1 == NULL ? 0 : 1); value = !option_map[i].negated; if (strncmp (argv[0], opt0, opt0_len) == 0 && (opt1 == NULL || (argv[1] != NULL && strncmp (argv[1], opt1, opt1_len) == 0)) && (!another_char_needed || argv[extra_args][optn_len] != 0)) { size_t arglen = strlen (argv[extra_args]); char *dup; adjust_len = (int) optn_len - (int) new_prefix_len; dup = XNEWVEC (char, arglen + 1 - adjust_len); memcpy (dup, new_prefix, new_prefix_len); memcpy (dup + new_prefix_len, argv[extra_args] + optn_len, arglen - optn_len + 1); opt_index = find_opt (dup + 1, lang_mask); free (dup); } i++; } if (opt_index == OPT_SPECIAL_unknown) { arg = argv[0]; extra_args = 0; value = 1; goto done; } option = &cl_options[opt_index]; /* Reject negative form of switches that don't take negatives as unrecognized. */ if (!value && (option->flags & CL_REJECT_NEGATIVE)) { opt_index = OPT_SPECIAL_unknown; errors |= CL_ERR_NEGATIVE; arg = argv[0]; goto done; } result = extra_args + 1; warn_message = option->warn_message; /* Check to see if the option is disabled for this configuration. */ if (option->flags & CL_DISABLED) errors |= CL_ERR_DISABLED; /* Determine whether there may be a separate argument based on whether this option is being processed for the driver. */ separate_arg_flag = ((option->flags & CL_SEPARATE) && !((option->flags & CL_NO_DRIVER_ARG) && (lang_mask & CL_DRIVER))); joined_arg_flag = (option->flags & CL_JOINED) != 0; /* Sort out any argument the switch takes. */ if (joined_arg_flag) { /* Have arg point to the original switch. This is because some code, such as disable_builtin_function, expects its argument to be persistent until the program exits. */ arg = argv[extra_args] + cl_options[opt_index].opt_len + 1 + adjust_len; if (*arg == '\0' && !(option->flags & CL_MISSING_OK)) { if (separate_arg_flag) { arg = argv[extra_args + 1]; result = extra_args + 2; if (arg == NULL) result = extra_args + 1; else have_separate_arg = true; } else /* Missing argument. */ arg = NULL; } } else if (separate_arg_flag) { arg = argv[extra_args + 1]; result = extra_args + 2; if (arg == NULL) result = extra_args + 1; else have_separate_arg = true; } if (arg == NULL && (separate_arg_flag || joined_arg_flag)) errors |= CL_ERR_MISSING_ARG; /* Is this option an alias (or an ignored option, marked as an alias of OPT_SPECIAL_ignore)? */ if (option->alias_target != N_OPTS && (!(option->flags & CL_SEPARATE_ALIAS) || have_separate_arg)) { size_t new_opt_index = option->alias_target; if (new_opt_index == OPT_SPECIAL_ignore) { gcc_assert (option->alias_arg == NULL); gcc_assert (option->neg_alias_arg == NULL); opt_index = new_opt_index; arg = NULL; value = 1; } else { const struct cl_option *new_option = &cl_options[new_opt_index]; /* The new option must not be an alias itself. */ gcc_assert (new_option->alias_target == N_OPTS || (new_option->flags & CL_SEPARATE_ALIAS)); if (option->neg_alias_arg) { gcc_assert (option->alias_arg != NULL); gcc_assert (arg == NULL); if (value) arg = option->alias_arg; else arg = option->neg_alias_arg; value = 1; } else if (option->alias_arg) { gcc_assert (value == 1); gcc_assert (arg == NULL); arg = option->alias_arg; } opt_index = new_opt_index; option = new_option; if (value == 0) gcc_assert (!(option->flags & CL_REJECT_NEGATIVE)); /* Recompute what arguments are allowed. */ separate_arg_flag = ((option->flags & CL_SEPARATE) && !((option->flags & CL_NO_DRIVER_ARG) && (lang_mask & CL_DRIVER))); joined_arg_flag = (option->flags & CL_JOINED) != 0; if (!(errors & CL_ERR_MISSING_ARG)) { if (separate_arg_flag || joined_arg_flag) { if ((option->flags & CL_MISSING_OK) && arg == NULL) arg = ""; gcc_assert (arg != NULL); } else gcc_assert (arg == NULL); } /* Recheck for warnings and disabled options. */ if (option->warn_message) { gcc_assert (warn_message == NULL); warn_message = option->warn_message; } if (option->flags & CL_DISABLED) errors |= CL_ERR_DISABLED; } } /* Check if this is a switch for a different front end. */ if (!option_ok_for_language (option, lang_mask)) errors |= CL_ERR_WRONG_LANG; /* If the switch takes an integer, convert it. */ if (arg && (option->flags & CL_UINTEGER)) { value = integral_argument (arg); if (value == -1) errors |= CL_ERR_UINT_ARG; } done: decoded->opt_index = opt_index; decoded->arg = arg; decoded->value = value; decoded->errors = errors; decoded->warn_message = warn_message; if (opt_index == OPT_SPECIAL_unknown) { /* Skip the correct number of arguments for options handled through specs. */ const char *popt = argv[0] + 1; int c = *popt; gcc_assert (result == 1); if (SWITCH_TAKES_ARG (c) > (popt[1] != 0)) result += SWITCH_TAKES_ARG (c) - (popt[1] != 0); else if (WORD_SWITCH_TAKES_ARG (popt)) result += WORD_SWITCH_TAKES_ARG (popt); if (result > 1) for (i = 1; i < result; i++) if (argv[i] == NULL) { result = i; break; } } gcc_assert (result >= 1 && result <= ARRAY_SIZE (decoded->canonical_option)); decoded->canonical_option_num_elements = result; total_len = 0; for (i = 0; i < ARRAY_SIZE (decoded->canonical_option); i++) { if (i < result) { if (opt_index == OPT_SPECIAL_unknown) decoded->canonical_option[i] = argv[i]; else decoded->canonical_option[i] = NULL; total_len += strlen (argv[i]) + 1; } else decoded->canonical_option[i] = NULL; } if (opt_index != OPT_SPECIAL_unknown && opt_index != OPT_SPECIAL_ignore) generate_canonical_option (opt_index, arg, value, decoded); decoded->orig_option_with_args_text = p = XNEWVEC (char, total_len); for (i = 0; i < result; i++) { size_t len = strlen (argv[i]); memcpy (p, argv[i], len); p += len; if (i == result - 1) *p++ = 0; else *p++ = ' '; } return result; } #ifdef TARGET_OPTION_TRANSLATE_TABLE static const struct { const char *const option_found; const char *const replacements; } target_option_translations[] = { TARGET_OPTION_TRANSLATE_TABLE, { 0, 0 } }; #endif /* Decode command-line options (ARGC and ARGV being the arguments of main) into an array, setting *DECODED_OPTIONS to a pointer to that array and *DECODED_OPTIONS_COUNT to the number of entries in the array. The first entry in the array is always one for the program name (OPT_SPECIAL_program_name). LANG_MASK indicates the language flags applicable for decoding (including CL_COMMON and CL_TARGET if those options should be considered applicable). Do not produce any diagnostics or set state outside of these variables. */ void decode_cmdline_options_to_array (unsigned int argc, const char **argv, unsigned int lang_mask, struct cl_decoded_option **decoded_options, unsigned int *decoded_options_count) { unsigned int n, i, target_translate_from; struct cl_decoded_option *opt_array; unsigned int num_decoded_options; bool argv_copied = false; opt_array = XNEWVEC (struct cl_decoded_option, argc); opt_array[0].opt_index = OPT_SPECIAL_program_name; opt_array[0].warn_message = NULL; opt_array[0].arg = argv[0]; opt_array[0].orig_option_with_args_text = argv[0]; opt_array[0].canonical_option_num_elements = 1; opt_array[0].canonical_option[0] = argv[0]; opt_array[0].canonical_option[1] = NULL; opt_array[0].canonical_option[2] = NULL; opt_array[0].canonical_option[3] = NULL; opt_array[0].value = 1; opt_array[0].errors = 0; num_decoded_options = 1; target_translate_from = 1; for (i = 1; i < argc; i += n) { const char *opt = argv[i]; /* Interpret "-" or a non-switch as a file name. */ if (opt[0] != '-' || opt[1] == '\0') { generate_option_input_file (opt, &opt_array[num_decoded_options]); num_decoded_options++; n = 1; continue; } if (i >= target_translate_from && (lang_mask & CL_DRIVER)) { #ifdef TARGET_OPTION_TRANSLATE_TABLE int tott_idx; for (tott_idx = 0; target_option_translations[tott_idx].option_found; tott_idx++) { if (strcmp (target_option_translations[tott_idx].option_found, argv[i]) == 0) { unsigned int spaces = 0; unsigned int m = 0; const char *sp; char *np; for (sp = target_option_translations[tott_idx].replacements; *sp; sp++) { if (*sp == ' ') { spaces++; while (*sp == ' ') sp++; sp--; } } if (spaces) { int new_argc = argc + spaces; if (argv_copied) argv = XRESIZEVEC (const char *, argv, new_argc + 1); else { const char **new_argv = XNEWVEC (const char *, new_argc + 1); memcpy (new_argv, argv, (argc + 1) * sizeof (const char *)); argv = new_argv; argv_copied = true; } memmove (&argv[i] + spaces, &argv[i], (argc + 1 - i) * sizeof (const char *)); argc = new_argc; opt_array = XRESIZEVEC (struct cl_decoded_option, opt_array, argc); } sp = target_option_translations[tott_idx].replacements; np = xstrdup (sp); while (1) { while (*np == ' ') np++; if (*np == 0) break; argv[i + m++] = np; while (*np != ' ' && *np) np++; if (*np == 0) break; *np++ = 0; } target_translate_from = i + m; gcc_assert (m == spaces + 1); break; } } #endif } n = decode_cmdline_option (argv + i, lang_mask, &opt_array[num_decoded_options]); num_decoded_options++; } if (argv_copied) free (argv); *decoded_options = opt_array; *decoded_options_count = num_decoded_options; prune_options (decoded_options, decoded_options_count); } /* Return true if NEXT_OPT_IDX cancels OPT_IDX. Return false if the next one is the same as ORIG_NEXT_OPT_IDX. */ static bool cancel_option (int opt_idx, int next_opt_idx, int orig_next_opt_idx) { /* An option can be canceled by the same option or an option with Negative. */ if (cl_options [next_opt_idx].neg_index == opt_idx) return true; if (cl_options [next_opt_idx].neg_index != orig_next_opt_idx) return cancel_option (opt_idx, cl_options [next_opt_idx].neg_index, orig_next_opt_idx); return false; } /* Filter out options canceled by the ones after them. */ static void prune_options (struct cl_decoded_option **decoded_options, unsigned int *decoded_options_count) { unsigned int old_decoded_options_count = *decoded_options_count; struct cl_decoded_option *old_decoded_options = *decoded_options; unsigned int new_decoded_options_count; struct cl_decoded_option *new_decoded_options = XNEWVEC (struct cl_decoded_option, old_decoded_options_count); unsigned int i; const struct cl_option *option; /* Remove arguments which are negated by others after them. */ new_decoded_options_count = 0; for (i = 0; i < old_decoded_options_count; i++) { unsigned int j, opt_idx, next_opt_idx; if (old_decoded_options[i].errors & ~CL_ERR_WRONG_LANG) goto keep; opt_idx = old_decoded_options[i].opt_index; switch (opt_idx) { case OPT_SPECIAL_unknown: case OPT_SPECIAL_ignore: case OPT_SPECIAL_program_name: case OPT_SPECIAL_input_file: goto keep; default: gcc_assert (opt_idx < cl_options_count); option = &cl_options[opt_idx]; if (option->neg_index < 0) goto keep; /* Skip joined switches. */ if ((option->flags & CL_JOINED)) goto keep; for (j = i + 1; j < old_decoded_options_count; j++) { if (old_decoded_options[j].errors & ~CL_ERR_WRONG_LANG) continue; next_opt_idx = old_decoded_options[j].opt_index; if (next_opt_idx >= cl_options_count) continue; if (cl_options[next_opt_idx].neg_index < 0) continue; if ((cl_options[next_opt_idx].flags & CL_JOINED)) continue; if (cancel_option (opt_idx, next_opt_idx, next_opt_idx)) break; } if (j == old_decoded_options_count) { keep: new_decoded_options[new_decoded_options_count] = old_decoded_options[i]; new_decoded_options_count++; } break; } } free (old_decoded_options); new_decoded_options = XRESIZEVEC (struct cl_decoded_option, new_decoded_options, new_decoded_options_count); *decoded_options = new_decoded_options; *decoded_options_count = new_decoded_options_count; } /* Handle option DECODED for the language indicated by LANG_MASK, using the handlers in HANDLERS. KIND is the diagnostic_t if this is a diagnostics option, DK_UNSPECIFIED otherwise. Returns false if the switch was invalid. */ bool handle_option (const struct cl_decoded_option *decoded, unsigned int lang_mask, int kind, const struct cl_option_handlers *handlers) { size_t opt_index = decoded->opt_index; const char *arg = decoded->arg; int value = decoded->value; const struct cl_option *option = &cl_options[opt_index]; size_t i; if (option->flag_var) set_option (opt_index, value, arg, kind); for (i = 0; i < handlers->num_handlers; i++) if (option->flags & handlers->handlers[i].mask) { if (!handlers->handlers[i].handler (decoded, lang_mask, kind, handlers)) return false; else handlers->post_handling_callback (decoded, handlers->handlers[i].mask); } return true; } /* Like handle_option, but OPT_INDEX, ARG and VALUE describe the option instead of DECODED. This is used for callbacks when one option implies another instead of an option being decoded from the command line. */ bool handle_generated_option (size_t opt_index, const char *arg, int value, unsigned int lang_mask, int kind, const struct cl_option_handlers *handlers) { struct cl_decoded_option decoded; generate_option (opt_index, arg, value, lang_mask, &decoded); return handle_option (&decoded, lang_mask, kind, handlers); } /* Fill in *DECODED with an option described by OPT_INDEX, ARG and VALUE for a front end using LANG_MASK. This is used when the compiler generates options internally. */ void generate_option (size_t opt_index, const char *arg, int value, unsigned int lang_mask, struct cl_decoded_option *decoded) { const struct cl_option *option = &cl_options[opt_index]; decoded->opt_index = opt_index; decoded->warn_message = NULL; decoded->arg = arg; decoded->value = value; decoded->errors = (option_ok_for_language (option, lang_mask) ? 0 : CL_ERR_WRONG_LANG); generate_canonical_option (opt_index, arg, value, decoded); switch (decoded->canonical_option_num_elements) { case 1: decoded->orig_option_with_args_text = decoded->canonical_option[0]; break; case 2: decoded->orig_option_with_args_text = concat (decoded->canonical_option[0], " ", decoded->canonical_option[1], NULL); break; default: gcc_unreachable (); } } /* Fill in *DECODED with an option for input file FILE. */ void generate_option_input_file (const char *file, struct cl_decoded_option *decoded) { decoded->opt_index = OPT_SPECIAL_input_file; decoded->warn_message = NULL; decoded->arg = file; decoded->orig_option_with_args_text = file; decoded->canonical_option_num_elements = 1; decoded->canonical_option[0] = file; decoded->canonical_option[1] = NULL; decoded->canonical_option[2] = NULL; decoded->canonical_option[3] = NULL; decoded->value = 1; decoded->errors = 0; } /* Handle the switch DECODED for the language indicated by LANG_MASK, using the handlers in *HANDLERS. */ void read_cmdline_option (struct cl_decoded_option *decoded, unsigned int lang_mask, const struct cl_option_handlers *handlers) { const struct cl_option *option; const char *opt = decoded->orig_option_with_args_text; if (decoded->warn_message) warning (0, decoded->warn_message, opt); if (decoded->opt_index == OPT_SPECIAL_unknown) { if (handlers->unknown_option_callback (decoded)) error ("unrecognized command line option %qs", decoded->arg); return; } if (decoded->opt_index == OPT_SPECIAL_ignore) return; option = &cl_options[decoded->opt_index]; if (decoded->errors & CL_ERR_DISABLED) { error ("command line option %qs" " is not supported by this configuration", opt); return; } if (decoded->errors & CL_ERR_WRONG_LANG) { handlers->wrong_lang_callback (decoded, lang_mask); return; } if (decoded->errors & CL_ERR_MISSING_ARG) { if (option->missing_argument_error) error (option->missing_argument_error, opt); else error ("missing argument to %qs", opt); return; } if (decoded->errors & CL_ERR_UINT_ARG) { error ("argument to %qs should be a non-negative integer", option->opt_text); return; } gcc_assert (!decoded->errors); if (!handle_option (decoded, lang_mask, DK_UNSPECIFIED, handlers)) error ("unrecognized command line option %qs", opt); } /* Set any variable for option OPT_INDEX according to VALUE and ARG, diagnostic kind KIND. */ void set_option (int opt_index, int value, const char *arg, int kind) { const struct cl_option *option = &cl_options[opt_index]; if (!option->flag_var) return; switch (option->var_type) { case CLVC_BOOLEAN: *(int *) option->flag_var = value; break; case CLVC_EQUAL: *(int *) option->flag_var = (value ? option->var_value : !option->var_value); break; case CLVC_BIT_CLEAR: case CLVC_BIT_SET: if ((value != 0) == (option->var_type == CLVC_BIT_SET)) *(int *) option->flag_var |= option->var_value; else *(int *) option->flag_var &= ~option->var_value; if (option->flag_var == &target_flags) target_flags_explicit |= option->var_value; break; case CLVC_STRING: *(const char **) option->flag_var = arg; break; } if ((diagnostic_t) kind != DK_UNSPECIFIED) diagnostic_classify_diagnostic (global_dc, opt_index, (diagnostic_t) kind, UNKNOWN_LOCATION); }