--- /dev/null
+/* 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"
+
+/* 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);
+ }
+}
+
+/* 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;
+}