This is options.c in view mode; [Download] [Up]
/***************************************************************************** * $Id: options.c,v 1.10 1997/04/07 05:24:54 darren Exp $ * * Copyright (c) 1996-1997, Darren Hiebert * * Contains functions to process command line options. *****************************************************************************/ /*============================================================================ = Include files ============================================================================*/ #ifdef HAVE_CONFIG_H # include <config.h> #endif /* To declare "struct stat" and stat(). */ #if __MWERKS__ # include <stat.h> /* there is no sys directory on the Mac */ #else # include <sys/types.h> # include <sys/stat.h> #endif #ifdef DEBUG # include <assert.h> #endif #include "ctags.h" /*============================================================================ = Defines ============================================================================*/ /*---------------------------------------------------------------------------- * Miscellaneous defines *--------------------------------------------------------------------------*/ #define VERSION "Exuberant Ctags, Version 1.6b1, by Darren Hiebert" #define CTAGS_INVOCATION "\ Usage: ctags [-aBdeFnNsStTuwWx] [-{f|o} name] [-h list] [-i [+-=]types]\n\ [-I list] [-L file] [-p path] [--help] file(s)\n" #define ETAGS_INVOCATION "\ Usage: etags [-adsStTx] [-{f|o} name] [-h list] [-i [+-=]types]\n\ [-I list] [-L file] [-p path] [--help] file(s)\n" #define CTAGS_ENVIRONMENT "CTAGS" #define ETAGS_ENVIRONMENT "ETAGS" /* The following separators are permitted for list options. */ #define HEADER_SEPARATORS ".,;" #define IGNORE_SEPARATORS ",; \t\n" /*============================================================================ = Data declarations ============================================================================*/ typedef struct { boolean usedByEtags; const char *const description; } optionDescription; /*============================================================================ = Data definitions ============================================================================*/ /*---------------------------------------------------------------------------- - Globally shared ----------------------------------------------------------------------------*/ optionValues Option = { { TRUE, /* -id */ TRUE, /* -ie */ TRUE, /* -if */ TRUE, /* -ig */ FALSE, /* -ip */ TRUE, /* -it */ TRUE, /* -iv */ FALSE, /* -iP */ TRUE /* -iS */ }, { NULL, 0, 0 }, /* -I */ FALSE, /* -a */ FALSE, /* -B */ FALSE, /* -e */ EX_MIX, /* -n */ NULL, /* -p */ FALSE, /* -u */ FALSE, /* -w */ FALSE, /* -x */ NULL, /* -L */ NULL, /* -o */ { "h", "H", "hpp", "hxx", "h++", NULL }, /* -h */ #ifdef DEBUG 0, 0, /* -D, -b */ #endif FALSE, /* started as etags */ FALSE /* brace formatting */ }; /*---------------------------------------------------------------------------- - Locally used only ----------------------------------------------------------------------------*/ static optionDescription OptionDescription[] = { {1," --help Prints a more detailed help message."}, {1," -a Append tags to existing tag file."}, #ifdef DEBUG {1," -b <line> Set break line."}, #endif {0," -B Use backward searching patterns (?...?)."}, #ifdef DEBUG {1," -D <level> Set debug level."}, #endif {0," -e Output tag file for use with Emacs."}, {1," -f <name> Name for output tag file (default \"tags\"; or \"TAGS\" if -e)."}, {0," -F Use forward searching patterns (/.../) (default)."}, {1," -h <list> List of header file extensions (default \".h.H.hpp.hxx.h++\")."}, {1," -i <types> List of tag types to include [defgptvPS] (default \"=defgtvS\")."}, {1," -I <list> List of tokens to ignore is read from command line or file."}, {1," -L <file> List of source file names are read from specified file."}, {0," -n Use line numbers in tag file instead of search patterns."}, {0," -N Use search patterns in tag file instead of line numbers."}, {1," -o <name> Alternative for -f."}, {1," -p <path> Default path to use for all (relative path) filenames."}, {0," -u Unsorted; do not sort tags. Disables duplicate tag warnings."}, {0," -w Exclude warnings about duplicate tags (default)."}, {0," -W Generate warnings about duplicate tags."}, {1," -x Print tabular cross reference file to standard output."}, {1," -[dsStT] Backward compatibility options. See --help for more info."}, {1, NULL} }; static optionDescription LongOptionDescription[] = { {1," -a Append the tags to an existing tag file."}, #ifdef DEBUG {1," -b <line>"}, {1," Set break line."}, #endif {0," -B Use backward searching patterns (?...?)."}, #ifdef DEBUG {1," -D <level>"}, {1," Set debug level."}, #endif {0," -e Output tag file for use with Emacs."}, {1," -f <name>"}, {1," Output tags to the specified file (default is \"tags\"; or \"TAGS\""}, {1," if -e is specified). If specified as \"-\", tags are written to"}, {1," standard output."}, {0," -F Use forward searching patterns (/.../) (default)."}, {1," -h <list>"}, {1," Specifies a list of file extensions used for headers."}, {1," The default list is \".h.H.hpp.hxx.h++\"."}, {1," -i <types>"}, {1," Specifies the list of tag types to include in the output file."}, {1," \"Types\" is a group of letters designating the types of tags"}, {1," affected. Each letter or group of letters may be preceded by"}, {1," either a '+' sign (default, if omitted) to add it to those already"}, {1," included, a '-' sign to exclude it from the list (e.g. to exclude"}, {1," a default tag type), or an '=' sign to include its corresponding"}, {1," tag type at the exclusion of those not listed. A space separating"}, {1," the option letter from the list is optional. The following tag"}, {1," types are supported:"}, {1," d macro definitions"}, {1," e enumerated values (values inside enum{...})"}, {1," f function and method definitions"}, {1," g enum/struct/union tags (or new C++ types)"}, {1," p external function prototypes"}, {1," t typedefs"}, {1," v variable declarations"}, {1," In addition, the following two modifiers are accepted:"}, {1," P prefix static tags with \"filename:\" (Elvis style)."}, {1," S include static tags (special case of above types)"}, {1," The default value of list is \"=defgtvS\" (i.e all tag types"}, {1," except for function prototypes; include static tags but do not"}, {1," prefix them)."}, {1," -I <list | file>"}, {1," A list of tokens to ignore is read from either the command line,"}, {1," or the specified file (if leading character is '.', '/', or '\\')."}, {1," Particularly useful when a function definition or declaration"}, {1," contains some special macro before the parameter list."}, {1," -L <file>"}, {1," A list of source file names are read from the specified file."}, {1," If specified as \"-\", then standard input is read."}, {0," -n Use line numbers in tag file instead of search patterns."}, {0," -N Use search patterns in tag file instead of line numbers."}, {1," -o Alternative for -f."}, {1," -p <path>"}, {1," Default path to use for all (relative path) filenames."}, {0," -u Unsorted; do not sort tags. Disables warnings for duplicate tags"}, {0," -w Exclude warnings about duplicate tags (default)."}, {0," -W Generate warnings about duplicate tags."}, {1," -x Print a tabular cross reference file to standard output."}, {1,""}, {1," The following tag control options are accepted only for backwards"}, {1," compatibility with other versions of ctags and (except for -s) are"}, {1," selected by default in this version. Use of the -i option is preferred."}, {1," -d Include macro definitions (equiv. to -i+d)."}, {1," -s Include static tags prefixed by \"filename:\" (equiv. to -i+SP)."}, {1," -S Include static tags without filename prefix (equiv. to -i+S-P)."}, {1," -t Include typedefs (equiv. to -i+t)."}, {1," -T Include typedefs and enum/struct/union tags (equiv. to -i+gt)."}, {1, NULL} }; /* Contains a set of strings describing the set of "features" compiled into * the code. */ static const char *const Features[] = { #ifdef DEBUG "debug", #endif #ifdef WIN32 "win32", #endif #ifdef DJGPP "msdos_32", #else # ifdef MSDOS "msdos_16", # endif #endif #ifdef OS2 "os2", #endif #ifdef AMIGA "amiga", #endif #ifndef EXTERNAL_SORT "internal_sort", #endif NULL }; /*============================================================================ = Function prototypes ============================================================================*/ static void printfFeatureList __ARGS((FILE *const where)); static void printInvocationDescription __ARGS((FILE *const where)); static void printOptionDescriptions __ARGS((const optionDescription *const optDesc, FILE *const where)); static void printHelp __ARGS((const optionDescription *const optDesc, FILE *const where)); static void readExtensionList __ARGS((char *const list)); static void clearTagList __ARGS((void)); static void applyTagInclusionList __ARGS((const char *const list)); static void readIgnoreList __ARGS((char *const list)); static void readIgnoreListFromFile __ARGS((const char *const fileName)); static char *readOptionArg __ARGS((const int option, char **const arg, char *const *const argList, int *const argNum)); static void processHeaderListOption __ARGS((const int option, char **const argP, char *const *const argList, int *const argNumP)); static void processIgnoreOption __ARGS((const int option, char **const argP, char *const *const argList, int *const argNumP)); static void processExtendedOption __ARGS((const char *const optionString)); static void processLongOption __ARGS((const int option, char **const argP, char *const *const argList, int *const argNumP)); static boolean processShortOption __ARGS((const int option)); static void parseStringToArgs __ARGS((const char *const string, char *parsedBuffer, char **const argList, const int maxArgs)); static char **creatArgListForString __ARGS((const char *const string)); /*============================================================================ = Function definitions ============================================================================*/ static void printfFeatureList( where ) FILE *const where; { int i; for (i = 0 ; Features[i] != NULL ; ++i) { if (i == 0) fputs(" (", where); fprintf(where, "%s+%s", (i>0 ? ", " : ""), Features[i]); } fputs(i>0 ? ")" : "", where); } static void printInvocationDescription( where ) FILE *const where; { if (Option.startedAsEtags) fprintf(where, ETAGS_INVOCATION); else fprintf(where, CTAGS_INVOCATION); } static void printOptionDescriptions( optDesc, where ) const optionDescription *const optDesc; FILE *const where; { int i; for (i = 0 ; optDesc[i].description != NULL ; ++i) { if (! Option.startedAsEtags || optDesc[i].usedByEtags) { fputs(optDesc[i].description, where); fputc('\n', where); } } } static void printHelp( optDesc, where ) const optionDescription *const optDesc; FILE *const where; { fprintf(where, "%s", VERSION); printfFeatureList(where); fputc('\n', where); printInvocationDescription(where); printOptionDescriptions(optDesc, where); } extern void printUsage( error ) const char *const error; { printHelp(OptionDescription, errout); if (error != NULL) { fprintf(errout, "\nError: %s", error); #if !defined(MSDOS) && !defined(WIN32) && !defined(OS2) fputs("\n", errout); #endif } exit(1); } /* Reads a list of header file extensions. */ static void readExtensionList( list ) char *const list; { const char *extension = strtok(list, HEADER_SEPARATORS); int extIndex = 0; while (extension != NULL && extIndex < MaxHeaderExtensions) { #ifdef DEBUG if (debug(DEBUG_STATUS)) printf("header extension: %s\n", extension); #endif Option.headerExt[extIndex++] = extension; extension = strtok(NULL, HEADER_SEPARATORS); } Option.headerExt[extIndex] = NULL; } static void clearTagList() { Option.include.defines = FALSE; Option.include.enumValues = FALSE; Option.include.functions = FALSE; Option.include.blockTags = FALSE; Option.include.prototypes = FALSE; Option.include.typedefs = FALSE; Option.include.variables = FALSE; Option.include.prefix = FALSE; Option.include.statics = FALSE; } static void applyTagInclusionList( list ) const char *const list; { boolean mode = TRUE; /* default mode is to add following types */ const char *p; for (p = list ; *p != '\0' ; ++p) { switch (*p) { case '=': /* exclusive mode; ONLY types following are included */ clearTagList(); mode = TRUE; break; case '+': mode = TRUE; break; /* types following are included */ case '-': mode = FALSE; break; /* types following are excluded */ case 'd': Option.include.defines = mode; break; case 'e': Option.include.enumValues = mode; break; case 'f': Option.include.functions = mode; break; case 'g': Option.include.blockTags = mode; break; case 'p': Option.include.prototypes = mode; break; case 't': Option.include.typedefs = mode; break; case 'v': Option.include.variables = mode; break; case 'P': Option.include.prefix = mode; break; case 'S': Option.include.statics = mode; break; default: { char msg[80]; sprintf(msg, "-i: Invalid tag option '%c'", *p); printUsage(msg); break; } } } } static void readIgnoreList( list ) char *const list; { const char *token = strtok(list, IGNORE_SEPARATORS); while (token != NULL) { unsigned int i = Option.ignore.count++; if (Option.ignore.count > Option.ignore.max) { Option.ignore.max = Option.ignore.count + 10; Option.ignore.list = (char **)realloc(Option.ignore.list, Option.ignore.max * sizeof(char *)); } Option.ignore.list[i] = (char *)malloc(strlen(token) + 1); strcpy(Option.ignore.list[i], token); #ifdef DEBUG if (debug(DEBUG_STATUS)) printf("ignore token: %s\n", token); #endif token = strtok(NULL, IGNORE_SEPARATORS); } } static void readIgnoreListFromFile( fileName ) const char *const fileName; { FILE *const fp = fopen(fileName, "r"); if (fp == NULL) { perror(fileName); exit(1); } else { char ignoreToken[MaxNameLength]; unsigned int i = Option.ignore.count; while (fscanf(fp, "%255s", ignoreToken) == 1) ++Option.ignore.count; rewind(fp); if (Option.ignore.count > Option.ignore.max) { Option.ignore.max = Option.ignore.count; Option.ignore.list = (char **)realloc(Option.ignore.list, Option.ignore.max * sizeof(char *)); } if (Option.ignore.list == NULL) perror("Cannot create ignore list"); else while (fscanf(fp, "%255s", ignoreToken) == 1) { #ifdef DEBUG assert(i < Option.ignore.count); #endif Option.ignore.list[i] = (char *)malloc(strlen(ignoreToken) + 1); strcpy(Option.ignore.list[i], ignoreToken); ++i; #ifdef DEBUG if (debug(DEBUG_STATUS)) printf("ignore token: %s\n", ignoreToken); #endif } } } static char *readOptionArg( option, arg, argList, argNum ) const int option; char **const arg; char *const *const argList; int *const argNum; { char *list = NULL; if ((*arg)[0] != '\0') /* does list immediately follow option? */ { list = *arg; *arg += strlen(*arg); } else if ((list = argList[++(*argNum)]) == NULL) /* at least 1 more arg? */ { char msg[80]; sprintf(msg, "-%c: Parameter missing", option); printUsage(msg); } #ifdef DEBUG if (debug(DEBUG_OPTION)) fputs(list, stderr); #endif return list; } extern void freeIgnoreList() { while (Option.ignore.count > 0) free(Option.ignore.list[--Option.ignore.count]); if (Option.ignore.list != NULL) free(Option.ignore.list); Option.ignore.list = NULL; Option.ignore.max = 0; } static void processHeaderListOption( option, argP, argList, argNumP ) const int option; char **const argP; char *const *const argList; int *const argNumP; { struct stat file_status; char *const param = readOptionArg(option, argP, argList, argNumP); /* Check to make sure that the user did not enter "ctags -h *.c" * by testing to see if the list is a filename that exists. */ if (stat(param, &file_status) == 0) printUsage("-h: Invalid list"); else readExtensionList(param); } static void processIgnoreOption( option, argP, argList, argNumP ) const int option; char **const argP; char *const *const argList; int *const argNumP; { char *const param = readOptionArg(option, argP, argList, argNumP); if (strchr("./\\", param[0]) != NULL) readIgnoreListFromFile(param); else readIgnoreList(param); } static void processExtendedOption( optionString ) const char *const optionString; { if (strcmp(optionString,"help") == 0) { printHelp(LongOptionDescription, stdout); exit(0); } } static void processLongOption( option, argP, argList, argNumP ) const int option; char **const argP; char *const *const argList; int *const argNumP; { char *param = NULL; #ifdef DEBUG if (debug(DEBUG_OPTION)) fprintf(stderr, "Option: -%c ", option); #endif switch (option) { /* Options requiring parameters. */ case '-': processExtendedOption(*argP); break; case 'f': case 'o': Option.tagFile = readOptionArg(option, argP, argList, argNumP); break; case 'h': processHeaderListOption(option, argP, argList, argNumP); break; case 'i': param = readOptionArg(option, argP, argList, argNumP); applyTagInclusionList(param); break; case 'I': processIgnoreOption(option, argP, argList, argNumP); break; case 'L': Option.fileList = readOptionArg(option, argP, argList, argNumP); break; case 'p': Option.path = readOptionArg(option, argP, argList, argNumP); break; #ifdef DEBUG case 'D': param = readOptionArg(option, argP, argList, argNumP); Option.debugLevel = atoi(param); break; case 'b': param = readOptionArg(option, argP, argList, argNumP); Option.breakLine = atol(param); break; #endif default: { char msg[40]; sprintf(msg, "Invalid option character: '%c'", option); printUsage(msg); break; } } #ifdef DEBUG if (debug(DEBUG_OPTION)) fputs("\n", stderr); #endif } static boolean processShortOption( option ) const int option; { boolean handled = TRUE; switch (option) { case 'a': Option.append = TRUE; break; case 'B': Option.backward = TRUE; break; case 'd': Option.include.defines = TRUE; break; case 'e': Option.etags = TRUE; Option.unsorted = TRUE; break; case 'F': Option.backward = FALSE; break; case 'n': Option.locate = EX_LINENUM; break; case 'N': Option.locate = EX_PATTERN; break; case 's': Option.include.statics = TRUE; Option.include.prefix = TRUE; break; case 'S': Option.include.statics = TRUE; Option.include.prefix = FALSE; break; case 't': Option.include.typedefs = TRUE; break; case 'T': Option.include.blockTags= TRUE; Option.include.typedefs = TRUE; break; case 'u': Option.unsorted = TRUE; break; case 'w': Option.warnings = FALSE; break; case 'W': Option.warnings = TRUE; break; case 'x': Option.xref = TRUE; break; case '?': printHelp(LongOptionDescription, stdout); exit(0); default: handled = FALSE; break; } #ifdef DEBUG if (handled && debug(DEBUG_OPTION)) fprintf(stderr, "Option: -%c\n", option); #endif return handled; } extern char *const *parseOptions( argList ) char *const *const argList; { int argNum; for (argNum = 0 ; argList[argNum] != NULL ; ++argNum) { char *arg = argList[argNum]; int c; if (*arg++ != '-') /* stop at first non-option switch */ break; while ((c = *arg++) != '\0') if (! processShortOption(c)) processLongOption(c, &arg, argList, &argNum); } return &argList[argNum]; } static void parseStringToArgs( string, parsedBuffer, argList, maxArgs ) const char *const string; char *parsedBuffer; char **const argList; const int maxArgs; { boolean argInProgress = FALSE; int count = 0; const char *src; for (src = string ; *src != '\0' ; ++src) { if (*src == ' ') /* designates end of argument */ { if (argInProgress) { *parsedBuffer++ = '\0'; /* terminate arg in progress */ argInProgress = FALSE; if (count >= maxArgs) break; } } else { if (! argInProgress) { argInProgress = TRUE; argList[count++] = parsedBuffer; /* point to new arg */ } if (*src == '\\') /* next character is literal */ ++src; /* skip over '\\' */ *parsedBuffer++ = *src; } } *parsedBuffer = '\0'; /* null terminate last argument */ argList[count] = NULL; /* terminate list */ } static char **creatArgListForString( string ) const char *const string; { char **argList = NULL; if (string != NULL && string[0] != '\0') { /* We place the parsed string at the end of the memory block, past * the bottom of the argument table. */ const size_t argListSize= (MaxEnvOptions + 1) * sizeof(char *); const size_t blockSize = argListSize + strlen(string) + 1; argList = (char **)malloc(blockSize); if (argList != NULL) parseStringToArgs(string, (char *)argList + argListSize, argList, MaxEnvOptions); } return argList; } extern void *parseEnvironmentOptions() { const char *envOptions = NULL; char **argList = NULL; if (Option.startedAsEtags) envOptions = getenv(ETAGS_ENVIRONMENT); if (envOptions == NULL) envOptions = getenv(CTAGS_ENVIRONMENT); if (envOptions != NULL) { argList = creatArgListForString(envOptions); parseOptions(argList); } return argList; } /* vi:set tabstop=8 shiftwidth=4: */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.