gcc/gcc/opts.c

357 lines
8.2 KiB
C

/* 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"
#include "flags.h"
#include "toplev.h"
/* Value of the -G xx switch, and whether it was passed or not. */
unsigned HOST_WIDE_INT g_switch_value;
bool g_switch_set;
/* True if we should exit after parsing options. */
bool exit_after_options;
/* If -version. */
bool version_flag;
static size_t find_opt (const char *, int);
static int common_handle_option (size_t scode, const char *arg, int value);
/* 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 size_t
find_opt (const char *input, int lang_mask)
{
size_t md, mn, mx;
size_t opt_len;
size_t result = cl_options_count;
int comp;
mn = 0;
mx = cl_options_count;
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 = 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 < cl_options_count; 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;
}
/* If ARG is a postive 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;
}
/* Handle the switch beginning at ARGV, with ARGC remaining. */
int
handle_option (int argc ATTRIBUTE_UNUSED, char **argv, int lang_mask)
{
size_t opt_index;
const char *opt, *arg = 0;
char *dup = 0;
int value = 1;
int result = 0, temp;
const struct cl_option *option;
opt = argv[0];
/* Interpret "-" or a non-switch as a file name. */
if (opt[0] != '-' || opt[1] == '\0')
{
opt_index = cl_options_count;
arg = opt;
main_input_filename = opt;
result = (*lang_hooks.handle_option) (opt_index, arg, value);
}
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;
value = 0;
}
opt_index = find_opt (opt + 1, lang_mask | CL_COMMON);
if (opt_index == cl_options_count)
goto done;
option = &cl_options[opt_index];
/* Reject negative form of switches that don't take negatives. */
if (!value && (option->flags & CL_REJECT_NEGATIVE))
goto done;
/* We've recognized this switch. */
result = 1;
/* 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;
}
/* 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->flags & lang_mask)
{
temp = (*lang_hooks.handle_option) (opt_index, arg, value);
if (temp <= 0)
result = temp;
}
if (result > 0 && (option->flags & CL_COMMON))
{
if (common_handle_option (opt_index, arg, value) == 0)
result = 0;
}
}
done:
if (dup)
free (dup);
return result;
}
/* Handle target- and language-independent options. Return zero to
generate an "unknown option" message. */
static int
common_handle_option (size_t scode, const char *arg,
int value ATTRIBUTE_UNUSED)
{
const struct cl_option *option = &cl_options[scode];
enum opt_code code = (enum opt_code) scode;
if (arg == NULL && (option->flags & (CL_JOINED | CL_SEPARATE)))
{
error ("missing argument to \"-%s\"", option->opt_text);
return 1;
}
switch (code)
{
default:
abort ();
case OPT__help:
display_help ();
exit_after_options = true;
break;
case OPT__target_help:
display_target_options ();
exit_after_options = true;
break;
case OPT__version:
print_version (stderr, "");
exit_after_options = true;
break;
case OPT_G:
g_switch_value = value;
g_switch_set = true;
break;
case OPT_aux_info:
case OPT_aux_info_:
aux_info_file_name = arg;
flag_gen_aux_info = 1;
break;
case OPT_auxbase:
aux_base_name = arg;
break;
case OPT_auxbase_strip:
{
char *tmp = xstrdup (arg);
strip_off_ending (tmp, strlen (tmp));
if (tmp[0])
aux_base_name = tmp;
}
break;
case OPT_d:
decode_d_option (arg);
break;
case OPT_dumpbase:
dump_base_name = arg;
break;
case OPT_o:
asm_file_name = arg;
break;
case OPT_p:
profile_flag = 1;
break;
case OPT_pedantic:
pedantic = 1;
break;
case OPT_pedantic_errors:
flag_pedantic_errors = pedantic = 1;
break;
case OPT_quiet:
quiet_flag = 1;
break;
case OPT_version:
version_flag = 1;
break;
case OPT_w:
inhibit_warnings = 1;
break;
}
return 1;
}