coan 4.2.4
|
00001 /*************************************************************************** 00002 * Copyright (C) 2004, 2006 Symbian Software Ltd. * 00003 * All rights reserved. * 00004 * Copyright (C) 2007-2011 Mike Kinghan, imk@strudl.org * 00005 * All rights reserved. * 00006 * * 00007 * Contributed originally by Mike Kinghan, imk@strudl.org * 00008 * * 00009 * Redistribution and use in source and binary forms, with or without * 00010 * modification, are permitted provided that the following conditions * 00011 * are met: * 00012 * * 00013 * Redistributions of source code must retain the above copyright * 00014 * notice, this list of conditions and the following disclaimer. * 00015 * * 00016 * Redistributions in binary form must reproduce the above copyright * 00017 * notice, this list of conditions and the following disclaimer in the * 00018 * documentation and/or other materials provided with the distribution. * 00019 * * 00020 * Neither the name of Symbian Software Ltd. nor the names of its * 00021 * contributors may be used to endorse or promote products derived from * 00022 * this software without specific prior written permission. * 00023 * * 00024 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 00025 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * 00026 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * 00027 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * 00028 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * 00029 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * 00030 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * 00031 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * 00032 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,* 00033 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * 00034 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * 00035 * DAMAGE. * 00036 * * 00037 **************************************************************************/ 00038 00039 #include "platform.h" 00040 #include "args.h" 00041 #include "report.h" 00042 #include "contradiction.h" 00043 #include "io.h" 00044 #include "line_despatch.h" 00045 #include "configured_symbols.h" 00046 #include "filesys.h" 00047 #include "dataset.h" 00048 00049 00057 00059 STATE_DEF(args) 00060 { 00062 INCLUDE_PUBLIC(args); 00063 ptr_vector_h argfile_argv; 00065 char *memfile; 00067 int arg_dirs_ignored; 00071 } 00072 STATE_T(args); 00077 00078 IMPLEMENT(args,USER_INITABLE) 00079 00080 00084 DEFINE_USER_INIT(args)(STATE_T(args) * args_st) 00085 { 00086 args_st->argfile_argv = ptr_vector_new(NULL,NULL); 00087 } 00088 00093 DEFINE_USER_FINIS(args)(STATE_T(args) * args_st) 00094 { 00095 ptr_vector_dispose((SET_STATE(args,argfile_argv))); 00096 SET_STATE(args,argfile_argv) = NULL; 00097 } 00102 00104 #define PROGRESS_GAGGED() \ 00105 ((GET_PUBLIC(args,diagnostic_filter) & MSGCLASS_PROGRESS) != 0) 00106 00107 00109 enum option_codes { 00110 OPT_FILE = 'f', 00111 OPT_REPLACE = 'r', 00112 OPT_BACKUP = 'b', 00113 OPT_DEF = 'D', 00114 OPT_UNDEF = 'U', 00115 OPT_CONFLICT = 'x', 00116 OPT_GAG = 'g', 00117 OPT_VERBOSE = 'V', 00118 OPT_COMPLEMENT = 'c', 00119 OPT_DEBUG = 1, 00120 OPT_EVALCONSTS = 'E', 00121 OPT_DISCARD = 'k', 00122 OPT_LINE = 2, 00123 OPT_POD = 'P', 00124 OPT_RECURSE = 'R', 00125 OPT_FILTER = 'F', 00126 OPT_KEEPGOING = 'K', 00127 OPT_IFS = 'i', 00128 OPT_DEFS = 'd', 00129 OPT_UNDEFS = 'u', 00130 OPT_INCLUDES = 3, 00131 OPT_LOCATE = 'L', 00132 OPT_ONCE = 'o', 00133 OPT_SYSTEM = 's', 00134 OPT_LOCAL = 'l', 00135 OPT_ACTIVE = 'A', 00136 OPT_INACTIVE = 'I', 00137 OPT_EVALSYMS = 'e', 00138 OPT_IMPLICIT = 'm' 00139 }; 00140 00143 static struct option long_options [] = { 00144 { "file", required_argument, NULL, OPT_FILE }, 00145 { "replace",no_argument, NULL, OPT_REPLACE }, 00146 { "backup",required_argument,NULL,OPT_BACKUP}, 00147 { "define", required_argument, NULL, OPT_DEF }, 00148 { "undef", required_argument, NULL, OPT_UNDEF }, 00149 { "conflict", required_argument, NULL, OPT_CONFLICT }, 00150 { "gag", required_argument, NULL, OPT_GAG }, 00151 { "verbose", no_argument, NULL, OPT_VERBOSE }, 00152 { "complement", no_argument, NULL, OPT_COMPLEMENT }, 00153 { "debug", no_argument, NULL, OPT_DEBUG }, 00154 { "evalconsts", no_argument, NULL, OPT_EVALCONSTS }, 00155 { "discard", required_argument, NULL, OPT_DISCARD }, 00156 { "line", no_argument, NULL, OPT_LINE }, 00157 { "pod", no_argument, NULL, OPT_POD }, 00158 { "recurse", no_argument, NULL, OPT_RECURSE }, 00159 { "filter", required_argument, NULL, OPT_FILTER }, 00160 { "keepgoing", no_argument, NULL, OPT_KEEPGOING }, 00161 { "ifs", no_argument, NULL, OPT_IFS }, 00162 { "defs", no_argument, NULL, OPT_DEFS }, 00163 { "undefs", no_argument, NULL, OPT_UNDEFS }, 00164 { "includes", no_argument, NULL, OPT_INCLUDES }, 00165 { "locate", no_argument, NULL, OPT_LOCATE }, 00166 { "once", no_argument, NULL, OPT_ONCE }, 00167 { "system", no_argument, NULL, OPT_SYSTEM }, 00168 { "local", no_argument, NULL, OPT_LOCAL }, 00169 { "active", no_argument, NULL, OPT_ACTIVE }, 00170 { "inactive", no_argument, NULL, OPT_INACTIVE }, 00171 { "evalsyms", no_argument, NULL, OPT_EVALSYMS }, 00172 { "implicit", no_argument, NULL, OPT_IMPLICIT }, 00173 { 0, 0, 0, 0 } 00174 }; 00175 00181 static char opts[(sizeof(long_options)/sizeof(struct option)) * 3]; 00182 00184 static struct cmd_option commands [] = { 00185 { "help", CMD_HELP, CMD_HELP_MASK }, 00186 { "-h", CMD_HELP, CMD_HELP_MASK }, 00187 { "--help", CMD_HELP, CMD_HELP_MASK }, 00188 { "version", CMD_VERSION, CMD_VERSION_MASK }, 00189 { "-v", CMD_VERSION, CMD_VERSION_MASK }, 00190 { "--version", CMD_VERSION, CMD_VERSION_MASK }, 00191 { "source", CMD_SOURCE, CMD_SOURCE_MASK }, 00192 { "symbols", CMD_SYMBOLS, CMD_SYMBOLS_MASK }, 00193 { "includes", CMD_INCLUDES, CMD_INCLUDES_MASK }, 00194 { "defs", CMD_DEFS, CMD_DEFS_MASK }, 00195 { "pragmas", CMD_PRAGMAS, CMD_PRAGMAS_MASK }, 00196 { "errors", CMD_ERRORS, CMD_ERRORS_MASK }, 00197 { "directives", CMD_DIRECTIVES, CMD_DIRECTIVES_MASK }, 00198 { 0, 0 } 00199 }; 00200 00202 static int const source_cmd_exclusions[] = { 00203 OPT_IFS, OPT_DEFS, OPT_UNDEFS, OPT_INCLUDES, OPT_LOCATE, 00204 OPT_ONCE, OPT_SYSTEM, OPT_LOCAL, OPT_ACTIVE, OPT_INACTIVE, 00205 OPT_EVALSYMS, 0 00206 }; 00208 static int const symbols_cmd_exclusions[] = { 00209 OPT_REPLACE, OPT_CONFLICT, OPT_DISCARD, OPT_LINE, OPT_SYSTEM, 00210 OPT_LOCAL, OPT_BACKUP, OPT_COMPLEMENT, 0 00211 }; 00213 static int const includes_cmd_exclusions[] = { 00214 OPT_REPLACE, OPT_CONFLICT, OPT_DISCARD, OPT_LINE, OPT_BACKUP, 00215 OPT_IFS, OPT_DEFS, OPT_UNDEFS, OPT_INCLUDES, OPT_COMPLEMENT, OPT_EVALSYMS, 0 00216 }; 00218 static int const directives_cmd_exclusions[] = { 00219 OPT_REPLACE, OPT_CONFLICT, OPT_DISCARD, OPT_LINE, OPT_BACKUP, 00220 OPT_IFS, OPT_DEFS, OPT_UNDEFS, OPT_INCLUDES, OPT_COMPLEMENT, OPT_EVALSYMS, 0 00221 }; 00223 static int const defs_cmd_exclusions[] = { 00224 OPT_REPLACE, OPT_CONFLICT, OPT_DISCARD, OPT_LINE, OPT_BACKUP, 00225 OPT_SYSTEM, OPT_LOCAL, OPT_IFS, OPT_DEFS, OPT_UNDEFS, OPT_INCLUDES, 00226 OPT_COMPLEMENT, OPT_EVALSYMS, 0 00227 }; 00229 static int const pragmas_cmd_exclusions[] = { 00230 OPT_REPLACE, OPT_CONFLICT, OPT_DISCARD, OPT_LINE, OPT_BACKUP, 00231 OPT_SYSTEM, OPT_LOCAL, OPT_IFS, OPT_DEFS, OPT_UNDEFS, OPT_INCLUDES, 00232 OPT_COMPLEMENT, OPT_EVALSYMS, 0 00233 }; 00235 static int const errors_cmd_exclusions[] = { 00236 OPT_REPLACE, OPT_CONFLICT, OPT_DISCARD, OPT_LINE, OPT_BACKUP, 00237 OPT_SYSTEM, OPT_LOCAL, OPT_IFS, OPT_DEFS, OPT_UNDEFS, OPT_INCLUDES, 00238 OPT_COMPLEMENT, OPT_EVALSYMS, 0 00239 }; 00240 00241 00242 00246 static struct exclusion_list const cmd_exclusion_lists[] = { 00247 /* Dummy 0th element*/ 00248 { 0, NULL }, 00249 /* Exclusion list for the help command*/ 00250 { CMD_HELP, NULL }, 00251 /* Exclusion list the version command*/ 00252 { CMD_VERSION, NULL }, 00253 /* Exclusion list the code command*/ 00254 { CMD_SOURCE, source_cmd_exclusions}, 00255 /* Exclusion list for the symbols command*/ 00256 { CMD_SYMBOLS, symbols_cmd_exclusions }, 00257 /* Exclusion list for the includes command*/ 00258 { CMD_INCLUDES, includes_cmd_exclusions }, 00259 /* Exclusion list for the defs command*/ 00260 { CMD_DEFS, defs_cmd_exclusions }, 00261 /* Exclusion list for the pragmas command*/ 00262 { CMD_PRAGMAS, pragmas_cmd_exclusions }, 00263 /* Exclusion list for the pragmas command*/ 00264 { CMD_ERRORS, errors_cmd_exclusions }, 00265 /* Exclusion list for the directives command*/ 00266 { CMD_DIRECTIVES, directives_cmd_exclusions }, 00267 { 0, NULL } 00268 }; 00269 00277 static void 00278 make_opts_list(void) 00279 { 00280 struct option * longopt = long_options; 00281 char *opts_str = opts; 00282 for ( ; longopt->name; ++longopt, ++opts_str) { 00283 *opts_str = longopt->val; 00284 switch(longopt->has_arg) { 00285 case no_argument: 00286 break; 00287 case optional_argument: 00288 ++opts_str; 00289 *opts_str = ':'; 00290 /* Yes, fall through */ 00291 case required_argument: 00292 ++opts_str; 00293 *opts_str = ':'; 00294 break; 00295 default: 00296 assert(0); 00297 } 00298 } 00299 } 00300 00301 00305 static void 00306 usage(FILE * fp) 00307 { 00308 const char *prog_name = GET_PUBLIC(args,prog_name); 00309 00310 fprintf(fp,"usage:\n" 00311 "%s COMMAND [OPTION... [FILE...]]\n" 00312 "1. %s { help | --help | -h }\n" 00313 "\tDisplay this message and exit.\n" 00314 "2. %s { version | --version | -v }\n" 00315 "\tDisplay version information and exit.\n" 00316 "3. %s source OPTION... [FILE...]\n" 00317 "\tSimplify source FILEs in accordance with OPTIONs, " 00318 "parsing in the manner of the C preprocessor.\n" 00319 "\tInput lines may be dropped from output. Truth functional directives " 00320 "may be simplified on output.\n" 00321 "4. %s symbols OPTION... [FILE...]\n" 00322 "\tList preprocessor symbols from FILEs in accordance with " 00323 "OPTIONs, parsing in the manner of the C preprocessor.\n" 00324 "5. %s includes OPTION... [FILE...]\n" 00325 "\tList #includes fom FILEs in accordance with OPTIONs, parsing in " 00326 "the manner of the C preprocessor\n" 00327 "6. %s defs OPTION... [FILE...]\n" 00328 "\tList #defines and #undefs fom FILEs in accordance with OPTIONs, " 00329 "parsing in the manner of the C preprocessor.\n" 00330 "7. %s pragmas OPTION... [FILE...]\n" 00331 "\tList #pragmas fom FILEs in accordance with OPTIONs, parsing in the " 00332 "manner of the C preprocessor\n" 00333 "8. %s directives OPTION... [FILE...]\n" 00334 "\tList #-directives fom FILEs in accordance with OPTIONs, " 00335 "parsing in the manner of the C preprocessor. " 00336 "(Directives are #includes, #defines, #undefs, " 00337 "#pragmas, #errors).\n" 00338 "General OPTIONS:\n" 00339 "\t-fARGFILE, --file ARGFILE\n" 00340 "\t\tRead other arguments from ARGFILE.\n" 00341 "\t-R, --recurse\n" 00342 "\t\tRecurse into directories to find input files.\n" 00343 "\t-FEXT1[,EXT2...]\n" 00344 "\t--filter EXT1[,EXT2...]\n" 00345 "\t\tProcess only input files that have one of the file extensions " 00346 "EXT1,EXT2...\n" 00347 "\t-DSYM[=VAL], --define SYM[=VAL]\n" 00348 "\t\tAssume symbol SYM to be defined [=VAL]\n" 00349 "\t-USYM, --undef SYM\n" 00350 "\t\tAssume symbol SYM to be undefined.\n" 00351 "\t-m, --implicit\n" 00352 "\t\tAssume that any symbol that is not --define-ed is implicitly --undef-ed.\n" 00353 "\t-g{p|i|w|e|a},\n" 00354 "\t--gag { progress| info | warning | error | abend }\n" 00355 "\t\tSuppress diagnostics no worse than " 00356 "{progress | info | warning | error | abend}.\n" 00357 "\t-gs, --gag summary\n" 00358 "\t\tSuppress summary diagnostics at exit.\n" 00359 "\t\t(Default: -gp -gi -gs)\n" 00360 "\t-V, --verbose\n" 00361 "\t\tOutput all diagnostics.\n" 00362 "\t--debug\n" 00363 "\t\tDisplay debugging info.\n" 00364 "\t-K, --keepgoing\n" 00365 "\t\tIf a parse error is encountered in an input file, continue " 00366 "processing subsequent input files.\n" 00367 "\t-P, --pod\n" 00368 "\t\tApart from #-directives, input is Plain Old Data.\n" 00369 "\t\tComments and quotations will not be parsed.\n" 00370 "\t-E, --evalconsts\n" 00371 "\t\tEvaluate constants occurring as truth-functional operands #ifs. " 00372 "By default constants as truth-functional operands are not evaluated.\n" 00373 "source OPTIONs:-\n" 00374 "\t-r, --replace\n" 00375 "\t\tOverwrite input file with output file. Implied by --recurse\n" 00376 "\t\tWith -r, stdin supplies the input *filenames*.\n" 00377 "\t\tOtherwise stdin supplies an input *file*; " 00378 "the output file is stdout.\n" 00379 "\t-BSUFFIX, --backup SUFFIX\n" 00380 "\t\tBackup each input file by appending SUFFIX to the name.\n" 00381 "\t\tApplies only with -r.\n" 00382 "\t-kd, --discard drop\n" 00383 "\t\tDrop discarded lines from output.\n" 00384 "\t-kb, --discard blank\n" 00385 "\t\tBlank discarded lines on output.\n" 00386 "\t-kc, --discard comment\n" 00387 "\t\tComment out discarded lines on output.\n" 00388 "\t-xd, --conflict delete\n" 00389 "\t\tDelete #defines and #undefs that contradict -D or -U options.\n" 00390 "\t-xc, --conflict comment\n" 00391 "\t\tInsert diagnostic comments on contradictions as per -xd. " 00392 "(Default.)\n" 00393 "\t-xe, --conflict error\n" 00394 "\t\tInsert diagnostic #errors on contradictions as per -xd.\n" 00395 "\t--line\n" 00396 "\t\tGenerate #line directives to make CPP line-numbering of output " 00397 "agree with input even of lines are dropped.\n" 00398 "\t-c, --complement\n" 00399 "\t\tComplement. Retain the lines that ought to be dropped and " 00400 "vice versa.\n" 00401 "\t\t(Retained #-directives will still be simplified where possible.)\n" 00402 "symbols OPTIONs:-\n" 00403 "\t-i, --ifs\n" 00404 "\t\tList symbols that occur #if[[n]def]/#elif directives.\n" 00405 "\t-d, --defs\n" 00406 "\t\tList symbols that occur in #define directives.\n" 00407 "\t-u, --undefs\n" 00408 "\t\tList symbols that occur in #undef directives.\n" 00409 "\t--includes\n" 00410 "\t\tList symbols that occur in #include directives.\n" 00411 "\t(Default: -i -d -u --includes)\n" 00412 "\t-o, --once\n" 00413 "\t\tList only the first occurrence of each symbol. " 00414 "(Default: List all occurrences.)\n" 00415 "\t-A, --active\n" 00416 "\t\tList only symbols from operative directives\n" 00417 "\t-I, --inactive\n" 00418 "\t\tList only symbols from inoperative directives\n" 00419 "\t-L, --locate\n" 00420 "\t\tReport the source file and line number of each listed " 00421 "occurrence.\n" 00422 "\t-e, --evalsyms\n" 00423 "\t\tReport the resolved value of each symbol.\n" 00424 "includes OPTIONs:-\n" 00425 "\t-s, --system\n" 00426 "\t\tList system headers, i.e. <header.h>\n" 00427 "\t-L, --local\n" 00428 "\t\tList local headers, i.e. \"header.h\"\n" 00429 "\t(Default: -s -L)\n" 00430 "\t-o, --once\n" 00431 "\t\tList only the first occurrence of each header. " 00432 "(Default: List all occurrences.)\n" 00433 "\t-A --active\n" 00434 "\t\tList only headers from operative directives.\n" 00435 "\t-I --inactive\n" 00436 "\t\tList only headers from inoperative directives.\n" 00437 "\t-L, --locate\n" 00438 "\t\tReport the source file and line number of each listed " 00439 "occurrence.\n" 00440 "defs OPTIONs:-\n" 00441 "\t-o, --once\n" 00442 "\t\tList only the first occurrence of each distinct #define or " 00443 "#undef directive (Default: List all occurrences.)\n" 00444 "\t-A --active\n" 00445 "\t\tList only operative #define and #undef directives.\n" 00446 "\t-I --inactive\n" 00447 "\t\tList only inoperative #define and #undef directives.\n" 00448 "\t-L, --locate\n" 00449 "\t\tReport the source file and line number of each listed " 00450 "occurrence.\n" 00451 "pragmas OPTIONs:-\n" 00452 "\t-o, --once\n" 00453 "\t\tList only the first occurrence of each distinct pragma " 00454 "(Default: List all occurrences.)\n" 00455 "\t-A, --active\n" 00456 "\t\tList only pragmas from lines that are retained.\n" 00457 "\t-I, --inactive\n" 00458 "\t\tList only pragmas from lines that are dropped.\n" 00459 "\t-L, --locate\n" 00460 "\t\tReport the source file and line number of each listed " 00461 "occurrence.\n" 00462 "errors OPTIONs:-\n" 00463 "\t-o, --once\n" 00464 "\t\tList only the first occurrence of each #error directive " 00465 "(Default: List all occurrences.)\n" 00466 "\t-A, --active\n" 00467 "\t\tList only operative #error directives.\n" 00468 "\t-I, --inactive\n" 00469 "\t\tList only inoperative #error directives.\n" 00470 "\t-L, --locate\n" 00471 "\t\tReport the source file and line number of each listed " 00472 "occurrence.\n" 00473 "directives OPTIONs:-\n" 00474 "\t-o, --once\n" 00475 "\t\tList only the first occurrence of each distinct directive " 00476 "(Default: List all occurrences.)\n" 00477 "\t-A, --active\n" 00478 "\t\tList only operative directives.\n" 00479 "\t-I, --inactive\n" 00480 "\t\tList only inoperative directives.\n" 00481 "\t-L, --locate\n" 00482 "\t\tReport the source file and line number of each listed " 00483 "occurrence.\n", 00484 prog_name,prog_name,prog_name, 00485 prog_name,prog_name,prog_name, 00486 prog_name,prog_name,prog_name); 00487 } 00488 00492 static void 00493 usage_error_summary(void) 00494 { 00495 usage(stderr); 00496 } 00497 00507 static void 00508 usage_error(int reason, const char *format,...) 00509 { 00510 if (format) { 00511 va_list argp; 00512 atexit(usage_error_summary); 00513 va_start(argp,format); 00514 vbail(reason,format,argp); 00515 va_end(argp); 00516 } else { 00517 usage_error(GRIPE_USAGE_ERROR,"Invalid usage"); 00518 } 00519 } 00520 00525 static void 00526 usage_help(void) 00527 { 00528 usage(stdout); 00529 exit(MSGCLASS_NONE); 00530 } 00531 00532 #ifndef VERSION 00533 #ifdef NIX 00534 #error VERSION not defined. 00535 #endif 00536 00539 #define VERSION "4.2.3" 00540 #endif 00541 00543 static void 00544 version(void) 00545 { 00546 printf("%s, version %s for %s (built %s, %s)\n", 00547 GET_PUBLIC(args,prog_name),VERSION,OS_TYPE,__DATE__,__TIME__); 00548 exit(MSGCLASS_NONE); 00549 } 00550 00555 static void 00556 config_diagnostics(const char * arg) 00557 { 00558 int mask = MSGCLASS_NONE; 00559 if (GET_PUBLIC(args,diagnostic_filter) < 0 && strcmp(arg,"verbose")) { 00560 report(GRIPE_VERBOSE_ONLY,NULL, 00561 "Can't mix --verbose with --gag.'--gag %s' ignored",arg); 00562 return; 00563 } 00564 if (!strcmp(arg,"progress")) { 00565 mask = MSGCLASS_PROGRESS; 00566 } else if (!strcmp(arg,"info")) { 00567 mask = MSGCLASS_INFO; 00568 } else if (!strcmp(arg,"warning")) { 00569 mask = MSGCLASS_WARNING; 00570 } else if (!strcmp(arg,"error")) { 00571 mask = MSGCLASS_ERROR; 00572 } else if (!strcmp(arg,"abort")) { 00573 mask = MSGCLASS_ABEND; 00574 } else if (!strcmp(arg,"summary")) { 00575 mask = MSGCLASS_SUMMARY; 00576 } else if (!strcmp(arg,"verbose")) { 00577 int diagnostic_filter = GET_PUBLIC(args,diagnostic_filter); 00578 if (diagnostic_filter > 0) { 00579 report(GRIPE_VERBOSE_ONLY,NULL, 00580 "Can't mix --verbose with --gag. '--verbose' ignored"); 00581 return; 00582 } else if (diagnostic_filter < 0) { 00583 report(GRIPE_DUPLICATE_MASK,NULL,"'--verbose' already seen"); 00584 return; 00585 } 00586 SET_PUBLIC(args,diagnostic_filter) = -1; 00587 return; 00588 } else { 00589 usage_error(GRIPE_USAGE_ERROR,"Invalid argument for --gag: \"%s\"",arg); 00590 } 00591 if (mask & GET_PUBLIC(args,diagnostic_filter)) { 00592 report(GRIPE_DUPLICATE_MASK,NULL, 00593 "'--gag %s' already seen",arg); 00594 } 00595 SET_PUBLIC(args,diagnostic_filter) |= mask; 00596 if (mask == MSGCLASS_INFO) { 00597 config_diagnostics("progress"); 00598 } else if (mask == MSGCLASS_WARNING) { 00599 config_diagnostics("info"); 00600 } else if (mask == MSGCLASS_ERROR) { 00601 config_diagnostics("warning"); 00602 } else if (mask == MSGCLASS_ABEND) { 00603 config_diagnostics("error"); 00604 } 00605 } 00606 00612 static void 00613 finalise_diagnostics(void) 00614 { 00615 int mask = GET_PUBLIC(args,diagnostic_filter); 00616 if (!mask) { 00617 /* Default diagnostic masking to no progress 00618 messages, no infos, no summaries*/ 00619 config_diagnostics("info"); 00620 config_diagnostics("summary"); 00621 } else if (mask == -1) { 00622 /* --verbose was temporarily set as -1 to block later 00623 --gag options. Can now reset as 0*/ 00624 SET_PUBLIC(args,diagnostic_filter) = 0; 00625 } 00626 } 00627 00633 static void 00634 error_invalid_opt(cmd_option_t const *cmd, int bad_opt) 00635 { 00636 char const *cmdname = cmd->name; 00637 char const *optname = get_long_opt_name(long_options,bad_opt); 00638 assert(optname); 00639 usage_error(GRIPE_INVALID_ARGS, 00640 "\"%s\" is not a valid option for command \"%s\"",optname,cmdname); 00641 } 00642 00664 static bool 00665 add_files(char const *path) 00666 { 00667 bool verdict = true; 00668 fs_obj_type_t obj_type = fs_obj_type(path); 00669 if (obj_type == FS_OBJ_NONE) { 00670 report(GRIPE_NO_FILE,NULL, 00671 "No such file or directory as \"%s\"",path); 00672 verdict = false; 00673 } 00674 else if (FS_IS_FILE(obj_type)) { 00675 dataset_add(path); 00676 } 00677 else if (FS_IS_DIR(obj_type)) { 00678 if (!GET_PUBLIC(args,recurse)) { 00679 report(GRIPE_DIR_IGNORED,NULL, 00680 "--recurse not specified. Ignoring directory \"%s\"",path); 00681 verdict = false; 00682 } 00683 dataset_add(path); 00684 } 00685 else if (FS_IS_SLINK(obj_type)) { 00686 report(GRIPE_BROKEN_SYMLINK,NULL, 00687 "Broken symbolic link \"%s\" ignored",path); 00688 verdict = false; 00689 } 00690 else { 00691 assert(0); 00692 } 00693 return verdict; 00694 } 00695 00696 /* Forward decl*/ 00697 static void 00698 parse_args_file(const char *argsfile); 00699 00700 00705 static void 00706 parse_command_args(int argc, char *argv[]) 00707 { 00708 static bool parsing_file; 00709 int args = argc; 00710 int opt, save_ind, long_index; 00711 cmd_option_t const * command = GET_PUBLIC(args,command); 00712 if (!opts[0]) { 00713 make_opts_list(); 00714 } 00715 for ( optind = 0; 00716 (opt = getopt_long(argc,argv,opts,long_options,&long_index)) != -1; ) { 00717 if (!opts_are_compatible(command->cmd_code,opt,cmd_exclusion_lists,true)) { 00718 error_invalid_opt(command,opt); 00719 } 00720 switch (opt) { 00721 case OPT_FILE: /* Read further args from file*/ 00722 save_ind = optind; 00723 /* Remember where we have parsed up to*/ 00724 parsing_file = true; 00725 parse_args_file(optarg); /* Parse file*/ 00726 parsing_file = false; 00727 optind = save_ind; /* Restore position*/ 00728 break; 00729 case OPT_CONFLICT: { /* Policy for contradictions*/ 00730 int conflict_policy = CONTRADICTION_COMMENT; 00731 if (strlen(optarg) > 1) { 00732 if (!strcmp(optarg,"delete")) { 00733 conflict_policy = CONTRADICTION_DELETE; 00734 } else if (!strcmp(optarg,"comment")) { 00735 conflict_policy = CONTRADICTION_COMMENT; 00736 } else if (!strcmp(optarg,"error")) { 00737 conflict_policy = CONTRADICTION_ERROR; 00738 } else { 00739 usage_error(GRIPE_USAGE_ERROR, 00740 "Invalid argument for --conflict: \"%s\"",optarg); 00741 } 00742 } else { 00743 switch(*optarg) { 00744 case 'd': 00745 conflict_policy = CONTRADICTION_DELETE; 00746 break; 00747 case 'c': 00748 conflict_policy = CONTRADICTION_COMMENT; 00749 break; 00750 case 'e': 00751 conflict_policy = CONTRADICTION_ERROR; 00752 break; 00753 default: 00754 usage_error(GRIPE_USAGE_ERROR, 00755 "Invalid argument for -x: \"%c\"",*optarg); 00756 } 00757 } 00758 contradiction_policy(conflict_policy); 00759 } 00760 break; 00761 case OPT_GAG: { 00762 char const *gag_arg = optarg; 00763 if (strlen(optarg) == 1) { 00764 switch(*optarg) { 00765 case 'p': 00766 gag_arg = "progress"; 00767 break; 00768 case 'i': 00769 gag_arg = "info"; 00770 break; 00771 case 'w': 00772 gag_arg = "warning"; 00773 break; 00774 case 'e': 00775 gag_arg = "error"; 00776 break; 00777 case 'a': 00778 gag_arg = "abend"; 00779 break; 00780 case 's': 00781 gag_arg = "summary"; 00782 break; 00783 default: 00784 assert(false); 00785 } 00786 } 00787 config_diagnostics(gag_arg); 00788 } 00789 break; 00790 case OPT_VERBOSE: 00791 config_diagnostics("verbose"); 00792 break; 00793 case OPT_DEF: /* define a symbol*/ 00794 symbol_evaluate_status(true,optarg,NULL,NULL); 00795 break; 00796 case OPT_UNDEF: /* undef a symbol*/ 00797 symbol_evaluate_status(false,optarg,NULL,NULL); 00798 break; 00799 case OPT_COMPLEMENT: /* treat -D as -U and vice versa*/ 00800 SET_PUBLIC(args,complement) = true; 00801 break; 00802 case OPT_REPLACE: 00803 SET_PUBLIC(args,replace) = true; 00804 break; 00805 case OPT_BACKUP: 00806 SET_PUBLIC(args,backup_suffix) = optarg; 00807 break; 00808 case OPT_DEBUG: 00809 debugging(true); 00810 break; 00811 case OPT_EVALCONSTS: 00812 SET_PUBLIC(args,eval_consts) = true; 00813 break; 00814 case OPT_DISCARD: /* policy for discarding lines on output*/ 00815 if (strlen(optarg) > 1) { 00816 if (!strcmp("drop",optarg)) { 00817 SET_PUBLIC(args,discard_policy) = DISCARD_DROP; 00818 } else if (!strcmp("blank",optarg)) { 00819 SET_PUBLIC(args,discard_policy) = DISCARD_BLANK; 00820 } else if (!strcmp("comment",optarg)) { 00821 SET_PUBLIC(args,discard_policy) = DISCARD_COMMENT; 00822 } else { 00823 usage_error(GRIPE_USAGE_ERROR, 00824 "Invalid argument for --discard: \"%s\"",optarg); 00825 } 00826 } else { 00827 switch(*optarg) { 00828 case 'd': 00829 SET_PUBLIC(args,discard_policy) = DISCARD_DROP; 00830 break; 00831 case 'b': 00832 SET_PUBLIC(args,discard_policy) = DISCARD_BLANK; 00833 break; 00834 case 'c': 00835 SET_PUBLIC(args,discard_policy) = DISCARD_COMMENT; 00836 break; 00837 default: 00838 usage_error(GRIPE_USAGE_ERROR, 00839 "Invalid argument for -k: \"%c\"",*optarg); 00840 } 00841 } 00842 break; 00843 case OPT_LINE: 00844 SET_PUBLIC(args,line_directives) = true; 00845 break; 00846 case OPT_LOCATE: 00847 SET_PUBLIC(args,list_locate) = true; 00848 break; 00849 case OPT_ACTIVE: 00850 SET_PUBLIC(args,list_only_active) = true; 00851 break; 00852 case OPT_INACTIVE: 00853 SET_PUBLIC(args,list_only_inactive) = true; 00854 break; 00855 case OPT_EVALSYMS: 00856 SET_PUBLIC(args,resolve_symbols) = true; 00857 break; 00858 case OPT_ONCE: 00859 SET_PUBLIC(args,list_only_once) = true; 00860 break; 00861 case OPT_IFS: 00862 SET_PUBLIC(args,list_symbols_in_ifs) = true; 00863 break; 00864 case OPT_DEFS: 00865 SET_PUBLIC(args,list_symbols_in_defs) = true; 00866 break; 00867 case OPT_UNDEFS: 00868 SET_PUBLIC(args,list_symbols_in_undefs) = true; 00869 break; 00870 case OPT_INCLUDES: 00871 SET_PUBLIC(args,list_symbols_in_includes) = true; 00872 break; 00873 case OPT_SYSTEM: 00874 SET_PUBLIC(args,list_system_includes) = true; 00875 break; 00876 case OPT_LOCAL: 00877 SET_PUBLIC(args,list_local_includes) = true; 00878 break; 00879 case OPT_POD: /* don't parse quotes or comments*/ 00880 SET_PUBLIC(args,plaintext) = true; 00881 break; 00882 case OPT_RECURSE: /* recurse into directories*/ 00883 SET_PUBLIC(args,recurse) = true; 00884 if (command->cmd_code == CMD_SOURCE) { 00885 SET_PUBLIC(args,replace) = true; 00886 } 00887 break; 00888 case OPT_FILTER: /* Filter input by file extensions*/ 00889 dataset_filter_filetypes(optarg); 00890 break; 00891 case OPT_KEEPGOING: /* Continue to process subsequent in 00892 put files after errors*/ 00893 SET_PUBLIC(args,keepgoing) = true; 00894 break; 00895 case OPT_IMPLICIT: /* Implicitly --undef any unconfigured symbol */ 00896 SET_PUBLIC(args,implicit) = true; 00897 break; 00898 default: 00899 usage_error(GRIPE_USAGE_ERROR, 00900 "Invalid option: \"%s\"",argv[optind - 1]); 00901 } 00902 } 00903 if (!parsing_file) { 00904 SET_PUBLIC(args,got_opts) = true; 00905 finalise_diagnostics(); 00906 if (!PROGRESS_GAGGED()) { 00907 heap_str argstr = concatenate(args,argv,' '); 00908 report(PROGRESS_GOT_OPTIONS,NULL,"Args: %s",argstr); 00909 free(argstr); 00910 } 00911 if (command->cmd_code == CMD_SOURCE) { 00912 ptr_set_h st = GET_PUBLIC(configured_symbols,global_sym_tab); 00913 if (ptr_set_count(st) == 0) { 00914 report(GRIPE_NO_SYMS,NULL, 00915 "You have not --define-ed or --undef-ed any symbols. " 00916 "Only in-source #define/#undef directives will have any effects"); 00917 } 00918 } 00919 } 00920 if (argc) { 00921 report(PROGRESS_BUILDING_TREE,NULL,"Building input tree"); 00922 } 00923 argc -= optind; 00924 argv += optind; 00925 for ( ; argc; --argc,++argv) { 00926 if (!add_files(*argv)) { 00927 ++SET_STATE(args,arg_dirs_ignored); 00928 } 00929 } 00930 } 00931 00939 static void 00940 parse_args_file(const char *argsfile) 00941 { 00942 char *arg, * delims=" \t\n\r"; 00943 char **argv; 00944 int argc; 00945 size_t filesz,read; 00946 FILE *in; 00947 if (GET_STATE(args,memfile)) { 00948 bail(GRIPE_MULTIPLE_ARGFILES,"--file can only be used once"); 00949 } 00950 in = open_file(argsfile,"r"); 00951 fseek(in,0,SEEK_END); 00952 filesz = ftell(in); 00953 fseek(in,0,SEEK_SET); /* Back to start of file*/ 00954 SET_STATE(args,memfile) = zallocate(filesz + 1); 00955 ptr_vector_append(GET_STATE(args,argfile_argv),GET_PUBLIC(args,prog_name)); 00956 /* Remember program name comes first*/ 00957 read = fread(GET_STATE(args,memfile),1,filesz,in); 00958 if (!read) { /* Read args file into heap*/ 00959 bail(GRIPE_CANT_READ_INPUT,"Read error on file %s",argsfile); 00960 /* Not bullet-proof to assume that only 0 bytes read is 00961 a read error, but cannot portably test `read' == `filesz' 00962 because if there are newlines in the file then on Windows, fewer 00963 bytes will be read than there are in the file due to newline 00964 conversion*/ 00965 00966 } 00967 fclose(in); 00968 GET_STATE(args,memfile)[read] = '\0'; /* 0-terminate commandline*/ 00969 for(arg = strtok(GET_STATE(args,memfile),delims); 00970 arg != NULL; arg = strtok(NULL,delims)) { 00971 ptr_vector_append(GET_STATE(args,argfile_argv),arg); 00972 } 00973 argc = (int)ptr_vector_count(GET_STATE(args,argfile_argv)); 00974 argv = (char **)ptr_vector_begin(GET_STATE(args,argfile_argv)); 00975 parse_command_args(argc,argv); 00976 } 00977 00980 /* API ********************************************************************/ 00981 00982 void 00983 parse_executable(char **argv) 00984 { 00985 char *last_slash; 00986 SET_PUBLIC(args,exec_path) = *argv; 00987 last_slash = strrchr(*argv,PATH_DELIM); 00988 if (!last_slash) { 00989 SET_PUBLIC(args,prog_name) = *argv; 00990 } else { 00991 SET_PUBLIC(args,prog_name) = last_slash + 1; 00992 } 00993 } 00994 00995 void 00996 parse_args(int argc, char *argv[]) 00997 { 00998 cmd_option_t const *cmd = get_command_option(argc,argv,commands); 00999 if (cmd) { 01000 switch(cmd->cmd_code) { 01001 case CMD_HELP: 01002 usage_help(); 01003 break; 01004 case CMD_VERSION: 01005 version(); 01006 break; 01007 case CMD_SYMBOLS: 01008 case CMD_INCLUDES: 01009 case CMD_DEFS: 01010 case CMD_PRAGMAS: 01011 case CMD_ERRORS: 01012 case CMD_DIRECTIVES: 01013 line_despatch_no_op(); 01014 /* Yes, fall through*/ 01015 default: 01016 SET_PUBLIC(args,command) = (cmd_option_t *)cmd; 01017 argc -= 1; 01018 argv += 1; 01019 parse_command_args(argc,argv); 01020 } 01021 } else { 01022 usage_error(GRIPE_USAGE_ERROR,"\"%s\" is not a coan command", 01023 argv[1]); 01024 } 01025 } 01026 01027 void 01028 finish_args(void) 01029 { 01030 int command = GET_PUBLIC(args,command)->cmd_code; 01031 bool replace = GET_PUBLIC(args,replace); 01032 bool input_is_stdin = false; 01033 01034 if (GET_PUBLIC(args,list_only_active) && 01035 GET_PUBLIC(args,list_only_inactive)) { 01036 usage_error(GRIPE_USAGE_ERROR, 01037 "--active is inconsistent with --inactive"); 01038 } 01039 if (file_tree_is_empty(GET_PUBLIC(dataset,file_tree)) && 01040 GET_STATE(args,arg_dirs_ignored) == 0) { 01041 /* No input files on command line*/ 01042 if (!GET_PUBLIC(args,replace)) { 01043 /* Without --replace, stdin is the input file*/ 01044 input_is_stdin = true; 01045 } else { 01046 /* With --replace, stdin supplies input filenames*/ 01047 char * infile; 01048 while ((infile = read_filename()) != NULL) { 01049 (void)add_files(infile); 01050 } 01051 } 01052 } 01053 if (file_tree_is_empty(GET_PUBLIC(dataset,file_tree)) && !input_is_stdin) { 01054 bail(GRIPE_NOTHING_TO_DO, 01055 "Nothing to do. No input files."); 01056 } 01057 if (command == CMD_SOURCE && !input_is_stdin && 01058 file_tree_count(GET_PUBLIC(dataset,file_tree),FT_COUNT_FILES,NULL) > 1 && 01059 !replace) { 01060 bail(GRIPE_ONE_FILE_ONLY, 01061 "The \"source\" command needs --replace to process multiple files"); 01062 } 01063 if (command == CMD_SYMBOLS) { 01064 if (!GET_PUBLIC(args,list_symbols_in_ifs) && 01065 !GET_PUBLIC(args,list_symbols_in_defs) && 01066 !GET_PUBLIC(args,list_symbols_in_undefs) && 01067 !GET_PUBLIC(args,list_symbols_in_includes)) { 01068 /* No restriction on listed symbols implies list all*/ 01069 SET_PUBLIC(args,list_symbols_in_ifs) = true; 01070 SET_PUBLIC(args,list_symbols_in_defs) = true; 01071 SET_PUBLIC(args,list_symbols_in_undefs) = true; 01072 SET_PUBLIC(args,list_symbols_in_includes) = true; 01073 } 01074 } 01075 if (command == CMD_INCLUDES) { 01076 if (!GET_PUBLIC(args,list_system_includes) && 01077 !GET_PUBLIC(args,list_local_includes)) { 01078 /* No restriction on listed #includes implies list all*/ 01079 SET_PUBLIC(args,list_system_includes) = true; 01080 SET_PUBLIC(args,list_local_includes) = true; 01081 } 01082 } 01083 report(PROGRESS_FILE_TALLY,NULL,"%d files to process", 01084 file_tree_count(GET_PUBLIC(dataset,file_tree),FT_COUNT_FILES,NULL)); 01085 } 01086 01087 01088 /* EOF*/