aboutsummaryrefslogtreecommitdiff
path: root/gcc/opts.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/opts.c')
-rw-r--r--gcc/opts.c209
1 files changed, 209 insertions, 0 deletions
diff --git a/gcc/opts.c b/gcc/opts.c
new file mode 100644
index 0000000..3d3fa10
--- /dev/null
+++ b/gcc/opts.c
@@ -0,0 +1,209 @@
+/* Command line option handling.
+ Copyright (C) 2002, 2003 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, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "langhooks.h"
+#include "opts.h"
+#include "options.h"
+
+static enum opt_code find_opt (const char *, int);
+
+/* Perform a binary search to find which option the command-line INPUT
+ matches. Returns its index in the option array, and N_OPTS on
+ failure.
+
+ Complications arise since some options can be suffixed with an
+ argument, and multiple complete matches can occur, e.g. -pedantic
+ and -pedantic-errors. Also, some options are only accepted by some
+ languages. If a switch matches for a different language and
+ doesn't match any alternatives for the true front end, the index of
+ the matched switch is returned anyway. The caller should check for
+ this case. */
+static enum opt_code
+find_opt (const char *input, int lang_mask)
+{
+ size_t md, mn, mx;
+ size_t opt_len;
+ enum opt_code result = N_OPTS;
+ int comp;
+
+ mn = 0;
+ mx = N_OPTS;
+
+ while (mx > mn)
+ {
+ md = (mn + mx) / 2;
+
+ opt_len = cl_options[md].opt_len;
+ comp = strncmp (input, cl_options[md].opt_text, opt_len);
+
+ if (comp < 0)
+ mx = md;
+ else if (comp > 0)
+ mn = md + 1;
+ else
+ {
+ /* The switch matches. It it an exact match? */
+ if (input[opt_len] == '\0')
+ return md;
+ else
+ {
+ mn = md + 1;
+
+ /* If the switch takes no arguments this is not a proper
+ match, so we continue the search (e.g. input="stdc++"
+ match was "stdc"). */
+ if (!(cl_options[md].flags & CL_JOINED))
+ continue;
+
+ /* Is this switch valid for this front end? */
+ if (!(cl_options[md].flags & lang_mask))
+ {
+ /* If subsequently we don't find a better match,
+ return this and let the caller report it as a bad
+ match. */
+ result = (enum opt_code) md;
+ continue;
+ }
+
+ /* Two scenarios remain: we have the switch's argument,
+ or we match a longer option. This can happen with
+ -iwithprefix and -withprefixbefore. The longest
+ possible option match succeeds.
+
+ Scan forwards, and return an exact match. Otherwise
+ return the longest valid option-accepting match (mx).
+ This loops at most twice with current options. */
+ mx = md;
+ for (md = md + 1; md < N_OPTS; md++)
+ {
+ opt_len = cl_options[md].opt_len;
+ if (strncmp (input, cl_options[md].opt_text, opt_len))
+ break;
+ if (input[opt_len] == '\0')
+ return md;
+ if (cl_options[md].flags & lang_mask
+ && cl_options[md].flags & CL_JOINED)
+ mx = md;
+ }
+
+ return mx;
+ }
+ }
+ }
+
+ return result;
+}
+
+/* Handle the switch beginning at ARGV, with ARGC remaining. */
+int
+handle_option (int argc, char **argv, int lang_mask)
+{
+ size_t opt_index;
+ const char *opt, *arg = 0;
+ char *dup = 0;
+ bool on = true;
+ int result = 0, temp;
+ const struct cl_option *option;
+
+ /* If the front end isn't yet converted, use the old hook. */
+ if (!lang_hooks.handle_option)
+ return (*lang_hooks.decode_option) (argc, argv);
+
+ opt = argv[0];
+
+ /* Interpret "-" or a non-switch as a file name. */
+ if (opt[0] != '-' || opt[1] == '\0')
+ {
+ opt_index = N_OPTS;
+ arg = opt;
+ result = 1;
+ }
+ else
+ {
+ /* Drop the "no-" from negative switches. */
+ if ((opt[1] == 'W' || opt[1] == 'f')
+ && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-')
+ {
+ size_t len = strlen (opt) - 3;
+
+ dup = xmalloc (len + 1);
+ dup[0] = '-';
+ dup[1] = opt[1];
+ memcpy (dup + 2, opt + 5, len - 2 + 1);
+ opt = dup;
+ on = false;
+ }
+
+ /* Skip over '-'. */
+ opt_index = find_opt (opt + 1, lang_mask);
+ if (opt_index == N_OPTS)
+ goto done;
+
+ option = &cl_options[opt_index];
+
+ /* Reject negative form of switches that don't take negatives. */
+ if (!on && (option->flags & CL_REJECT_NEGATIVE))
+ goto done;
+
+ /* We've recognised this switch. */
+ result = 1;
+
+ /* Sort out any argument the switch takes. */
+ if (option->flags & (CL_JOINED | CL_SEPARATE))
+ {
+ 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 (!on)
+ arg += strlen ("no-");
+ }
+
+ /* If we don't have an argument, and CL_SEPARATE, try the next
+ argument in the vector. */
+ if (!arg || (*arg == '\0' && option->flags & CL_SEPARATE))
+ {
+ arg = argv[1];
+ result = 2;
+ }
+
+ /* Canonicalize missing arguments as NULL for the handler. */
+ if (*arg == '\0')
+ arg = NULL;
+ }
+ }
+
+ temp = (*lang_hooks.handle_option) (opt_index, arg, on);
+ if (temp <= 0)
+ result = temp;
+
+ done:
+ if (dup)
+ free (dup);
+ return result;
+}