Subversion Repositories tendra.SVN

Rev

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