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