Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/nmake/option.c
1808 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1984-2012 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
* make options support
26
*
27
* option name mappings are here
28
* option flag mappings are in options.h
29
*/
30
31
#include "make.h"
32
#include "options.h"
33
34
#define OPT_OFFSET 10
35
#define OPT_NON '-'
36
#define OPT_SEP ';'
37
38
static const char usage1[] =
39
"+"
40
"[-?%s\n]"
41
USAGE_LICENSE
42
"[+NAME?nmake - configure, manage and update file hierarchies]"
43
"[+DESCRIPTION?\bnmake\b reads input \amakefiles\a and triggers shell"
44
" actions to build target files that are out of date with prerequisite"
45
" files. Most information used to build targets is contained in"
46
" the global \abase rules\a that are augmented by user \amakefiles\a."
47
" Each operand may be an option, script, or target. An option operand"
48
" is preceded by \b-\b or \b+\b. A script operand contains at least"
49
" one of \bspace\b, \btab\b, \bnewline\b, \b:\b, \b=\b, \b\"\b, or"
50
" \b\\\b and is parsed as a separate, complete makefile. Otherwise"
51
" the operand is a \atarget\a that is generated according to the"
52
" \amakefile\a and \aglobal\a rules. \atarget\a operands are made"
53
" in order from left to right and override the default targets.]"
54
"[+?Command line options, scripts and targets may appear in any order,"
55
" with the exception that no option operand may appear after a"
56
" \b--\b operand.]"
57
"[+?Options are qualified by the base name of the makefile that defined"
58
" them. Unqualified options are defined by \bnmake\b itself.]"
59
;
60
61
static Option_t options[] = /* option table */
62
{
63
64
{ "accept", OPT_accept, (char*)&state.accept, 0,
65
"Accept filesystem timestamps of existing targets." },
66
{ "alias", OPT_alias, (char*)&state.alias, 0,
67
"Enable directory aliasing." },
68
{ "base", OPT_base, (char*)&state.base, 0,
69
"Compile base or global rules." },
70
{ "believe", OPT_believe, (char*)&state.believe, 0,
71
"Believe the state file time of files lower than view level"
72
" \alevel-1\a. The file system time will be checked for files with"
73
" no state or files in views equal to or higher than \alevel\a."
74
" \alevel=0\a causes the file system time to be checked for"
75
" files on all view levels. The top view is level 0.", "level:=0" },
76
{ "compatibility",OPT_compatibility,(char*)&state.compatibility,0,
77
"Disable compatibility messages." },
78
{ "compile", OPT_compile, (char*)&state.compileonly, 0,
79
"Compile the input makefile and exit." },
80
{ "corrupt",OPT_corrupt, (char*)&state.corrupt, 0,
81
"\aaction\a determines the action to take for corrupt or invalid"
82
" top view state files. The top view default is \berror\b and the"
83
" lower view default is \baccept\b. \aaction\a may be one of:",
84
"[action:!accept]"
85
"{"
86
" [+accept?print a warning and set \b--accept\b]"
87
" [+error?print a diagnostic and exit]"
88
" [+ignore?print a warning and set \b--noreadstate\b]"
89
"}" },
90
{ "cross", OPT_cross, (char*)&state.cross, 0,
91
"Don't run generated executables." },
92
{ "debug", OPT_debug, 0, 0,
93
"Set the debug trace level to \alevel\a. Higher levels produce"
94
" more output.", "level" },
95
{ "errorid", OPT_errorid, (char*)&state.errorid, 0,
96
"Add \aid\a to the error message command identifier.", "id:=make" },
97
{ "exec", OPT_exec, (char*)&state.exec, 0,
98
"Enable shell action execution. \b--noexec\b"
99
" disables all but \b.ALWAYS\b shell actions and also disables"
100
" make object and state file generation/updates." },
101
{ "expandview", OPT_expandview, (char*)&state.expandview, 0,
102
"Expand \a3d\a filesystem paths." },
103
{ "explain", OPT_explain, (char*)&state.explain, 0,
104
"Explain each action." },
105
{ "file", OPT_file, (char*)&internal.makefiles, 0,
106
"Read the makefile \afile\a. If \b--file\b is not specified then"
107
" the makefile names specified by \b$(MAKEFILES)\b are attempted in"
108
" order from left to right. The file \b-\b is equivalent"
109
" to \b/dev/null\b.", "file" },
110
{ "force", OPT_force, (char*)&state.force, 0,
111
"Force all targets to be out of date." },
112
{ "global", OPT_global, (char*)&internal.globalfiles, 0,
113
"Read the global makefile \afile\a. The \b--file\b search is not"
114
" affected.", "file" },
115
{ "ignore", OPT_ignore, (char*)&state.ignore, 0,
116
"Ignore shell action errors." },
117
{ "ignorelock", OPT_ignorelock, (char*)&state.ignorelock, 0,
118
"Ignore state file locks." },
119
{ "include", OPT_include, 0, 0,
120
"Add \adirectory\a to the makefile search list.", "directory" },
121
{ "intermediate", OPT_intermediate,(char*)&state.intermediate, 0,
122
"Force intermediate target generation." },
123
{ "jobs", OPT_jobs, (char*)&state.jobs, 0,
124
"Set the shell action concurrency level to \alevel\a."
125
" Level \b1\b allows dependency checking while an action is"
126
" executing; level \b0\b stops all activity while an action"
127
" is executing.", "level:=${" CO_ENV_PROC "::-1}" },
128
{ "keepgoing", OPT_keepgoing, (char*)&state.keepgoing, 0,
129
"Continue after error with sibling prerequisites." },
130
{ "list", OPT_list, (char*)&state.list, 0,
131
"List the current rules and variables on the standard output in"
132
" makefile form." },
133
{ "mam", OPT_mam, (char*)&state.mam.options, 0,
134
"Write \amake abstract machine\a output to \afile\a if specified or"
135
" to the standard output otherwise. See \bmam\b(5) for details on"
136
" the \amake abstract machine\a language. If \aparent\a !=0 then it is"
137
" the process id of a parent \amam\a process. \adirectory\a is"
138
" the working directory of the current \amam\a process relative"
139
" to the root \amam\a process, \b.\b if not specified. \atype\a"
140
" must be one of:",
141
"[type[,subtype]][::file[::parent[::directory]]]]]]]"
142
"{"
143
"[+dynamic?\amam\a trace of an actual build]"
144
"[+regress?\amam\a for regression testing; labels, path"
145
" names and time stamps are canonicalized for easy comparison]"
146
"[+static?\amam\a representation of the makefile assertions;"
147
" used for makefile conversion]"
148
"[+----?0 or more comma separated subtypes ----]"
149
"[+port?used by the base rules to generate portable"
150
" makefiles; some paths are parameterized; on by default]"
151
"[+----?mam options ----]"
152
"[+[no]]hold?\bhold\b \amam\a output until nested \bnohold\b]"
153
"}" },
154
{ "never", OPT_never, (char*)&state.never, 0,
155
"Don't execute any shell actions. \b--noexec\b executes \b.ALWAYS\b"
156
" shell actions." },
157
{ "option", OPT_option, 0, 0,
158
"Define a new option. The definition is a delimiter separated field"
159
" list. Any non-alpha-numeric delimiter other than \b-\b may be used."
160
" \b;\b is used in this description. Makefile \bset option\b"
161
" definitions must be '...' quoted. Two adjacent delimiters specifies"
162
" the literal delimiter character and a \b-\b field value specifies an"
163
" empty field. \achar\a is the single character option name, \aname\a"
164
" is the long option name, \aset\a is an optional \b.FUNCTION\b that"
165
" is called when the option value is changed by \bset\b, \avalues\a is"
166
" an \boptget\b(3) value list, and \aflags\a are a combination of:",
167
"['char;name;flags;set;description;values']"
168
"{"
169
" [+a?multiple values appended]"
170
" [+b?boolean value]"
171
" [+i?internal value inverted]"
172
" [+n?numeric value]"
173
" [+o?\a-char\a means \b--no\b\aname\a]"
174
" [+p?.mo probe prerequisite]"
175
" [+s?string value]"
176
" [+v?optional option argument]"
177
" [+x?not expanded in \b$(-)\b]"
178
"}" },
179
{ "override", OPT_override, (char*)&state.override, 0,
180
"Implicit rules or metarules override explicit rules." },
181
{ "questionable", OPT_questionable,(char*)&state.questionable, 0,
182
"Enable questionable features defined by \amask\a. Questionable"
183
" features are artifacts of previous implementations (\bnmake\b has"
184
" been around since 1984-11-01) that will eventually be dropped."
185
" The questionable \amask\a registry is in the \bmain.c\b \bnmake\b"
186
" source file.", "mask" },
187
{ "readonly", OPT_readonly, (char*)&state.readonly, 0,
188
"Current assignments and assertions will be marked \breadonly\b." },
189
{ "readstate", OPT_readstate, (char*)&state.readstate, 0,
190
"Ignore state files lower than view level \alevel\a. \alevel=0\a"
191
" ignores state files on all view levels. The top view is level 0.",
192
"level:=0" },
193
{ "regress", OPT_regress, (char*)&state.regress, 0,
194
"Massage output for regression testing. \aaction\a may be one of:",
195
"[action:!message]"
196
"{"
197
" [+message?alter messages only]"
198
" [+sync?sync 1-second clocks if necessary and alter messages]"
199
"}" },
200
{ "reread", OPT_reread, (char*)&state.reread, 0,
201
"Ignore any previously generated \b.mo\b files and re-read all"
202
" input makefiles." },
203
{ "ruledump", OPT_ruledump, (char*)&state.ruledump, 0,
204
"Dump rule information in tabular form on the standard"
205
" error when \bnmake\b exits." },
206
{ "scan", OPT_scan, (char*)&state.scan, 0,
207
"Scan for and/or check implicit file prerequisites. On by default." },
208
{ "serialize", OPT_serialize, (char*)&state.serialize, 0,
209
"Serialize concurrent output by caching job stdout and stderr"
210
" output until job completion." },
211
{ "silent", OPT_silent, (char*)&state.silent, 0,
212
"Do not trace shell actions as they are executed." },
213
{ "strictview", OPT_strictview, (char*)&state.strictview, 0,
214
"Set \bVPATH\b \b.SOURCE\b rule interpretation to follow strict"
215
" \a3d\a filesystem semantics, where directories in the top views"
216
" take precedence. On by default when running in \a2d\a with"
217
" \bVPATH\b defined, off by default otherwise." },
218
{ "target-context",OPT_targetcontext,(char*)&state.targetcontext, 0,
219
"Expand and execute shell actions in the target directory context."
220
" This allows a single makefile to control a directory tree while"
221
" generating target files at the source file directory level. By"
222
" default target files are generated in the current directory." },
223
{ "target-prefix", OPT_targetprefix,(char*)&state.targetprefix, 0,
224
"Allow metarules to match \aseparator\a in the target to \b/\b"
225
" in the source. Used to disambiguate source file base name clashes"
226
" when target files are generated in the current directory."
227
" \aseparator\a must not contain metarule or shell pattern characters.",
228
"separator" },
229
{ "test", OPT_test, (char*)&state.test, 0,
230
"Enable test code defined by \amask\a. Test code is implementation"
231
" specific. The test \amask\a registry is in the \bmain.c\b \bnmake\b"
232
" source file.", "mask" },
233
{ "tolerance", OPT_tolerance, (char*)&state.tolerance, 0,
234
"Set the time comparison tolerance to \aseconds\a. Times within"
235
" the tolerance range compare equal. Useful on systems that can't"
236
" quite get the file system and local clocks in sync. A tolerance"
237
" of more that 5 seconds soon becomes intolerable.", "seconds" },
238
{ "touch", OPT_touch, (char*)&state.touch, 0,
239
"Touch the time stamps of out of date targets rather than execute"
240
" the shell action." },
241
{ "vardump", OPT_vardump, (char*)&state.vardump, 0,
242
"Dump variable information in tabular form on the standard"
243
" error when \bnmake\b exits." },
244
{ "warn", OPT_warn, (char*)&state.warn, 0,
245
"Enable verbose warning messages." },
246
{ "writeobject", OPT_writeobject,(char*)&state.writeobject, 0,
247
"Generate a \b.mo\b make object file in \afile\a that can be read"
248
" instead of the input makefiles on the next \bnmake\b invocation."
249
" On by default. \b--nowriteobject\b prevents the generation."
250
" The default name is used if \afile\a is omitted or \b-\b."
251
" If \afile\a is a directory then the default is placed in that"
252
" directory.",
253
"file:=$(MAKEFILE::B::S=.mo)" },
254
{ "writestate", OPT_writestate, (char*)&state.writestate, 0,
255
"Generate a \b.ms\b make state file in \afile\a when \bnmake\b exits."
256
"The state contains the time stamps of all prerequisites and targets"
257
" that have been accessed since the state file was first generated."
258
" On by default. \b--nowritestate\b prevents the generation."
259
" The default name is used if \afile\a is omitted or \b-\b."
260
" If \afile\a is a directory then the default is placed in that"
261
" directory.",
262
"file:=$(MAKEFILE::B::S=.ms)" },
263
264
{ "byname", OPT_byname, 0, 0,
265
"(obsolete) Set options by name.", "name[=value]]" },
266
{ "define", OPT_define, 0, 0,
267
"(obsolete) Pass macro definition to the makefile preprocessor.",
268
"name[=value]]" },
269
{ "preprocess", OPT_preprocess, 0, 0,
270
"(obsolete) Preprocess all makefiles." },
271
{ "undef", OPT_undef, 0, 0,
272
"(obsolete) Pass macro deletion to the makefile preprocessor.",
273
"name" },
274
275
};
276
277
static const char usage2[] =
278
"\n"
279
"[ script ... ] [ target ... ]\n"
280
"\n"
281
"[+DIAGNOSTICS?Diagnostic messages are printed on the standard error and are"
282
" classified by levels. The level determines if the diagnostic"
283
" is printed, if it causes \bnmake\b to exit, and if it affects"
284
" the \bnmake\b exit status. The levels are:]{"
285
" [+<0?Debug message, enabled when the absolute value of"
286
" \alevel\a is greater than or equal to the"
287
" \b--debug\b level. Debug diagnostics are prefixed"
288
" by \bdebug\b-\alevel\a\b:\b.]"
289
" [+1?Warning message, disabled by \b--silent\b. Warning"
290
" diagnostics are prefixed by \bwarning\a\b:\b]"
291
" [+2?Non-fatal error message. Processing continues after"
292
" the diagnostic, but the eventual \bnmake\b exit"
293
" status will be non-zero.]"
294
" [+>2?Fatal error message. \bnmake\b exits after the"
295
" diagnostic (and internal cleanup) with exit"
296
" status \alevel\a-2.]"
297
"}"
298
"[+SEE ALSO?\b3d\b(1), \bar\b(1), \bcc\b(1), \bcoshell\b(1), \bcpp\b(1),"
299
" \bprobe\b(1), \bsh\b(1)]"
300
;
301
302
struct Oplist_s; typedef struct Oplist_s Oplist_t;
303
304
struct Oplist_s /* linked option list */
305
{
306
char* option; /* option value for set() */
307
Oplist_t* next; /* next in list */
308
};
309
310
typedef struct Optstate_s /* option state */
311
{
312
Oplist_t* hidden; /* options hidden by cmd line */
313
Oplist_t* lasthidden; /* tail of hidden */
314
Oplist_t* delayed; /* delayed unknown options */
315
Oplist_t* lastdelayed; /* tail of delayed */
316
317
Option_t* head; /* head of external option list */
318
Option_t* tail; /* tail of external option list */
319
320
Hash_table_t* table;
321
322
Sfio_t* usage; /* generated optget() usage */
323
int usageindex; /* next user index */
324
} Optstate_t;
325
326
static Optstate_t opt;
327
328
static Option_t*
329
getoption(const char* name)
330
{
331
register Option_t* op;
332
register int c;
333
334
if (!(op = (Option_t*)hashget(opt.table, name)) && (strchr(name, '-') || strchr(name, '_')))
335
{
336
while (c = *name++)
337
if (c != '-' && c != '_')
338
sfputc(internal.tmp, c);
339
op = (Option_t*)hashget(opt.table, sfstruse(internal.tmp));
340
}
341
return op;
342
}
343
344
static void
345
putoption(register Option_t* op, int index)
346
{
347
register char* s;
348
register int c;
349
char buf[16];
350
351
hashput(opt.table, op->name, (char*)op);
352
if (strchr(op->name, '-') || strchr(op->name, '_'))
353
{
354
s = op->name;
355
while (c = *s++)
356
if (c != '-' && c != '_')
357
sfputc(internal.tmp, c);
358
hashput(opt.table, strdup(sfstruse(internal.tmp)), (char*)op);
359
}
360
if (op->flags & Of)
361
sfsprintf(buf, sizeof(buf), "+%d", OPT(op->flags));
362
else
363
{
364
buf[0] = '-';
365
buf[1] = OPT(op->flags);
366
buf[2] = 0;
367
}
368
hashput(opt.table, strdup(buf), (char*)op);
369
if (index >= elementsof(options))
370
{
371
sfsprintf(buf, sizeof(buf), "-%d", index);
372
hashput(opt.table, strdup(buf), (char*)op);
373
}
374
}
375
376
/*
377
* initialize the option hash table
378
*/
379
380
void
381
optinit(void)
382
{
383
register int i;
384
385
opt.table = hashalloc(NiL, HASH_name, "options", 0);
386
for (i = 0; i < elementsof(options); i++)
387
{
388
options[i].flags |= Om;
389
switch (OPT(options[i].flags))
390
{
391
case OPT(OPT_debug):
392
options[i].value = (char*)&error_info.trace;
393
break;
394
}
395
putoption(&options[i], i);
396
if (opt.tail)
397
opt.tail->next = &options[i];
398
else
399
opt.head = &options[i];
400
opt.tail = &options[i];
401
}
402
}
403
404
/*
405
* return option table entry given OPT_[a-z]+ flag
406
* type==0 panics if not in table
407
*/
408
409
Option_t*
410
optflag(register int flag)
411
{
412
register Option_t* op;
413
char buf[8];
414
415
if (flag & Of)
416
sfsprintf(buf, sizeof(buf), "+%d", OPT(flag));
417
else
418
{
419
buf[0] = '-';
420
buf[1] = OPT(flag);
421
buf[2] = 0;
422
}
423
if (!(op = getoption(buf)) && (flag & ~((1<<8)-1)))
424
error(ERROR_PANIC, "%s: unknown option flag", buf);
425
return op;
426
}
427
428
/*
429
* call op->set with new value
430
*/
431
432
static void
433
setcall(register Option_t* op, int readonly)
434
{
435
Rule_t* r;
436
char* oset;
437
int oreadonly;
438
char buf[16];
439
440
if (op->set && (r = getrule(op->set)))
441
{
442
oset = op->set;
443
op->set = 0;
444
oreadonly = state.readonly;
445
state.readonly = readonly;
446
switch (op->flags & (Ob|On|Os))
447
{
448
case Ob:
449
call(r, *((unsigned char*)op->value) ? "1" : null);
450
break;
451
case On:
452
sfsprintf(buf, sizeof(buf), "%d", *((int*)op->value));
453
call(r, buf);
454
break;
455
case Os:
456
call(r, *((char**)op->value));
457
break;
458
}
459
state.readonly = oreadonly;
460
op->set = oset;
461
}
462
}
463
464
/*
465
* copy a declare() string entry s to sp
466
*/
467
468
static void
469
declarestr(register Sfio_t* sp, register const char* s)
470
{
471
register int c;
472
473
if (s && *s)
474
while (c = *s++)
475
{
476
if (c == OPT_SEP)
477
sfputc(sp, c);
478
sfputc(sp, c);
479
}
480
else
481
sfputc(sp, OPT_NON);
482
sfputc(sp, OPT_SEP);
483
}
484
485
/*
486
* generate external option declaration
487
*/
488
489
static void
490
declare(Sfio_t* sp, register Option_t* op)
491
{
492
if (!(op->flags & Of))
493
sfputc(internal.tmp, OPT(op->flags));
494
sfputc(internal.tmp, OPT_SEP);
495
declarestr(internal.tmp, op->name);
496
if (op->flags & Oa)
497
sfputc(internal.tmp, 'a');
498
if (op->flags & Ob)
499
sfputc(internal.tmp, 'b');
500
if (op->flags & On)
501
sfputc(internal.tmp, 'n');
502
if (op->flags & Oo)
503
sfputc(internal.tmp, 'o');
504
if (op->flags & Op)
505
sfputc(internal.tmp, 'p');
506
if (op->flags & Os)
507
sfputc(internal.tmp, 's');
508
if (op->flags & Ov)
509
sfputc(internal.tmp, 'v');
510
if (op->flags & Ox)
511
sfputc(internal.tmp, 'x');
512
sfputc(internal.tmp, OPT_SEP);
513
declarestr(internal.tmp, op->set);
514
declarestr(internal.tmp, op->description);
515
declarestr(internal.tmp, op->arg);
516
shquote(sp, fmtesc(sfstruse(internal.tmp)));
517
}
518
519
/*
520
* generate optget() usage for op
521
*/
522
523
static void
524
genusage(register Option_t* op, int index, int last)
525
{
526
long pos;
527
528
if (op)
529
{
530
sfputc(opt.usage, '[');
531
if (!(op->flags & Of))
532
{
533
sfputc(opt.usage, OPT(op->flags));
534
if (op->flags & Oo)
535
sfputc(opt.usage, '!');
536
sfputc(opt.usage, '=');
537
}
538
sfprintf(opt.usage, "%d:%s?%s]", index + OPT_OFFSET, op->name, op->description);
539
if (op->arg)
540
{
541
if (op->flags & On)
542
sfputc(opt.usage, '#');
543
else
544
sfputc(opt.usage, ':');
545
if (op->flags & Ov)
546
sfputc(opt.usage, '?');
547
if (*op->arg != '[')
548
sfputc(opt.usage, '[');
549
sfputr(opt.usage, op->arg, -1);
550
if (*op->arg != '[')
551
sfputc(opt.usage, ']');
552
}
553
sfputc(opt.usage, '\n');
554
}
555
pos = sfstrtell(opt.usage);
556
if (last)
557
sfprintf(opt.usage, usage2, version);
558
else
559
sfputc(opt.usage, 0);
560
sfstrseek(opt.usage, pos, SEEK_SET);
561
}
562
563
/*
564
* mam output discipline to parameterize local paths
565
*/
566
567
static ssize_t
568
mamwrite(Sfio_t* fp, const void* buf, size_t n, Sfdisc_t* dp)
569
{
570
char* s;
571
size_t z;
572
573
static char* tmp;
574
static int siz;
575
576
z = n;
577
if (n > 1 && ((char*)buf)[n-1] == '\n')
578
{
579
if (n >= siz)
580
{
581
siz = roundof(n + 1, 1024);
582
tmp = newof(tmp, char, siz, 0);
583
}
584
memcpy(tmp, buf, n);
585
tmp[n-1] = 0;
586
if (s = call(makerule(external.mamaction), tmp))
587
{
588
z = strlen(s);
589
if (z >= siz)
590
{
591
siz = roundof(z + 1, 1024);
592
tmp = newof(tmp, char, siz, 0);
593
}
594
memcpy(tmp, s, z);
595
tmp[z++] = '\n';
596
buf = (const char*)tmp;
597
}
598
}
599
return sfwr(fp, buf, z, dp) == z ? n : -1;
600
}
601
602
/*
603
* make sure the current time is > the start time
604
* to differentiate strtime() "recent" vs. "current"
605
* if the clock or filesystem doesn't support subsecond
606
* granularity then we sleep until the next integral
607
* second ticks off
608
*
609
* the filesystem checks assume that file time stamp
610
* subseconds==0 rarely happens by chance -- the penalty
611
* for a wrong guess is slightly slower but still correct
612
* regression tests
613
*
614
* this also assumes that regression tests run faster than
615
* the disk inode flush frequency on systems where the
616
* cache time resolution is higher than the disk
617
*/
618
619
static void
620
regressinit(const char* type)
621
{
622
Stat_t st;
623
Time_t t;
624
int i;
625
626
error_info.version = 0;
627
if (*type == 's')
628
{
629
t = CURTIME;
630
if (i = tmxnsec(t) && !stat(".", &st) && !tmxnsec(tmxgetatime(&st)) && !tmxnsec(tmxgetmtime(&st)))
631
state.start = tmxsns(tmxsec(t)+1, 0);
632
while (state.start >= (t = CURTIME))
633
tmsleep(0L, 100000000L);
634
if (!i)
635
state.start = t;
636
}
637
}
638
639
/*
640
* return option name and details
641
*/
642
643
static char*
644
showop(register Option_t* op)
645
{
646
sfprintf(internal.tmp, "%s,", op->name);
647
sfprintf(internal.tmp, (op->flags & Of) ? "%03o," : "'%c',", op->flags & ((1<<8) - 1));
648
if (op->flags & Oa)
649
sfprintf(internal.tmp, "|a");
650
if (op->flags & Ob)
651
sfprintf(internal.tmp, "|b");
652
if (op->flags & Of)
653
sfprintf(internal.tmp, "|f");
654
if (op->flags & Oi)
655
sfprintf(internal.tmp, "|i");
656
if (op->flags & On)
657
sfprintf(internal.tmp, "|n");
658
if (op->flags & Oo)
659
sfprintf(internal.tmp, "|o");
660
if (op->flags & Op)
661
sfprintf(internal.tmp, "|p");
662
if (op->flags & Os)
663
sfprintf(internal.tmp, "|s");
664
if (op->flags & Ov)
665
sfprintf(internal.tmp, "|v");
666
if (op->flags & Ox)
667
sfprintf(internal.tmp, "|x");
668
if (op->flags & OPT_COMPILE)
669
sfprintf(internal.tmp, "|COMPILE");
670
if (op->flags & OPT_DECLARE)
671
sfprintf(internal.tmp, "|DECLARE");
672
if (op->flags & OPT_DEFAULT)
673
sfprintf(internal.tmp, "|DEFAULT");
674
if (op->flags & OPT_EXTERNAL)
675
sfprintf(internal.tmp, "|EXTERNAL");
676
if (op->flags & OPT_READONLY)
677
sfprintf(internal.tmp, "|READONLY");
678
if (op->flags & OPT_SET)
679
sfprintf(internal.tmp, "|SET");
680
sfputc(internal.tmp, '|');
681
return sfstruse(internal.tmp);
682
}
683
684
/*
685
* return next option definition field
686
*/
687
688
static char*
689
field(char** p, int sep, int app, int lenient)
690
{
691
register char* s;
692
register char* t;
693
char* v;
694
register int c;
695
696
if (!(c = *(s = *p)) || c == app)
697
return 0;
698
if (c == sep)
699
{
700
*p = s + 1;
701
return 0;
702
}
703
v = t = s;
704
for (;;)
705
{
706
if (!(c = *t++ = *s++))
707
{
708
s--;
709
t--;
710
break;
711
}
712
else if (c == sep)
713
{
714
if (lenient || !*s)
715
{
716
t--;
717
s--;
718
break;
719
}
720
if (*s == OPT_NON && (!*(s + 1) || *(s + 1) == sep))
721
{
722
t--;
723
s++;
724
break;
725
}
726
if (*s != c)
727
{
728
t--;
729
s--;
730
break;
731
}
732
s++;
733
}
734
}
735
if (*s)
736
s++;
737
*p = s;
738
if (*t)
739
*t = 0;
740
if (!*v || lenient && *v == OPT_NON && !*(v + 1))
741
return 0;
742
return v;
743
}
744
745
/*
746
* set an option given its pointer
747
*/
748
749
static void
750
setop(register Option_t* op, register int n, char* s, int type)
751
{
752
char* t;
753
Rule_t* r;
754
int readonly;
755
756
readonly = state.readonly;
757
if (OPT(op->flags) != OPT(OPT_option))
758
{
759
if (type == ':' && (op->flags & OPT_SET))
760
return;
761
if (readonly)
762
op->flags |= OPT_READONLY;
763
else if (!state.user && (op->flags & OPT_READONLY))
764
{
765
Oplist_t* x;
766
767
/*
768
* save for listops(*,'@')
769
*/
770
771
sfprintf(internal.tmp, "%s", op->name);
772
if (type == ':' && !(op->flags & OPT_SET))
773
sfputc(internal.tmp, ':');
774
if (!s)
775
sfprintf(internal.tmp, "=%d", n);
776
else if (!strchr(s, ' ') && !strchr(s, '\t'))
777
sfprintf(internal.tmp, "=%s", s);
778
else if (!strchr(s, '\''))
779
sfprintf(internal.tmp, "='%s'", s);
780
else
781
sfprintf(internal.tmp, "=\"%s\"", s);
782
n = sfstrtell(internal.tmp) + 1;
783
s = sfstruse(internal.tmp);
784
x = newof(0, Oplist_t, 1, n);
785
x->option = strcpy((char*)(x + 1), s);
786
if (opt.lasthidden)
787
opt.lasthidden = opt.lasthidden->next = x;
788
else
789
opt.hidden = opt.lasthidden = x;
790
return;
791
}
792
if (error_info.trace <= -3)
793
error(-3, "option(%s,%d,\"%s\")", showop(op), n, s ? s : null);
794
}
795
if (type != ':')
796
{
797
op->flags |= OPT_SET;
798
op->flags &= ~OPT_DEFAULT;
799
}
800
else if (!(op->flags & OPT_SET))
801
{
802
op->flags |= OPT_DEFAULT;
803
if (!state.loading)
804
op->flags |= OPT_COMPILE;
805
}
806
if (state.reading)
807
op->flags |= OPT_COMPILE;
808
if (op->flags & Oi)
809
{
810
if (op->flags & On)
811
n = -n;
812
else
813
n = !n;
814
}
815
else if (op->flags & Ob)
816
n = n != 0;
817
else if ((op->flags & (Os|Ov)) == Os && n && !s)
818
error(3, "-%c: option argument expected", OPT(op->flags));
819
if (!n)
820
s = 0;
821
switch (OPT(op->flags))
822
{
823
case OPT(OPT_believe):
824
if (state.compile < COMPILED)
825
state.believe = n;
826
else
827
error(2, "%s: option must be set before %s", op->name, external.makeinit);
828
return;
829
case OPT(OPT_byname):
830
if (s)
831
set(s, 1, NiL);
832
return;
833
case OPT(OPT_corrupt):
834
if (!s)
835
s = "-";
836
if ((*s == *(state.corrupt = "accept") || *s == '-') && (!*(s + 1) || !strcmp(s, state.corrupt)))
837
;
838
else if (*s == *(state.corrupt = "error") && (!*(s + 1) || !strcmp(s, state.corrupt)))
839
state.corrupt = 0;
840
else if (*s == *(state.corrupt = "ignore") && (!*(s + 1) || !strcmp(s, state.corrupt)))
841
;
842
else
843
{
844
state.corrupt = 0;
845
error(2, "%s: invalid corrupt action", s);
846
}
847
return;
848
case OPT(OPT_global):
849
if (!s)
850
{
851
if (n)
852
{
853
state.pushed = 1;
854
state.push_global = state.global;
855
state.global = 1;
856
state.push_user = state.user;
857
state.user = 0;
858
}
859
else if (state.pushed)
860
{
861
state.pushed = 0;
862
state.global = state.push_global;
863
state.user = state.push_user;
864
}
865
return;
866
}
867
break;
868
case OPT(OPT_include):
869
addprereq(catrule(internal.source->name, external.source, NiL, 1), makerule(s), PREREQ_APPEND);
870
if (!(op->flags & OPT_READONLY))
871
break;
872
/*FALLTHROUGH*/
873
case OPT(OPT_define):
874
case OPT(OPT_undef):
875
if (s)
876
{
877
sfprintf(internal.tmp, "-%c%s", OPT(op->flags), s);
878
if (!(r = getrule(sfstruse(internal.tmp))))
879
r = makerule(NiL);
880
addprereq(internal.preprocess, r, PREREQ_APPEND);
881
}
882
return;
883
case OPT(OPT_preprocess):
884
if (!state.preprocess)
885
{
886
state.preprocess = 1;
887
if (!state.compatibility)
888
error(1, "makefile preprocessing is obsolete -- use make statements");
889
}
890
return;
891
case OPT(OPT_errorid):
892
if (s && *s)
893
{
894
if (state.errorid)
895
sfprintf(internal.tmp, "%s/", state.errorid);
896
sfprintf(internal.tmp, "%s", s);
897
state.errorid = strdup(sfstruse(internal.tmp));
898
sfprintf(internal.tmp, "%s [%s]", idname, state.errorid);
899
error_info.id = strdup(sfstruse(internal.tmp));
900
}
901
else
902
{
903
op->flags &= ~OPT_SET;
904
error_info.id = idname;
905
}
906
return;
907
case OPT(OPT_jobs):
908
if (n >= MAXJOBS)
909
n = MAXJOBS - 1;
910
if (n < 1)
911
n = 0;
912
state.jobs = n;
913
return;
914
case OPT(OPT_mam):
915
if (t = s)
916
{
917
if (t[0] == 'n' && t[1] == 'o')
918
t += 2;
919
if (streq(t, "hold"))
920
{
921
if (t == s)
922
state.mam.hold++;
923
else
924
state.mam.hold--;
925
return;
926
}
927
}
928
if (state.mam.label != null)
929
{
930
if (state.mam.label)
931
free(state.mam.label);
932
state.mam.label = null;
933
}
934
if (state.mam.options)
935
{
936
free(state.mam.options);
937
state.mam.options = 0;
938
}
939
if (state.mam.root)
940
{
941
free(state.mam.root);
942
state.mam.root = 0;
943
}
944
if (state.mam.out)
945
{
946
if (state.mam.out != sfstdout && state.mam.out != sfstderr)
947
sfclose(state.mam.out);
948
state.mam.out = 0;
949
}
950
state.mam.dontcare = state.mam.dynamic = state.mam.regress = state.mam.statix = state.mam.parent = 0;
951
state.mam.port = 1;
952
if (s)
953
{
954
char* o;
955
char* u;
956
Sfio_t* tmp;
957
958
tmp = sfstropen();
959
sfputr(tmp, s, 0);
960
s = sfstruse(tmp);
961
if (t = strchr(s, ':'))
962
*t++ = 0;
963
if (o = strchr(s, ','))
964
*o++ = 0;
965
if (*s == *(state.mam.type = "dynamic") && (!*(s + 1) || !strcmp(s, state.mam.type)))
966
state.mam.dynamic = 1;
967
else if (*s == *(state.mam.type = "regress") && (!*(s + 1) || !strcmp(s, state.mam.type)))
968
{
969
state.regress = "sync";
970
state.mam.regress = 1;
971
state.silent = 1;
972
if (!table.regress)
973
table.regress = hashalloc(table.rule, HASH_name, "regress-paths", 0);
974
regressinit(state.regress);
975
}
976
else if (*s == *(state.mam.type = "static") && (!*(s + 1) || !strcmp(s, state.mam.type)))
977
state.mam.statix = 1;
978
else
979
error(3, "%s: invalid mam type: {dynamic,regress,static} expected", s);
980
while (s = o)
981
{
982
if (o = strchr(s, ','))
983
*o++ = 0;
984
if (*s == 'n' && *(s + 1) == 'o')
985
{
986
s += 2;
987
n = 0;
988
}
989
else
990
n = 1;
991
if (*s == *(u = "dontcare") && (!*(s + 1) || !strcmp(s, u)))
992
state.mam.dontcare = n;
993
else if (*s == *(u = "port") && (!*(s + 1) || !strcmp(s, u)))
994
state.mam.port = n;
995
else
996
error(3, "%s: invalid mam option: [no]{dontcare,port} expected", s);
997
}
998
if (t)
999
{
1000
s = t;
1001
if (t = strchr(s, ':'))
1002
{
1003
*t++ = 0;
1004
if (isdigit(*t))
1005
{
1006
while (isdigit(*t))
1007
state.mam.parent = state.mam.parent * 10 + *t++ - '0';
1008
if (!state.mam.regress)
1009
{
1010
sfprintf(internal.tmp, "%05d ", state.pid);
1011
state.mam.label = strdup(sfstruse(internal.tmp));
1012
}
1013
}
1014
if (*t)
1015
{
1016
if (*t != ':')
1017
error(3, "%s: mam label expected", t);
1018
t++;
1019
}
1020
if (!*t)
1021
t = 0;
1022
}
1023
}
1024
else s = null;
1025
if (!*s || streq(s, "-") || streq(s, "/dev/fd/1") || streq(s, "/dev/stdout"))
1026
{
1027
s = "/dev/stdout";
1028
state.mam.out = sfstdout;
1029
}
1030
else if (streq(s, "/dev/fd/2") || streq(s, "/dev/stderr"))
1031
state.mam.out = sfstderr;
1032
else if (!(state.mam.out = sfopen(NiL, s, state.mam.parent ? "ae" : "we")))
1033
error(ERROR_SYSTEM|3, "%s: cannot write mam output file", s);
1034
sfset(state.mam.out, SF_LINE, 1);
1035
state.mam.disc.writef = mamwrite;
1036
if (sfdisc(state.mam.out, &state.mam.disc) != &state.mam.disc)
1037
error(3, "%s: cannot push mam output discipline", s);
1038
sfprintf(internal.tmp, "%s", state.mam.type);
1039
if (state.mam.dontcare)
1040
sfprintf(internal.tmp, ",dontcare");
1041
sfprintf(internal.tmp, ",%sport", state.mam.port ? null : "no");
1042
sfprintf(internal.tmp, ":");
1043
if (*s != '/')
1044
sfprintf(internal.tmp, "%s/", internal.pwd);
1045
sfprintf(internal.tmp, "%s:%d", s, state.pid);
1046
if (t)
1047
{
1048
sfprintf(internal.nam, "$(\"%s\":P=A)", t);
1049
expand(tmp, sfstruse(internal.nam));
1050
state.mam.root = strdup(sfstruse(tmp));
1051
state.mam.rootlen = strlen(state.mam.root);
1052
sfprintf(internal.tmp, ":%s", state.mam.root);
1053
}
1054
state.mam.options = strdup(sfstruse(internal.tmp));
1055
sfstrclose(tmp);
1056
}
1057
return;
1058
case OPT(OPT_option):
1059
s = strdup(s);
1060
while (*s)
1061
{
1062
char* name;
1063
char* func;
1064
char* desc;
1065
char* args;
1066
Option_t* nop;
1067
int app;
1068
int sep;
1069
char buf[16];
1070
1071
sep = *s;
1072
if (isalpha(sep))
1073
{
1074
n = sep|Ob;
1075
sep = *++s;
1076
}
1077
else
1078
{
1079
n = '?'|Of|Ob;
1080
if (sep == OPT_NON)
1081
sep = *++s;
1082
}
1083
app = (sep == ':') ? ';' : ':';
1084
s++;
1085
if (!(name = field(&s, sep, app, 1)))
1086
{
1087
if (n & Of)
1088
error(2, "option flag and name omitted");
1089
else
1090
error(2, "-%c: option name omitted", OPT(n));
1091
break;
1092
}
1093
if (t = field(&s, sep, app, 1))
1094
{
1095
for (;;)
1096
{
1097
switch (*t++)
1098
{
1099
case 0:
1100
break;
1101
case 'a':
1102
n |= Oa;
1103
continue;
1104
case 'b':
1105
n &= ~(On|Os);
1106
n |= Ob;
1107
continue;
1108
case 'n':
1109
n &= ~(Ob|Os);
1110
n |= On;
1111
continue;
1112
case 'o':
1113
n |= Oo;
1114
continue;
1115
case 'p':
1116
n |= Op;
1117
continue;
1118
case 's':
1119
n &= ~(Ob|On);
1120
n |= Os;
1121
continue;
1122
case 'v':
1123
n |= Ov;
1124
continue;
1125
case 'x':
1126
n |= Ox;
1127
continue;
1128
/* no complaints here for future extensions */
1129
}
1130
break;
1131
}
1132
}
1133
func = field(&s, sep, app, 1);
1134
desc = field(&s, sep, app, 0);
1135
args = field(&s, sep, app, 0);
1136
if (!(n & Of))
1137
{
1138
for (nop = &options[0]; nop < &options[elementsof(options)]; nop++)
1139
if (OPT(nop->flags) == OPT(n))
1140
break;
1141
if (nop < &options[elementsof(options)])
1142
{
1143
error(2, "--%s: -%c conflicts with --%s", s, OPT(n), nop->name);
1144
return;
1145
}
1146
buf[0] = '-';
1147
buf[1] = OPT(n);
1148
buf[2] = 0;
1149
nop = getoption(buf);
1150
}
1151
else
1152
nop = 0;
1153
if (nop)
1154
{
1155
if (n & On)
1156
*((int*)nop->value) = *((unsigned char*)nop->value);
1157
else if (n & Os)
1158
*((char**)nop->value) = 0;
1159
nop->flags = n;
1160
set_insert:
1161
nop->name = name;
1162
nop->set = func;
1163
if ((n & (Os|Oa)) == (Os|Oa) && !op->value)
1164
*((Rule_t**)nop->value) = catrule(".OPTION.", nop->name, ".LIST.", 1);
1165
if (!desc)
1166
desc = "option.";
1167
if (*desc != '(')
1168
{
1169
sfputc(internal.tmp, '(');
1170
if ((t = parsefile()) && *t)
1171
edit(internal.tmp, t, DELETE, KEEP, DELETE);
1172
else
1173
sfputr(internal.tmp, state.base ? "rules" : state.global ? "global" : "user", -1);
1174
sfprintf(internal.tmp, ") %s", desc);
1175
desc = strdup(sfstruse(internal.tmp));
1176
}
1177
nop->description = desc;
1178
if (!args && (nop->flags & (On|Os)))
1179
args = (nop->flags & On) ? "number" : "string";
1180
if (args && (nop->flags & Ob))
1181
{
1182
nop->flags &= ~Ob;
1183
nop->flags |= Os;
1184
}
1185
nop->arg = args;
1186
putoption(nop, opt.usageindex);
1187
genusage(nop, opt.usageindex++, 1);
1188
if (nop->set && (nop->flags & OPT_SET))
1189
readonly = 1;
1190
}
1191
else if (!(nop = getoption(name)))
1192
{
1193
nop = newof(0, Option_t, 1, sizeof(char*));
1194
nop->value = (char*)(nop + 1);
1195
nop->flags = n|OPT_EXTERNAL;
1196
if (!state.loading)
1197
nop->flags |= OPT_DECLARE;
1198
if (opt.tail)
1199
opt.tail->next = nop;
1200
else
1201
opt.head = nop;
1202
opt.tail = nop;
1203
goto set_insert;
1204
}
1205
else if (!(nop->flags & OPT_EXTERNAL))
1206
error(1, "--%s is an internal option", nop->name);
1207
else
1208
{
1209
if (nop->flags & Of)
1210
{
1211
if ((n & (Ob|On|Os)) != (nop->flags & (Ob|On|Os)))
1212
{
1213
if (n & Os)
1214
*((char**)nop->value) = 0;
1215
else if ((n & On) && (nop->flags & Ob))
1216
*((int*)nop->value) = *((unsigned char*)nop->value);
1217
else if ((n & Ob) && (nop->flags & On))
1218
*((unsigned char*)nop->value) = *((int*)nop->value) != 0;
1219
}
1220
nop->flags = n;
1221
}
1222
else if (OPT(nop->flags) != OPT(n))
1223
error(1, "--%s: option flag -%c conflicts with -%c", nop->name, OPT(n), OPT(nop->flags));
1224
if ((nop->flags & (Ob|On|Os)) != (n & (Ob|On|Os)))
1225
error(1, "--%s: option is %s", nop->name, (nop->flags & Ob) ? "boolean" : (nop->flags & On) ? "numeric" : "string valued");
1226
}
1227
1228
/*
1229
* skip the remaining fields for future extensions
1230
* and consume the append char if specified
1231
*/
1232
1233
while (field(&s, sep, app, 0));
1234
if (*s == app)
1235
s++;
1236
}
1237
optcheck(0);
1238
return;
1239
case OPT(OPT_never):
1240
if (state.never = n)
1241
state.exec = 0;
1242
return;
1243
case OPT(OPT_regress):
1244
if (n)
1245
{
1246
if (!s)
1247
s = "-";
1248
if ((*s == *(state.regress = "message") || *s == '-') && (!*(s + 1) || !strcmp(s, state.regress)))
1249
;
1250
else if (*s == *(state.regress = "sync") && (!*(s + 1) || !strcmp(s, state.regress)))
1251
;
1252
else
1253
{
1254
state.regress = 0;
1255
error(2, "%s: invalid regress action", s);
1256
}
1257
if (state.regress)
1258
regressinit(state.regress);
1259
}
1260
else
1261
state.regress = 0;
1262
return;
1263
case OPT(OPT_reread):
1264
if (state.reread = n)
1265
state.forceread = 1;
1266
return;
1267
case OPT(OPT_silent):
1268
if (state.silent = n)
1269
{
1270
if (!error_info.trace)
1271
error_info.trace = 2;
1272
}
1273
else
1274
if (error_info.trace > 0)
1275
error_info.trace = 0;
1276
return;
1277
case OPT(OPT_targetprefix):
1278
if (!n)
1279
s = 0;
1280
else if (s)
1281
s = strdup(s);
1282
if (state.targetprefix = s)
1283
for (;;)
1284
{
1285
switch (*s++)
1286
{
1287
case 0:
1288
break;
1289
case '%':
1290
case '*':
1291
case '?':
1292
case '&':
1293
case '"':
1294
case '\'':
1295
case '\\':
1296
error(3, "--%s: %s: value must not contain metarule or shell pattern characters", op->name, state.targetprefix);
1297
break;
1298
default:
1299
continue;
1300
}
1301
break;
1302
}
1303
return;
1304
case OPT(OPT_tolerance):
1305
if ((state.tolerance = n) > 60)
1306
error(1, "the time comparison tolerance should probably be less than a minute");
1307
return;
1308
case OPT(OPT_writeobject):
1309
if (!n)
1310
s = 0;
1311
else if (state.makefile)
1312
{
1313
error(1, "%s: object file name cannot change after %s read", op->name, state.makefile);
1314
return;
1315
}
1316
else if (!s)
1317
s = "-";
1318
else
1319
s = strdup(s);
1320
state.writeobject = s;
1321
return;
1322
case OPT(OPT_writestate):
1323
if (!n)
1324
s = 0;
1325
else if (!s)
1326
s = "-";
1327
else
1328
s = strdup(s);
1329
state.writestate = s;
1330
if (state.statefile)
1331
{
1332
free(state.statefile);
1333
state.statefile = 0;
1334
}
1335
return;
1336
}
1337
if (op->value)
1338
{
1339
if (op->flags & Ob)
1340
{
1341
switch (type)
1342
{
1343
case '^':
1344
*((unsigned char*)op->value) ^= n;
1345
break;
1346
default:
1347
*((unsigned char*)op->value) = n != 0;
1348
break;
1349
}
1350
}
1351
else if (op->flags & On)
1352
{
1353
switch (type)
1354
{
1355
case '+':
1356
*((int*)op->value) += n;
1357
break;
1358
case '-':
1359
*((int*)op->value) -= n;
1360
break;
1361
case '|':
1362
*((int*)op->value) |= n;
1363
break;
1364
case '&':
1365
*((int*)op->value) &= n;
1366
break;
1367
case '^':
1368
*((int*)op->value) ^= n;
1369
break;
1370
default:
1371
*((int*)op->value) = n;
1372
break;
1373
}
1374
}
1375
else if (op->flags & Os)
1376
{
1377
if (op->flags & Oa)
1378
{
1379
if (s)
1380
{
1381
/*
1382
* s is a ':' list
1383
*/
1384
1385
for (;;)
1386
{
1387
if (t = strchr(s, ':'))
1388
*t = 0;
1389
addprereq((*(Rule_t**)op->value), makerule(s), PREREQ_APPEND);
1390
if (!t)
1391
break;
1392
*t++ = ':';
1393
s = t;
1394
}
1395
}
1396
else
1397
{
1398
freelist((*(Rule_t**)op->value)->prereqs);
1399
(*(Rule_t**)op->value)->prereqs = 0;
1400
}
1401
}
1402
else
1403
*((char**)op->value) = s ? strdup(s) : 0;
1404
}
1405
}
1406
if (op->set)
1407
setcall(op, readonly);
1408
if ((op->flags & Op) && !state.reading && !state.user)
1409
{
1410
if ((op->flags & Os) && s)
1411
{
1412
sfprintf(internal.tmp, "--%s=%s", op->name, s);
1413
if (!(r = getrule(sfstruse(internal.tmp))))
1414
r = makerule(NiL);
1415
addprereq(internal.preprocess, r, PREREQ_APPEND);
1416
}
1417
else if ((op->flags & (Ob|On)) && n)
1418
{
1419
if (!n)
1420
sfprintf(internal.tmp, "--no%s", op->name);
1421
else if (n != 1)
1422
sfprintf(internal.tmp, "--%s=%d", op->name, n);
1423
else
1424
sfprintf(internal.tmp, "--%s", op->name);
1425
if (!(r = getrule(sfstruse(internal.tmp))))
1426
r = makerule(NiL);
1427
addprereq(internal.preprocess, r, PREREQ_APPEND);
1428
}
1429
}
1430
}
1431
1432
/*
1433
* generate a single option setting in sp given the option pointer
1434
* setting:
1435
* 0 only the value is generated, "" if option not set
1436
* '+' only the value is generated, "" if Os option not set, 0 for Ob|Oi not set
1437
* '-' option name and value suitable for set()
1438
* '?' 1 if OPT_SET, "" otherwise
1439
* '#' table attributes with the current value
1440
* flag!=0 if relative to option flag rather than option name
1441
*/
1442
1443
static void
1444
genop(register Sfio_t* sp, register Option_t* op, int setting, int flag)
1445
{
1446
register long n;
1447
char* v;
1448
List_t* p;
1449
1450
switch (setting)
1451
{
1452
case '?':
1453
if (op->flags & OPT_SET)
1454
sfprintf(sp, "1");
1455
return;
1456
case '#':
1457
sfprintf(sp, "%s=", showop(op));
1458
break;
1459
case 0:
1460
break;
1461
default:
1462
flag &= ~Oi;
1463
break;
1464
}
1465
switch (op->flags & (Ob|On|Os))
1466
{
1467
case Ob:
1468
if (op->value)
1469
n = *((unsigned char*)op->value);
1470
else
1471
n = 0;
1472
if ((op->flags & Oi) ^ (flag & Oi))
1473
n = !n;
1474
if ((flag & Of) && (op->flags & Oo))
1475
n = !n;
1476
switch (setting)
1477
{
1478
case 0:
1479
if (!n)
1480
return;
1481
/*FALLTHROUGH*/
1482
case '+':
1483
case '#':
1484
break;
1485
default:
1486
if (op->flags & OPT_DEFAULT)
1487
sfprintf(sp, "--%s:=", op->name);
1488
else if (n)
1489
{
1490
sfprintf(sp, "--%s", op->name);
1491
return;
1492
}
1493
else
1494
{
1495
sfprintf(sp, "--no%s", op->name);
1496
return;
1497
}
1498
break;
1499
}
1500
sfputc(sp, n ? '1' : '0');
1501
break;
1502
case On:
1503
if (op->value)
1504
n = *((int*)op->value);
1505
else
1506
n = 0;
1507
if (op->flags & Oi)
1508
n = -n;
1509
if (flag & Oi)
1510
n = !n;
1511
switch (setting)
1512
{
1513
case 0:
1514
if (!n)
1515
return;
1516
/*FALLTHROUGH*/
1517
case '+':
1518
case '#':
1519
break;
1520
default:
1521
if (op->flags & OPT_DEFAULT)
1522
sfprintf(sp, "--%s:=", op->name);
1523
else if (n)
1524
sfprintf(sp, "--%s=", op->name);
1525
else
1526
{
1527
sfprintf(sp, "--no%s", op->name);
1528
return;
1529
}
1530
break;
1531
}
1532
sfprintf(sp, (op->flags & Oa) ? "0x%08lx" : "%ld", n);
1533
break;
1534
case Os:
1535
if ((op->flags & Oa) && op->value && !(flag & Oi))
1536
{
1537
p = (*(Rule_t**)op->value)->prereqs;
1538
switch (setting)
1539
{
1540
case 0:
1541
if (!p)
1542
return;
1543
/*FALLTHROUGH*/
1544
case '+':
1545
case '#':
1546
break;
1547
default:
1548
if (op->flags & OPT_DEFAULT)
1549
sfprintf(sp, "--%s:=", op->name);
1550
else if (p)
1551
sfprintf(sp, "--%s=", op->name);
1552
else
1553
{
1554
sfprintf(sp, "--no%s", op->name);
1555
return;
1556
}
1557
break;
1558
}
1559
if (p)
1560
for (;;)
1561
{
1562
shquote(sp, fmtesc(p->rule->name));
1563
if (!(p = p->next))
1564
break;
1565
sfputc(sp, ':');
1566
}
1567
}
1568
else
1569
{
1570
if (op->value && !(flag & Oi))
1571
v = *((char**)op->value);
1572
else
1573
v = 0;
1574
switch (setting)
1575
{
1576
case 0:
1577
case '#':
1578
if (!v)
1579
return;
1580
setting = 0;
1581
break;
1582
case '+':
1583
break;
1584
default:
1585
if (op->flags & OPT_DEFAULT)
1586
sfprintf(sp, "--%s:=", op->name);
1587
else if (v)
1588
sfprintf(sp, "--%s=", op->name);
1589
else
1590
{
1591
sfprintf(sp, "--no%s", op->name);
1592
return;
1593
}
1594
break;
1595
}
1596
if (v)
1597
{
1598
if (setting)
1599
shquote(sp, fmtesc(v));
1600
else
1601
sfputr(sp, v, -1);
1602
}
1603
}
1604
break;
1605
#if DEBUG
1606
default:
1607
error(PANIC, "%s: option has%s%s%s", op->name, (op->flags & Ob) ? " Ob" : null, (op->flags & On) ? " On" : null, (op->flags & Os) ? " Os" : null);
1608
break;
1609
#endif
1610
}
1611
}
1612
1613
/*
1614
* check and set delayed options
1615
* this gives base, global and local makefiles a chance to
1616
* define the options via --option=definition
1617
*/
1618
1619
void
1620
optcheck(int must)
1621
{
1622
Oplist_t* x;
1623
int errors;
1624
1625
if (must)
1626
{
1627
errors = error_info.errors;
1628
while (x = opt.delayed)
1629
{
1630
opt.delayed = x->next;
1631
if (*x->option)
1632
set(x->option, 1, NiL);
1633
free(x);
1634
}
1635
if (error_info.errors != errors)
1636
finish(2);
1637
}
1638
else
1639
for (x = opt.delayed; x; x = x->next)
1640
if (!set(x->option, 0, NiL))
1641
*x->option = 0;
1642
}
1643
1644
/*
1645
* generate option setting list in sp suitable for set()
1646
* setting:
1647
* 0 non-Ox OPT_SET options
1648
* '+' non-Om non-Ox OPT_SET options
1649
* '-' all
1650
* '?' non-Ox OPT_DEFAULT
1651
* '#' table attributes with the current value
1652
* '@' internal object file dump
1653
*/
1654
1655
void
1656
listops(register Sfio_t* sp, int setting)
1657
{
1658
register Option_t* op;
1659
register Oplist_t* x;
1660
int sc;
1661
int sep;
1662
long mask;
1663
long test;
1664
long clear;
1665
1666
sep = 0;
1667
sc = ' ';
1668
clear = 0;
1669
switch (setting)
1670
{
1671
case '-':
1672
mask = 0;
1673
test = 0;
1674
break;
1675
case '+':
1676
setting = '-';
1677
mask = Om|Ox|OPT_SET;
1678
test = Om|OPT_SET;
1679
break;
1680
case '?':
1681
setting = '-';
1682
mask = Ox|OPT_DEFAULT;
1683
test = OPT_DEFAULT;
1684
break;
1685
case '#':
1686
sc = '\n';
1687
mask = 0;
1688
test = 0;
1689
break;
1690
case '@':
1691
setting = '-';
1692
mask = Ox|OPT_COMPILE;
1693
test = OPT_COMPILE;
1694
clear = ~OPT_COMPILE;
1695
for (op = opt.head; op; op = op->next)
1696
if (op->flags & OPT_DECLARE)
1697
{
1698
op->flags &= ~OPT_DECLARE;
1699
if (sep)
1700
sfputc(sp, ':');
1701
else
1702
{
1703
sep = 1;
1704
sfprintf(sp, "--%s=", optflag(OPT_option)->name);
1705
}
1706
declare(sp, op);
1707
}
1708
while (x = opt.hidden)
1709
{
1710
opt.hidden = x->next;
1711
if (sep)
1712
sfputc(sp, sc);
1713
else
1714
sep = 1;
1715
sfputr(sp, x->option, -1);
1716
free(x);
1717
}
1718
break;
1719
default:
1720
setting = '-';
1721
mask = Ox|OPT_SET;
1722
test = OPT_SET;
1723
break;
1724
}
1725
for (op = opt.head; op; op = op->next)
1726
if ((op->flags & mask) == test)
1727
{
1728
if (sep)
1729
sfputc(sp, sc);
1730
else
1731
sep = 1;
1732
genop(sp, op, setting, 0);
1733
if (clear)
1734
op->flags &= clear;
1735
}
1736
}
1737
1738
/*
1739
* generate a single option setting in sp given the option name
1740
* setting passed to genop()
1741
* end of s is returned
1742
*/
1743
1744
void
1745
getop(register Sfio_t* sp, char* name, int setting)
1746
{
1747
register Option_t* op;
1748
int flag;
1749
1750
if ((op = getoption(name)) && !(flag = 0) || name[0] == 'n' && name[1] == 'o' && (op = getoption(&name[2])) && (flag = Oi) || name[0] && !name[1] && (op = optflag(name[0])) && (flag = Of))
1751
genop(sp, op, setting, flag);
1752
}
1753
1754
/*
1755
* set an option by its optget()/optstr() index
1756
*/
1757
1758
static void
1759
optset(int i, char* v, Sfio_t* scope)
1760
{
1761
register char* s;
1762
int n;
1763
Option_t* op;
1764
Oplist_t* x;
1765
char buf[16];
1766
1767
if (i > 0)
1768
{
1769
if (state.readonly && !state.interpreter)
1770
{
1771
if (strchr(v, ' ') || strchr(v, '\t'))
1772
{
1773
while (*v && *v != '=')
1774
sfputc(internal.tmp, *v++);
1775
if (*v)
1776
{
1777
sfputc(internal.tmp, *v++);
1778
if (!strchr(v, '\"'))
1779
sfprintf(internal.tmp, "\"%s\"", v);
1780
else
1781
sfprintf(internal.tmp, "'%s'", v);
1782
}
1783
n = sfstrtell(internal.tmp);
1784
v = sfstruse(internal.tmp);
1785
}
1786
else
1787
n = strlen(v);
1788
x = newof(0, Oplist_t, 1, n + 1);
1789
x->option = strcpy((char*)(x + 1), v);
1790
if (opt.lastdelayed)
1791
opt.lastdelayed = opt.lastdelayed->next = x;
1792
else
1793
opt.delayed = opt.lastdelayed = x;
1794
}
1795
else
1796
error((i == '?' && opt_info.option[0] == '-' && opt_info.option[1] != '?') ? (ERROR_USAGE|(state.interpreter ? 2 : 4)) : 2, "%s", opt_info.arg);
1797
}
1798
else
1799
{
1800
if ((i = -OPT_OFFSET - i) < elementsof(options))
1801
op = &options[i];
1802
else
1803
{
1804
sfsprintf(buf, sizeof(buf), "-%d", i);
1805
op = getoption(buf);
1806
}
1807
n = (op->flags & On) ? (opt_info.arg ? opt_info.num : 0) : (op->flags & Ob) ? (opt_info.num != 0) : (opt_info.num != 0) == !(op->flags & Oi);
1808
if (*opt_info.option == '+')
1809
n = !n;
1810
if ((s = opt_info.arg) && (!*s || !(op->flags & Os)))
1811
s = 0;
1812
if (scope)
1813
genop(scope, op, '-', 0);
1814
setop(op, n, s, opt_info.assignment);
1815
}
1816
}
1817
1818
/*
1819
* set options by name
1820
*/
1821
1822
int
1823
set(char* s, int must, Sfio_t* scope)
1824
{
1825
register int i;
1826
int r;
1827
int oreadonly;
1828
Opt_t info;
1829
1830
r = 0;
1831
info = opt_info;
1832
while (i = optstr(s, sfstrbase(opt.usage)))
1833
{
1834
if (i > 0 && !must)
1835
{
1836
r = -1;
1837
break;
1838
}
1839
s += opt_info.offset;
1840
if (!must)
1841
{
1842
oreadonly = state.readonly;
1843
state.readonly = 1;
1844
}
1845
optset(i, opt_info.argv[1], scope);
1846
if (!must)
1847
state.readonly = oreadonly;
1848
}
1849
opt_info = info;
1850
return r;
1851
}
1852
1853
/*
1854
* set command line options with optget(3)
1855
* options may appear in any position before --
1856
* read command line assignments
1857
* mark the command line scripts and targets
1858
* index of the first command line script or target is returned
1859
*/
1860
1861
int
1862
scanargs(int argc, char** argv, int* argf)
1863
{
1864
register int i;
1865
register char* s;
1866
register int c;
1867
int args;
1868
int done;
1869
char* e;
1870
1871
/*
1872
* generate the optget() usage string from options[]
1873
*/
1874
1875
if (!(opt.usage = sfstropen()))
1876
error(ERROR_SYSTEM|3, "out of space [usage]");
1877
sfprintf(opt.usage, usage1, version);
1878
for (i = 0; i < elementsof(options); i++)
1879
genusage(options + i, i, 0);
1880
genusage(NiL, 0, 1);
1881
opt.usageindex = i;
1882
args = 0;
1883
done = 0;
1884
again:
1885
while (i = optget(argv, sfstrbase(opt.usage)))
1886
optset(i, argv[opt_info.index - (opt_info.offset == 0)], NiL);
1887
if (!done && streq(argv[opt_info.index - 1], "--"))
1888
done = 1;
1889
for (i = opt_info.index; i < argc; i++)
1890
{
1891
s = argv[i];
1892
while (isspace(*s))
1893
s++;
1894
if (!done && (*s == '-' || *s == '+') && *(s + 1))
1895
{
1896
opt_info.index = i;
1897
opt_info.offset = 0;
1898
goto again;
1899
}
1900
if (*s)
1901
{
1902
for (e = s; c = *s; s++)
1903
if (c == ',')
1904
{
1905
s = null;
1906
break;
1907
}
1908
else if (istype(c, C_TERMINAL) && c != '+' && c != '&')
1909
{
1910
while (isspace(*s))
1911
s++;
1912
if (*s == '=' || *(s + 1) == '=')
1913
{
1914
argf[i] |= ARG_ASSIGN;
1915
state.reading = 1;
1916
parse(NiL, e, "command line assignment", NiL);
1917
state.reading = 0;
1918
}
1919
else
1920
{
1921
argf[i] |= ARG_SCRIPT;
1922
if (!args)
1923
args = i;
1924
}
1925
break;
1926
}
1927
if (!*s)
1928
{
1929
argf[i] |= ARG_TARGET;
1930
if (!args)
1931
args = i;
1932
}
1933
}
1934
}
1935
return error_info.errors ? -1 : args ? args : argc;
1936
}
1937
1938
/*
1939
* please reboot your program to finish setup ...
1940
*
1941
* old!=0 execs external.old for backwards compatibility
1942
* otherwise re-exec forcing input files to be read
1943
*/
1944
1945
void
1946
punt(int old)
1947
{
1948
register char* s;
1949
register char** av;
1950
int i;
1951
List_t* p;
1952
Oplist_t* x;
1953
Sfio_t* vec;
1954
1955
if (state.reread > 1)
1956
error(PANIC, "makefile prerequisites cause unbounded make exec recursion");
1957
vec = sfstropen();
1958
if (old)
1959
{
1960
expand(internal.tmp, getval(external.old, VAL_PRIMARY));
1961
putptr(vec, strdup(sfstruse(internal.tmp)));
1962
1963
/*
1964
* this chunk must track external.old options
1965
*/
1966
1967
sfputc(internal.tmp, '-');
1968
1969
/*
1970
* options with same flag and meaning
1971
*/
1972
1973
if (error_info.trace < -3)
1974
sfputc(internal.tmp, 'd');
1975
if (state.ignore)
1976
sfputc(internal.tmp, 'i');
1977
if (state.keepgoing)
1978
sfputc(internal.tmp, 'k');
1979
if (!state.mam.options && !state.exec)
1980
sfputc(internal.tmp, 'n');
1981
if (state.silent)
1982
sfputc(internal.tmp, 's');
1983
if (state.touch)
1984
sfputc(internal.tmp, 't');
1985
1986
/*
1987
* options with different flag but same meaning
1988
*/
1989
1990
if (state.vardump)
1991
sfputc(internal.tmp, 'p');
1992
if (!state.mam.options && state.force)
1993
sfputc(internal.tmp, 'u');
1994
1995
/*
1996
* options with different flag and meaning
1997
* the external.old meaning prevails
1998
*/
1999
2000
if (state.base)
2001
sfputc(internal.tmp, 'b');
2002
if (state.explain)
2003
sfputc(internal.tmp, 'e');
2004
if (state.ruledump)
2005
sfputc(internal.tmp, 'r');
2006
s = sfstruse(internal.tmp);
2007
if (s[1])
2008
putptr(vec, strdup(s));
2009
2010
/*
2011
* mam arguments -- assume oldmake knows mam
2012
*/
2013
2014
if (state.mam.options)
2015
{
2016
sfputc(internal.tmp, '-');
2017
if (state.never)
2018
sfputc(internal.tmp, 'N');
2019
else if (!state.exec)
2020
sfputc(internal.tmp, 'n');
2021
if (state.force)
2022
sfputc(internal.tmp, 'F');
2023
sfputc(internal.tmp, 'M');
2024
sfputr(internal.tmp, state.mam.options, -1);
2025
putptr(vec, strdup(sfstruse(internal.tmp)));
2026
}
2027
2028
/*
2029
* delayed (unknown) options
2030
*/
2031
2032
for (x = opt.delayed; x; x = x->next)
2033
putptr(vec, x->option);
2034
2035
/*
2036
* makefile arguments
2037
*/
2038
2039
if (!(p = internal.makefiles->prereqs))
2040
{
2041
putptr(vec, "-f");
2042
putptr(vec, state.makefile);
2043
}
2044
else for (; p; p = p->next)
2045
{
2046
putptr(vec, "-f");
2047
putptr(vec, p->rule->name);
2048
}
2049
2050
/*
2051
* variable assignment arguments
2052
*/
2053
2054
for (i = 1; i < state.argc; i++)
2055
if (state.argf[i] & (ARG_ASSIGN|ARG_TARGET))
2056
putptr(vec, state.argv[i]);
2057
if (!state.silent)
2058
{
2059
/*
2060
* echo the exec action external.old style
2061
*/
2062
2063
#if !__sun__ && !sun
2064
sfprintf(sfstderr, "\t");
2065
#endif
2066
putptr(vec, 0);
2067
av = (char**)sfstrbase(vec);
2068
while (*av)
2069
sfprintf(sfstderr, "%s ", *av++);
2070
sfprintf(sfstderr, "\n");
2071
}
2072
}
2073
else
2074
{
2075
/*
2076
* copy the original argv adding OPT_reread
2077
* and possibly OPT_preprocess
2078
*/
2079
2080
for (av = state.argv; *av; putptr(vec, *av++));
2081
sfprintf(internal.tmp, "--%s=%d", optflag(OPT_reread)->name, state.reread + 1);
2082
if (state.preprocess)
2083
sfprintf(internal.tmp, "--%s", optflag(OPT_preprocess)->name);
2084
putptr(vec, sfstruse(internal.tmp));
2085
}
2086
putptr(vec, 0);
2087
2088
/*
2089
* tidy up
2090
*/
2091
2092
sfsync(sfstdout);
2093
sfsync(sfstderr);
2094
if (internal.openfile)
2095
close(internal.openfd);
2096
2097
/*
2098
* start fresh
2099
*/
2100
2101
av = (char**)sfstrbase(vec);
2102
execvp(av[0], av);
2103
error(3, "cannot exec %s", av[0]);
2104
}
2105
2106
/*
2107
* return 1 if name is an option
2108
*/
2109
2110
int
2111
isoption(const char* name)
2112
{
2113
return getoption(name) != 0 || name[0] == 'n' && name[1] == 'o' && getoption(&name[2]) != 0;
2114
}
2115
2116