Subversion Repositories tendra.SVN

Rev

Rev 38 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 7u83 1
/*
7 7u83 2
 * Copyright (c) 2002-2005 The TenDRA Project <http://www.tendra.org/>.
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright notice,
11
 *    this list of conditions and the following disclaimer in the documentation
12
 *    and/or other materials provided with the distribution.
13
 * 3. Neither the name of The TenDRA Project nor the names of its contributors
14
 *    may be used to endorse or promote products derived from this software
15
 *    without specific, prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
18
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
21
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22
 * EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
 *
29
 * $Id$
30
 */
31
/*
2 7u83 32
    		 Crown Copyright (c) 1997
7 7u83 33
 
2 7u83 34
    This TenDRA(r) Computer Program is subject to Copyright
35
    owned by the United Kingdom Secretary of State for Defence
36
    acting through the Defence Evaluation and Research Agency
37
    (DERA).  It is made available to Recipients with a
38
    royalty-free licence for its use, reproduction, transfer
39
    to other parties and amendment for any purpose not excluding
40
    product development provided that any such use et cetera
41
    shall be deemed to be acceptance of the following conditions:-
7 7u83 42
 
2 7u83 43
        (1) Its Recipients shall ensure that this Notice is
44
        reproduced upon any copies or amended versions of it;
7 7u83 45
 
2 7u83 46
        (2) Any amended version of it shall be clearly marked to
47
        show both the nature of and the organisation responsible
48
        for the relevant amendment or amendments;
7 7u83 49
 
2 7u83 50
        (3) Its onward transfer from a recipient to another
51
        party shall be deemed to be that party's acceptance of
52
        these conditions;
7 7u83 53
 
2 7u83 54
        (4) DERA gives no warranty or assurance as to its
55
        quality or suitability for any purpose and DERA accepts
56
        no liability whatsoever in relation to any use to which
57
        it may be put.
58
*/
59
 
60
 
89 7u83 61
#include "config.h"
62
 
63
#if FS_STAT
7 7u83 64
#include <sys/types.h>
65
#include <sys/stat.h>
89 7u83 66
#endif
67
 
7 7u83 68
#include <errno.h>
69
 
2 7u83 70
#include "filename.h"
71
#include "list.h"
72
#include "archive.h"
73
#include "environ.h"
74
#include "flags.h"
75
#include "main.h"
76
#include "options.h"
77
#include "startup.h"
78
#include "suffix.h"
79
#include "utility.h"
80
 
81
 
82
/*
7 7u83 83
 * THE LIST OF ALL INPUT FILES
84
 *
85
 * All input files found by process_options are added to this list.
86
 */
2 7u83 87
 
7 7u83 88
filename *input_files = null;
2 7u83 89
 
90
 
91
/*
7 7u83 92
 * THE MAIN OPTION MAP
93
 *
94
 * This table gives all the command-line options. The first entry is the 'match
95
 * in' and roughly corresponds to command line input. The second entry is the
96
 * 'match out' and provides instructions to the command line interpreter. The
97
 * third entry is a description. The the final entry is a relative ranking,
98
 * with lower numbers being higher priority. Thus, no matter what order the
99
 * command line options are given, the lower ranked option will always be
100
 * evaluated first. (Option rankings can be disabled with the -no_shuffle
101
 * option.)
102
 */
2 7u83 103
 
