options.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:32k
源码类别:

编辑器/阅读器

开发平台:

DOS

  1. /*****************************************************************************
  2. *   $Id: options.c,v 6.11 1998/08/04 03:25:29 darren Exp $
  3. *
  4. *   Copyright (c) 1996-1998, Darren Hiebert
  5. *
  6. *   This source code is released for free distribution under the terms of the
  7. *   GNU General Public License.
  8. *
  9. *   This module contains functions to process command line options.
  10. *****************************************************************************/
  11. /*============================================================================
  12. =   Include files
  13. ============================================================================*/
  14. #ifdef HAVE_CONFIG_H
  15. # include <config.h>
  16. #endif
  17. #ifdef DEBUG
  18. # include <assert.h>
  19. #endif
  20. #include "ctags.h"
  21. /*============================================================================
  22. =   Defines
  23. ============================================================================*/
  24. /*----------------------------------------------------------------------------
  25.  *  Miscellaneous defines
  26.  *--------------------------------------------------------------------------*/
  27. #define CTAGS_INVOCATION  "
  28.   Usage: ctags [-aBeFnNRux] [-{f|o} name] [-h list] [-i [+-=]types]n
  29.                [-I list] [-L file] [-p path] [--append] [--excmd=n|p|m]n
  30.                [--format=level] [--help] [--if0] [--lang=lang] [--recurse]n
  31.        [--sort] [--totals] [--version] file(s)n"
  32. #define ETAGS_INVOCATION  "
  33.   Usage: etags [-aRx] [-{f|o} name] [-h list] [-i [+-=]types] [-I list]n
  34.                [-L file] [-p path] [--append] [--help] [--if0] [--lang=lang]n
  35.        [--recurse] [--totals] [--version] file(s)n"
  36. #define CTAGS_ENVIRONMENT "CTAGS"
  37. #define ETAGS_ENVIRONMENT "ETAGS"
  38. /*  The following separators are permitted for list options.
  39.  */
  40. #define EXTENSION_SEPARATORS   "."
  41. #define IGNORE_SEPARATORS   ", tn"
  42. #ifndef DEFAULT_FILE_FORMAT
  43. # define DEFAULT_FILE_FORMAT 2
  44. #endif
  45. /*============================================================================
  46. =   Data declarations
  47. ============================================================================*/
  48. typedef struct {
  49.     int usedByEtags;
  50.     const char *const description;
  51. } optionDescription;
  52. /*============================================================================
  53. =   Data definitions
  54. ============================================================================*/
  55. /*----------------------------------------------------------------------------
  56. -   Globally shared
  57. ----------------------------------------------------------------------------*/
  58. static const char *const CExtensionList[] = {
  59.     "c", NULL
  60. };
  61. static const char *const CppExtensionList[] = {
  62. #if !defined(MSDOS) && !defined(WIN32) && !defined(OS2)
  63.     "C",
  64. #endif
  65.     "c++", "cc", "cpp", "cxx", NULL
  66. };
  67. static const char *const JavaExtensionList[] = {
  68.     "java", NULL
  69. };
  70. static const char *const HeaderExtensionList[] = {
  71.     "h", "H", "hh", "hpp", "hxx", "h++", NULL
  72. };
  73. optionValues Option = {
  74.     {
  75. TRUE, /* -ic */
  76. TRUE, /* -id */
  77. TRUE, /* -ie */
  78. TRUE, /* -if */
  79. TRUE, /* -ig */
  80. TRUE, /* -ii */
  81. FALSE, /* -im */
  82. TRUE, /* -in */
  83. FALSE, /* -ip */
  84. TRUE, /* -is */
  85. TRUE, /* -it */
  86. TRUE, /* -iu */
  87. TRUE, /* -iv */
  88. FALSE, /* -ix */
  89. FALSE, /* -iC */
  90. FALSE, /* -iF */
  91. TRUE, /* -iS */
  92.     },
  93.     { NULL, 0, 0 }, /* -I */
  94.     FALSE, /* -a */
  95.     FALSE, /* -B */
  96.     FALSE, /* -e */
  97. #ifdef MACROS_USE_PATTERNS
  98.     EX_PATTERN, /* -n, --excmd */
  99. #else
  100.     EX_MIX, /* -n, --excmd */
  101. #endif
  102.     NULL, /* -p */
  103.     FALSE, /* -R */
  104.     TRUE, /* -u, --sort */
  105.     FALSE, /* -x */
  106.     NULL, /* -L */
  107.     NULL, /* -o */
  108.     HeaderExtensionList,/* -h */
  109. #ifdef DEBUG
  110.     0, 0, /* -D, -b */
  111. #endif
  112.     FALSE, /* started as etags */
  113.     FALSE, /* brace formatting */
  114.     DEFAULT_FILE_FORMAT,/* --format */
  115.     FALSE, /* --if0 */
  116.     LANG_AUTO, /* --lang */
  117.     { /* --langmap */
  118. CExtensionList,
  119. CppExtensionList,
  120. JavaExtensionList,
  121.     },
  122.     FALSE /* --totals */
  123. };
  124. /*----------------------------------------------------------------------------
  125. -   Locally used only
  126. ----------------------------------------------------------------------------*/
  127. static optionDescription LongOptionDescription[] = {
  128.  {1,"  -a   Append the tags to an existing tag file."},
  129. #ifdef DEBUG
  130.  {1,"  -b <line>"},
  131.  {1,"       Set break line."},
  132. #endif
  133.  {0,"  -B   Use backward searching patterns (?...?)."},
  134. #ifdef DEBUG
  135.  {1,"  -D <level>"},
  136.  {1,"       Set debug level."},
  137. #endif
  138.  {0,"  -e   Output tag file for use with Emacs."},
  139.  {1,"  -f <name>"},
  140.  {1,"       Output tags to the specified file (default is "tags"; or "TAGS""},
  141.  {1,"       if -e is specified). If specified as "-", tags are written to"},
  142.  {1,"       standard output."},
  143.  {0,"  -F   Use forward searching patterns (/.../) (default)."},
  144.  {1,"  -h <list>"},
  145.  {1,"       Specifies a list of file extensions used for headers."},
  146.  {1,"       The default list is ".h.H.hh.hpp.hxx.h++"."},
  147.  {1,"  -i <types>"},
  148.  {1,"       Specifies the list of tag types to include in the output file."},
  149.  {1,"       "Types" is a group of letters designating the types of tags"},
  150.  {1,"       affected. Each letter or group of letters may be preceded by"},
  151.  {1,"       either a '+' sign (default, if omitted) to add it to those already"},
  152.  {1,"       included, a '-' sign to exclude it from the list (e.g. to exclude"},
  153.  {1,"       a default tag type), or an '=' sign to include its corresponding"},
  154.  {1,"       tag type at the exclusion of those not listed. A space separating"},
  155.  {1,"       the option letter from the list is optional. The following tag"},
  156.  {1,"       types are supported (default settings are on except as noted):"},
  157.  {1,"          c   class names"},
  158.  {1,"          d   macro definitions"},
  159.  {1,"          e   enumerators (values inside an enumeration)"},
  160.  {1,"          f   function (or method) definitions"},
  161.  {1,"          g   enumeration names"},
  162.  {1,"          i   interface names (Java only)"},
  163.  {1,"          m   data members [off]"},
  164.  {1,"          n   namespace names (C++ only)"},
  165.  {1,"          p   function prototypes [off]"},
  166.  {1,"          s   structure names"},
  167.  {1,"          t   typedefs"},
  168.  {1,"          u   union names"},
  169.  {1,"          v   variable definitions"},
  170.  {1,"          x   external variable declarations [off]"},
  171.  {1,"       In addition, the following modifiers are accepted:"},
  172.  {1,"          C   include extra, class-qualified member tag entries [off]"},
  173.  {1,"          F   include source filenames as tags [off]"},
  174.  {1,"          S   include static tags"},
  175.  {1,"  -I <list | file>"},
  176.  {1,"       A list of tokens to ignore is read from either the command line,"},
  177.  {1,"       or the specified file (if leading character is '.', '/', or '\')."},
  178.  {1,"       Particularly useful when a function definition or declaration"},
  179.  {1,"       contains some special macro before the parameter list."},
  180.  {1,"  -L <file>"},
  181.  {1,"       A list of source file names are read from the specified file."},
  182.  {1,"       If specified as "-", then standard input is read."},
  183.  {0,"  -n   Equivalent to --excmd=number."},
  184.  {0,"  -N   Equivalent to --excmd=pattern."},
  185.  {1,"  -o   Alternative for -f."},
  186.  {1,"  -p <path>"},
  187.  {1,"       Default path to use for all (relative path) filenames."},
  188. #ifdef RECURSE_SUPPORTED
  189.  {1,"  -R   Equivalent to --recurse=yes."},
  190. #else
  191.  {1,"  -R   Not supported on this platform."},
  192. #endif
  193.  {0,"  -u   Equivalent to --sort=no."},
  194.  {1,"  -x   Print a tabular cross reference file to standard output."},
  195.  {1,"  --append=[yes|no]"},
  196.  {1,"       Indicates whether tags should be appended to existing tag file"},
  197.  {1,"       (default=no)."},
  198.  {0,"  --excmd=number|pattern|mix"},
  199. #ifdef MACROS_USE_PATTERNS
  200.  {0,"       Uses the specified type of EX command to locate tags (default=pattern)."},
  201. #else
  202.  {0,"       Uses the specified type of EX command to locate tags (default=mix)."},
  203. #endif
  204.  {0,"  --format=level"},
  205. #if DEFAULT_FILE_FORMAT==1
  206.  {0,"       Forces output of specified tag file format (default=1)."},
  207. #else
  208.  {0,"       Forces output of specified tag file format (default=2)."},
  209. #endif
  210.  {1,"  --help"},
  211.  {1,"       Prints this option summary."},
  212.  {1,"  --if0=[yes|no]"},
  213.  {1,"       Indicates whether code within #if 0 conditional branches should"},
  214.  {1,"       be examined for tags (default=no)."},
  215.  {1,"  --lang=[c|c++|java]"},
  216.  {1,"       Forces specified language, disabling automatic selection."},
  217.  {1,"  --recurse=[yes|no]"},
  218. #ifdef RECURSE_SUPPORTED
  219.  {1,"       Recurse into directories supplied on command line (default=no)."},
  220. #else
  221.  {1,"       Not supported on this platform."},
  222. #endif
  223.  {0,"  --sort=[yes|no]"},
  224.  {0,"       Indicates whether tags should be sorted (default=yes)."},
  225.  {1,"  --totals=[yes|no]"},
  226.  {1,"       Prints statistics about source and tag files (default=no)."},
  227.  {1,"  --version"},
  228.  {1,"       Prints a version identifier to standard output."},
  229.  {1, NULL}
  230. };
  231. /*  Contains a set of strings describing the set of "features" compiled into
  232.  *  the code.
  233.  */
  234. static const char *const Features[] = {
  235. #ifdef DEBUG
  236.     "debug",
  237. #endif
  238. #ifdef WIN32
  239.     "win32",
  240. #endif
  241. #ifdef DJGPP
  242.     "msdos_32",
  243. #else
  244. # ifdef MSDOS
  245.     "msdos_16",
  246. # endif
  247. #endif
  248. #ifdef OS2
  249.     "os2",
  250. #endif
  251. #ifdef AMIGA
  252.     "amiga",
  253. #endif
  254. #ifndef EXTERNAL_SORT
  255.     "internal_sort",
  256. #endif
  257.     NULL
  258. };
  259. /*============================================================================
  260. =   Function prototypes
  261. ============================================================================*/
  262. static void printfFeatureList __ARGS((FILE *const where));
  263. static void printProgramIdentification __ARGS((FILE *const where));
  264. static void printInvocationDescription __ARGS((FILE *const where));
  265. static void printOptionDescriptions __ARGS((const optionDescription *const optDesc, FILE *const where));
  266. static void printHelp __ARGS((const optionDescription *const optDesc, FILE *const where));
  267. static char *readOptionArg __ARGS((const int option, char **const pArg, char *const *const argList, int *const pArgNum));
  268. static unsigned int countExtensions __ARGS((const char *const list));
  269. static const char *const *readExtensionList __ARGS((const char *const list));
  270. static void clearTagList __ARGS((void));
  271. static void applyTagInclusionList __ARGS((const char *const list));
  272. static char *saveString __ARGS((const char *const string));
  273. static void resizeIgnoreList __ARGS((void));
  274. static void saveIgnoreToken __ARGS((const char *const ignoreToken));
  275. static void readIgnoreList __ARGS((char *const list));
  276. static void readIgnoreListFromFile __ARGS((const char *const fileName));
  277. static void processHeaderListOption __ARGS((const int option, char **const argP, char *const *const argList, int *const argNumP));
  278. static void processIgnoreOption __ARGS((const int option, char **const argP, char *const *const argList, int *const argNumP));
  279. static boolean getBooleanOption __ARGS((const char *const optionName, const char *const parameter, const boolean defaultValue));
  280. static void processExcmdOption __ARGS((const char *const optionName, const char *const parameter));
  281. static void processFormatOption __ARGS((const char *const optionName, const char *const parameter));
  282. static langType getLangType __ARGS((const char *const name));
  283. static void processLangOption __ARGS((const char *const optionName, const char *const parameter));
  284. static void installLangMap __ARGS((char *const map));
  285. static void processLangMapOption __ARGS((const char *const optionName, const char *const parameter));
  286. static void processLongOption __ARGS((const char *const optionString));
  287. static void processCompoundOption __ARGS((const int option, char **const pArg, char *const *const argList, int *const pArgNum));
  288. static boolean processSimpleOption __ARGS((const int option));
  289. static void parseStringToArgs __ARGS((const char *const string, char *parsedBuffer, char **const argList, const unsigned int maxArgs));
  290. static unsigned int countStringWords __ARGS((const char *const string));
  291. static char **creatArgListForString __ARGS((const char *const string));
  292. /*============================================================================
  293. =   Function definitions
  294. ============================================================================*/
  295. static void printfFeatureList( where )
  296.     FILE *const where;
  297. {
  298.     int i;
  299.     for (i = 0 ; Features[i] != NULL ; ++i)
  300.     {
  301. if (i == 0)
  302.     fputs(" (", where);
  303. fprintf(where, "%s+%s", (i>0 ? ", " : ""), Features[i]);
  304.     }
  305.     fputs(i>0 ? ")" : "", where);
  306. }
  307. static void printProgramIdentification( where )
  308.     FILE *const where;
  309. {
  310.     fprintf(where, "%s %s, by %s", PROGRAM_NAME, PROGRAM_VERSION, AUTHOR_NAME);
  311.     printfFeatureList(where);
  312.     fputs("n", where);
  313. }
  314. static void printInvocationDescription( where )
  315.     FILE *const where;
  316. {
  317.     if (Option.startedAsEtags)
  318. fprintf(where, ETAGS_INVOCATION);
  319.     else
  320. fprintf(where, CTAGS_INVOCATION);
  321. }
  322. static void printOptionDescriptions( optDesc, where )
  323.     const optionDescription *const optDesc;
  324.     FILE *const where;
  325. {
  326.     int i;
  327.     for (i = 0 ; optDesc[i].description != NULL ; ++i)
  328.     {
  329. if (! Option.startedAsEtags || optDesc[i].usedByEtags)
  330. {
  331.     fputs(optDesc[i].description, where);
  332.     fputc('n', where);
  333. }
  334.     }
  335. }
  336. static void printHelp( optDesc, where )
  337.     const optionDescription *const optDesc;
  338.     FILE *const where;
  339. {
  340.     printProgramIdentification(where);
  341.     fputs("n", where);
  342.     printInvocationDescription(where);
  343.     fputs("n", where);
  344.     printOptionDescriptions(optDesc, where);
  345. }
  346. static char *readOptionArg( option, pArg, argList, pArgNum )
  347.     const int option;
  348.     char **const pArg;
  349.     char *const *const argList;
  350.     int *const pArgNum;
  351. {
  352.     char *list;
  353.     if ((*pArg)[0] != '')     /* does list immediately follow option? */
  354.     {
  355. list = *pArg;
  356. *pArg += strlen(*pArg);
  357.     }
  358.     else if ((list = argList[++(*pArgNum)]) == NULL) /* at least 1 more arg? */
  359. error(FATAL, "-%c: Parameter missing", option);
  360.     DebugStatement( if (debug(DEBUG_OPTION)) fputs(list, errout); )
  361.     return list;
  362. }
  363. /*  Reads a list of file extensions.
  364.  */
  365. static unsigned int countExtensions( list )
  366.     const char *const list;
  367. {
  368.     unsigned int count = 0;
  369.     const char *p;
  370.     /*  Increase count by one if list does not begin with a separator.
  371.      */
  372.     if (strchr(EXTENSION_SEPARATORS, list[0]) == NULL)
  373. ++count;
  374.     for (p = list  ;  *p != ''  ;  ++p)
  375.     {
  376. if (strchr(EXTENSION_SEPARATORS, *p) != NULL)
  377.     ++count;
  378.     }
  379.     return count + 1;
  380. }
  381. static const char *const *readExtensionList( list )
  382.     const char *const list;
  383. {
  384.     int extIndex = 0;
  385.     const char *extension;
  386.     const unsigned int numExtensions = countExtensions(list);
  387.     char *const extensionList  = (char *)malloc(strlen(list) + 1);
  388.     const char **const extensionArray = (const char **)malloc(
  389. (numExtensions + 1) * sizeof(char *));
  390.     if (extensionList == NULL  ||  extensionArray == NULL)
  391. error(FATAL | PERROR, "");
  392.     strcpy(extensionList, list);
  393.     extension = strtok(extensionList, EXTENSION_SEPARATORS);
  394.     while (extension != NULL)
  395.     {
  396. DebugStatement( if (debug(DEBUG_STATUS))
  397.     printf("extension: %sn", extension); )
  398. extensionArray[extIndex++] = extension;
  399. extension = strtok(NULL, EXTENSION_SEPARATORS);
  400.     }
  401.     extensionArray[extIndex] = NULL;
  402.     return extensionArray;
  403. }
  404. static void clearTagList()
  405. {
  406.     Option.include.classNames = FALSE; /* -ic */
  407.     Option.include.defines = FALSE; /* -id */
  408.     Option.include.enumerators = FALSE; /* -ie */
  409.     Option.include.functions = FALSE; /* -if */
  410.     Option.include.enumNames = FALSE; /* -ig */
  411.     Option.include.interfaceNames = FALSE; /* -ii */
  412.     Option.include.members = FALSE; /* -im */
  413.     Option.include.namespaceNames = FALSE; /* -in */
  414.     Option.include.prototypes = FALSE; /* -ip */
  415.     Option.include.structNames = FALSE; /* -is */
  416.     Option.include.typedefs = FALSE; /* -it */
  417.     Option.include.unionNames = FALSE; /* -iu */
  418.     Option.include.variables = FALSE; /* -iC */
  419.     Option.include.sourceFiles = FALSE; /* -iF */
  420.     Option.include.statics = FALSE; /* -iS */
  421. }
  422. static void applyTagInclusionList( list )
  423.     const char *const list;
  424. {
  425.     boolean mode = TRUE; /* default mode is to add following types */
  426.     const char *p;
  427.     for (p = list  ;  *p != ''  ;  ++p)
  428. switch (*p)
  429. {
  430.     case '=': /* exclusive mode; ONLY types following are included */
  431. clearTagList();
  432. mode = TRUE;
  433. break;
  434.     case '+': mode = TRUE; break; /* include types following */
  435.     case '-': mode = FALSE; break; /* exclude types following */
  436.     case 'c': Option.include.classNames = mode; break;
  437.     case 'd': Option.include.defines = mode; break;
  438.     case 'e': Option.include.enumerators = mode; break;
  439.     case 'f': Option.include.functions = mode; break;
  440.     case 'g': Option.include.enumNames = mode; break;
  441.     case 'i': Option.include.interfaceNames = mode; break;
  442.     case 'm': Option.include.members = mode; break;
  443.     case 'n': Option.include.namespaceNames = mode; break;
  444.     case 'p': Option.include.prototypes = mode; break;
  445.     case 's': Option.include.structNames = mode; break;
  446.     case 't': Option.include.typedefs = mode; break;
  447.     case 'u': Option.include.unionNames = mode; break;
  448.     case 'v': Option.include.variables = mode; break;
  449.     case 'x': Option.include.externVars = mode; break;
  450.     case 'C': Option.include.classPrefix = mode; break;
  451.     case 'F': Option.include.sourceFiles = mode; break;
  452.     case 'S': Option.include.statics = mode; break;
  453.     default: error(FATAL, "-i: Invalid tag option '%c'", *p); break;
  454. }
  455. }
  456. /*  Determines whether or not "name" should be ignored, per the ignore list.
  457.  */
  458. extern boolean isIgnoreToken( name )
  459.     const char *const name;
  460. {
  461.     boolean ignore = FALSE;
  462.     unsigned int i;
  463.     for (i = 0  ;  i < Option.ignore.count ; ++i)
  464.     {
  465. if (strcmp(Option.ignore.list[i], name) == 0)
  466. {
  467.     ignore = TRUE;
  468.     break;
  469. }
  470.     }
  471.     return ignore;
  472. }
  473. static char *saveString( string )
  474.     const char *const string;
  475. {
  476.     char *const here = (char *)malloc(strlen(string) + 1);
  477.     if (here == NULL)
  478. error(FATAL | PERROR, "");
  479.     strcpy(here, string);
  480.     return here;
  481. }
  482. static void resizeIgnoreList()
  483. {
  484.     size_t newSize;
  485.     Option.ignore.max = Option.ignore.count + 10;
  486.     newSize = Option.ignore.max * sizeof(char *);
  487.     if (Option.ignore.list == NULL)
  488. Option.ignore.list = (char **)malloc(newSize);
  489.     else
  490. Option.ignore.list = (char **)realloc(Option.ignore.list, newSize);
  491.     if (Option.ignore.list == NULL)
  492. error(FATAL | PERROR, "cannot create ignore list");
  493. }
  494. static void saveIgnoreToken( ignoreToken )
  495.     const char *const ignoreToken;
  496. {
  497.     const unsigned int i = Option.ignore.count++;
  498.     if (Option.ignore.count > Option.ignore.max)
  499. resizeIgnoreList();
  500.     Option.ignore.list[i] = saveString(ignoreToken);
  501.     DebugStatement( if (debug(DEBUG_STATUS))
  502. printf("ignore token: %sn", ignoreToken); )
  503. }
  504. static void readIgnoreList( list )
  505.     char *const list;
  506. {
  507.     const char *token = strtok(list, IGNORE_SEPARATORS);
  508.     while (token != NULL)
  509.     {
  510. saveIgnoreToken(token);
  511. token = strtok(NULL, IGNORE_SEPARATORS);
  512.     }
  513. }
  514. static void readIgnoreListFromFile( fileName )
  515.     const char *const fileName;
  516. {
  517.     FILE *const fp = fopen(fileName, "r");
  518.     if (fp == NULL)
  519. error(FATAL | PERROR, "cannot open "%s"", fileName);
  520.     else
  521.     {
  522. char ignoreToken[MaxNameLength];
  523. while (fscanf(fp, "%255s", ignoreToken) == 1)
  524.     saveIgnoreToken(ignoreToken);
  525.     }
  526. }
  527. extern void freeIgnoreList()
  528. {
  529.     while (Option.ignore.count > 0)
  530. free(Option.ignore.list[--Option.ignore.count]);
  531.     if (Option.ignore.list != NULL)
  532. free(Option.ignore.list);
  533.     Option.ignore.list = NULL;
  534.     Option.ignore.max = 0;
  535. }
  536. static void processHeaderListOption( option, argP, argList, argNumP )
  537.     const int option;
  538.     char **const argP;
  539.     char *const *const argList;
  540.     int *const argNumP;
  541. {
  542.     char *const list = readOptionArg(option, argP, argList, argNumP);
  543.     /*  Check to make sure that the user did not enter "ctags -h *.c"
  544.      *  by testing to see if the list is a filename that exists.
  545.      */
  546.     if (doesFileExist(list) == 0)
  547. error(FATAL, "-h: Invalid list");
  548.     else
  549.     {
  550. DebugStatement( if (debug(DEBUG_STATUS))
  551.     printf("Header Extensions:n"); )
  552. Option.headerExt = readExtensionList(list);
  553.     }
  554. }
  555. static void processIgnoreOption( option, argP, argList, argNumP )
  556.     const int option;
  557.     char **const argP;
  558.     char *const *const argList;
  559.     int *const argNumP;
  560. {
  561.     char *const list = readOptionArg(option, argP, argList, argNumP);
  562.     if (strchr("./\", list[0]) != NULL)
  563. readIgnoreListFromFile(list);
  564.     else
  565. readIgnoreList(list);
  566. }
  567. static boolean getBooleanOption( optionName, parameter, defaultValue )
  568.     const char *const optionName;
  569.     const char *const parameter;
  570.     const boolean defaultValue;
  571. {
  572.     boolean selection = defaultValue;
  573.     if (parameter[0] == '')
  574. selection = defaultValue;
  575.     else if (strcmp(parameter, "0") == 0  ||  strcmp(parameter, "no") == 0)
  576. selection = FALSE;
  577.     else if (strcmp(parameter, "1") == 0  ||  strcmp(parameter, "yes") == 0)
  578. selection = TRUE;
  579.     else
  580. error(FATAL, "Invalid value for option --%s", optionName);
  581.     return selection;
  582. }
  583. static void processExcmdOption( optionName, parameter )
  584.     const char *const optionName;
  585.     const char *const parameter;
  586. {
  587.     switch (*parameter)
  588.     {
  589. case 'm': Option.locate = EX_MIX; break;
  590. case 'n': Option.locate = EX_LINENUM; break;
  591. case 'p': Option.locate = EX_PATTERN; break;
  592. default:
  593.     error(FATAL, "Invalid value for option --%s", optionName);
  594.     break;
  595.     }
  596. }
  597. static void processFormatOption( optionName, parameter )
  598.     const char *const optionName;
  599.     const char *const parameter;
  600. {
  601.     unsigned int format;
  602.     if (sscanf(parameter, "%u", &format) < 1)
  603. error(FATAL, "Missing or invalid value for "--%s" option",optionName);
  604.     else if (format <= (unsigned int)MaxSupportedTagFormat)
  605. Option.tagFileFormat = format;
  606.     else
  607. error(FATAL, "Unsupported value for "--%s" option", optionName);
  608. }
  609. extern const char *getLanguageName( language )
  610.     const langType language;
  611. {
  612.     static const char *const names[] = { "c", "c++", "java" };
  613.     DebugStatement( if (sizeof(names)/sizeof(names[0]) != LANG_COUNT)
  614. error(FATAL, "LangNames array not consistent with LANG enumeration"); )
  615.     return names[(int)language];
  616. }
  617. extern boolean strequiv( s1, s2 )
  618.     const char *s1;
  619.     const char *s2;
  620. {
  621.     boolean equivalent;
  622.     if (strcmp(s1, s2) == 0)
  623. equivalent = TRUE;
  624.     else
  625.     {
  626. equivalent = TRUE;
  627. do
  628. {
  629.     if (toupper(*s1) != toupper(*s2))
  630.     {
  631. equivalent = FALSE;
  632. break;
  633.     }
  634. } while (*s1++ != ''  &&  *s2++ != '');
  635.     }
  636.     return equivalent;
  637. }
  638. static langType getLangType( name )
  639.     const char *const name;
  640. {
  641.     unsigned int i;
  642.     langType language = LANG_IGNORE;
  643.     for (i = 0  ;  i < LANG_COUNT  ;  ++i)
  644.     {
  645.          if (strequiv(name, getLanguageName((langType)i)))
  646.  {
  647.     language = (langType)i;
  648.     break;
  649.  }
  650.     }
  651.     return language;
  652. }
  653. static void processLangOption( optionName, parameter )
  654.     const char *const optionName;
  655.     const char *const parameter;
  656. {
  657.     const langType language = getLangType(parameter);
  658.     if (language == LANG_IGNORE)
  659. error(FATAL, "Invalid value for option --%s", optionName);
  660.     else
  661. Option.language = language;
  662. }
  663. static void installLangMap( map )
  664.     char *const map;
  665. {
  666.     char *const separator = strchr(map, ':');
  667.     if (separator != NULL)
  668.     {
  669. langType language;
  670. *separator = '';
  671. language = getLangType(map);
  672. if (language == LANG_IGNORE)
  673.     error(FATAL, "Invalid language specified for option --langmap");
  674. DebugStatement( if (debug(DEBUG_STATUS))
  675.     printf("%s map:n", map); )
  676. Option.langMap[(int)language] = readExtensionList(separator + 1);
  677.     }
  678. }
  679. static void processLangMapOption( optionName, parameter )
  680.     const char *const __unused__ optionName;
  681.     const char *const parameter;
  682. {
  683.     char *const maps = (char *)malloc(strlen(parameter) + 1);
  684.     char *map = maps;
  685.     if (maps == NULL)
  686. error(FATAL | PERROR, "");
  687.     strcpy(maps, parameter);
  688.     DebugStatement( if (debug(DEBUG_STATUS))
  689. printf("Language-extension maps:n"); )
  690.     while (map != NULL)
  691.     {
  692. char *end = strchr(parameter, ',');
  693. if (end != NULL)
  694.     *end = '';
  695. installLangMap(map);
  696. if (end != NULL)
  697.     map = end + 1;
  698. else
  699.     map = NULL;
  700.     }
  701.     free(maps);
  702. }
  703. static void processLongOption( optionString )
  704.     const char *const optionString;
  705. {
  706.     enum { MaxOptionName = 10 };
  707.     char optionName[MaxOptionName + 1];
  708.     const char *const equal = strchr(optionString, '=');
  709.     const char *parameter = (equal == NULL) ? "" : equal + 1;
  710.     const size_t optionLength = (equal == NULL) ? strlen(optionString) :
  711.        (equal - optionString);
  712.     DebugStatement( if (debug(DEBUG_OPTION))
  713. fprintf(errout, "Option: --%sn", optionString); )
  714.     strncpy(optionName, optionString, optionLength);
  715.     if (optionLength < (size_t)MaxOptionName)
  716. optionName[optionLength] = '';
  717.     else
  718. optionName[(size_t)MaxOptionName] = '';
  719. #define isOption(string) (strcmp(optionName, string) == 0)
  720.     if (isOption("append"))
  721. Option.append = getBooleanOption(optionName, parameter, TRUE);
  722.     else if (isOption("excmd"))
  723. processExcmdOption(optionName, parameter);
  724.     else if (isOption("format"))
  725. processFormatOption(optionName, parameter);
  726.     else if (isOption("help"))
  727. { printHelp(LongOptionDescription, stdout); exit(0); }
  728.     else if (isOption("if0"))
  729. Option.if0 = getBooleanOption(optionName, parameter, TRUE);
  730.     else if (isOption("lang"))
  731. processLangOption(optionName, parameter);
  732.     else if (isOption("langmap"))
  733. processLangMapOption(optionName, parameter);
  734.     else if (isOption("recurse"))
  735. #ifdef RECURSE_SUPPORTED
  736. Option.recurse = getBooleanOption(optionName, parameter, TRUE);
  737. #else
  738. error(FATAL, "--%s option not supported on this host", optionName);
  739. #endif
  740.     else if (isOption("sort"))
  741. Option.sorted = getBooleanOption(optionName, parameter, TRUE);
  742.     else if (isOption("totals"))
  743. Option.printTotals = getBooleanOption(optionName, parameter, TRUE);
  744.     else if (isOption("version"))
  745.     {
  746. printProgramIdentification(stdout);
  747. exit(0);
  748.     }
  749.     else
  750. error(FATAL, "Unknown option: --%s", optionName);
  751. #undef isOption
  752. }
  753. static void processCompoundOption( option, pArg, argList, pArgNum )
  754.     const int option;
  755.     char **const pArg;
  756.     char *const *const argList;
  757.     int *const pArgNum;
  758. {
  759.     char *param;
  760.     DebugStatement( if (debug(DEBUG_OPTION) && option != '-')
  761. fprintf(errout, "Option: -%c ", option); )
  762.     switch (option)
  763.     {
  764.     /* Options requiring parameters.
  765.      */
  766.     case 'f':
  767.     case 'o': Option.tagFileName=readOptionArg(option, pArg, argList,pArgNum);
  768. break;
  769.     case 'h': processHeaderListOption(option, pArg, argList, pArgNum);
  770. break;
  771.     case 'i': param = readOptionArg(option, pArg, argList, pArgNum);
  772. applyTagInclusionList(param);
  773. break;
  774.     case 'I': processIgnoreOption(option, pArg, argList, pArgNum);
  775. break;
  776.     case 'L': Option.fileList = readOptionArg(option, pArg, argList, pArgNum);
  777. break;
  778.     case 'p': Option.path = readOptionArg(option, pArg, argList, pArgNum);
  779. break;
  780. #ifdef DEBUG
  781.     case 'D': param = readOptionArg(option, pArg, argList, pArgNum);
  782. Option.debugLevel = atoi(param);
  783. break;
  784.     case 'b': param = readOptionArg(option, pArg, argList, pArgNum);
  785. if (atol(param) < 0)
  786.     error(FATAL, "-%c: Invalid line number", option);
  787. Option.breakLine = atol(param);
  788. break;
  789. #endif
  790.     default: error(FATAL, "Unknown option: -%c", option); break;
  791.     }
  792.     DebugStatement( if (debug(DEBUG_OPTION)) fputs("n", errout); )
  793. }
  794. static boolean processSimpleOption( option )
  795.     const int option;
  796. {
  797.     boolean handled = TRUE;
  798.     switch (option)
  799.     {
  800. case 'a': Option.append = TRUE; break;
  801. case 'B': Option.backward = TRUE; break;
  802. case 'e': Option.etags = TRUE;
  803. Option.sorted = FALSE; break;
  804. case 'F': Option.backward = FALSE; break;
  805. case 'n': Option.locate = EX_LINENUM; break;
  806. case 'N': Option.locate = EX_PATTERN; break;
  807. case 'R':
  808. #ifdef RECURSE_SUPPORTED
  809. Option.recurse = TRUE; break;
  810. #else
  811. error(FATAL, "-R option not supported on this host");
  812. #endif
  813. case 'u': Option.sorted = FALSE; break;
  814. case 'w':
  815. case 'W': break;
  816. case 'x': Option.xref = TRUE; break;
  817. case '?': printHelp(LongOptionDescription, stdout);
  818. exit(0);
  819. default: handled = FALSE; break;
  820.     }
  821.     DebugStatement( if (handled && debug(DEBUG_OPTION))
  822. fprintf(errout, "Option: -%cn", option); )
  823.     return handled;
  824. }
  825. extern char *const *parseOptions( argList )
  826.     char *const *const argList;
  827. {
  828.     int argNum;
  829.     for (argNum = 0  ;  argList[argNum] != NULL  ;  ++argNum)
  830.     {
  831. char *arg = argList[argNum];
  832. int c;
  833. if (*arg++ != '-') /* stop at first non-option switch */
  834.     break;
  835. else if (*arg == '-') /* double dash: "--" */
  836.     processLongOption(arg + 1);
  837. else while ((c = *arg++) != '')
  838. {
  839.     if (! processSimpleOption(c))
  840. processCompoundOption(c, &arg, argList, &argNum);
  841. }
  842.     }
  843.     return &argList[argNum];
  844. }
  845. /*----------------------------------------------------------------------------
  846. *- Conversion of string into arg list
  847. ----------------------------------------------------------------------------*/
  848. static void parseStringToArgs( string, parsedBuffer, argList, maxArgs )
  849.     const char *const string;
  850.     char *parsedBuffer;
  851.     char **const argList;
  852.     const unsigned int maxArgs;
  853. {
  854.     boolean argInProgress = FALSE;
  855.     unsigned int count = 0;
  856.     const char *src;
  857.     for (src = string  ;  *src != ''  ;  ++src)
  858.     {
  859. if (*src == ' ') /* designates end of argument */
  860. {
  861.     if (argInProgress)
  862.     {
  863. *parsedBuffer++ = ''; /* terminate arg in progress */
  864. argInProgress = FALSE;
  865. if (count >= maxArgs)
  866.     break;
  867.     }
  868. }
  869. else
  870. {
  871.     if (! argInProgress)
  872.     {
  873. argInProgress = TRUE;
  874. argList[count++] = parsedBuffer; /* point to new arg */
  875.     }
  876.     if (*src == '\') /* next character is literal */
  877. ++src; /* skip over '\' */
  878.     *parsedBuffer++ = *src;
  879. }
  880.     }
  881.     *parsedBuffer = ''; /* null terminate last argument */
  882.     argList[count] = NULL; /* terminate list */
  883. }
  884. static unsigned int countStringWords( string )
  885.     const char *const string;
  886. {
  887.     const char *const whiteSpace = " tn";
  888.     const char *p = string;
  889.     unsigned int numWords = 0;
  890.     p += strspn(p, whiteSpace); /* skip over leading spaces */
  891.     while (*p != '')
  892.     {
  893. ++numWords;
  894. p += strcspn(p, whiteSpace); /* skip to white space */
  895. p += strspn(p, whiteSpace); /* skip to non-white space */
  896.     }
  897.     return numWords;
  898. }
  899. static char **creatArgListForString( string )
  900.     const char *const string;
  901. {
  902.     const unsigned int numWords = countStringWords(string);
  903.     char **argList = NULL;
  904.     if (string != NULL  &&  string[0] != '')
  905.     {
  906. /*  We place the parsed string at the end of the memory block, past
  907.  *  the bottom of the argument table.
  908.  */
  909. const size_t argListSize= (numWords + 1) * sizeof(char *);
  910. const size_t blockSize = argListSize + strlen(string) + 1;
  911. argList = (char **)malloc(blockSize);
  912. if (argList != NULL)
  913.     parseStringToArgs(string, (char *)argList + argListSize,
  914.       argList, numWords);
  915.     }
  916.     return argList;
  917. }
  918. extern void *parseEnvironmentOptions()
  919. {
  920.     const char *envOptions = NULL;
  921.     char **argList = NULL;
  922.     if (Option.startedAsEtags)
  923. envOptions = getenv(ETAGS_ENVIRONMENT);
  924.     if (envOptions == NULL)
  925. envOptions = getenv(CTAGS_ENVIRONMENT);
  926.     if (envOptions != NULL  &&  envOptions[0] != '')
  927.     {
  928. argList = creatArgListForString(envOptions);
  929. parseOptions(argList);
  930.     }
  931.     return argList;
  932. }
  933. /* vi:set tabstop=8 shiftwidth=4: */