Subversion Repositories tendra.SVN

Rev

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

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