opts.c 10.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/* 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"
29 30 31
#include "options.h"
#include "flags.h"
#include "toplev.h"
neil's avatar
neil committed
32
#include "params.h"
33

neil's avatar
neil committed
34 35 36 37 38 39 40 41 42 43
/* 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;

neil's avatar
neil committed
44 45 46
/* Hack for cooperation between set_Wunused and set_Wextra.  */
static bool maybe_warn_unused_parameter;

47
static size_t find_opt (const char *, int);
48
static int common_handle_option (size_t scode, const char *arg, int value);
neil's avatar
neil committed
49 50
static void handle_param (const char *);
static void set_Wextra (int);
51 52 53 54 55 56 57 58 59 60 61 62

/* 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.  */
63
static size_t
64 65 66 67
find_opt (const char *input, int lang_mask)
{
  size_t md, mn, mx;
  size_t opt_len;
68
  size_t result = cl_options_count;
69 70 71
  int comp;

  mn = 0;
72
  mx = cl_options_count;
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105

  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.  */
106
		  result = md;
107 108 109 110 111 112 113 114 115 116 117 118
		  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;
119
	      for (md = md + 1; md < cl_options_count; md++)
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
		{
		  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;
}

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
/* 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;
}

155 156
/* Handle the switch beginning at ARGV, with ARGC remaining.  */
int
157
handle_option (int argc ATTRIBUTE_UNUSED, char **argv, int lang_mask)
158 159 160 161
{
  size_t opt_index;
  const char *opt, *arg = 0;
  char *dup = 0;
162
  int value = 1;
163 164 165 166 167 168 169 170
  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')
    {
171
      opt_index = cl_options_count;
172
      arg = opt;
173
      main_input_filename = opt;
174
      result = (*lang_hooks.handle_option) (opt_index, arg, value);
175 176 177 178 179 180 181 182 183 184 185 186 187 188
    }
  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;
189
	  value = 0;
190 191
	}

192
      opt_index = find_opt (opt + 1, lang_mask | CL_COMMON);
193
      if (opt_index == cl_options_count)
194 195 196 197 198
	goto done;

      option = &cl_options[opt_index];

      /* Reject negative form of switches that don't take negatives.  */
199
      if (!value && (option->flags & CL_REJECT_NEGATIVE))
200 201
	goto done;

202
      /* We've recognized this switch.  */
203 204 205
      result = 1;

      /* Sort out any argument the switch takes.  */
206
      if (option->flags & CL_JOINED)
207
	{
208 209 210 211 212 213 214 215
	  /* 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))
216
	    {
217 218 219 220 221 222 223 224
	      if (option->flags & CL_SEPARATE)
		{
		  arg = argv[1];
		  result = 2;
		}
	      else
		/* Missing argument.  */
		arg = NULL;
225
	    }
226 227 228 229 230 231
	}
      else if (option->flags & CL_SEPARATE)
	{
	  arg = argv[1];
	  result = 2;
	}
232

233 234 235 236 237
      /* If the switch takes an integer, convert it.  */
      if (arg && (option->flags & CL_UINTEGER))
	{
	  value = integral_argument (arg);
	  if (value == -1)
238
	    {
239 240 241
	      error ("argument to \"-%s\" should be a non-negative integer",
		     option->opt_text);
	      goto done;
242 243 244
	    }
	}

245 246
      if (option->flags & lang_mask)
	{
247
	  temp = (*lang_hooks.handle_option) (opt_index, arg, value);
248 249 250 251 252 253
	  if (temp <= 0)
	    result = temp;
	}

      if (result > 0 && (option->flags & CL_COMMON))
	{
254
	  if (common_handle_option (opt_index, arg, value) == 0)
255 256 257
	    result = 0;
	}
    }
258 259 260 261 262 263

 done:
  if (dup)
    free (dup);
  return result;
}
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284

/* 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 ();

neil's avatar
neil committed
285 286 287 288 289
    case OPT__help:
      display_help ();
      exit_after_options = true;
      break;

neil's avatar
neil committed
290 291 292 293
    case OPT__param:
      handle_param (arg);
      break;

neil's avatar
neil committed
294 295 296 297 298 299 300 301 302 303 304
    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:
305
      g_switch_value = value;
neil's avatar
neil committed
306 307 308
      g_switch_set = true;
      break;

neil's avatar
neil committed
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    case OPT_O:
    case OPT_Os:
      /* Currently handled in a prescan.  */
      break;

    case OPT_W:
      /* For backward compatibility, -W is the same as -Wextra.  */
      set_Wextra (value);
      break;

    case OPT_Wextra:
      set_Wextra (value);
      break;

    case OPT_Wunused:
      set_Wunused (value);
      break;

neil's avatar
neil committed
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
    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;

neil's avatar
neil committed
354 355 356 357
    case OPT_m:
      set_target_switch (arg);
      break;

neil's avatar
neil committed
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
    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;

374 375 376
    case OPT_quiet:
      quiet_flag = 1;
      break;
neil's avatar
neil committed
377 378 379 380 381 382 383 384

    case OPT_version:
      version_flag = 1;
      break;

    case OPT_w:
      inhibit_warnings = 1;
      break;      
385 386 387 388
    }

  return 1;
}
neil's avatar
neil committed
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448

/* Handle --param NAME=VALUE.  */
static void
handle_param (const char *carg)
{
  char *equal, *arg;
  int value;

  arg = xstrdup (carg);
  equal = strchr (arg, '=');
  if (!equal)
    error ("%s: --param arguments should be of the form NAME=VALUE", arg);
  else
    {
      value = integral_argument (equal + 1);
      if (value == -1)
	error ("invalid --param value `%s'", equal + 1);
      else
	{
	  *equal = '\0';
	  set_param_value (arg, value);
	}
    }

  free (arg);
}

/* Handle -W and -Wextra.  */
static void
set_Wextra (int setting)
{
  extra_warnings = setting;
  warn_unused_value = setting;
  warn_unused_parameter = (setting && maybe_warn_unused_parameter);

  /* We save the value of warn_uninitialized, since if they put
     -Wuninitialized on the command line, we need to generate a
     warning about not using it without also specifying -O.  */
  if (setting == 0)
    warn_uninitialized = 0;
  else if (warn_uninitialized != 1)
    warn_uninitialized = 2;
}

/* Initialize unused warning flags.  */
void
set_Wunused (int setting)
{
  warn_unused_function = setting;
  warn_unused_label = setting;
  /* Unused function parameter warnings are reported when either
     ``-Wextra -Wunused'' or ``-Wunused-parameter'' is specified.
     Thus, if -Wextra has already been seen, set warn_unused_parameter;
     otherwise set maybe_warn_extra_parameter, which will be picked up
     by set_Wextra.  */
  maybe_warn_unused_parameter = setting;
  warn_unused_parameter = (setting && extra_warnings);
  warn_unused_variable = setting;
  warn_unused_value = setting;
}