Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libpp/ppargs.c
1808 views
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 <[email protected]> *
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
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
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
613