OSDN Git Service

2007-07-08 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / opts-common.c
1 /* Command line option handling.
2    Copyright (C) 2006 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 2, 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 COPYING.  If not, write to the Free
18 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-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.  */
51 size_t
52 find_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
114 static bool
115 cancel_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
131 void
132 prune_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         {
169 cont:
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         {
219 keep:
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     {
232 done:
233       free (argv);
234     }
235
236   free (options);
237 }