1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1986-2011 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * Glenn Fowler
23 * AT&T Research
24 *
25 * common preprocessor command line argument parse
26 * called by optjoin()
27 */
28
29 static const char usage[] =
30 "[-?\n@(#)$Id: cpp (AT&T Research) 2009-02-02 $\n]"
31 USAGE_LICENSE
32 "[+NAME?cpp - C language preprocessor]"
33 "[+DESCRIPTION?\bcpp\b is the preprocessor for all C language dialects. It is"
34 " a standalone version of the \blibpp\b(3) preprocessor library. The"
35 " C dialect implemented by \bcpp\b is determined by probing \bcc\b(1)"
36 " using \bprobe\b(1). The path of the emulated compiler can be changed"
37 " by the \b-D-X\b command line option.]"
38 "[+?If \aoutput\a is omitted then the standard output is written; if \ainput\a"
39 " is also omitted then the standard input is read. NOTE: this is an"
40 " ancient, non-standard, non-intuitiive file operand syntax that is"
41 " required by \bcc\b(1); use shell file name expansion at your peril.]"
42 "[+?\bcpp\b specific options are set by the \b-D-\b and \b-I-\b options.]"
43
44 "[C:comments?Pass comments to the output. By default comments are omitted.]"
45 "[D:define?Define the macro \aname\a to have \avalue\a; \b1\b is assumed if"
46 " \b=\b\avalue\a is omitted. If \aname\a begins with \b:\b then it is"
47 " interpreted as a \blibpp\b(3) \b#pragma pp:\b statement; if \aname\a"
48 " begins with \b%\b then it is interpreted as a \blibpp\b(3) \b#\b"
49 " directive statement; if \aname\a begins with \b-\b or \b+\b then it is"
50 " interpreted as a \blibpp\b(3) option; \b-\b turns the option on,"
51 " \b+\b turns it off. Most options have a \b#pragma\b counterpart that"
52 " is listed with the option definition. Right, this is ugly, but its the"
53 " only portable way to pass options through \bcc\b(1) to"
54 " \bcpp\b:]:[name[=value]]]{"
55 " [+-D-C, pp::compatibility?Preprocess for K&R compatibility.]"
56 " [+-D-D\alevel\a, \bpp::debug\b \alevel\a?Set the debug trace level."
57 " Higher levels produce more output. Levels higher than 3"
58 " enabled only in \b-g\b compiled versions.]"
59 " [+-D-F\aname\a?Set the main input file name to \aname\a. This only"
60 " affects error message and line sync output.]"
61 " [+-D-H, pp::hosted?All directories are hosted; compatibility"
62 " warning messages from hosted directory headers are suppressed.]"
63 " [+-D-I, pp::cdir?All directories contain C headers; used only with"
64 " \b-D-+\b.]"
65 " [+-D-K, pp::keyargs?Enable the non-standard \aname=value\a macro"
66 " argument mode.]"
67 " [+-D-L\b[\aid\a]], \bpp::lineid\b [\aid\a]]?Set the line sync directive"
68 " id to \aid\a or null if omitted.]"
69 " [+-D-M, pp::nomultiple?Disable multiple include detection.]"
70 " [+-D-P, pp::passthrough?Enable the non-standard passthrough mode; may"
71 " be useful for processing non-C input.]"
72 " [+-D-Q, pp::dump?Dump macro definitions to the output so that the"
73 " output may be passed through \bcpp\b again. Used for"
74 " generating precompiled headers.]"
75 " [+-D-R, pp::transition?Enable the transition preprocessing mode. Used"
76 " for compilers that can't make up their semantics between"
77 " K&R and ISO.]"
78 " [+-D-S, pp::strict?Enable strict preprocessing semantics and warnings."
79 " Works with any mode (compatibiliy, transition,"
80 " or the default ISO).]"
81 " [+-D-T\atest\a, \bpp::test\b \atest\a?Enable implementation specific"
82 " test code according to \atest\a.]"
83 " [+-D-W, pp::warn?Enable warnings in non-hosted files.]"
84 " [+-D-X\b[\acc\a]]?Preprocess for the compiler \acc\a which must be"
85 " an executable path or an executable on \b$PATH\b.]"
86 " [+-D-Y, pp::pedantic?Enable pedantic \bpp::warn\b warnings in"
87 " non-hosted files.]"
88 " [+-D-Z, pp::pool?Enable pool mode. See \blibpp\b(3).]"
89 " [+-D-d?List canonicalized \b#define\b statements for non-predefined"
90 " macros in the output. ]"
91 " [+-D-m?List canonicalized \b#define\b statements for all macros. All"
92 " other output is disabled.]"
93 " [+-D-+, pp::plusplus?Preprocess for the C++ dialect.]"
94 "}"
95 "[I:include?Append \adirectory\a to the list of directories searched for"
96 " \b#include\b files. If \adirectory\a is \b-\b then: (1) \b-I\b"
97 " directories before \b-I-\b are searched only for \"...\" include"
98 " files; (2) \b-I\b directories after \b-I-\b are searched for"
99 " \"...\" and <...> include files; (3) the directory \b.\b is searched"
100 " only if it is explicitly specified by a \b-I\b option.]:?[directory]{"
101 " [+-I-C\adirectory\a, \bpp::cdir\b \adirectory\a?Mark \adirectory\a"
102 " as a C header directory. Used with \bpp:plusplus\b.]"
103 " [+-I-D[\afile\a]]?Read the default \bprobe\b(1) definitions from"
104 " \afile\a, or ignore the default definitions if \afile\a"
105 " is omitted.]"
106 " [+-I-H\adirectory\a, \bpp::hostdir\b \adirectory\a?Mark \adirectory\a"
107 " as a hosted directory. Headers from hosted directories have"
108 " compatibility warnings disabled.]"
109 " [+-I-I\aheader\a, \bpp::ignore\b \aheader\a?Add \aheader\a to the"
110 " list of ignored headers.]"
111 " [+-I-M\afile\a?\afile\a contains a sequence of \aheader\a"
112 " [= \"\amap\a\" ]] lines, where \aheader\a is either <\aname\a>"
113 " or \"\aname\a\", and \"\amap\a\" is an explicit binding"
114 " for \aheader\a. \aheader\a is ignored if = \"\amap\a\" is"
115 " omitted.]"
116 " [+-I-R\afile\a?Include \afile\a but do not emit text or line syncs.]"
117 " [+-I-S\adirectory\a?Add \adirectory\a to the default standard include"
118 " directory list.]"
119 " [+-I-T\afile\a?Include \afile\a and emit text to the output file.]"
120 "}"
121 "[M:dependencies?Generate \bmake\b(1) dependencies. Not needed with"
122 " \bnmake\b(1). \b-M\b may be followed by optional \aflags\a to change"
123 " dependency output styles:]{"
124 " [+D?Generate dependencies in a separate \b.d\b file. Preprocessed"
125 " output is still written to \aoutput\a, or the standard output"
126 " if \aoutput\a is omitted.]"
127 " [+G?Generate missing dependencies too.]"
128 " [+M?Only generate local header dependencies; \ahosted\a headers are"
129 " omitted. Note that \ahosted\a headers are determined by"
130 " \b-I-H\b and the \bpp:hosted\b and \bpp:hostdir\b pragmas;"
131 " no special distiction is made between \"\" and <> \binclude\b"
132 " styles.]"
133 "}"
134 "[P!:sync?Emit line syncs.]"
135 "[U:undefine?Remove the definition for the macro \aname\a.]:[name]"
136
137 "[A:assert?Enter the assertion via \b#assert\b for system V"
138 " compatibility.]:[assertion]"
139 "[E:preprocess?Ignored for compatibility with ancient compilers.]"
140 "[H:include-reference?Emit \b#include\b file paths on the standard error,"
141 " one per line, indented to show nesting. If the optional \asize\a"
142 " argument is specified then the entire \b-H\b option is"
143 " ignored.]#?[size]"
144 "[T?If not \bgcc\b(1) then truncate identifiers to \alength\a"
145 " characters for compatibility with old AT&T (I guess only Lucent needs"
146 " them now) compilers.]#?[length]"
147 "[V:version?Emit the \blibpp\b(3) version.]"
148 "[X:argmode?Enable \aname\a=\avalue\a macro arguments for \beasel\b(1)"
149 " compatibility.]"
150 "[Y:standard?Add \adirectory\a to the list searched for"
151 " \b#include\b \b<...>\b files.]:[directory]"
152
153 "\n"
154 "\n[ input [ output ] ]\n"
155 "\n"
156
157 "[+SEE ALSO?\bcc\b(1), \bgcc\b(1), \blibpp\b(3)]"
158 ;
159
160 #include "pplib.h"
161
162 #include <ctype.h>
163
164 /*
165 * convert lint comments to pragmas
166 */
167
168 static void
pplint(char * head,char * comment,char * tail,int line)169 pplint(char* head, char* comment, char* tail, int line)
170 {
171 NoP(line);
172 if (strmatch(comment, "(ARGSUSED|PRINTFLIKE|PROTOLIB|SCANFLIKE|VARARGS)*([0-9])|CONSTCOND|CONSTANTCOND|CONSTANTCONDITION|EMPTY|FALLTHRU|FALLTHROUGH|LINTLIBRARY|LINTED*|NOTREACHED"))
173 {
174 strncopy(pp.token, comment, MAXTOKEN);
175 ppprintf("\n#%s %s:%s\n", dirname(PRAGMA), pp.pass, pp.token);
176 ppline(error_info.line, NiL);
177 }
178 }
179
180 /*
181 * if last!=0 then argv[opt_info.index]==0 with return(0)
182 * else if argv[opt_info.index]==0 then return(0)
183 * otherwise argv[opt_info.index] is the first unrecognized
184 * option with return(1)
185 *
186 * use last=0 if the preprocessor is combined with other passes
187 * so that unknown options may be interpreted for those passes
188 */
189
190 int
ppargs(char ** argv,int last)191 ppargs(char** argv, int last)
192 {
193 register char* s;
194 register int c;
195 register int n;
196 char* p;
197
198 /*
199 * check the args and initialize
200 */
201
202 if (!error_info.id)
203 error_info.id = "cpp";
204 for (;;)
205 {
206 for (; c = optget(argv, usage); last = 0) switch (c)
207 {
208 case 'C':
209 ppop(PP_COMMENT, ppcomment);
210 break;
211 case 'D':
212 /*
213 * this allows single arg pp option extensions
214 * without touching cc
215 * (not all cc wrappers have -W...)
216 */
217
218 switch (*(s = opt_info.arg))
219 {
220 case '-':
221 case '+':
222 n = (*s++ == '-');
223 while (c = *s++) switch (c)
224 {
225 case 'C':
226 ppop(PP_COMPATIBILITY, n);
227 break;
228 case 'D':
229 if (n && ((c = strtol(s, &p, 0)) || p != s))
230 {
231 s = p;
232 n = c;
233 }
234 ppop(PP_DEBUG, -n);
235 break;
236 case 'F':
237 ppop(PP_FILENAME, n ? s : NiL);
238 goto hasarg;
239 case 'H':
240 ppop(PP_HOSTDIR, "-", n);
241 break;
242 case 'I':
243 ppop(PP_CDIR, "-", n);
244 break;
245 case 'K':
246 ppop(PP_KEYARGS, n);
247 break;
248 case 'L':
249 ppop(PP_LINEID, n && *s ? s : "line");
250 goto hasarg;
251 case 'M':
252 ppop(PP_MULTIPLE, !n);
253 break;
254 case 'P':
255 ppop(PP_PASSTHROUGH, n);
256 break;
257 case 'Q':
258 ppop(PP_DUMP, n);
259 break;
260 case 'R':
261 ppop(PP_TRANSITION, n);
262 break;
263 case 'S':
264 ppop(PP_STRICT, n);
265 break;
266 case 'T':
267 ppop(PP_TEST, s);
268 goto hasarg;
269 case 'V':
270 ppop(PP_VENDOR, "-", n);
271 break;
272 case 'W':
273 ppop(PP_WARN, n);
274 break;
275 case 'X':
276 ppop(PP_PROBE, n && *s ? s : 0);
277 goto hasarg;
278 case 'Y':
279 ppop(PP_PEDANTIC, n);
280 break;
281 case 'Z':
282 ppop(PP_POOL, n);
283 break;
284 case 'd':
285 pp.option |= DEFINITIONS;
286 break;
287 case 'm':
288 pp.state |= NOTEXT;
289 pp.option |= KEEPNOTEXT|DEFINITIONS|PREDEFINITIONS;
290 pp.linesync = 0;
291 break;
292 case '+':
293 ppop(PP_PLUSPLUS, n);
294 break;
295 default:
296 if (pp.optarg)
297 {
298 if ((c = (*pp.optarg)(n, c, s)) > 0) goto hasarg;
299 else if (!c) break;
300 }
301 error(1, "%c%s: unknown -D option overload", n ? '-' : '+', s - 1);
302 goto hasarg;
303 }
304 hasarg:
305 break;
306 case ':':
307 ppop(PP_OPTION, s + 1);
308 break;
309 case '%':
310 ppop(PP_DIRECTIVE, s + 1);
311 break;
312 case '_':
313 if (strmatch(s, "__GNUC__*"))
314 pp.arg_style |= STYLE_gnu;
315 else if (strmatch(s, "__(ANSI|STDC|STRICT)__*") || !(pp.arg_style & STYLE_gnu) && strmatch(s, "__STRICT_ANSI__*"))
316 ppop(PP_STRICT, 1);
317 else if (strmatch(s, "__cplusplus*"))
318 ppop(PP_PLUSPLUS, 1);
319 /*FALLTHROUGH*/
320 default:
321 ppop(PP_DEFINE, s);
322 break;
323 }
324 break;
325 case 'E':
326 /* historically ignored */
327 break;
328 case 'I':
329 if (!(s = opt_info.arg))
330 {
331 /*
332 * some compilers interpret `-I ...' as
333 * `-I-S' and arg ... while others interpret
334 * it as `-I...'
335 */
336
337 p = "-S";
338 if ((s = argv[opt_info.index]) && ((n = *s++) == '-' || n == '+') && *s++ == 'D')
339 {
340 if (isalpha(*s) || *s == '_')
341 while (isalnum(*++s) || *s == '_');
342 if (*s && *s != '=' && *s != '-' && *s != '+')
343 p = argv[opt_info.index++];
344 }
345 s = p;
346 }
347 switch (*s)
348 {
349 case '-':
350 case '+':
351 n = *(p = s++) == '-';
352 c = *s++;
353 if (!n && !*s) s = 0;
354 switch (c)
355 {
356 case 0:
357 ppop(PP_LOCAL);
358 break;
359 case 'C':
360 ppop(PP_CDIR, s, n);
361 break;
362 case 'D':
363 ppop(PP_DEFAULT, s);
364 break;
365 case 'H':
366 ppop(PP_HOSTDIR, s, n);
367 break;
368 case 'I':
369 ppop(PP_IGNORE, s);
370 break;
371 case 'M':
372 ppop(PP_IGNORELIST, s);
373 break;
374 case 'R':
375 ppop(PP_READ, s);
376 break;
377 case 'S':
378 ppop(PP_STANDARD, s);
379 break;
380 case 'T':
381 ppop(PP_TEXT, s);
382 break;
383 case 'V':
384 ppop(PP_VENDOR, s, n);
385 break;
386 default:
387 error(1, "%s: unknown -I option overload", p);
388 break;
389 }
390 break;
391 default:
392 ppop(PP_INCLUDE, s);
393 break;
394 }
395 break;
396 case 'M':
397 for (n = PP_deps; argv[opt_info.index]; opt_info.offset++)
398 {
399 switch (argv[opt_info.index][opt_info.offset])
400 {
401 case 'D':
402 n |= PP_deps_file;
403 continue;
404 case 'G':
405 n |= PP_deps_generated;
406 continue;
407 case 'M':
408 n |= PP_deps_local;
409 continue;
410 }
411 break;
412 }
413 ppop(PP_FILEDEPS, n);
414 break;
415 case 'P':
416 ppop(PP_LINE, (PPLINESYNC)0);
417 break;
418 case 'U':
419 ppop(PP_UNDEF, opt_info.arg);
420 break;
421
422 /*
423 * System V CCS compatibility
424 */
425
426 case 'A':
427 if (isalpha(opt_info.arg[0]) || opt_info.arg[0] == '_' || opt_info.arg[0] == '$')
428 ppop(PP_ASSERT, opt_info.arg);
429 break;
430 case 'H':
431 if (!opt_info.arg)
432 ppop(PP_INCREF, ppincref);
433 break;
434 case 'T':
435 if (!(pp.arg_style & STYLE_gnu))
436 ppop(PP_TRUNCATE, TRUNCLENGTH);
437 /* else enable ANSI trigraphs -- default */
438 break;
439 case 'V':
440 error(0, "%s", pp.version);
441 break;
442 case 'X':
443 pp.arg_mode = (*(opt_info.arg + 1) || pp.arg_mode && pp.arg_mode != *opt_info.arg) ? '-' : *opt_info.arg;
444 break;
445 case 'Y':
446 if (*(s = opt_info.arg) && *(s + 1) == ',')
447 {
448 if (*s != 'I') break;
449 s += 2;
450 }
451 ppop(PP_STANDARD, s);
452 break;
453
454 /*
455 * errors
456 */
457
458 case '?':
459 error(ERROR_USAGE|4, "%s", opt_info.arg);
460 break;
461 case ':':
462 if (!last)
463 {
464 opt_info.again = 1;
465 return(1);
466 }
467
468 /*
469 * cross your fingers
470 */
471
472 if (!(s = argv[opt_info.index]))
473 error(3, "%s", opt_info.arg);
474 if (opt_info.offset == 2 && (pp.arg_style & STYLE_gnu))
475 {
476 p = argv[opt_info.index + 1];
477 if (streq(s, "-$"))
478 {
479 ppop(PP_OPTION, "noid \"$\"");
480 goto ignore;
481 }
482 else if (streq(s, "-dD"))
483 {
484 pp.option |= DEFINITIONS;
485 goto ignore;
486 }
487 else if (streq(s, "-dM"))
488 {
489 pp.state |= NOTEXT;
490 pp.option |= KEEPNOTEXT|DEFINITIONS|PREDEFINITIONS;
491 pp.linesync = 0;
492 goto ignore;
493 }
494 else if (streq(s, "-imacros"))
495 {
496 if (p)
497 {
498 ppop(PP_READ, p);
499 opt_info.index++;
500 opt_info.offset = 0;
501 }
502 goto ignore;
503 }
504 else if (streq(s, "-include"))
505 {
506 if (p)
507 {
508 ppop(PP_TEXT, p);
509 opt_info.index++;
510 opt_info.offset = 0;
511 }
512 opt_info.offset = 0;
513 goto ignore;
514 }
515 else if (strneq(s, "-lang-", 6))
516 {
517 s += 6;
518 if (streq(s, "c"))
519 c = 0;
520 else if (streq(s, "c++"))
521 c = 1;
522 else if (streq(s, "objc"))
523 c = 2;
524 else if (streq(s, "objc++"))
525 c = 3;
526 ppop(PP_PLUSPLUS, c & 1);
527 if (c & 2)
528 ppop(PP_DIRECTIVE, "pragma pp:map \"/#(pragma )?import>/\" \"/#(pragma )?import(.*)/__STDPP__IMPORT__(\\2)/\"\n\
529 #macdef __STDPP__IMPORT__(x)\n\
530 #pragma pp:noallmultiple\n\
531 #include x\n\
532 #pragma pp:allmultiple\n\
533 #endmac");
534 goto ignore;
535 }
536 else if (streq(s, "-lint"))
537 {
538 ppop(PP_COMMENT, pplint);
539 goto ignore;
540 }
541 }
542 s += opt_info.offset - 1;
543 if (strmatch(s, "i*.h"))
544 ppop((pp.arg_style & STYLE_gnu) || s[1] == '/' ? PP_READ : PP_TEXT, s + 1);
545 else if (strmatch(s, "*@(nostandard|nostdinc)*"))
546 ppop(PP_STANDARD, "");
547 else if (strmatch(s, "*@(exten|xansi)*|std"))
548 {
549 ppop(PP_COMPATIBILITY, 0);
550 ppop(PP_TRANSITION, 1);
551 }
552 else if (strmatch(s, "*@(ansi|conform|pedantic|stand|std1|strict[!-])*"))
553 {
554 ppop(PP_COMPATIBILITY, 0);
555 ppop(PP_STRICT, 1);
556 if (strmatch(s, "*pedantic*"))
557 ppop(PP_PEDANTIC, 1);
558 }
559 else if (strmatch(s, "*@(trans)*"))
560 {
561 ppop(PP_COMPATIBILITY, 1);
562 ppop(PP_TRANSITION, 1);
563 }
564 else if (strmatch(s, "*@(classic|compat|std0|tradition|[kK][n&+][rR])*"))
565 {
566 ppop(PP_COMPATIBILITY, 1);
567 ppop(PP_TRANSITION, 0);
568 }
569 else if (strmatch(s, "*@(plusplus|++)*"))
570 ppop(PP_PLUSPLUS, 1);
571 else if (strmatch(s, "*@(warn)*"))
572 ppop(PP_WARN, 1);
573
574 /*
575 * ignore unknown options
576 * the probe info takes care of these
577 * fails if an option value is in the next arg
578 * and this is the last option
579 */
580
581 if (argv[opt_info.index + 1] && argv[opt_info.index + 1][0] != '-' && argv[opt_info.index + 2] && argv[opt_info.index + 2][0] == '-')
582 {
583 opt_info.index++;
584 opt_info.offset = 0;
585 }
586 ignore:
587 while (argv[opt_info.index][opt_info.offset]) opt_info.offset++;
588 break;
589 }
590 if (!(s = argv[opt_info.index])) return(0);
591 switch (pp.arg_file)
592 {
593 case 0:
594 if (*s != '-' || *(s + 1)) ppop(PP_INPUT, s);
595 break;
596 case 1:
597 if (*s != '-' || *(s + 1)) ppop(PP_OUTPUT, s);
598 break;
599 default:
600 if (!last) return(1);
601 error(1, "%s: extraneous argument ignored", s);
602 break;
603 }
604 pp.arg_file++;
605 if (!argv[++opt_info.index]) return(0);
606
607 /*
608 * old versions allow options after file args
609 */
610 }
611 }
612