Merge from vendor branch NTPD:
[dragonfly.git] / contrib / gcc / cppspec.c
1 /* Specific flags and argument handling of the C preprocessor.
2    Copyright (C) 1999 Free Software Foundation, Inc.
3
4 This file is part of GNU CC.
5
6 GNU CC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU CC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING.  If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 #include "config.h"
22 #include "system.h"
23
24 /* The `cpp' executable installed in $(bindir) and $(cpp_install_dir)
25    is a customized version of the gcc driver.  It forces -E; -S and -c
26    are errors.  It defaults to -x c for files with unrecognized
27    extensions, unless -x options appear in argv, in which case we
28    assume the user knows what they're doing.  If no explicit input is
29    mentioned, it will read stdin. */
30
31 /* Snarfed from gcc.c: */
32
33 /* This defines which switch letters take arguments.  */
34
35 #define DEFAULT_SWITCH_TAKES_ARG(CHAR) \
36   ((CHAR) == 'D' || (CHAR) == 'U' || (CHAR) == 'o' \
37    || (CHAR) == 'e' || (CHAR) == 'T' || (CHAR) == 'u' \
38    || (CHAR) == 'I' || (CHAR) == 'm' || (CHAR) == 'x' \
39    || (CHAR) == 'L' || (CHAR) == 'A' || (CHAR) == 'V' \
40    || (CHAR) == 'B' || (CHAR) == 'b')
41
42 #ifndef SWITCH_TAKES_ARG
43 #define SWITCH_TAKES_ARG(CHAR) DEFAULT_SWITCH_TAKES_ARG(CHAR)
44 #endif
45
46 /* This defines which multi-letter switches take arguments.  */
47
48 #define DEFAULT_WORD_SWITCH_TAKES_ARG(STR)              \
49  (!strcmp (STR, "Tdata") || !strcmp (STR, "Ttext")      \
50   || !strcmp (STR, "Tbss") || !strcmp (STR, "include")  \
51   || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \
52   || !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \
53   || !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \
54   || !strcmp (STR, "isystem") || !strcmp (STR, "specs"))
55
56 #ifndef WORD_SWITCH_TAKES_ARG
57 #define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
58 #endif
59
60 /* Suffixes for known sorts of input files.  Note that we do not list
61    files which are normally considered to have been preprocessed already,
62    since the user's expectation is that `cpp' always preprocesses.  */
63 static const char *const known_suffixes[] =
64 {
65   ".c",  ".C",   ".S",   ".m",
66   ".cc", ".cxx", ".cpp", ".cp",  ".c++",
67   NULL
68 };
69
70 /* Filter argc and argv before processing by the gcc driver proper. */
71 void
72 lang_specific_driver (errfn, in_argc, in_argv, in_added_libraries)
73      void (*errfn) PVPROTO((const char *, ...));
74      int *in_argc;
75      char ***in_argv;
76      int *in_added_libraries ATTRIBUTE_UNUSED;
77 {
78   int argc = *in_argc;
79   char **argv = *in_argv;
80   
81   /* Do we need to read stdin? */
82   int read_stdin = 1;
83
84   /* Do we need to insert -E? */
85   int need_E = 1;
86
87   /* Do we need to insert -no-gcc? */
88   int need_no_gcc = 1;
89
90   /* Have we seen an input file? */
91   int seen_input = 0;
92   
93   /* Positions to insert -xc, -xassembler-with-cpp, and -o, if necessary.
94      0 means unnecessary. */
95   int lang_c_here = 0;
96   int lang_S_here = 0;
97   int o_here = 0;
98
99   /* Do we need to fix up an input file with an unrecognized suffix? */
100   int need_fixups = 1;
101   
102   int i, j, quote;
103   char **new_argv;
104   int new_argc;
105
106   /* First pass.  If we see an -S or -c, barf.  If we see an input file,
107      turn off read_stdin.  If we see a second input file, it is actually
108      the output file.  If we see a third input file, barf.  */
109   for (i = 1; i < argc; i++)
110     {
111       if (quote == 1)
112         {
113           quote = 0;
114           continue;
115         }
116       
117       if (argv[i][0] == '-')
118         {
119           if (argv[i][1] == '\0')
120             read_stdin = 0;
121           else if (argv[i][2] == '\0')
122             {
123               if (argv[i][1] == 'E')
124                 need_E = 0;
125               else if (argv[i][1] == 'S' || argv[i][1] == 'c')
126                 {
127                   (*errfn) ("`%s' is not a legal option to the preprocessor",
128                             argv[i]);
129                   return;
130                 }
131               else if (argv[i][1] == 'x')
132                 {
133                   need_fixups = 0;
134                   quote = 1;
135                 }
136               else if (SWITCH_TAKES_ARG (argv[i][1]))
137                 quote = 1;
138             }
139           else if (argv[i][1] == 'x')
140             need_fixups = 0;
141           else if (argv[i][1] == 'g' && !strcmp(&argv[i][2], "cc"))
142             need_no_gcc = 0;
143           else if (WORD_SWITCH_TAKES_ARG (&argv[i][1]))
144             quote = 1;
145         }
146       else /* not an option */
147         {
148           seen_input++;
149           if (seen_input == 3)
150             {
151               (*errfn) ("too many input files");
152               return;
153             }
154           else if (seen_input == 2)
155             {
156               o_here = i;
157             }
158           else
159             {
160               read_stdin = 0;
161               if (need_fixups)
162                 {
163                   int l = strlen (argv[i]);
164                   int known = 0;
165                   const char *const *suff;
166
167                   for (suff = known_suffixes; *suff; suff++)
168                     if (!strcmp (*suff, &argv[i][l - strlen(*suff)]))
169                       {
170                         known = 1;
171                         break;
172                       }
173
174                   if (! known)
175                     {
176                       /* .s files are a special case; we have to treat
177                          them like .S files so -D__ASSEMBLER__ will be
178                          in effect.  */
179                       if (!strcmp (".s", &argv[i][l - 2]))
180                         lang_S_here = i;
181                       else
182                         lang_c_here = i;
183                     }
184                 }
185             }
186         }
187     }
188
189   /* If we don't need to edit the command line, we can bail early.  */
190
191   new_argc = argc + need_E + need_no_gcc + read_stdin
192     + !!o_here + !!lang_c_here + !!lang_S_here;
193
194   if (new_argc == argc)
195     return;
196
197   new_argv = xmalloc (new_argc * sizeof(char *));
198
199   new_argv[0] = argv[0];
200   j = 1;
201
202   if (need_E)
203     new_argv[j++] = "-E";
204
205   if (need_no_gcc)
206     new_argv[j++] = "-no-gcc";
207
208   for (i = 1; i < argc; i++, j++)
209     {
210       if (i == lang_c_here)
211         new_argv[j++] = "-xc";
212       else if (i == lang_S_here)
213         new_argv[j++] = "-xassembler-with-cpp";
214       else if (i == o_here)
215         new_argv[j++] = "-o";
216
217       new_argv[j] = argv[i];
218     }
219
220   if (read_stdin)
221     new_argv[j] = "-";
222
223   *in_argc = new_argc;
224   *in_argv = new_argv;
225
226
227 /* Called before linking.  Returns 0 on success and -1 on failure. */
228 int lang_specific_pre_link ()
229 {
230   return 0;  /* Not used for cpp. */
231 }
232
233 /* Number of extra output files that lang_specific_pre_link may generate. */
234 int lang_specific_extra_outfiles = 0;  /* Not used for cpp. */