7 7u83 104
optmap main_optmap[] = {
105
	/* Common options */
106
	{"^-$", "I?$0", "specifies an input file", 1000},
107
	{"-o+$", "SFN$1", "specifies output file name", 100},
108
	{"-D+$=$", "D#define$s$1$s$2$n|AOC$0", "defines a macro", 101},
109
	{"-D+$", "D#define$s$1$s1$n|AOC$0", "defines a macro to be 1", 102},
110
	{"-F?", "H$1", "halts the compilation at the given stage", 103},
111
	{"-I+$", "AUI$0|AOC$0|AUP$0", "specifies an include file directory",
112
		104},
113
	{"-L+$", "1ON|Io$0|AUL$0", "specifies a system library directory", 105},
114
	{"-N+$:+$", "AUI$0|AOC-I$2",
115
		"specifies an include file directory (with mode)", 106},
116
	{"-O$", "1OP|AOC$0", "switches optimisation level", 107},
117
	{"-P?*", "K$1", "causes intermediate files to be preserved", 108},
118
	{"-S", "Hs", "halts compilation after creating .s files", 109},
119
	{"-T+$", "CAT:$1|AOC-D$1", "specifies a command-line token", 110},
120
	{"-U+$", "D#undef$s$1$n|AOC$0", "undefines a macro", 111},
121
	{"-W?,+$,+*", "AQ$1$2", "passed an option to a compilation tool", 112},
122
	{"-W?:+$", "AQ$1$2", "passed an option to a compilation tool", 113},
123
	{"-X:+$,+*", "CAP:$1", "specifies a compilation option", 114},
124
	{"-X$", "EX$1", "specifies a compilation mode", 115},
125
	{"-Y+$", "E$1", "reads an environment", 12},
126
	{"-copyright", "1CR", "outputs copyright notice", 117},
127
	{"-c", "Ho", "halts compilation after creating .o files", 118},
128
	{"-d", "Hd", "halts compilation after creating .d files", 119},
129
	{"-dry", "1VB|1DR", "causes a dry run", 120},
130
	{"-e+$", "AUe$0", "specifies a producer end-up file", 121},
131
	{"-f+$", "AUf$0", "specifies a producer start-up file", 122},
132
	{"-g", "1DG", "produces debugging information (default format)", 123},
133
	{"-g1", "1DG", "produces debugging information (old format)", 124},
134
	{"-g2", "2DG", "produces debugging information (new format)", 125},
135
	{"-g3", "3DG", "produces debugging information (new format)", 126},
136
	{"-k", "Hk|HK", "halts compilation after creating .k and .K files",
137
		128},
138
	{"-l+$", "1ON|Io$0|AUl$0", "specifies a system library", 129},
139
	{"-not_ansi", "ASs-fnot_ansi", "allows some non-ANSI C features", 130},
140
	{"-nepc", "1NE|ASs-fnepc", "switches off extra portability checks",
141
		131},
142
	{"-sym", "1CS|SDO-d=", "enables symbol table dump linking", 132},
143
	{"-sym:$", "1CS|SDO-d$1=",
144
		"enables symbol table dump linking with flags", 133},
145
	{"-v", "1VB", "specifies verbose mode", 50},
146
	{"-vb", "1TC", "specifies fairly verbose mode", 51},
147
	{"-vd", "1TD", "dump the env information tcc got hold of", 51},
148
	{"-ve", "1TE", "verbose information about tool chain environment", 51},
149
	{"-vt", "1TT", "verbose information about tool chain invocation", 51},
150
	{"-no_shuffle", "1ES", "turns off shuffle ranking of cmd line args",
151
		-1},
152
	{"-y+$=$", "E?$1?$2", "sets an env directory variable", 1},
2 7u83 153
 
7 7u83 154
	/* Options not allowed in checker */
155
	{"-J+$", "AUJ-L$1", "specifies a TDF library directory", 20},
156
	{"-M", "1MC", "causes all .j files to be merged", 133},
157
	{"-MA", "1MC|1MP", "as -M, but with hiding", 134},
158
	{"-ch", "1CH", "invokes checker mode", 135},
159
	{"-disp", "1PP", "causes all .j files to be pretty printed", 136},
160
	{"-disp_t", "2PP", "causes all .t files to be pretty printed", 137},
161
	{"-i", "Hj", "halts compilation after creating .j files", 139},
162
	{"-im", "1CS", "enables intermodular checks", 139},
163
	{"-j+$", "AUj-l$1", "specifies a TDF library", 30},
164
	{"-prod", "1AR", "causes a TDF archive to be produced", 141},
2 7u83 165
 
7 7u83 166
	/* Less common options */
167
	{"-A+-", "AOC$0", "unasserts all built-in predicates", 142},
168
	{"-A+$", "D#pragma$saccept$sdirective$sassert$n|D#assert$s$1$n|AOC$0",
169
		"asserts a predicate", 143},
170
	{"-B+$", "1ON|Io$0", "passed to the system linker", 144},
171
	{"-C", "AOC$0", "preserves comments when preprocessing", 30},
172
	{"-E", "1PR", "causes C source files to be preprocessed", 145},
173
	{"-E?:+$", "LE$1$2", "specifies an executable to be used", 146},
174
	{"-H", "1PI", "causes included files to be printed", 147},
175
	{"-S?,+$,+*", "I$1$2", "specifies input files", 15},
176
	{"-S?:+$", "I$1$2", "specifies input files", 15},
177
	{"-V", "EVersions|1CR",
178
		"causes all tools to print their version numbers", 21},
179
	{"-cc", "1CC", "forces the system compiler to be used", 23},
180
	{"-cc_only", "2CC", "forces only the system compiler to be used", 22},
181
	{"-do?+$", "SN$1$2", "sets a default output file name", 148},
182
	{"-dump", "CDS", "dumps the current status", 200},
183
	{"-ignore_case", "1LC", "ignores case in file names", 12},
184
	{"-im0", "2CS", "disables intermodular checks", 148},
185
	{"-info", "1SA", "causes API information to be printed", 201},
186
	{"-keep_errors", "1KE", "causes files to be preserved on errors", 13},
187
	{"-make_up_names", "1MN", "makes up names for intermediate files", 149},
188
	{"-message+$", "@X$1", "causes %s to print a message", 24},
189
	{"-p", "1PF", "causes profiling information to be produced", 31},
190
	{"-q", "0VB", "specifies quiet mode", 1},
191
	{"-quiet", "0VB", "equivalent to -q", 1},
192
	{"-query", "Q", "causes a list of options to be printed", 2},
193
	{"-s?:+$", "SS$1$2|1SO", "specifies a suffix override", 25},
194
	{"-show_errors", "1SE", "causes error producing commands to be shown",
195
		3},
196
	{"-show_env", "CSE", "causes the environment path to be printed", 202},
197
	{"-special+$", "SXX$1|CSP", "allows various internal options", 4},
198
	{"-startup+$", "@D$1$n", "specifies a start-up option", 5 },
199
	{"-target+$", "AOC-target|AOC$1", "provided for cc compatibility", 150},
200
	{"-temp+$", "STD$1", "specifies the temporary directory", 1},
201
	{"-tidy", "1TU", "causes %s to tidy up as it goes along", 152},
202
	{"-time", "1TI|1VB", "causes all commands to be timed", 153},
203
	{"-verbose", "1VB", "equivalent to -v", 1},
204
	{"-version", "CPV", "causes %s to print its version number", 1},
205
	{"-w", "0WA", "suppresses %s warnings", 1},
206
	{"-work+$", "SWD$1", "specifies the work directory", 1},
2 7u83 207
 
7 7u83 208
	/* Options not allowed in checker */
209
	{"-G", "EGoption", "provided for cc compatibility", 154},
210
	{"-K+$,+*", "EK-$1", "provided for cc compatibility", 155},
211
	{"-Z$", "EZ-$1", "provided for cc compatibility", 156},
212
	{"-b", "LSc", "suppresses -lc in system linking", 157},
213
	{"-dn", "AOl$0", "passed to the system linker", 158},
214
	{"-dy", "AOl$0", "passed to the system linker", 159},
215
	{"-h+$", "AOl$0", "passed to the system linker", 160},
216
	{"-no_startup_options", "0ST", "suppresses start-up options", 161},
217
	{"-s", "1SR", "passed to the system linker", 162},
218
	{"-u+$", "AOl$0", "passed to the system linker", 163},
219
	{"-wsl", "Ewsl", "causes string literals to be made writable", 164},
220
	{"-z+$", "AOl$0", "passed to the system linker", 165},
221
	{"-#", "1VB", "equivalent to -v", 1},
222
	{"-##", "1VB", "equivalent to -v", 1},
223
	{"-###", "1VB|1DR", "equivalent to -dry", 1},
2 7u83 224
 
7 7u83 225
	/* Default options */
226
	{"--+$,+*", "$1", "communicates directly with the option interpreter",
227
		0},
228
	{"$", "XUnknown option,$s$0|AXO$0", "unknown option", 0},
2 7u83 229
 
7 7u83 230
	/* End marker */
231
	{null, null, null, 9999}
232
};
2 7u83 233
 
234
 
235
/*
7 7u83 236
 * THE ENVIRONMENT OPTION MAP
237
 *
238
 * This table gives all the environment options. It needs to be kept in line
239
 * with Table 4.
240
 */
2 7u83 241
 
7 7u83 242
optmap environ_optmap[] = {
243
	/* Options */
244
	{"\\+FLAG $", "=$1", null, 0},
245
	{"\\+FLAG_TDFC $", "AOc$1", null, 0},
246
	{"\\+FLAG_TDFCPP $", "AOp$1", null, 0},
247
	{"\\+FLAG_TCPPLUS $", "AOx$1", null, 0},
248
	{"\\+FLAG_TCPPLUSPP $", "AOg$1", null, 0},
249
	{"\\+FLAG_TOT_CAT $", "", null, 0},
250
	{"\\+FLAG_TLD $", "AOL$1", null, 0},
251
	{"\\+FLAG_TRANS $", "AOt$1", null, 0},
252
	{"\\+FLAG_AS $", "AOa$1", null, 0},
253
	{"\\+FLAG_DYN_LINK $", "AOD$1", null, 0},
254
	{"\\+FLAG_LD $", "AOl$1", null, 0},
255
	{"\\+FLAG_DISP $", "AOd$1", null, 0},
256
	{"\\+FLAG_TNC $", "AOn$1", null, 0},
257
	{"\\+FLAG_PL_TDF $", "AOP$1", null, 0},
258
	{"\\+FLAG_AS1 $", "AOA$1", null, 0},
259
	{"\\+FLAG_TDFOPT $", "", null, 0},
260
	{"\\+FLAG_SPEC_LINK $", "AOs$1", null, 0},
261
	{"\\+FLAG_CPP_SPEC_LINK $", "AOS$1", null, 0},
262
	{"\\+FLAG_DUMP_ANAL $", "AOe$1", null, 0},
263
	{"\\+FLAG_DUMP_LINK $", "AOu$1", null, 0},
264
	{"\\+FLAG_CC $", "AOC$1", null, 0},
265
	{"\\+FLAG_INSTALL $", "AOI$1", null, 0},
2 7u83 266
 
7 7u83 267
	/* Additional filename suffixes */
268
	{"\\+SUFFIX_CPP $", "SSC$1|1SO", null, 0},
2 7u83 269
 
7 7u83 270
	/* Executables */
271
	{"?AS $", "$1Ea$2", null, 0},
272
	{"?AS1 $", "$1EA$2", null, 0},
273
	{"?BUILD_ARCH $", "$1BB$2", null, 0},
274
	{"?CAT $", "$1BC$2", null, 0},
275
	{"?CC $", "$1EC$2", null, 0},
276
	{"?CPP_SPEC_LINK $", "$1ES$2", null, 0},
277
	{"?DISP $", "$1Ed$2", null, 0},
278
	{"?DUMP_ANAL $", "$1Ee$2", null, 0},
279
	{"?DUMP_LINK $", "$1Eu$2", null, 0},
280
	{"?DYN_LINK $", "$1ED$2", null, 0},
281
	{"?LD $", "$1El$2", null, 0},
282
	{"?MKDIR $", "$1BD$2", null, 0},
283
	{"?MOVE $", "$1BM$2", null, 0},
284
	{"?PL_TDF $", "$1EP$2", null, 0},
285
	{"?REMOVE $", "$1BR$2", null, 0},
286
	{"?SPEC_LINK $", "$1Es$2", null, 0},
287
	{"?SPLIT_ARCH $", "$1BS$2", null, 0},
288
	{"?TCPPLUS $", "$1Ex$2", null, 0},
289
	{"?TCPPLUSPP $", "$1Eg$2", null, 0},
290
	{"?TDFC $", "$1Ec$2", null, 0},
291
	{"?TDFCPP $", "$1Ep$2", null, 0},
292
	{"?TDFOPT $", "", null, 0},
293
	{"?TLD $", "$1EL$2", null, 0},
294
	{"?TNC $", "$1En$2", null, 0},
295
	{"?TOUCH $", "$1BT$2", null, 0},
296
	{"?TRANS $", "$1Et$2", null, 0},
2 7u83 297
 
7 7u83 298
	/*
299
	 * Set special env file variables.
300
	 * These must be kept in sync with Table 5 in utility.h
301
	 */
302
	{"$TENDRA_MACHDIR $", "SSV0$2", null, 0},
303
	{"$TENDRA_BINDIR $", "SSV1$2", null, 0},
304
	{"$TENDRA_ENVDIR $", "SSV2$2", null, 0},
305
	{"$TENDRA_LIBDIR $", "SSV3$2", null, 0},
306
	{"$TENDRA_INCLDIR $", "SSV4$2", null, 0},
307
	{"$TENDRA_STARTUPDIR $", "SSV5$2", null, 0},
308
	{"$TENDRA_TMPDIR $", "SSV6$2", null, 0},
309
	{"$TENDRA_BASEDIR $", "SSV7$2", null, 0},
310
	{"$TENDRA_SRCDIR $", "SSV8$2", null, 0},
2 7u83 311
 
7 7u83 312
	/* Flags */
313
	{"?API $", "", null, 0},
314
	{"?API_NAME $", "", null, 0},
315
	{"?INCL $", "$1SI$2", null, 0},
316
	{"?INCL_CPP $", "$1Si$2", null, 0},
317
	{"?STARTUP_DIR $", "$1Sd$2", null, 0},
318
	{"?STARTUP $", "$1Ss$2", null, 0},
319
	{"?STARTUP_CPP_DIR $", "$1SD$2", null, 0},
320
	{"?STARTUP_CPP $", "$1SS$2", null, 0},
321
	{"?PORTABILITY $", "$1SP$2", null, 0},
322
	{"?LINK $", "$1SJ$2", null, 0},
323
	{"?LIB $", "$1Sj$2", null, 0},
324
	{"?CRT0 $", "$1S0$2", null, 0},
325
	{"?CRT1 $", "$1S1$2", null, 0},
326
	{"?CRTN $", "$1S2$2", null, 0},
327
	{"?CRTP_N $", "$1S3$2", null, 0},
328
	{"?SYS_LINK $", "$1SL$2", null, 0},
329
	{"?SYS_LIB $", "$1Sl$2", null, 0},
330
	{"?SYS_LIBC $", "$1Sc$2", null, 0},
331
	{"?LINK_ENTRY $", "$1Se$2", null, 0},
2 7u83 332
 
7 7u83 333
	/* Startup and endup lines */
334
	{"\\+COMP_OPTION $", "@CAP:$1", null, 0},
335
	{"\\+LINE_START $", "@D$1$n", null, 0},
336
	{"\\+LINE_END $", "@F$1$n", null, 0},
2 7u83 337
 
7 7u83 338
	/* Miscellaneous */
339
	{"\\+INFO $", "@SAI$1", null, 0},
340
	{">INFO $", "@SAI$SAI@plus@$1", null, 0},
341
	{"<INFO $", "@SAI$1@plus@$SAI", null, 0},
342
	{"\\+ENVDIR $", "SED$1|CFE", null, 0},
343
	{"\\?ENVDIR $", "?:ED$1", null, 0},
344
	{"\\+MACHINE $", "SMN$1|CSM", null, 0},
345
	{"\\?MACHINE $", "?:MN$1", null, 0},
346
	{"\\+SUFFIX $", "STD$1", null, 0}, /* XXX: this MUST be wrong !!! */
347
	{"\\+TEMP $", "STD$1", null, 0},
348
	{"\\?TEMP $", "?:TD$1", null, 0},
349
	{"\\+VERSION $", "SVF$1", null, 0},
350
	{"\\?VERSION $", "?:VF$1", null, 0},
2 7u83 351
 
7 7u83 352
	/* Errors */
353
	{"\\+E$ $", "X+E$soptions$sno$slonger$ssupported", null, 0},
354
	{"$ $", "XUnknown$senvironmental$svariable,$s$1", null, 0},
355
	{"$", "XIllegal$senvironmental$soption,$s$0", null, 0},
2 7u83 356
 
7 7u83 357
	/* End marker */
358
	{ null, null, null, 9999 }
359
};
2 7u83 360
 
361
 
362
/*
7 7u83 363
 * OPTION INTERPRETER DEBUGGING FLAG
364
 *
365
 * This flag indicates whether option interpreter debugging information should
366
 * be printed.
367
 */
2 7u83 368
 
7 7u83 369
static boolean debug_options = 0;
2 7u83 370
 
371
 
372
/*
7 7u83 373
 * LOCAL FLAGS
374
 *
375
 * These values may be used for temporary storage by the option interpreter.
376
 */
2 7u83 377
 
7 7u83 378
static boolean xx_bool = 0;
379
static list *xx_list = null;
380
static char *xx_string = null;
2 7u83 381
 
382
 
383
/*
7 7u83 384
 * ROUTINE IMPLEMENTING THE -SPECIAL OPTION
385
 *
386
 * This routine enables certain internal options depending on the value of the
387
 * string held in xx_string.
388
 */
2 7u83 389
 
7 7u83 390
static void
391
special_option(void)
2 7u83 392
{
7 7u83 393
	boolean b = 1;
394
	char *s = xx_string;
395
	if (strneq(s, "no_", 3)) {
396
		b = 0;
397
		s += 3;
398
	}
399
	if (streq(s, "cpp")) {
400
		allow_cpp = b;
401
	} else if (streq(s, "tnc") && !checker) {
402
		allow_notation = b;
403
	} else if (streq(s, "pl_tdf") && !checker) {
404
		allow_pl_tdf = b;
405
	} else if (streq(s, "c_spec") || streq(s, "cpp_spec")) {
406
		allow_specs = b;
407
	} else if (streq(s, "dump") || streq(s, "cpp_dump")) {
408
		allow_specs = b;
409
		if (dump_opts == null) {
410
			dump_opts = "-d=";
411
		}
412
	} else {
413
		error(WARNING, "Unknown special option, '%s'", s);
414
	}
415
	return;
2 7u83 416
}
417
 
418
 
419
/*
7 7u83 420
 * CONVERT A TWO LETTER CODE INTO A BOOLEAN
421
 *
422
 * This routine takes a two letter code, s, and returns a pointer to the
423
 * corresponding boolean variable.
424
 */
2 7u83 425
 
7 7u83 426
static boolean *
427
lookup_bool(char *s)
428
{
429
	char a = s[0];
430
	char b = 0;
2 7u83 431
 
7 7u83 432
	if (a) {
433
		b = s[1];
2 7u83 434
	}
7 7u83 435
	switch (a) {
436
	case 'A':
437
		if (b == 'A') return (&use_alpha_assembler);
438
		if (b == 'C') return (&api_checks);
439
		if (b == 'R') return (&make_archive);
440
		if (b == 'S') return (&use_assembler);
441
		break;
442
	case 'C':
443
		if (b == 'C') return (&use_system_cc);
444
		if (b == 'H') return (&checker);
445
		if (b == 'R') return (&copyright);
446
		if (b == 'S') return (&allow_specs);
447
		break;
448
	case 'D':
449
		if (b == 'B') return (&debug_options);
450
		if (b == 'G') return (&flag_diag);
451
		if (b == 'L') return (&use_dynlink);
452
		if (b == 'R') return (&dry_run);
453
		break;
454
	case 'E':
455
		if (b == 'S') return (&no_shuffle);
456
	case 'H':
457
		if (b == 'L') return (&use_hp_linker);
458
		break;
459
	case 'K':
460
		if (b == 'E') return (&flag_keep_err);
461
		break;
462
	case 'L':
463
		if (b == 'C') return (&case_insensitive);
464
		if (b == 'S') return (&link_specs);
465
		break;
466
	case 'M':
467
		if (b == 'A') return (&use_mips_assembler);
468
		if (b == 'C') return (&make_complex);
469
		if (b == 'N') return (&make_up_names);
470
		if (b == 'P') return (&flag_merge_all);
471
		break;
472
	case 'N':
473
		if (b == 'E') return (&flag_nepc);
474
		break;
475
	case 'O':
476
		if (b == 'N') return (&option_next);
477
		if (b == 'P') return (&flag_optim);
478
		break;
479
	case 'P':
480
		if (b == 'F') return (&flag_prof);
481
		if (b == 'I') return (&flag_incl);
482
		if (b == 'L') return (&allow_pl_tdf);
483
		if (b == 'P') return (&make_pretty);
484
		if (b == 'R') return (&make_preproc);
485
		break;
486
	case 'S':
487
		if (b == 'A') return (&show_api);
488
		if (b == 'C') return (&use_sparc_cc);
489
		if (b == 'E') return (&show_errors);
490
		if (b == 'O') return (&suffix_overrides);
491
		if (b == 'R') return (&flag_strip);
492
		if (b == 'T') return (&flag_startup);
493
		break;
494
	case 'T':
495
		if (b == 'C') return (&taciturn);
496
		if (b == 'D') return (&env_dump);
497
		if (b == 'E') return (&tool_chain_environ);
498
		if (b == 'I') return (&time_commands);
499
		if (b == 'N') return (&allow_notation);
500
		if (b == 'S') return (&make_tspec);
501
		if (b == 'T') return (&tool_chain);
502
		if (b == 'U') return (&tidy_up);
503
		break;
504
	case 'V':
505
		if (b == 'B') return (&verbose);
506
		break;
507
	case 'W':
508
		if (b == 'A') return (&warnings);
509
		break;
510
	case 'X':
511
		if (b == 'X') return (&xx_bool);
512
		break;
2 7u83 513
	}
7 7u83 514
	error(OPTION, "Unknown boolean identifier, '%c%c'", a, b);
515
	return (null);
2 7u83 516
}
517
 
518
 
519
/*
7 7u83 520
 * CONVERT A TWO LETTER CODE INTO A LIST
521
 *
522
 * This routine takes a two letter code, s, and returns a pointer to the
523
 * corresponding list variable. This routine needs to be kept in step with
524
 * Table 4.
525
 */
2 7u83 526
 
7 7u83 527
static list **
528
lookup_list(char *s)
2 7u83 529
{
7 7u83 530
	char a = s[0];
531
	char b = 0;
532
	if (a) {
533
		b = s[1];
2 7u83 534
	}
7 7u83 535
	switch (a) {
536
	case 'B':
537
		switch (b) {
538
		case 'B':
539
			return (&exec_build_arch);
540
		case 'C':
541
			return (&exec_cat);
542
		case 'D':
543
			return (&exec_mkdir);
544
		case 'M':
545
			return (&exec_move);
546
		case 'R':
547
			return (&exec_remove);
548
		case 'S':
549
			return (&exec_split_arch);
550
		case 'T':
551
			return (&exec_touch);
2 7u83 552
		}
7 7u83 553
		break;
554
	case 'E':
555
		switch (b) {
556
		case PRODUCE_ID:
557
			return (&exec_produce);
558
		case PREPROC_ID:
559
			return (&exec_preproc);
560
		case CPP_PRODUCE_ID:
561
			return (&exec_cpp_produce);
562
		case CPP_PREPROC_ID:
563
			return (&exec_cpp_preproc);
564
		case TDF_LINK_ID:
565
			return (&exec_tdf_link);
566
		case TRANSLATE_ID:
567
			return (&exec_translate);
568
		case ASSEMBLE_ID:
569
			return (&exec_assemble);
570
		case LINK_ID:
571
			return (&exec_link);
572
		case PRETTY_ID:
573
			return (&exec_pretty);
574
		case NOTATION_ID:
575
			return (&exec_notation);
576
		case PL_TDF_ID:
577
			return (&exec_pl_tdf);
578
		case ASSEMBLE_MIPS_ID:
579
			return (&exec_assemble_mips);
580
		case SPEC_LINK_ID:
581
			return (&exec_spec_link);
582
		case CPP_SPEC_LINK_ID:
583
			return (&exec_cpp_spec_link);
584
		case CC_ID:
585
			return (&exec_cc);
586
		case DYNLINK_ID:
587
			return (&exec_dynlink);
588
		case DUMP_ANAL_ID:
589
			return (&exec_dump_anal);
590
		case DUMP_LINK_ID:
591
			return (&exec_dump_link);
592
		}
593
		error(OPTION, "Unknown compilation stage, '%c'", b);
594
		return (null);
595
	case 'Q':
596
		if (checker) {
597
			switch (b) {
598
			case PRODUCE_ID:
599
				return (&opt_produce);
600
			case CPP_PRODUCE_ID:
601
				return (&opt_cpp_produce);
602
			case SPEC_LINK_ID:
603
				return (&opt_spec_link);
604
			case CPP_SPEC_LINK_ID:
605
				return (&opt_cpp_spec_link);
606
			case ARCHIVER_ID:
607
				return (&opt_joiner);
608
			case CC_ID:
609
				return (&opt_cc);
610
			}
611
			error(OPTION, "Unknown compilation stage, '%c'", b);
612
			return (null);
613
		}
614
		goto case_O;
615
	case 'O':
616
case_O:
617
		switch (b) {
618
		case PRODUCE_ID:
619
			return (&opt_produce);
620
		case PREPROC_ID:
621
			return (&opt_preproc);
622
		case CPP_PRODUCE_ID:
623
			return (&opt_cpp_produce);
624
		case CPP_PREPROC_ID:
625
			return (&opt_cpp_preproc);
626
		case TDF_LINK_ID:
627
			return (&opt_tdf_link);
628
		case TRANSLATE_ID:
629
			return (&opt_translate);
630
		case ASSEMBLE_ID:
631
			return (&opt_assemble);
632
		case DYNLINK_ID:
633
			return (&opt_dynlink);
634
		case LINK_ID:
635
			return (&opt_link);
636
		case PRETTY_ID:
637
			return (&opt_pretty);
638
		case NOTATION_ID:
639
			return (&opt_notation);
640
		case PL_TDF_ID:
641
			return (&opt_pl_tdf);
642
		case ASSEMBLE_MIPS_ID:
643
			return (&opt_assemble_mips);
644
		case SPEC_LINK_ID:
645
			return (&opt_spec_link);
646
		case CPP_SPEC_LINK_ID:
647
			return (&opt_cpp_spec_link);
648
		case INSTALL_ID:
649
			return (&opt_archive);
650
		case ARCHIVER_ID:
651
			return (&opt_joiner);
652
		case CC_ID:
653
			return (&opt_cc);
654
		case DUMP_ANAL_ID:
655
			return (&opt_dump_anal);
656
		case DUMP_LINK_ID:
657
			return (&opt_dump_link);
658
		}
659
		error(OPTION, "Unknown compilation stage, '%c'", b);
660
		return (null);
661
	case 'S':
662
		switch (b) {
663
		case 'I':
664
			return (&std_prod_incldirs);
665
		case 'P':
666
			return (&std_prod_portfile);
667
		case 'd':
668
			return (&std_prod_startdirs);
669
		case 's':
670
			return (&std_prod_startup);
671
		case 'i':
672
			return (&std_cpp_prod_incldirs);
673
		case 'D':
674
			return (&std_cpp_prod_startdirs);
675
		case 'S':
676
			return (&std_cpp_prod_startup);
677
		case 'J':
678
			return (&std_tdf_link_libdirs);
679
		case 'j':
680
			return (&std_tdf_link_libs);
681
		case '0':
682
			return (&std_link_crt0);
683
		case '1':
684
			return (&std_link_crt1);
685
		case '2':
686
			return (&std_link_crtn);
687
		case '3':
688
			return (&std_link_crtp_n);
689
		case 'L':
690
			return (&std_link_libdirs);
691
		case 'l':
692
			return (&std_link_libs);
693
		case 'c':
694
			return (&std_link_c_libs);
695
		case 'e':
696
			return (&std_link_entry);
697
		}
698
		break;
699
	case 'U':
700
		switch (b) {
701
		case 'I':
702
			return (&usr_prod_incldirs);
703
		case 's':
704
			return (&usr_prod_startup);
705
		case 'e':
706
			return (&usr_prod_eoptions);
707
		case 'f':
708
			return (&usr_prod_foptions);
709
		case 'P':
710
			return (&usr_pl_tdf_incldirs);
711
		case 'J':
712
			return (&usr_tdf_link_libdirs);
713
		case 'j':
714
			return (&usr_tdf_link_libs);
715
		case 'L':
716
			return (&usr_link_libdirs);
717
		case 'l':
718
			return (&usr_link_libs);
719
		}
720
		break;
721
	case 'X':
722
		switch (b) {
723
		case 'O':
724
			return (&opt_unknown);
725
		case 'X':
726
			return (&xx_list);
727
		}
728
		break;
2 7u83 729
	}
7 7u83 730
	error(OPTION, "Unknown list identifier, '%c%c'", a, b);
731
	return (null);
2 7u83 732
}
733
 
734
 
735
/*
7 7u83 736
 * CONVERT A TWO LETTER CODE INTO A STRING
737
 *
738
 * This routine takes a two letter code, s, and returns a pointer to the
739
 * corresponding string variable.
740
 */
2 7u83 741
 
7 7u83 742
static char **
743
lookup_string(char *s)
2 7u83 744
{
7 7u83 745
	char a = s[0];
746
	char b = 0;
747
	if (a) {
748
		b = s[1];
2 7u83 749
	}
7 7u83 750
	if (a == 'N') {
751
		switch (b) {
752
		case INDEP_TDF_KEY:
753
			return (&name_j_file);
754
		case C_SPEC_KEY:
755
			return (&name_k_file);
756
		case CPP_SPEC_KEY:
757
			return (&name_K_file);
758
		case STARTUP_FILE_KEY:
759
			return (&name_h_file);
760
		case PRETTY_TDF_KEY:
761
			return (&name_p_file);
762
		}
763
		error(OPTION, "Unknown output file specifier, '%c'", b);
764
		return (null);
765
	}
766
	if (a == 'S') {
767
		int t;
768
		char *p1;
769
 
770
		if (b == 'V') {
771
			int i = s[2] - '0';
772
			p1 = (s + 3);
773
			/* change the path, if it was not set at cmd line */
774
			if (env_paths[i] == NULL) {
775
				env_paths[i] = p1;
776
			}
777
			/* XXX: hack */
778
			return (&dev_null);
779
		}
780
 
781
		t = find_type(b, 0);
782
		return (suffixes + t);
783
	}
784
	if (a == 'A' && b == 'I') return (&api_info);
785
	if (a == 'A' && b == 'O') return (&api_output);
786
	if (a == 'D' && b == 'O') return (&dump_opts);
787
	if (a == 'E' && b == 'D') return (&environ_dir);
788
	if (a == 'F' && b == 'N') return (&final_name);
789
	if (a == 'M' && b == 'N') return (&machine_name);
790
	if (a == 'P' && b == 'N') return (&progname);
791
	if (a == 'T' && b == 'D') return (&temporary_dir);
792
	if (a == 'V' && b == 'F') return (&version_flag);
793
	if (a == 'W' && b == 'D') return (&workdir);
794
	if (a == 'X' && b == 'X') return (&xx_string);
795
	error(OPTION, "Unknown string identifier, '%c%c'", a, b);
796
	return (null);
2 7u83 797
}
798
 
799
 
800
/*
7 7u83 801
 * DUMMY ARGUMENT FOR PROCEDURE
802
 *
803
 * This variable is used to hold any argument passed to one of the procedures
804
 * in lookup_proc.
805
 */
2 7u83 806
 
7 7u83 807
static char *lookup_proc_arg = null;
2 7u83 808
 
809
 
810
/*
7 7u83 811
 * DUMMY WRAPPER PROCEDURES
812
 *
813
 * These routine(s) are used to call procedures with an argument using
814
 * lookup_proc.
815
 */
2 7u83 816
 
7 7u83 817
static void
818
add_pragma_aux(void)
2 7u83 819
{
7 7u83 820
	add_pragma(lookup_proc_arg);
821
	return;
2 7u83 822
}
823
 
7 7u83 824
static void
825
add_token_aux(void)
2 7u83 826
{
7 7u83 827
	add_token(lookup_proc_arg);
828
	return;
2 7u83 829
}
830
 
831
 
832
/*
7 7u83 833
 * CONVERT A TWO LETTER CODE INTO A PROCEDURE
834
 *
835
 * This routine takes a two letter code, s, and returns a pointer to the
836
 * corresponding procedure.
837
 */
2 7u83 838
 
7 7u83 839
typedef void	(*proc)(void);
2 7u83 840
 
7 7u83 841
static proc
842
lookup_proc(char *s)
2 7u83 843
{
7 7u83 844
	char a = s[0];
845
	char b = 0;
846
	if (a) {
847
		b = s[1];
848
	}
849
	if (a == 'A' && b == 'P') return (add_pragma_aux);
850
	if (a == 'A' && b == 'T') return (add_token_aux);
851
	if (a == 'F' && b == 'E') return (find_envpath);
852
	if (a == 'P' && b == 'V') return (print_version);
853
	if (a == 'S' && b == 'E') return (show_envpath);
854
	if (a == 'S' && b == 'M') return (set_machine);
855
	if (a == 'S' && b == 'P') return (special_option);
856
	error(OPTION, "Unknown procedure identifier, '%c%c'", a, b);
857
	return (null);
2 7u83 858
}
859
 
860
 
861
/*
7 7u83 862
 * RETURN VALUES FOR MATCH_OPTION
863
 *
864
 * These values are returned by match_option. MATCH_OK means that the option
865
 * matches, MATCH_MORE means that it may match with an additional option,
866
 * MATCH_FAILED means it does not match, and the other values indicate errors
867
 * of some kind.
868
 */
2 7u83 869
 
870
#define MATCH_OK		0
871
#define MATCH_MORE		1
872
#define MATCH_FAILED		2
873
#define MATCH_IN_ERR		3
874
#define MATCH_OUT_ERR		4
875
#define MATCH_OPT_ERR		5
876
 
877
 
878
/*
7 7u83 879
 * MATCH AN OPTION
880
 */
2 7u83 881
 
7 7u83 882
static int
883
match_option(char *in, char *out, char *opt, args_out *res)
2 7u83 884
{
7 7u83 885
    char *p = in;
886
    char *q = opt;
2 7u83 887
 
7 7u83 888
    int i, a, v = 1;
889
    int go = 1, loop = 1, loopv = -1;
890
    struct { char *txt; int len; } var[max_var];
2 7u83 891
 
892
    /* Process input */
7 7u83 893
    while (*p && go) {
894
	if (*p == '$') {
895
	    char c = p[1];
896
	    if (c) {
897
		int wraps = 0;
898
		if (p[2] == '+' && p[3] == '*') {
2 7u83 899
		    /* List of strings with breaks : $c+* */
7 7u83 900
		    wraps = 1;
901
		    p++;
2 7u83 902
		}
7 7u83 903
		if (p[2] == '*') {
2 7u83 904
		    /* List of strings : $c* */
7 7u83 905
		    loop = 0;
906
		    loopv = v;
907
		    if (p[3]) return (MATCH_IN_ERR);
908
		    while (*q) {
909
			int l = 0;
910
			var[v].txt = q;
911
			while (*q && *q != c) {
912
			    l++;
913
			    q++;
2 7u83 914
			}
7 7u83 915
			var[v].len = l;
916
			if (*q) {
2 7u83 917
			    /* Found c */
7 7u83 918
			    q++;
919
			    if (*q == 0 && wraps) return (MATCH_MORE);
2 7u83 920
			}
7 7u83 921
			if (++v >= max_var) return (MATCH_OPT_ERR);
922
			loop++;
2 7u83 923
		    }
7 7u83 924
		    go = 0;
2 7u83 925
		} else {
926
		    /* Terminated string : $c */
7 7u83 927
		    int l = 0;
928
		    var[v].txt = q;
929
		    while (*q != c) {
930
			if (*q == 0) return (MATCH_FAILED);
931
			l++;
932
			q++;
2 7u83 933
		    }
7 7u83 934
		    var[v].len = l;
935
		    if (++v >= max_var) return (MATCH_OPT_ERR);
2 7u83 936
		}
937
	    } else {
938
		/* Simple string : $ */
7 7u83 939
		int l = (int)strlen(q);
940
		var[v].txt = q;
941
		var[v].len = l;
942
		if (++v >= max_var) return (MATCH_OPT_ERR);
943
		go = 0;
2 7u83 944
	    }
7 7u83 945
	} else if (*p == '?') {
946
	    if (p[1] == '*') {
2 7u83 947
		/* List of characters : ?* */
7 7u83 948
		if (p[2]) return (MATCH_IN_ERR);
949
		loop = 0;
950
		loopv = v;
951
		while (*q) {
952
		    var[v].txt = q;
953
		    var[v].len = 1;
954
		    if (++v >= max_var) return (MATCH_OPT_ERR);
955
		    q++;
956
		    loop++;
2 7u83 957
		}
7 7u83 958
		go = 0;
2 7u83 959
	    } else {
960
		/* Simple character : ? */
7 7u83 961
		if (*q == 0) return (MATCH_FAILED);
962
		var[v].txt = q;
963
		var[v].len = 1;
964
		if (++v >= max_var) return (MATCH_OPT_ERR);
965
		q++;
2 7u83 966
	    }
7 7u83 967
	} else if (*p == '+') {
2 7u83 968
	    /* Potential break : + */
7 7u83 969
	    if (*q == 0) return (MATCH_MORE);
970
	} else if (*p == '^') {
2 7u83 971
	    /* Negated letter */
7 7u83 972
	    p++;
973
	    if (*p == 0) return (MATCH_IN_ERR);
974
	    if (*p == *q) return (MATCH_FAILED);
975
	    q++;
976
	} else if (*p == '\\') {
2 7u83 977
	    /* Escaped letter : \c */
7 7u83 978
	    p++;
979
	    if (*p == 0) return (MATCH_IN_ERR);
980
	    if (*p != *q) return (MATCH_FAILED);
981
	    q++;
2 7u83 982
	} else {
983
	    /* Letter : c */
7 7u83 984
	    if (*p != *q) return (MATCH_FAILED);
985
	    q++;
2 7u83 986
	}
7 7u83 987
	p++;
2 7u83 988
    }
989
 
990
    /* Check end of option */
7 7u83 991
    if (go && *q) return (MATCH_FAILED);
2 7u83 992
 
993
    /* The first variable is the whole option */
7 7u83 994
    var[0].txt = opt;
995
    var[0].len = (int)strlen(opt);
2 7u83 996
 
997
    /* Print output */
7 7u83 998
    a = 0;
999
    for (i = 0; i < loop; i++) {
1000
	int count = 0;
1001
	char buff[MAX_LINE];
1002
	q = buff;
1003
	for (p = out; *p && count < MAX_LINE; p++, count++) {
1004
	    if (*p == '$') {
2 7u83 1005
		/* Variable */
7 7u83 1006
		int n;
1007
		char c = *(++p);
1008
		if (c == 's') {
2 7u83 1009
		    /* $s expands to a space */
7 7u83 1010
		    *(q++) = ' ';
1011
		} else if (c == 'n') {
2 7u83 1012
		    /* $n expands to a newline */
7 7u83 1013
		    *(q++) = '\n';
1014
		} else if (c >= '0' && c <= '9') {
1015
		    n = (c - '0');
1016
		    if (n == loopv)n += i;
1017
		    if (n < v) {
1018
			int l = var[n].len;
1019
			IGNORE strncpy(q, var[n].txt,(size_t)l);
1020
			q += l;
2 7u83 1021
		    }
7 7u83 1022
		} else if (c == 'B') {
1023
		    boolean *b = lookup_bool(p + 1);
1024
		    if (b == null) return (MATCH_OUT_ERR);
1025
		    IGNORE sprintf(q, "%d",(int)*b);
1026
		    while (*q)q++;
1027
		    p += 2;
1028
		} else if (c == 'L') {
1029
		    list *pt;
1030
		    list **sp = lookup_list(p + 1);
1031
		    if (sp == null) return (MATCH_OUT_ERR);
1032
		    for (pt = *sp; pt; pt = pt->next) {
1033
			int l = (int)strlen(pt->item);
1034
			IGNORE strncpy(q, pt->item,(size_t)l);
1035
			q += l;
1036
			*(q++) = ' ';
2 7u83 1037
		    }
7 7u83 1038
		    p += 2;
1039
		} else if (c == 'S') {
1040
		    int l;
1041
		    char **sp = lookup_string(p + 1);
1042
		    if (sp == null) return (MATCH_OUT_ERR);
1043
		    if (*sp) {
1044
			l = (int)strlen(*sp);
1045
			IGNORE strncpy(q, *sp,(size_t)l);
1046
			q += l;
2 7u83 1047
		    }
7 7u83 1048
		    p += 2;
2 7u83 1049
		} else {
7 7u83 1050
		    return (MATCH_OUT_ERR);
2 7u83 1051
		}
7 7u83 1052
	    } else if (*p == '|') {
2 7u83 1053
		/* Multiple output */
7 7u83 1054
		*q = 0;
1055
		res->argv[a] = string_copy(buff);
1056
		if (++a >= max_var) return (MATCH_OPT_ERR);
1057
		q = buff;
1058
	    } else if (*p == '\\') {
2 7u83 1059
		/* Escaped output character */
7 7u83 1060
		if (*(++p) == 0) return (MATCH_OUT_ERR);
1061
		*(q++) = *p;
2 7u83 1062
	    } else {
1063
		/* Simple output character */
7 7u83 1064
		*(q++) = *p;
2 7u83 1065
	    }
1066
	}
7 7u83 1067
	*q = 0;
1068
	res->argv[a] = string_copy(buff);
1069
	if (++a >= max_var) return (MATCH_OPT_ERR);
2 7u83 1070
    }
7 7u83 1071
    res->argc = a;
1072
    return (MATCH_OK);
2 7u83 1073
}
1074
 
