coan 4.2.4
args.c
Go to the documentation of this file.
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*/
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines