diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /support/cpp/opts.c | |
| download | sdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'support/cpp/opts.c')
| -rw-r--r-- | support/cpp/opts.c | 629 |
1 files changed, 629 insertions, 0 deletions
diff --git a/support/cpp/opts.c b/support/cpp/opts.c new file mode 100644 index 0000000..4f7e439 --- /dev/null +++ b/support/cpp/opts.c @@ -0,0 +1,629 @@ +/* Command line option handling. + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. + Contributed by Neil Booth. + +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 2, 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 COPYING. If not, write to the Free +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "intl.h" +#include "opts.h" +#include "options.h" +#include "version.h" + +/* True if we should exit after parsing options. */ +bool exit_after_options; + +/* Treat warnings as errors. -Werror. */ +bool warnings_are_errors; + +/* Don't suppress warnings from system headers. -Wsystem-headers. */ +bool warn_system_headers; + +/* Columns of --help display. */ +static unsigned int columns = 80; + +/* What to print when a switch has no documentation. */ +static const char undocumented_msg[] = N_("This switch lacks documentation"); + +/* Input file names. */ +const char **in_fnames; +unsigned num_in_fnames; + +static int common_handle_option (size_t scode, const char *arg, int value); +static unsigned int handle_option (const char **argv, unsigned int lang_mask); +static char *write_langs (unsigned int lang_mask); +static void complain_wrong_lang (const char *, const struct cl_option *, + unsigned int lang_mask); +static void handle_options (unsigned int, const char **, unsigned int); +static void wrap_help (const char *help, const char *item, unsigned int); +static void print_help (void); +static void print_filtered_help (unsigned int); +static unsigned int print_switch (const char *text, unsigned int indent); + +/* If ARG is a non-negative integer made up solely of digits, return its + value, otherwise return -1. */ +static int +integral_argument (const char *arg) +{ + const char *p = arg; + + while (*p && ISDIGIT (*p)) + p++; + + if (*p == '\0') + return atoi (arg); + + return -1; +} + +/* Return a malloced slash-separated list of languages in MASK. */ +static char * +write_langs (unsigned int mask) +{ + unsigned int n = 0, len = 0; + const char *lang_name; + char *result; + + for (n = 0; (lang_name = lang_names[n]) != 0; n++) + if (mask & (1U << n)) + len += strlen (lang_name) + 1; + + result = XNEWVEC (char, len); + len = 0; + for (n = 0; (lang_name = lang_names[n]) != 0; n++) + if (mask & (1U << n)) + { + if (len) + result[len++] = '/'; + strcpy (result + len, lang_name); + len += strlen (lang_name); + } + + result[len] = 0; + + return result; +} + +/* Complain that switch OPT_INDEX does not apply to this front end. */ +static void +complain_wrong_lang (const char *text, const struct cl_option *option, + unsigned int lang_mask) +{ + char *ok_langs, *bad_lang; + + ok_langs = write_langs (option->flags); + bad_lang = write_langs (lang_mask); + + /* Eventually this should become a hard error IMO. */ + warning (0, "command line option \"%s\" is valid for %s but not for %s", + text, ok_langs, bad_lang); + + free (ok_langs); + free (bad_lang); +} + +/* Handle the switch beginning at ARGV for the language indicated by + LANG_MASK. Returns the number of switches consumed. */ +static unsigned int +handle_option (const char **argv, unsigned int lang_mask) +{ + size_t opt_index; + const char *opt, *arg = 0; + char *dup = 0; + int value = 1; + unsigned int result = 0; + const struct cl_option *option; + + opt = argv[0]; + + opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET); + if (opt_index == cl_options_count + && (opt[1] == 'W' || opt[1] == 'f' || opt[1] == 'm') + && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-') + { + /* Drop the "no-" from negative switches. */ + size_t len = strlen (opt) - 3; + + dup = XNEWVEC (char, len + 1); + dup[0] = '-'; + dup[1] = opt[1]; + memcpy (dup + 2, opt + 5, len - 2 + 1); + opt = dup; + value = 0; + opt_index = find_opt (opt + 1, lang_mask | CL_COMMON | CL_TARGET); + } + + if (opt_index == cl_options_count) + 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)) + goto done; + + /* We've recognized this switch. */ + result = 1; + + /* Check to see if the option is disabled for this configuration. */ + if (option->flags & CL_DISABLED) + { + error ("command line option \"%s\"" + " is not supported by this configuration", opt); + goto done; + } + + /* Sort out any argument the switch takes. */ + if (option->flags & CL_JOINED) + { + /* 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[0] + cl_options[opt_index].opt_len + 1; + if (!value) + arg += strlen ("no-"); + + if (*arg == '\0' && !(option->flags & CL_MISSING_OK)) + { + if (option->flags & CL_SEPARATE) + { + arg = argv[1]; + result = 2; + } + else + /* Missing argument. */ + arg = NULL; + } + } + else if (option->flags & CL_SEPARATE) + { + arg = argv[1]; + result = 2; + } + + /* Now we've swallowed any potential argument, complain if this + is a switch for a different front end. */ + if (!(option->flags & (lang_mask | CL_COMMON | CL_TARGET))) + { + complain_wrong_lang (argv[0], option, lang_mask); + goto done; + } + + if (arg == NULL && (option->flags & (CL_JOINED | CL_SEPARATE))) + { + if (!lang_hooks.missing_argument (opt, opt_index)) + error ("missing argument to \"%s\"", opt); + goto done; + } + + /* If the switch takes an integer, convert it. */ + if (arg && (option->flags & CL_UINTEGER)) + { + value = integral_argument (arg); + if (value == -1) + { + error ("argument to \"%s\" should be a non-negative integer", + option->opt_text); + goto done; + } + } + + if (option->flag_var) + 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 (option->flags & lang_mask) + if (lang_hooks.handle_option (opt_index, arg, value) == 0) + result = 0; + + if (result && (option->flags & CL_COMMON)) + if (common_handle_option (opt_index, arg, value) == 0) + result = 0; + + ////if (result && (option->flags & CL_TARGET)) + //// if (!targetm.handle_option (opt_index, arg, value)) + //// result = 0; + + done: + if (dup) + free (dup); + return result; +} + +/* Handle FILENAME from the command line. */ +static void +add_input_filename (const char *filename) +{ + num_in_fnames++; + in_fnames = xrealloc (in_fnames, num_in_fnames * sizeof (in_fnames[0])); + in_fnames[num_in_fnames - 1] = filename; +} + +/* Decode and handle the vector of command line options. LANG_MASK + contains has a single bit set representing the current + language. */ +static void +handle_options (unsigned int argc, const char **argv, unsigned int lang_mask) +{ + unsigned int n, i; + + 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') + { + if (main_input_filename == NULL) + main_input_filename = opt; + add_input_filename (opt); + n = 1; + continue; + } + + n = handle_option (argv + i, lang_mask); + + if (!n) + { + n = 1; + error ("unrecognized command line option \"%s\"", opt); + } + } +} + +/* Parse command line options and set default flag values. Do minimal + options processing. */ +void +decode_options (unsigned int argc, const char **argv) +{ + unsigned int lang_mask; + + /* Perform language-specific options initialization. */ + lang_mask = lang_hooks.init_options (argc, argv); + + /* Scan to see what optimization level has been specified. That will + determine the default value of many flags. */ + + handle_options (argc, argv, lang_mask); +} + +/* Handle target- and language-independent options. Return zero to + generate an "unknown option" message. Only options that need + extra handling need to be listed here; if you simply want + VALUE assigned to a variable, it happens automatically. */ + +static int +common_handle_option (size_t scode, const char *arg, + int value ATTRIBUTE_UNUSED) +{ + enum opt_code code = (enum opt_code) scode; + + switch (code) + { + default: + abort (); + + case OPT__help: + print_help (); + exit_after_options = true; + break; + + case OPT__version: + print_version (stderr, ""); + exit_after_options = true; + break; + + case OPT_Werror: + warnings_are_errors = value; + break; + + case OPT_Wsystem_headers: + warn_system_headers = value; + break; + + case OPT_d: + decode_d_option (arg); + break; + + case OPT_pedantic_errors: + flag_pedantic_errors = 1; + break; + + case OPT_w: + inhibit_warnings = true; + break; + } + + return 1; +} + +/* Output --help text. */ +static void +print_help (void) +{ + size_t i; + const char *p; + + GET_ENVIRONMENT (p, "COLUMNS"); + if (p) + { + int value = atoi (p); + if (value > 0) + columns = value; + } + + puts (_("The following options are language-independent:\n")); + + print_filtered_help (CL_COMMON); + + for (i = 0; lang_names[i]; i++) + { + printf (_("The %s front end recognizes the following options:\n\n"), + lang_names[i]); + print_filtered_help (1U << i); + } + + printf (_("\nFor bug reporting instructions, please see:\n")); + printf ("%s.\n", bug_report_url); +} + +/* Print help for a specific front-end, etc. */ +static void +print_filtered_help (unsigned int flag) +{ + unsigned int i, len, filter, indent = 0; + bool duplicates = false; + const char *help, *opt, *tab; + static char *printed; + + if (flag == CL_COMMON || flag == CL_TARGET) + { + filter = flag; + if (!printed) + printed = xmalloc (cl_options_count); + memset (printed, 0, cl_options_count); + } + else + { + /* Don't print COMMON options twice. */ + filter = flag | CL_COMMON; + + for (i = 0; i < cl_options_count; i++) + { + if ((cl_options[i].flags & filter) != flag) + continue; + + /* Skip help for internal switches. */ + if (cl_options[i].flags & CL_UNDOCUMENTED) + continue; + + /* Skip switches that have already been printed, mark them to be + listed later. */ + if (printed[i]) + { + duplicates = true; + indent = print_switch (cl_options[i].opt_text, indent); + } + } + + if (duplicates) + { + putchar ('\n'); + putchar ('\n'); + } + } + + for (i = 0; i < cl_options_count; i++) + { + if ((cl_options[i].flags & filter) != flag) + continue; + + /* Skip help for internal switches. */ + if (cl_options[i].flags & CL_UNDOCUMENTED) + continue; + + /* Skip switches that have already been printed. */ + if (printed[i]) + continue; + + printed[i] = true; + + help = cl_options[i].help; + if (!help) + help = undocumented_msg; + + /* Get the translation. */ + help = _(help); + + tab = strchr (help, '\t'); + if (tab) + { + len = tab - help; + opt = help; + help = tab + 1; + } + else + { + opt = cl_options[i].opt_text; + len = strlen (opt); + } + + wrap_help (help, opt, len); + } + + putchar ('\n'); +} + +/* Output ITEM, of length ITEM_WIDTH, in the left column, followed by + word-wrapped HELP in a second column. */ +static unsigned int +print_switch (const char *text, unsigned int indent) +{ + unsigned int len = strlen (text) + 1; /* trailing comma */ + + if (indent) + { + putchar (','); + if (indent + len > columns) + { + putchar ('\n'); + putchar (' '); + indent = 1; + } + } + else + putchar (' '); + + putchar (' '); + fputs (text, stdout); + + return indent + len + 1; +} + +/* Output ITEM, of length ITEM_WIDTH, in the left column, followed by + word-wrapped HELP in a second column. */ +static void +wrap_help (const char *help, const char *item, unsigned int item_width) +{ + unsigned int col_width = 27; + unsigned int remaining, room, len; + + remaining = strlen (help); + + do + { + room = columns - 3 - MAX (col_width, item_width); + if (room > columns) + room = 0; + len = remaining; + + if (room < len) + { + unsigned int i; + + for (i = 0; help[i]; i++) + { + if (i >= room && len != remaining) + break; + if (help[i] == ' ') + len = i; + else if ((help[i] == '-' || help[i] == '/') + && help[i + 1] != ' ' + && i > 0 && ISALPHA (help[i - 1])) + len = i + 1; + } + } + + printf( " %-*.*s %.*s\n", col_width, item_width, item, len, help); + item_width = 0; + while (help[len] == ' ') + len++; + help += len; + remaining -= len; + } + while (remaining); +} + +/* Return 1 if OPTION is enabled, 0 if it is disabled, or -1 if it isn't + a simple on-off switch. */ + +int +option_enabled (int opt_idx) +{ + const struct cl_option *option = &(cl_options[opt_idx]); + if (option->flag_var) + switch (option->var_type) + { + case CLVC_BOOLEAN: + return *(int *) option->flag_var != 0; + + case CLVC_EQUAL: + return *(int *) option->flag_var == option->var_value; + + case CLVC_BIT_CLEAR: + return (*(int *) option->flag_var & option->var_value) == 0; + + case CLVC_BIT_SET: + return (*(int *) option->flag_var & option->var_value) != 0; + + case CLVC_STRING: + break; + } + return -1; +} + +/* Fill STATE with the current state of option OPTION. Return true if + there is some state to store. */ + +bool +get_option_state (int option, struct cl_option_state *state) +{ + if (cl_options[option].flag_var == 0) + return false; + + switch (cl_options[option].var_type) + { + case CLVC_BOOLEAN: + case CLVC_EQUAL: + state->data = cl_options[option].flag_var; + state->size = sizeof (int); + break; + + case CLVC_BIT_CLEAR: + case CLVC_BIT_SET: + state->ch = option_enabled (option); + state->data = &state->ch; + state->size = 1; + break; + + case CLVC_STRING: + state->data = *(const char **) cl_options[option].flag_var; + if (state->data == 0) + state->data = ""; + state->size = strlen (state->data) + 1; + break; + } + return true; +} |
