/* * Copyright (c) 2002, The Tendra Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice unmodified, this list of conditions, and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * Crown Copyright (c) 1997 * * This TenDRA(r) Computer Program is subject to Copyright * owned by the United Kingdom Secretary of State for Defence * acting through the Defence Evaluation and Research Agency * (DERA). It is made available to Recipients with a * royalty-free licence for its use, reproduction, transfer * to other parties and amendment for any purpose not excluding * product development provided that any such use et cetera * shall be deemed to be acceptance of the following conditions:- * * (1) Its Recipients shall ensure that this Notice is * reproduced upon any copies or amended versions of it; * * (2) Any amended version of it shall be clearly marked to * show both the nature of and the organisation responsible * for the relevant amendment or amendments; * * (3) Its onward transfer from a recipient to another * party shall be deemed to be that party's acceptance of * these conditions; * * (4) DERA gives no warranty or assurance as to its * quality or suitability for any purpose and DERA accepts * no liability whatsoever in relation to any use to which * it may be put. * * $TenDRA: tendra/src/tools/tcc/options.c,v 1.23 2005/10/22 16:50:14 stefanf Exp $ */ #include #include #include #include "config.h" #include "cstring.h" #include "fmm.h" #include "msgcat.h" #include "tenapp.h" #include "filename.h" #include "list.h" #include "archive.h" #include "environ.h" #include "flags.h" #include "main.h" #include "options.h" #include "startup.h" #include "suffix.h" #include "utility.h" /* * THE LIST OF ALL INPUT FILES * * All input files found by process_options are added to this list. */ filename *input_files = null; /* * THE MAIN OPTION MAP * * This table gives all the command-line options. The first entry is * the 'match in' and roughly corresponds to command line input. The * second entry is the 'match out' and provides instructions to the * command line interpreter. The third entry is a description. The * the final entry is a relative ranking, with lower numbers being * higher priority. Thus, no matter what order the command line * options are given, the lower ranked option will always be * evaluated first. (Option rankings can be disabled with the * -no_shuffle option.) */ optmap main_optmap [] = { /* Common options */ {"^-$", "I?$0", "specifies an input file" , 1000}, {"-o+$", "SFN$1", "specifies output file name", 100}, {"-D+$=$", "D#define$s$1$s$2$n|AOC$0", "defines a macro", 101}, {"-D+$", "D#define$s$1$s1$n|AOC$0", "defines a macro to be 1", 102}, {"-F?", "H$1", "halts the compilation at the given stage", 103}, {"-I+$", "AUI$0|AOC$0|AUP$0", "specifies an include file directory", 104}, {"-L+$", "1ON|Io$0|AUL$0", "specifies a system library directory", 105}, {"-N+$:+$", "AUI$0|AOC-I$2", "specifies an include file directory (with mode)", 106}, {"-O$", "1OP|AOC$0", "switches optimisation level", 107}, {"-P?*", "K$1", "causes intermediate files to be preserved", 108}, {"-S", "Hs", "halts compilation after creating .s files", 109}, {"-T+$", "CAT:$1|AOC-D$1", "specifies a command-line token", 110}, {"-U+$", "D#undef$s$1$n|AOC$0", "undefines a macro", 111}, {"-W?,+$,+*", "AQ$1$2", "passed an option to a compilation tool", 112}, {"-W?:+$", "AQ$1$2", "passed an option to a compilation tool", 113}, {"-X:+$,+*", "CAP:$1", "specifies a compilation option", 114}, {"-X$", "EX$1", "specifies a compilation mode", 115}, {"-Y+$", "E$1", "reads an environment", 12}, {"-copyright", "1CR", "outputs copyright notice", 117}, {"-c", "Ho", "halts compilation after creating .o files", 118}, {"-d", "Hd", "halts compilation after creating .d files", 119}, {"-dry", "1VB|1DR", "causes a dry run", 120}, {"-e+$", "AUe$0", "specifies a producer end-up file", 121}, {"-f+$", "AUf$0", "specifies a producer start-up file", 122}, {"-g", "1DG", "produces debugging information (default format)", 123}, {"-g1", "1DG", "produces debugging information (old format)", 124}, {"-g2", "2DG", "produces debugging information (new format)", 125}, {"-g3", "3DG", "produces debugging information (new format)", 126}, {"-k", "Hk|HK", "halts compilation after creating .k and .K files", 128}, {"-l+$", "1ON|Io$0|AUl$0", "specifies a system library", 129}, {"-not_ansi", "ASs-fnot_ansi", "allows some non-ANSI C features", 130}, {"-nepc", "1NE|ASs-fnepc", "switches off extra portability checks", 131}, {"-sym", "1CS|SDO-d=", "enables symbol table dump linking", 132}, {"-sym:$", "1CS|SDO-d$1=", "enables symbol table dump linking with flags", 133}, {"-v", "1VB", "specifies verbose mode", 50}, {"-vb", "1TC", "specifies fairly verbose mode", 51}, {"-vt", "1TT", "verbose information about tool chain invocation", 51}, {"-ve", "1TE", "verbose information about tool chain environment", 51}, {"-no_shuffle", "1ES", "turns off shuffle ranking of cmd line args", -1}, {"-y+$=$", "E?$1=$2", "sets an env directory variable", 1}, /* Options not allowed in checker */ {"-J+$", "AUJ-L$1", "specifies a TDF library directory", 20}, {"-M", "1MC", "causes all .j files to be merged", 133}, {"-MA", "1MC|1MP", "as -M, but with hiding",134}, {"-ch", "1CH", "invokes checker mode", 135}, {"-disp", "1PP", "causes all .j files to be pretty printed", 136}, {"-disp_t", "2PP", "causes all .t files to be pretty printed", 137}, {"-i", "Hj", "halts compilation after creating .j files", 138}, {"-im", "1CS", "enables intermodular checks", 139}, {"-j+$", "AUj-l$1", "specifies a TDF library", 30}, {"-prod", "1AR", "causes a TDF archive to be produced", 141}, /* Less common options */ {"-A+-", "AOC$0", "unasserts all built-in predicates", 142}, {"-A+$", "D#pragma$saccept$sdirective$sassert$n|D#assert$s$1$n|AOC$0", "asserts a predicate", 143}, {"-B+$", "1ON|Io$0", "passed to the system linker", 144}, {"-C", "AOC$0", "preserves comments when preprocessing", 30}, {"-E", "1PR", "causes C source files to be preprocessed", 145}, {"-P", "1PR|Ki|KI", "halts compilation after creating .i and .I files", 145}, {"-E?:+$", "LE$1$2", "specifies an executable to be used", 146}, {"-H", "1PI", "causes included files to be printed", 147}, {"-S?,+$,+*", "I$1$2", "specifies input files", 15}, {"-S?:+$", "I$1$2", "specifies input files", 15}, {"-V", "EVersions", "causes all tools to print their version numbers", 21}, {"-cc", "1CC", "forces the system compiler to be used", 23}, {"-cc_only", "2CC", "forces only the system compiler to be used", 22}, {"-do?+$", "SN$1$2", "sets a default output file name", 148}, {"-dump", "CDS", "dumps the current status", 200}, {"-ignore_case", "1LC", "ignores case in file names", 12}, {"-im0", "2CS", "disables intermodular checks", 148}, {"-info", "1SA", "causes API information to be printed", 201}, {"-keep_errors", "1KE", "causes files to be preserved on errors",13}, {"-make_up_names", "1MN", "makes up names for intermediate files", 149}, {"-message+$", "@X$1", "causes %s to print a message", 24}, {"-p", "1PF", "causes profiling information to be produced", 31}, {"-q", "0VB", "specifies quiet mode", 1}, {"-quiet", "0VB", "equivalent to -q", 1}, {"-query", "Q", "causes a list of options to be printed", 2}, {"-s?:+$", "SS$1$2|1SO", "specifies a suffix override", 25}, {"-show_errors", "1SE", "causes error producing commands to be shown", 3}, {"-show_env", "CSE", "causes the environment path to be printed", 202}, {"-special+$", "CSP:$1", "allows various internal options", 4}, {"-startup+$", "@D$1$n", "specifies a start-up option", 5}, {"-target+$", "AOC-target|AOC$1", "provided for cc compatibility", 150}, {"-temp+$", "STD$1", "specifies the temporary directory", 1}, {"-tidy", "1TU", "causes %s to tidy up as it goes along", 152}, {"-time", "1TI|1VB", "causes all commands to be timed", 153}, {"-verbose", "1VB", "equivalent to -v", 1}, {"-version", "CPV", "causes %s to print its version number", 1}, {"-w", "0WA", "suppresses %s warnings", 1}, {"-work+$", "SWD$1", "specifies the work directory",1}, /* Options not allowed in checker */ {"-G", "EGoption", "provided for cc compatibility", 154}, {"-K+$,+*", "EK-$1", "provided for cc compatibility", 155}, {"-Z$", "EZ-$1", "provided for cc compatibility", 156}, {"-b", "LSc", "suppresses -lc in system linking", 157}, {"-dn", "AOl$0", "passed to the system linker", 158}, {"-dy", "AOl$0", "passed to the system linker", 159}, {"-h+$", "AOl$0", "passed to the system linker", 160}, {"-no_startup_options", "0ST", "suppresses start-up options", 161}, {"-s", "1SR", "passed to the system linker", 162}, {"-u+$", "AOl$0", "passed to the system linker", 163}, {"-wsl", "Ewsl", "causes string literals to be made writable", 164}, {"-z+$", "AOl$0", "passed to the system linker", 165}, {"-#", "1VB", "equivalent to -v", 1}, {"-##", "1VB", "equivalent to -v",1 }, {"-###", "1VB|1DR", "equivalent to -dry", 1}, /* Default options */ {"--+$,+*", "$1", "communicates directly with the option interpreter", 0}, {"$", "XUnknown option,$s$0|AXO$0", "unknown option", 0}, /* End marker */ { null, null, null, 0 } }; /* * THE ENVIRONMENT OPTION MAP * * This table gives all the environment options. It needs to be kept * in line with Table 4. */ optmap environ_optmap [] = { /* Options */ {"\\+FLAG $", "=$1", null, 0}, {"\\+FLAG_TDFC $", "AOc$1", null, 0}, {"\\+FLAG_TDFCPP $", "AOp$1", null, 0}, {"\\+FLAG_TCPPLUS $", "AOx$1", null, 0}, {"\\+FLAG_TCPPLUSPP $", "AOg$1", null, 0}, {"\\+FLAG_TOT_CAT $", "", null, 0}, {"\\+FLAG_TLD $", "AOL$1", null, 0}, {"\\+FLAG_TRANS $", "AOt$1", null, 0}, {"\\+FLAG_AS $", "AOa$1", null, 0}, {"\\+FLAG_DYN_LINK $", "AOD$1", null, 0}, {"\\+FLAG_LD $", "AOl$1", null, 0}, {"\\+FLAG_DISP $", "AOd$1", null, 0}, {"\\+FLAG_TNC $", "AOn$1", null, 0}, {"\\+FLAG_PL_TDF $", "AOP$1", null, 0}, {"\\+FLAG_AS1 $", "AOA$1", null, 0}, {"\\+FLAG_TDFOPT $", "", null, 0}, {"\\+FLAG_SPEC_LINK $", "AOs$1", null, 0}, {"\\+FLAG_CPP_SPEC_LINK $", "AOS$1", null, 0}, {"\\+FLAG_DUMP_ANAL $", "AOe$1", null, 0}, {"\\+FLAG_DUMP_LINK $", "AOu$1", null, 0}, {"\\+FLAG_CC $", "AOC$1", null, 0}, {"\\+FLAG_INSTALL $", "AOI$1", null, 0}, /* Additional filename suffixes */ {"\\+SUFFIX_CPP $", "SSC$1|1SO", null, 0}, /* Executables */ {"?AS $", "$1Ea$2", null, 0}, {"?AS1 $", "$1EA$2", null, 0}, {"?BUILD_ARCH $", "$1BB$2", null, 0}, {"?CAT $", "$1BC$2", null, 0}, {"?CC $", "$1EC$2", null, 0}, {"?CPP_SPEC_LINK $", "$1ES$2", null, 0}, {"?DISP $", "$1Ed$2", null, 0}, {"?DUMP_ANAL $", "$1Ee$2", null, 0}, {"?DUMP_LINK $", "$1Eu$2", null, 0}, {"?DYN_LINK $", "$1ED$2", null, 0}, {"?LD $", "$1El$2", null, 0}, {"?MKDIR $", "$1BD$2", null, 0}, {"?MOVE $", "$1BM$2", null, 0}, {"?PL_TDF $", "$1EP$2", null, 0}, {"?REMOVE $", "$1BR$2", null, 0}, {"?SPEC_LINK $", "$1Es$2", null, 0}, {"?SPLIT_ARCH $", "$1BS$2", null, 0}, {"?TCPPLUS $", "$1Ex$2", null, 0}, {"?TCPPLUSPP $", "$1Eg$2", null, 0}, {"?TDFC $", "$1Ec$2", null, 0}, {"?TDFCPP $", "$1Ep$2", null, 0}, {"?TDFOPT $", "", null, 0}, {"?TLD $", "$1EL$2", null, 0}, {"?TNC $", "$1En$2", null, 0}, {"?TOUCH $", "$1BT$2", null, 0}, {"?TRANS $", "$1Et$2", null, 0}, /* * Set special env file variables. * These must be kept in sync with Table 5 in utility.c. */ {"$TENDRA_MACHDIR $", "CTV:0$2", null, 0}, {"$TENDRA_BINDIR $", "CTV:1$2", null, 0}, {"$TENDRA_ENVDIR $", "CTV:2$2", null, 0}, {"$TENDRA_LIBDIR $", "CTV:3$2", null, 0}, {"$TENDRA_INCLDIR $", "CTV:4$2", null, 0}, {"$TENDRA_STARTUPDIR $", "CTV:5$2", null, 0}, {"$TENDRA_TMPDIR $", "CTV:6$2", null, 0}, {"$TENDRA_BASEDIR $", "CTV:7$2", null, 0}, /* Flags */ {"?API $", "", null, 0}, {"?API_NAME $", "", null, 0}, {"?INCL $", "$1SI$2", null, 0}, {"?INCL_CPP $", "$1Si$2", null, 0}, {"?STARTUP_DIR $", "$1Sd$2", null, 0}, {"?STARTUP $", "$1Ss$2", null, 0}, {"?STARTUP_CPP_DIR $", "$1SD$2", null, 0}, {"?STARTUP_CPP $", "$1SS$2", null, 0}, {"?PORTABILITY $", "$1SP$2", null, 0}, {"?LINK $", "$1SJ$2", null, 0}, {"?LIB $", "$1Sj$2", null, 0}, {"?CRT0 $", "$1S0$2", null, 0}, {"?CRT1 $", "$1S1$2", null, 0}, {"?CRTN $", "$1S2$2", null, 0}, {"?CRTP_N $", "$1S3$2", null, 0}, {"?CRTI $", "$1S4$2", null, 0}, {"?SYS_LINK $", "$1SL$2", null, 0}, {"?SYS_LIB $", "$1Sl$2", null, 0}, {"?SYS_LIBC $", "$1Sc$2", null, 0}, {"?LINK_ENTRY $", "$1Se$2", null, 0}, /* Startup and endup lines */ {"\\+COMP_OPTION $", "@CAP:$1", null, 0}, {"\\+LINE_START $", "@D$1$n", null, 0}, {"\\+LINE_END $", "@F$1$n", null, 0}, /* Miscellaneous */ {"\\+INFO $", "@SAI$1", null, 0}, {">INFO $", "@SAI$SAI@plus@$1", null, 0}, {"= max_var) return (MATCH_OPT_ERR); loop++; } go = 0; } else { /* Terminated string : $c */ int l = 0; var [v].txt = q; while (*q != c) { if (*q == 0) return (MATCH_FAILED); l++; q++; } var [v].len = l; if (++v >= max_var) return (MATCH_OPT_ERR); } } else { /* Simple string : $ */ int l = (int) strlen (q); var [v].txt = q; var [v].len = l; if (++v >= max_var) return (MATCH_OPT_ERR); go = 0; } } else if (*p == '?') { if (p [1] == '*') { /* List of characters : ?* */ if (p [2]) return (MATCH_IN_ERR); loop = 0; loopv = v; while (*q) { var [v].txt = q; var [v].len = 1; if (++v >= max_var) return (MATCH_OPT_ERR); q++; loop++; } if (loop == 0) return (MATCH_FAILED); go = 0; } else { /* Simple character : ? */ if (*q == 0) return (MATCH_FAILED); var [v].txt = q; var [v].len = 1; if (++v >= max_var) return (MATCH_OPT_ERR); q++; } } else if (*p == '+') { /* Potential break : + */ if (*q == 0) return (MATCH_MORE); } else if (*p == '^') { /* Negated letter */ p++; if (*p == 0) return (MATCH_IN_ERR); if (*p == *q) return (MATCH_FAILED); q++; } else if (*p == '\\') { /* Escaped letter : \c */ p++; if (*p == 0) return (MATCH_IN_ERR); if (*p != *q) return (MATCH_FAILED); q++; } else { /* Letter : c */ if (*p != *q) return (MATCH_FAILED); q++; } p++; } /* Check end of option */ if (go && *q) return (MATCH_FAILED); /* The first variable is the whole option */ var [0].txt = opt; var [0].len = (int) strlen (opt); /* Print output */ a = 0; for (i = 0; i < loop; i++) { int count = 0; char buff [MAX_LINE]; q = buff; for (p = out; *p && count < MAX_LINE; p++, count++) { if (*p == '$') { /* Variable */ int n; char c = *(++p); if (c == 's') { /* $s expands to a space */ *(q++) = ' '; } else if (c == 'n') { /* $n expands to a newline */ *(q++) = '\n'; } else if (c >= '0' && c <= '9') { n = (c - '0'); if (n == loopv) n += i; if (n < v) { int l = var [n].len; IGNORE strncpy (q, var [n].txt, (size_t) l); q += l; } } else if (c == 'B') { boolean *b = lookup_bool (p + 1); if (b == null) return (MATCH_OUT_ERR); IGNORE sprintf (q, "%d", (int) *b); while (*q) q++; p += 2; } else if (c == 'L') { list *pt; list **sp = lookup_list (p + 1); if (sp == null) return (MATCH_OUT_ERR); for (pt = *sp; pt; pt = pt->next) { int l = (int) strlen (pt->item); IGNORE strncpy (q, pt->item, (size_t) l); q += l; *(q++) = ' '; } p += 2; } else if (c == 'S') { int l; char **sp = lookup_string (p + 1); if (sp == null) return (MATCH_OUT_ERR); if (*sp) { l = (int) strlen (*sp); IGNORE strncpy (q, *sp, (size_t) l); q += l; } p += 2; } else { return (MATCH_OUT_ERR); } } else if (*p == '|') { /* Multiple output */ *q = 0; res->argv [a] = string_copy (buff); if (++a >= max_var) return (MATCH_OPT_ERR); q = buff; } else if (*p == '\\') { /* Escaped output character */ if (*(++p) == 0) return (MATCH_OUT_ERR); *(q++) = *p; } else { /* Simple output character */ *(q++) = *p; } } *q = 0; res->argv [a] = string_copy (buff); if (++a >= max_var) return (MATCH_OPT_ERR); } res->argc = a; return (MATCH_OK); } /* * INTERPRET AN OPTION COMMAND */ static void interpret_cmd(char *cmd) { char c = *cmd; /* Debugging */ if (debug_options) MSG_interpreting (cmd); /* Deal with at-hack */ if (c == '@') { char *p = string_copy (cmd + 1), *q; for (q = p; *q; q++) { if (*q == '@') *q = ' '; } cmd = p; c = *p; } /* Deal with empty strings */ if (c == 0) return; /* Digits set values */ if (c >= '0' && c <= '9') { boolean *b = lookup_bool (cmd + 1); if (b == null) return; *b = (boolean) (c - '0'); return; } /* Translations */ if (c == '>') c = 'A'; if (c == '<') c = 'B'; if (c == '+') c = 'L'; /* Deal with list query */ if (c == '?') { if (cmd [1] == ':') { char **sp = lookup_string (cmd + 2); if (sp == null) return; comment (1, "%s=\"%s\"\n", cmd + 4, *sp); } else { list *p; list **sp = lookup_list (cmd + 1); if (sp == null) return; comment (1, "%s=\"", cmd + 3); for (p = *sp; p != null; p = p->next) { comment (1, "%s", p->item); if (p->next) comment (1, " "); } comment (1, "\"\n"); } return; } /* Deal with equivalences */ if (c == '=') { list *p = make_list (cmd + 1); process_options (p, main_optmap, 1); free_list (p); return; } /* Deal with primitives */ switch (c) { case 'A' : { /* Change list */ list **sp = lookup_list (cmd + 1); if (sp == null) return; *sp = add_list (*sp, make_list (cmd + 3)); return; } case 'B' : { /* Change list */ list **sp = lookup_list (cmd + 1); if (sp == null) return; *sp = add_list (make_list (cmd + 3), *sp); return; } case 'L' : { /* Change list */ list **sp = lookup_list (cmd + 1); if (sp == null) return; free_list (*sp); *sp = make_list (cmd + 3); return; } case 'C' : { /* Call */ char *arg = NULL; proc p = lookup_proc (cmd + 1); if (p == null) return; if (cmd [3] == ':') { arg = cmd + 4; } (*p) (arg); return; } case 'D' : { /* Startup options */ add_to_startup (cmd + 1); return; } case 'E' : { /* Environment */ if (cmd [1] == '?') { #if FS_STAT struct stat sb; #endif char *var = cmd + 2; char *val = strchr (var, '='); if (val == NULL) return; *val++ = '\0'; /* additional error checking for those platforms supporting stat */ #if FS_STAT if (stat (val, &sb) == -1) { MSG_interpret_cmd (val); } #endif if (!set_tendra_var (var, val)) MSG_ignoring_non_standard_env_assignment (var, val); } else { read_env (cmd + 1); } return; } case 'F' : { /* Endup options */ add_to_endup (cmd + 1); return; } case 'H' : { /* Halt */ char stage = cmd [1]; set_stage (find_type (stage, 0), STOP_STAGE); return; } case 'I' : { /* Input file */ int t; filename *f; char stage = cmd [1]; char *name = cmd + 2; if (stage == '?') { t = UNKNOWN_TYPE; } else { t = find_type (stage, 0); } f = find_filename (name, t); input_files = add_filename (input_files, f); return; } case 'K' : { /* Keep */ static int k = KEEP_STAGE; char stage = cmd [1]; if (stage == '-') { k = DONT_KEEP_STAGE; } else { set_stage (find_type (stage, 0), k); k = KEEP_STAGE; } return; } case 'Q' : { /* Query */ char *s; optmap *t = main_optmap; MSG_list_of_recognised_options (); while (s = t->in, s != null) { if (*s == '-') { char d; comment (0, " "); while (d = *(s++), d != 0) { switch (d) { case '$' : { IGNORE fputs ("", stderr); break; } case '?' : { IGNORE fputs ("", stderr); break; } case '*' : { IGNORE fputs ("...", stderr); break; } case '+' : { IGNORE fputc (' ', stderr); break; } case '\\' : { IGNORE fputc (*(s++), stderr); break; } default : { IGNORE fputc (d, stderr); break; } } } s = t->explain; if (s == null) s = "not documented"; comment (0, " : "); comment (0, s, progname); comment (0, ".\n"); } t++; } return; } case 'S' : { /* String */ char **s = lookup_string (cmd + 1); if (s == null) return; *s = cmd + 3; return; } case 'V' : { if (cmd [1] == 'B') { boolean *b = lookup_bool (cmd + 2); if (b == null) return; comment (1, "%c%c = %d\n", cmd [2], cmd [3], *b); return; } else if (cmd [1] == 'L') { list **sp = lookup_list (cmd + 2), *pt; if (sp == null) return; comment (1, "%c%c =", cmd [2], cmd [3]); for (pt = *sp; pt != null; pt = pt->next) { if (pt->item) { comment (1, " %s", pt->item); } else { comment (1, " (null)"); } } comment (1, "\n"); return; } else if (cmd [1] == 'S') { char **s = lookup_string (cmd + 2); if (s == null) return; if (*s) { comment (1, "%c%c = %s\n", cmd [2], cmd [3], *s); } else { comment (1, "%c%c = (null)\n", cmd [2], cmd [3]); } return; } break; } case 'X' : { /* Error */ MSG_X_error (cmd + 1); return; } } MSG_syntax_error (cmd); return; } /* * PROCESS A LIST OF OPTIONS * * This routine processes a list of options, opt, using the options * from table tab. */ void process_options(list *opt, optmap *tab, int fast) { optmap *t; list *p = opt; list *accum = null; char *arg = null; int status = MATCH_OK; int a; /* Scan through the options */ while (p != null) { if (status == MATCH_MORE) { arg = string_concat (arg, p->item); } else { arg = p->item; } status = MATCH_FAILED; for (t = tab; t->in != null; t++) { args_out res; status = match_option (t->in, t->out, arg, &res); switch (status) { case MATCH_OK : { /* Complete option - interpret result */ for (a = 0; a < res.argc; a++) { if (no_shuffle != 0 || fast == 1) { interpret_cmd (res.argv[a]); } else { ordered_node* dn = xalloc(sizeof(*dn)); dn->rank = t->rank; dn->cmd = res.argv[a]; accum = insert_inorder(dn, accum); } } goto end_search; } case MATCH_MORE : { /* Incomplete option - move on to next option */ goto end_search; } case MATCH_FAILED : { /* Try again */ break; } case MATCH_IN_ERR : { /* Error in optmap input */ MSG_illegal_input (t->in); status = MATCH_FAILED; break; } case MATCH_OUT_ERR : { /* Error in optmap output */ MSG_illegal_option (t->out); status = MATCH_FAILED; break; } case MATCH_OPT_ERR : { /* Ran out of space for result */ MSG_too_many_components (arg); status = MATCH_FAILED; break; } } } MSG_cant_interpret (arg); end_search : p = p->next; } /* Check for incomplete options */ if (status == MATCH_MORE) { MSG_option_is_incomplete (arg); } /* if the no_shuffle flag is unset, we have order cmds to run */ if (no_shuffle == 0 && fast == 0) { while (accum) { ordered_node* dn; dn = accum->item; interpret_cmd (dn->cmd); accum = accum->next; } } return; }