diff options
author | Patrick McCarty <patrick.mccarty@linux.intel.com> | 2013-04-12 10:40:25 -0700 |
---|---|---|
committer | Patrick McCarty <patrick.mccarty@linux.intel.com> | 2013-04-12 10:40:25 -0700 |
commit | 793eb3eb123664017100dfb1a5407f0da639a339 (patch) | |
tree | 2a6511443d115418007151f95f3a0fa8f5300974 /parse.c | |
download | ctags-793eb3eb123664017100dfb1a5407f0da639a339.tar.gz ctags-793eb3eb123664017100dfb1a5407f0da639a339.tar.bz2 ctags-793eb3eb123664017100dfb1a5407f0da639a339.zip |
Imported Upstream version 5.8upstream/5.8upstream
Diffstat (limited to 'parse.c')
-rw-r--r-- | parse.c | 677 |
1 files changed, 677 insertions, 0 deletions
@@ -0,0 +1,677 @@ +/* +* $Id: parse.c 597 2007-07-31 05:35:30Z dhiebert $ +* +* Copyright (c) 1996-2003, Darren Hiebert +* +* This source code is released for free distribution under the terms of the +* GNU General Public License. +* +* This module contains functions for managing source languages and +* dispatching files to the appropriate language parser. +*/ + +/* +* INCLUDE FILES +*/ +#include "general.h" /* must always come first */ + +#include <string.h> + +#include "debug.h" +#include "entry.h" +#include "main.h" +#define OPTION_WRITE +#include "options.h" +#include "parsers.h" +#include "read.h" +#include "routines.h" +#include "vstring.h" + +/* +* DATA DEFINITIONS +*/ +static parserDefinitionFunc* BuiltInParsers[] = { PARSER_LIST }; +static parserDefinition** LanguageTable = NULL; +static unsigned int LanguageCount = 0; + +/* +* FUNCTION DEFINITIONS +*/ + +extern void makeSimpleTag ( + const vString* const name, kindOption* const kinds, const int kind) +{ + if (kinds [kind].enabled && name != NULL && vStringLength (name) > 0) + { + tagEntryInfo e; + initTagEntry (&e, vStringValue (name)); + + e.kindName = kinds [kind].name; + e.kind = kinds [kind].letter; + + makeTagEntry (&e); + } +} + +/* +* parserDescription mapping management +*/ + +extern parserDefinition* parserNew (const char* name) +{ + parserDefinition* result = xCalloc (1, parserDefinition); + result->name = eStrdup (name); + return result; +} + +extern const char *getLanguageName (const langType language) +{ + const char* result; + if (language == LANG_IGNORE) + result = "unknown"; + else + { + Assert (0 <= language && language < (int) LanguageCount); + result = LanguageTable [language]->name; + } + return result; +} + +extern langType getNamedLanguage (const char *const name) +{ + langType result = LANG_IGNORE; + unsigned int i; + Assert (name != NULL); + for (i = 0 ; i < LanguageCount && result == LANG_IGNORE ; ++i) + { + const parserDefinition* const lang = LanguageTable [i]; + if (lang->name != NULL) + if (strcasecmp (name, lang->name) == 0) + result = i; + } + return result; +} + +static langType getExtensionLanguage (const char *const extension) +{ + langType result = LANG_IGNORE; + unsigned int i; + for (i = 0 ; i < LanguageCount && result == LANG_IGNORE ; ++i) + { + stringList* const exts = LanguageTable [i]->currentExtensions; + if (exts != NULL && stringListExtensionMatched (exts, extension)) + result = i; + } + return result; +} + +static langType getPatternLanguage (const char *const fileName) +{ + langType result = LANG_IGNORE; + const char* base = baseFilename (fileName); + unsigned int i; + for (i = 0 ; i < LanguageCount && result == LANG_IGNORE ; ++i) + { + stringList* const ptrns = LanguageTable [i]->currentPatterns; + if (ptrns != NULL && stringListFileMatched (ptrns, base)) + result = i; + } + return result; +} + +#ifdef SYS_INTERPRETER + +/* The name of the language interpreter, either directly or as the argument + * to "env". + */ +static vString* determineInterpreter (const char* const cmd) +{ + vString* const interpreter = vStringNew (); + const char* p = cmd; + do + { + vStringClear (interpreter); + for ( ; isspace ((int) *p) ; ++p) + ; /* no-op */ + for ( ; *p != '\0' && ! isspace ((int) *p) ; ++p) + vStringPut (interpreter, (int) *p); + vStringTerminate (interpreter); + } while (strcmp (vStringValue (interpreter), "env") == 0); + return interpreter; +} + +static langType getInterpreterLanguage (const char *const fileName) +{ + langType result = LANG_IGNORE; + FILE* const fp = fopen (fileName, "r"); + if (fp != NULL) + { + vString* const vLine = vStringNew (); + const char* const line = readLine (vLine, fp); + if (line != NULL && line [0] == '#' && line [1] == '!') + { + const char* const lastSlash = strrchr (line, '/'); + const char *const cmd = lastSlash != NULL ? lastSlash+1 : line+2; + vString* const interpreter = determineInterpreter (cmd); + result = getExtensionLanguage (vStringValue (interpreter)); + if (result == LANG_IGNORE) + result = getNamedLanguage (vStringValue (interpreter)); + vStringDelete (interpreter); + } + vStringDelete (vLine); + fclose (fp); + } + return result; +} + +#endif + +extern langType getFileLanguage (const char *const fileName) +{ + langType language = Option.language; + if (language == LANG_AUTO) + { + language = getExtensionLanguage (fileExtension (fileName)); + if (language == LANG_IGNORE) + language = getPatternLanguage (fileName); +#ifdef SYS_INTERPRETER + if (language == LANG_IGNORE) + { + fileStatus *status = eStat (fileName); + if (status->isExecutable) + language = getInterpreterLanguage (fileName); + } +#endif + } + return language; +} + +extern void printLanguageMap (const langType language) +{ + boolean first = TRUE; + unsigned int i; + stringList* map = LanguageTable [language]->currentPatterns; + Assert (0 <= language && language < (int) LanguageCount); + for (i = 0 ; map != NULL && i < stringListCount (map) ; ++i) + { + printf ("%s(%s)", (first ? "" : " "), + vStringValue (stringListItem (map, i))); + first = FALSE; + } + map = LanguageTable [language]->currentExtensions; + for (i = 0 ; map != NULL && i < stringListCount (map) ; ++i) + { + printf ("%s.%s", (first ? "" : " "), + vStringValue (stringListItem (map, i))); + first = FALSE; + } +} + +extern void installLanguageMapDefault (const langType language) +{ + parserDefinition* lang; + Assert (0 <= language && language < (int) LanguageCount); + lang = LanguageTable [language]; + if (lang->currentPatterns != NULL) + stringListDelete (lang->currentPatterns); + if (lang->currentExtensions != NULL) + stringListDelete (lang->currentExtensions); + + if (lang->patterns == NULL) + lang->currentPatterns = stringListNew (); + else + { + lang->currentPatterns = + stringListNewFromArgv (lang->patterns); + } + if (lang->extensions == NULL) + lang->currentExtensions = stringListNew (); + else + { + lang->currentExtensions = + stringListNewFromArgv (lang->extensions); + } + if (Option.verbose) + printLanguageMap (language); + verbose ("\n"); +} + +extern void installLanguageMapDefaults (void) +{ + unsigned int i; + for (i = 0 ; i < LanguageCount ; ++i) + { + verbose (" %s: ", getLanguageName (i)); + installLanguageMapDefault (i); + } +} + +extern void clearLanguageMap (const langType language) +{ + Assert (0 <= language && language < (int) LanguageCount); + stringListClear (LanguageTable [language]->currentPatterns); + stringListClear (LanguageTable [language]->currentExtensions); +} + +extern void addLanguagePatternMap (const langType language, const char* ptrn) +{ + vString* const str = vStringNewInit (ptrn); + parserDefinition* lang; + Assert (0 <= language && language < (int) LanguageCount); + lang = LanguageTable [language]; + if (lang->currentPatterns == NULL) + lang->currentPatterns = stringListNew (); + stringListAdd (lang->currentPatterns, str); +} + +extern boolean removeLanguageExtensionMap (const char *const extension) +{ + boolean result = FALSE; + unsigned int i; + for (i = 0 ; i < LanguageCount && ! result ; ++i) + { + stringList* const exts = LanguageTable [i]->currentExtensions; + if (exts != NULL && stringListRemoveExtension (exts, extension)) + { + verbose (" (removed from %s)", getLanguageName (i)); + result = TRUE; + } + } + return result; +} + +extern void addLanguageExtensionMap ( + const langType language, const char* extension) +{ + vString* const str = vStringNewInit (extension); + Assert (0 <= language && language < (int) LanguageCount); + removeLanguageExtensionMap (extension); + stringListAdd (LanguageTable [language]->currentExtensions, str); +} + +extern void enableLanguage (const langType language, const boolean state) +{ + Assert (0 <= language && language < (int) LanguageCount); + LanguageTable [language]->enabled = state; +} + +extern void enableLanguages (const boolean state) +{ + unsigned int i; + for (i = 0 ; i < LanguageCount ; ++i) + enableLanguage (i, state); +} + +static void initializeParsers (void) +{ + unsigned int i; + for (i = 0 ; i < LanguageCount ; ++i) + if (LanguageTable [i]->initialize != NULL) + (LanguageTable [i]->initialize) ((langType) i); +} + +extern void initializeParsing (void) +{ + unsigned int builtInCount; + unsigned int i; + + builtInCount = sizeof (BuiltInParsers) / sizeof (BuiltInParsers [0]); + LanguageTable = xMalloc (builtInCount, parserDefinition*); + + verbose ("Installing parsers: "); + for (i = 0 ; i < builtInCount ; ++i) + { + parserDefinition* const def = (*BuiltInParsers [i]) (); + if (def != NULL) + { + boolean accepted = FALSE; + if (def->name == NULL || def->name[0] == '\0') + error (FATAL, "parser definition must contain name\n"); + else if (def->regex) + { +#ifdef HAVE_REGEX + def->parser = findRegexTags; + accepted = TRUE; +#endif + } + else if ((def->parser == NULL) == (def->parser2 == NULL)) + error (FATAL, + "%s parser definition must define one and only one parsing routine\n", + def->name); + else + accepted = TRUE; + if (accepted) + { + verbose ("%s%s", i > 0 ? ", " : "", def->name); + def->id = LanguageCount++; + LanguageTable [def->id] = def; + } + } + } + verbose ("\n"); + enableLanguages (TRUE); + initializeParsers (); +} + +extern void freeParserResources (void) +{ + unsigned int i; + for (i = 0 ; i < LanguageCount ; ++i) + { + parserDefinition* const lang = LanguageTable [i]; + freeList (&lang->currentPatterns); + freeList (&lang->currentExtensions); + eFree (lang->name); + lang->name = NULL; + eFree (lang); + } + if (LanguageTable != NULL) + eFree (LanguageTable); + LanguageTable = NULL; + LanguageCount = 0; +} + +/* +* Option parsing +*/ + +extern void processLanguageDefineOption ( + const char *const option, const char *const parameter __unused__) +{ +#ifdef HAVE_REGEX + if (parameter [0] == '\0') + error (WARNING, "No language specified for \"%s\" option", option); + else if (getNamedLanguage (parameter) != LANG_IGNORE) + error (WARNING, "Language \"%s\" already defined", parameter); + else + { + unsigned int i = LanguageCount++; + parserDefinition* const def = parserNew (parameter); + def->parser = findRegexTags; + def->currentPatterns = stringListNew (); + def->currentExtensions = stringListNew (); + def->regex = TRUE; + def->enabled = TRUE; + def->id = i; + LanguageTable = xRealloc (LanguageTable, i + 1, parserDefinition*); + LanguageTable [i] = def; + } +#else + error (WARNING, "regex support not available; required for --%s option", + option); +#endif +} + +static kindOption *langKindOption (const langType language, const int flag) +{ + unsigned int i; + kindOption* result = NULL; + const parserDefinition* lang; + Assert (0 <= language && language < (int) LanguageCount); + lang = LanguageTable [language]; + for (i=0 ; i < lang->kindCount && result == NULL ; ++i) + if (lang->kinds [i].letter == flag) + result = &lang->kinds [i]; + return result; +} + +static void disableLanguageKinds (const langType language) +{ + const parserDefinition* lang; + Assert (0 <= language && language < (int) LanguageCount); + lang = LanguageTable [language]; + if (lang->regex) + disableRegexKinds (language); + else + { + unsigned int i; + for (i = 0 ; i < lang->kindCount ; ++i) + lang->kinds [i].enabled = FALSE; + } +} + +static boolean enableLanguageKind ( + const langType language, const int kind, const boolean mode) +{ + boolean result = FALSE; + if (LanguageTable [language]->regex) + result = enableRegexKind (language, kind, mode); + else + { + kindOption* const opt = langKindOption (language, kind); + if (opt != NULL) + { + opt->enabled = mode; + result = TRUE; + } + } + return result; +} + +static void processLangKindOption ( + const langType language, const char *const option, + const char *const parameter) +{ + const char *p = parameter; + boolean mode = TRUE; + int c; + + Assert (0 <= language && language < (int) LanguageCount); + if (*p != '+' && *p != '-') + disableLanguageKinds (language); + while ((c = *p++) != '\0') switch (c) + { + case '+': mode = TRUE; break; + case '-': mode = FALSE; break; + default: + if (! enableLanguageKind (language, c, mode)) + error (WARNING, "Unsupported parameter '%c' for --%s option", + c, option); + break; + } +} + +extern boolean processKindOption ( + const char *const option, const char *const parameter) +{ + boolean handled = FALSE; + const char* const dash = strchr (option, '-'); + if (dash != NULL && + (strcmp (dash + 1, "kinds") == 0 || strcmp (dash + 1, "types") == 0)) + { + langType language; + vString* langName = vStringNew (); + vStringNCopyS (langName, option, dash - option); + language = getNamedLanguage (vStringValue (langName)); + if (language == LANG_IGNORE) + error (WARNING, "Unknown language \"%s\" in \"%s\" option", vStringValue (langName), option); + else + processLangKindOption (language, option, parameter); + vStringDelete (langName); + handled = TRUE; + } + return handled; +} + +static void printLanguageKind (const kindOption* const kind, boolean indent) +{ + const char *const indentation = indent ? " " : ""; + printf ("%s%c %s%s\n", indentation, kind->letter, + kind->description != NULL ? kind->description : + (kind->name != NULL ? kind->name : ""), + kind->enabled ? "" : " [off]"); +} + +static void printKinds (langType language, boolean indent) +{ + const parserDefinition* lang; + Assert (0 <= language && language < (int) LanguageCount); + lang = LanguageTable [language]; + if (lang->kinds != NULL || lang->regex) + { + unsigned int i; + for (i = 0 ; i < lang->kindCount ; ++i) + printLanguageKind (lang->kinds + i, indent); + printRegexKinds (language, indent); + } +} + +extern void printLanguageKinds (const langType language) +{ + if (language == LANG_AUTO) + { + unsigned int i; + for (i = 0 ; i < LanguageCount ; ++i) + { + const parserDefinition* const lang = LanguageTable [i]; + printf ("%s%s\n", lang->name, lang->enabled ? "" : " [disabled]"); + printKinds (i, TRUE); + } + } + else + printKinds (language, FALSE); +} + +static void printMaps (const langType language) +{ + const parserDefinition* lang; + unsigned int i; + Assert (0 <= language && language < (int) LanguageCount); + lang = LanguageTable [language]; + printf ("%-8s", lang->name); + if (lang->currentExtensions != NULL) + for (i = 0 ; i < stringListCount (lang->currentExtensions) ; ++i) + printf (" *.%s", vStringValue ( + stringListItem (lang->currentExtensions, i))); + if (lang->currentPatterns != NULL) + for (i = 0 ; i < stringListCount (lang->currentPatterns) ; ++i) + printf (" %s", vStringValue ( + stringListItem (lang->currentPatterns, i))); + putchar ('\n'); +} + +extern void printLanguageMaps (const langType language) +{ + if (language == LANG_AUTO) + { + unsigned int i; + for (i = 0 ; i < LanguageCount ; ++i) + printMaps (i); + } + else + printMaps (language); +} + +static void printLanguage (const langType language) +{ + const parserDefinition* lang; + Assert (0 <= language && language < (int) LanguageCount); + lang = LanguageTable [language]; + if (lang->kinds != NULL || lang->regex) + printf ("%s%s\n", lang->name, lang->enabled ? "" : " [disabled]"); +} + +extern void printLanguageList (void) +{ + unsigned int i; + for (i = 0 ; i < LanguageCount ; ++i) + printLanguage (i); +} + +/* +* File parsing +*/ + +static void makeFileTag (const char *const fileName) +{ + if (Option.include.fileNames) + { + tagEntryInfo tag; + initTagEntry (&tag, baseFilename (fileName)); + + tag.isFileEntry = TRUE; + tag.lineNumberEntry = TRUE; + tag.lineNumber = 1; + tag.kindName = "file"; + tag.kind = 'F'; + + makeTagEntry (&tag); + } +} + +static boolean createTagsForFile ( + const char *const fileName, const langType language, + const unsigned int passCount) +{ + boolean retried = FALSE; + Assert (0 <= language && language < (int) LanguageCount); + if (fileOpen (fileName, language)) + { + const parserDefinition* const lang = LanguageTable [language]; + if (Option.etags) + beginEtagsFile (); + + makeFileTag (fileName); + + if (lang->parser != NULL) + lang->parser (); + else if (lang->parser2 != NULL) + retried = lang->parser2 (passCount); + + if (Option.etags) + endEtagsFile (getSourceFileTagPath ()); + + fileClose (); + } + + return retried; +} + +static boolean createTagsWithFallback ( + const char *const fileName, const langType language) +{ + const unsigned long numTags = TagFile.numTags.added; + fpos_t tagFilePosition; + unsigned int passCount = 0; + boolean tagFileResized = FALSE; + + fgetpos (TagFile.fp, &tagFilePosition); + while (createTagsForFile (fileName, language, ++passCount)) + { + /* Restore prior state of tag file. + */ + fsetpos (TagFile.fp, &tagFilePosition); + TagFile.numTags.added = numTags; + tagFileResized = TRUE; + } + return tagFileResized; +} + +extern boolean parseFile (const char *const fileName) +{ + boolean tagFileResized = FALSE; + langType language = Option.language; + if (Option.language == LANG_AUTO) + language = getFileLanguage (fileName); + Assert (language != LANG_AUTO); + if (language == LANG_IGNORE) + verbose ("ignoring %s (unknown language)\n", fileName); + else if (! LanguageTable [language]->enabled) + verbose ("ignoring %s (language disabled)\n", fileName); + else + { + if (Option.filter) + openTagFile (); + + tagFileResized = createTagsWithFallback (fileName, language); + + if (Option.filter) + closeTagFile (tagFileResized); + addTotals (1, 0L, 0L); + + return tagFileResized; + } + return tagFileResized; +} + +/* vi:set tabstop=4 shiftwidth=4 nowrap: */ |