1075
 
1076
/*
7 7u83 1077
 * INTERPRET AN OPTION COMMAND
1078
 */
2 7u83 1079
 
7 7u83 1080
static void
1081
interpret_cmd(char *cmd)
2 7u83 1082
{
7 7u83 1083
    char c = *cmd;
2 7u83 1084
 
1085
    /* Debugging */
7 7u83 1086
    if (debug_options) error(OPTION, "Interpreting '%s'", cmd);
2 7u83 1087
 
1088
    /* Deal with at-hack */
7 7u83 1089
    if (c == '@') {
1090
	char *p = string_copy(cmd + 1), *q;
1091
	for (q = p; *q; q++) {
1092
	    if (*q == '@') *q = ' ';
2 7u83 1093
	}
7 7u83 1094
	cmd = p;
1095
	c = *p;
2 7u83 1096
    }
1097
 
1098
    /* Deal with empty strings */
7 7u83 1099
    if (c == 0) return;
2 7u83 1100
 
1101
    /* Digits set values */
7 7u83 1102
    if (c >= '0' && c <= '9') {
1103
	boolean *b = lookup_bool(cmd + 1);
1104
	if (b == null) return;
1105
	*b = (boolean)(c - '0');
1106
	return;
2 7u83 1107
    }
1108
 
1109
    /* Translations */
7 7u83 1110
    if (c == '>') c = 'A';
1111
    if (c == '<') c = 'B';
1112
    if (c == '+') c = 'L';
2 7u83 1113
 
1114
    /* Deal with list query */
7 7u83 1115
    if (c == '?') {
1116
	if (cmd[1] == ':') {
1117
	    char **sp = lookup_string(cmd + 2);
1118
	    if (sp == null) return;
1119
	    comment(1, "%s=\"%s\"\n", cmd + 4, *sp);
2 7u83 1120
	} else {
7 7u83 1121
	    list *p;
1122
	    list **sp = lookup_list(cmd + 1);
1123
	    if (sp == null) return;
1124
	    comment(1, "%s=\"", cmd + 3);
1125
	    for (p = *sp; p != null; p = p->next) {
1126
		comment(1, "%s", p->item);
1127
		if (p->next)comment(1, " ");
2 7u83 1128
	    }
7 7u83 1129
	    comment(1, "\"\n");
2 7u83 1130
	}
7 7u83 1131
	return;
2 7u83 1132
    }
1133
 
1134
    /* Deal with equivalences */
7 7u83 1135
    if (c == '=') {
1136
	list *p = make_list(cmd + 1);
1137
	process_options(p, main_optmap, 1);
1138
	free_list(p);
1139
	return;
2 7u83 1140
    }
1141
 
1142
    /* Deal with primitives */
7 7u83 1143
    switch (c) {
1144
	case 'A': {
2 7u83 1145
	    /* Change list */
7 7u83 1146
	    list **sp = lookup_list(cmd + 1);
1147
	    if (sp == null) {
1148
		    return;
1149
	    }
1150
	    *sp = add_list(*sp, make_list(cmd + 3));
1151
	    return;
2 7u83 1152
	}
7 7u83 1153
	case 'B': {
2 7u83 1154
	    /* Change list */
7 7u83 1155
	    list **sp = lookup_list(cmd + 1);
1156
	    if (sp == null) {
1157
		    return;
1158
	    }
1159
	    *sp = add_list(make_list(cmd + 3), *sp);
1160
	    return;
2 7u83 1161
	}
7 7u83 1162
	case 'L': {
2 7u83 1163
	    /* Change list */
7 7u83 1164
	    list **sp = lookup_list(cmd + 1);
1165
	    if (sp == null) {
1166
		    return;
1167
	    }
1168
	    free_list(*sp);
1169
	    *sp = make_list(cmd + 3);
1170
	    return;
2 7u83 1171
	}
7 7u83 1172
	case 'C': {
2 7u83 1173
	    /* Call */
7 7u83 1174
	    proc p = lookup_proc(cmd + 1);
1175
	    if (p == null) {
1176
		    return;
1177
	    }
1178
	    if (cmd[3] == ':') {
1179
		lookup_proc_arg = cmd + 4;
2 7u83 1180
	    } else {
7 7u83 1181
		lookup_proc_arg = null;
2 7u83 1182
	    }
7 7u83 1183
	    (*p)();
1184
	    return;
2 7u83 1185
	}
7 7u83 1186
	case 'D':
2 7u83 1187
	    /* Startup options */
7 7u83 1188
	    add_to_startup(cmd + 1);
1189
	    return;
1190
	case 'E': {
1191
            /* Environment */
1192
            if (*(cmd + 1) == '?') {
1193
		char var[MAX_LINE];
1194
		char val[MAX_LINE];
1195
		int  count;
1196
		char *p, *q, *r;
1197
		char c1;
1198
		char **subs;
1199
		int i;
1200
#if FS_STAT
1201
		struct stat sb;
1202
#endif
1203
		q = var;
1204
		r = val;
1205
		p = cmd + 2;
1206
		count = 0;
1207
		while ((c1 = *p++) != '?') {
1208
		        *q++ = c1;
1209
		}
1210
		*q++='\0';
2 7u83 1211
 
38 7u83 1212
		while ((c1 = *p++) != '\0' /*NULL*/) {
7 7u83 1213
		    *r++ = c1;
1214
		    /*
1215
		     * Only the value is user supplied and needs bounds
1216
		     * checking.
1217
		     */
1218
		    if (++count >= MAX_LINE){
1219
			error(FATAL,
1220
			       "Exceeded maximum buffer length in -y argument\n");
1221
		    }
1222
		}
1223
 
1224
		*r++ ='\0';
1225
		/*
1226
		 * Additional error checking for those platforms supporting
1227
		 * stat().
1228
		 */
1229
#if FS_STAT
1230
		if (stat(val, &sb) == -1) {
1231
		    error(SERIOUS, "interpret_cmd: %s %s",
1232
			val, strerror(errno));
1233
		}
1234
#endif
1235
		i = 0;
1236
		subs = PATH_SUBS;
1237
		while (*subs) {
1238
		    if (!strcmp(*subs, var)) {
1239
			env_paths[i] = string_copy(val);
1240
			break;
1241
		    }
1242
		    i++;
1243
		    subs++;
1244
		}
1245
		if (!*subs)
1246
		    error(WARNING,
1247
			  "Ignoring non-standard env assignment: %s=%s", var,
1248
			  val);
1249
	    } else {
1250
		read_env(cmd + 1);
1251
            }
1252
            return;
2 7u83 1253
	}
7 7u83 1254
	case 'F':
2 7u83 1255
	    /* Endup options */
7 7u83 1256
	    add_to_endup(cmd + 1);
1257
	    return;
1258
	case 'H': {
2 7u83 1259
	    /* Halt */
7 7u83 1260
	    char stage = cmd[1];
1261
	    set_stage(find_type(stage, 0), STOP_STAGE);
1262
	    return;
2 7u83 1263
	}
7 7u83 1264
	case 'I': {
2 7u83 1265
	    /* Input file */
7 7u83 1266
	    int t;
1267
	    filename *f;
1268
	    char stage = cmd[1];
1269
	    char *name = cmd + 2;
1270
	    if (stage == '?') {
1271
		t = UNKNOWN_TYPE;
2 7u83 1272
	    } else {
7 7u83 1273
		t = find_type(stage, 0);
2 7u83 1274
	    }
7 7u83 1275
	    f = find_filename(name, t);
1276
	    input_files = add_filename(input_files, f);
1277
	    return;
2 7u83 1278
	}
7 7u83 1279
	case 'K': {
2 7u83 1280
	    /* Keep */
7 7u83 1281
	    static int k = KEEP_STAGE;
1282
	    char stage = cmd[1];
1283
	    if (stage == '-') {
1284
		k = DONT_KEEP_STAGE;
2 7u83 1285
	    } else {
7 7u83 1286
		set_stage(find_type(stage, 0), k);
1287
		k = KEEP_STAGE;
2 7u83 1288
	    }
7 7u83 1289
	    return;
2 7u83 1290
	}
7 7u83 1291
	case 'Q': {
2 7u83 1292
	    /* Query */
7 7u83 1293
	    char *s;
1294
	    optmap *t = main_optmap;
1295
	    error(INFO, "List of recognised options");
1296
	    while (s = t->in, s != null) {
1297
		if (*s == '-') {
1298
		    char d;
1299
		    comment(0, " ");
1300
		    while (d = *(s++), d != 0) {
1301
			switch (d) {
1302
			    case '$':
1303
				IGNORE fputs("<string>", stderr);
1304
				break;
1305
			    case '?':
1306
				IGNORE fputs("<letter>", stderr);
1307
				break;
1308
			    case '*':
1309
				IGNORE fputs("...", stderr);
1310
				break;
1311
			    case '+':
1312
				IGNORE fputc(' ', stderr);
1313
				break;
1314
			    case '\\':
1315
				IGNORE fputc(*(s++), stderr);
1316
				break;
1317
			    default:
1318
				IGNORE fputc(d, stderr);
1319
				break;
2 7u83 1320
			}
1321
		    }
7 7u83 1322
		    s = t->explain;
1323
		    if (s == null) {
1324
			    s = "not documented";
1325
		    }
1326
		    comment(0, " : ");
1327
		    comment(0, s, progname);
1328
		    comment(0, ".\n");
2 7u83 1329
		}
7 7u83 1330
		t++;
2 7u83 1331
	    }
7 7u83 1332
	    return;
2 7u83 1333
	}
7 7u83 1334
	case 'S': {
2 7u83 1335
	    /* String */
7 7u83 1336
	    char **s = lookup_string(cmd + 1);
1337
	    if (s == null) {
1338
		    return;
1339
	    }
1340
	    *s = cmd + 3;
1341
	    return;
2 7u83 1342
	}
7 7u83 1343
	case 'V':
1344
	    if (cmd[1] == 'B') {
1345
		boolean *b = lookup_bool(cmd + 2);
1346
		if (b == null) {
1347
			return;
1348
		}
1349
		comment(1, "%c%c = %d\n", cmd[2], cmd[3], *b);
1350
		return;
1351
	    } else if (cmd[1] == 'L') {
1352
		list **sp = lookup_list(cmd + 2), *pt;
1353
		if (sp == null) {
1354
			return;
1355
		}
1356
		comment(1, "%c%c =", cmd[2], cmd[3]);
1357
		for (pt = *sp; pt != null; pt = pt->next) {
1358
		    if (pt->item) {
1359
			comment(1, " %s", pt->item);
2 7u83 1360
		    } else {
7 7u83 1361
			comment(1, " (null)");
2 7u83 1362
		    }
1363
		}
7 7u83 1364
		comment(1, "\n");
1365
		return;
1366
	    } else if (cmd[1] == 'S') {
1367
		char **s = lookup_string(cmd + 2);
1368
		if (s == null) {
1369
			return;
1370
		}
1371
		if (*s) {
1372
		    comment(1, "%c%c = %s\n", cmd[2], cmd[3], *s);
2 7u83 1373
		} else {
7 7u83 1374
		    comment(1, "%c%c = (null)\n", cmd[2], cmd[3]);
2 7u83 1375
		}
7 7u83 1376
		return;
2 7u83 1377
	    }
7 7u83 1378
	    break;
1379
	case 'X':
2 7u83 1380
	    /* Error */
7 7u83 1381
	    error(WARNING, "%s", cmd + 1);
1382
	    return;
2 7u83 1383
    }
7 7u83 1384
    error(OPTION, "Syntax error, '%s'", cmd);
1385
    return;
2 7u83 1386
}
1387
 
