1/* Command line option handling.
2   Copyright (C) 2006 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 2, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING.  If not, write to the Free
18Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
1902110-1301, USA.  */
20
21#include "config.h"
22#include "system.h"
23#include "intl.h"
24#include "coretypes.h"
25#include "opts.h"
26
27/* Perform a binary search to find which option the command-line INPUT
28   matches.  Returns its index in the option array, and N_OPTS
29   (cl_options_count) on failure.
30
31   This routine is quite subtle.  A normal binary search is not good
32   enough because some options can be suffixed with an argument, and
33   multiple sub-matches can occur, e.g. input of "-pedantic" matching
34   the initial substring of "-pedantic-errors".
35
36   A more complicated example is -gstabs.  It should match "-g" with
37   an argument of "stabs".  Suppose, however, that the number and list
38   of switches are such that the binary search tests "-gen-decls"
39   before having tested "-g".  This doesn't match, and as "-gen-decls"
40   is less than "-gstabs", it will become the lower bound of the
41   binary search range, and "-g" will never be seen.  To resolve this
42   issue, opts.sh makes "-gen-decls" point, via the back_chain member,
43   to "-g" so that failed searches that end between "-gen-decls" and
44   the lexicographically subsequent switch know to go back and see if
45   "-g" causes a match (which it does in this example).
46
47   This search is done in such a way that the longest match for the
48   front end in question wins.  If there is no match for the current
49   front end, the longest match for a different front end is returned
50   (or N_OPTS if none) and the caller emits an error message.  */
51size_t
52find_opt (const char *input, int lang_mask)
53{
54  size_t mn, mx, md, opt_len;
55  size_t match_wrong_lang;
56  int comp;
57
58  mn = 0;
59  mx = cl_options_count;
60
61  /* Find mn such this lexicographical inequality holds:
62     cl_options[mn] <= input < cl_options[mn + 1].  */
63  while (mx - mn > 1)
64    {
65      md = (mn + mx) / 2;
66      opt_len = cl_options[md].opt_len;
67      comp = strncmp (input, cl_options[md].opt_text + 1, opt_len);
68
69      if (comp < 0)
70	mx = md;
71      else
72	mn = md;
73    }
74
75  /* This is the switch that is the best match but for a different
76     front end, or cl_options_count if there is no match at all.  */
77  match_wrong_lang = cl_options_count;
78
79  /* Backtrace the chain of possible matches, returning the longest
80     one, if any, that fits best.  With current GCC switches, this
81     loop executes at most twice.  */
82  do
83    {
84      const struct cl_option *opt = &cl_options[mn];
85
86      /* Is the input either an exact match or a prefix that takes a
87	 joined argument?  */
88      if (!strncmp (input, opt->opt_text + 1, opt->opt_len)
89	  && (input[opt->opt_len] == '\0' || (opt->flags & CL_JOINED)))
90	{
91	  /* If language is OK, return it.  */
92	  if (opt->flags & lang_mask)
93	    return mn;
94
95	  /* If we haven't remembered a prior match, remember this
96	     one.  Any prior match is necessarily better.  */
97	  if (match_wrong_lang == cl_options_count)
98	    match_wrong_lang = mn;
99	}
100
101      /* Try the next possibility.  This is cl_options_count if there
102	 are no more.  */
103      mn = opt->back_chain;
104    }
105  while (mn != cl_options_count);
106
107  /* Return the best wrong match, or cl_options_count if none.  */
108  return match_wrong_lang;
109}
110
111/* Return true if NEXT_OPT_IDX cancels OPT_IDX.  Return false if the
112   next one is the same as ORIG_NEXT_OPT_IDX.  */
113
114static bool
115cancel_option (int opt_idx, int next_opt_idx, int orig_next_opt_idx)
116{
117  /* An option can be canceled by the same option or an option with
118     Negative.  */
119  if (cl_options [next_opt_idx].neg_index == opt_idx)
120    return true;
121
122  if (cl_options [next_opt_idx].neg_index != orig_next_opt_idx)
123    return cancel_option (opt_idx, cl_options [next_opt_idx].neg_index,
124			  orig_next_opt_idx);
125
126  return false;
127}
128
129/* Filter out options canceled by the ones after them.  */
130
131void
132prune_options (int *argcp, char ***argvp)
133{
134  int argc = *argcp;
135  int *options = xmalloc (argc * sizeof (*options));
136  char **argv = xmalloc (argc * sizeof (char *));
137  int i, arg_count, need_prune = 0;
138  const struct cl_option *option;
139  size_t opt_index;
140
141  /* Scan all arguments.  */
142  for (i = 1; i < argc; i++)
143    {
144      int value = 1;
145      const char *opt = (*argvp) [i];
146
147      opt_index = find_opt (opt + 1, -1);
148      if (opt_index == cl_options_count
149	  && (opt[1] == 'W' || opt[1] == 'f' || opt[1] == 'm')
150	  && opt[2] == 'n' && opt[3] == 'o' && opt[4] == '-')
151	{
152	  char *dup;
153
154	  /* Drop the "no-" from negative switches.  */
155	  size_t len = strlen (opt) - 3;
156
157	  dup = XNEWVEC (char, len + 1);
158	  dup[0] = '-';
159	  dup[1] = opt[1];
160	  memcpy (dup + 2, opt + 5, len - 2 + 1);
161	  opt = dup;
162	  value = 0;
163	  opt_index = find_opt (opt + 1, -1);
164	  free (dup);
165	}
166
167      if (opt_index == cl_options_count)
168	{
169cont:
170	  options [i] = 0;
171	  continue;
172	}
173
174      option = &cl_options[opt_index];
175      if (option->neg_index < 0)
176	goto cont;
177
178      /* Skip joined switches.  */
179      if ((option->flags & CL_JOINED))
180	goto cont;
181
182      /* Reject negative form of switches that don't take negatives as
183	 unrecognized.  */
184      if (!value && (option->flags & CL_REJECT_NEGATIVE))
185	goto cont;
186
187      options [i] = (int) opt_index;
188      need_prune |= options [i];
189    }
190
191  if (!need_prune)
192    goto done;
193
194  /* Remove arguments which are negated by others after them.  */
195  argv [0] = (*argvp) [0];
196  arg_count = 1;
197  for (i = 1; i < argc; i++)
198    {
199      int j, opt_idx;
200
201      opt_idx = options [i];
202      if (opt_idx)
203	{
204	  int next_opt_idx;
205	  for (j = i + 1; j < argc; j++)
206	    {
207	      next_opt_idx = options [j];
208	      if (next_opt_idx
209		  && cancel_option (opt_idx, next_opt_idx,
210				    next_opt_idx))
211		break;
212	    }
213	}
214      else
215	goto keep;
216
217      if (j == argc)
218	{
219keep:
220	  argv [arg_count] = (*argvp) [i];
221	  arg_count++;
222	}
223    }
224
225  if (arg_count != argc)
226    {
227      *argcp = arg_count;
228      *argvp = argv;
229    }
230  else
231    {
232done:
233      free (argv);
234    }
235
236  free (options);
237}
238