1/* Specific flags and argument handling of the C preprocessor.
2   Copyright (C) 1999 Free Software Foundation, Inc.
3
4This file is part of GNU CC.
5
6GNU CC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU CC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU CC; see the file COPYING.  If not, write to
18the Free Software Foundation, 59 Temple Place - Suite 330,
19Boston, 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.  */
63static 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. */
71void
72lang_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. */
228int 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. */
234int lang_specific_extra_outfiles = 0;  /* Not used for cpp. */
235