1388
 
1389
/*
7 7u83 1390
 * PROCESS A LIST OF OPTIONS
1391
 *
1392
 * This routine processes a list of options, opt, using the options from table
1393
 * tab.
1394
 */
2 7u83 1395
 
7 7u83 1396
void
1397
process_options(list *opt, optmap *tab, int fast)
2 7u83 1398
{
7 7u83 1399
	optmap *t;
1400
	list *p = opt;
1401
	list *accum = null;
1402
	char *arg = null;
1403
	int status = MATCH_OK;
1404
	int a;
2 7u83 1405
 
7 7u83 1406
	/* Scan through the options */
1407
	while (p != null) {
1408
		if (status == MATCH_MORE) {
1409
			arg = string_concat(arg, p->item);
1410
		} else {
1411
			arg = p->item;
2 7u83 1412
		}
7 7u83 1413
		status = MATCH_FAILED;
1414
		for (t = tab; t->in != null; t++) {
1415
			args_out res;
1416
			status = match_option(t->in, t->out, arg, &res);
1417
			switch (status) {
1418
			case MATCH_OK:
1419
				/* Complete option - interpret result */
1420
				for (a = 0; a < res.argc; a++) {
1421
					if (no_shuffle != 0 || fast == 1) {
1422
						interpret_cmd(res.argv[a]);
1423
					} else {
1424
						ordered_node *dn =
1425
						    (ordered_node *)
1426
						    xalloc(sizeof(ordered_node));
1427
						dn->rank = t->rank;
1428
						dn->cmd  = res.argv[a];
1429
						accum = insert_inorder(dn,
1430
								       accum);
1431
					}
1432
				}
1433
				goto end_search;
1434
			case MATCH_MORE:
1435
				/* Incomplete option - move on to next option */
1436
				goto end_search;
1437
			case MATCH_FAILED:
1438
				/* Try again */
1439
				break;
1440
			case MATCH_IN_ERR:
1441
				/* Error in optmap input */
1442
				error(OPTION, "Illegal input '%s'", t->in);
1443
				status = MATCH_FAILED;
1444
				break;
1445
			case MATCH_OUT_ERR:
1446
				/* Error in optmap output */
1447
				error(OPTION, "Illegal option '%s'", t->out);
1448
				status = MATCH_FAILED;
1449
				break;
1450
			case MATCH_OPT_ERR:
1451
				/* Ran out of space for result */
1452
				error(OPTION, "Too many components, '%s'", arg);
1453
				status = MATCH_FAILED;
1454
				break;
1455
			}
2 7u83 1456
		}
7 7u83 1457
		error(OPTION, "Can't interpret '%s'", arg);
1458
end_search:
1459
		p = p->next;
1460
	}
1461
 
1462
	/* Check for incomplete options */
1463
	if (status == MATCH_MORE) {
1464
		error(WARNING, "Option '%s' is incomplete", arg);
1465
	}
1466
 
1467
	/* if the no_shuffle flag is unset, we have order cmds to run */
1468
	if (no_shuffle == 0 && fast == 0) {
1469
		while (accum) {
1470
			ordered_node* dn;
1471
			dn = accum->item;
1472
			interpret_cmd (dn->cmd);
1473
			accum = accum->next;
2 7u83 1474
		}
1475
	}
1476
 
7 7u83 1477
	return;
2 7u83 1478
}