static void makeEiffelFeatureTag (tokenInfo *const token) { if (EiffelKinds [EKIND_FEATURE].enabled && (token->isExported || isXtagEnabled(XTAG_FILE_SCOPE))) { const char *const name = vStringValue (token->string); tagEntryInfo e; initTagEntry (&e, name, &(EiffelKinds [EKIND_FEATURE])); e.isFileScope = (boolean) (! token->isExported); if (e.isFileScope) markTagExtraBit (&e, XTAG_FILE_SCOPE); e.extensionFields.scopeKind = &(EiffelKinds [EKIND_CLASS]); e.extensionFields.scopeName = vStringValue (token->className); makeTagEntry (&e); if (isXtagEnabled(XTAG_QUALIFIED_TAGS)) { vString* qualified = vStringNewInit (vStringValue (token->className)); vStringPut (qualified, '.'); vStringCat (qualified, token->string); e.name = vStringValue (qualified); markTagExtraBit (&e, XTAG_QUALIFIED_TAGS); makeTagEntry (&e); vStringDelete (qualified); } } vStringCopy (token->featureName, token->string); }
static void makeEiffelFeatureTag (tokenInfo *const token) { if (EiffelKinds [EKIND_FEATURE].enabled && (token->isExported || Option.include.fileScope)) { const char *const name = vStringValue (token->string); tagEntryInfo e; initTagEntry (&e, name); e.isFileScope = (boolean) (! token->isExported); e.kindName = EiffelKinds [EKIND_FEATURE].name; e.kind = EiffelKinds [EKIND_FEATURE].letter; e.extensionFields.scope [0] = EiffelKinds [EKIND_CLASS].name; e.extensionFields.scope [1] = vStringValue (token->className); makeTagEntry (&e); if (Option.include.qualifiedTags) { vString* qualified = vStringNewInit (vStringValue (token->className)); vStringPut (qualified, '.'); vStringCat (qualified, token->string); e.name = vStringValue (qualified); makeTagEntry (&e); vStringDelete (qualified); } } vStringCopy (token->featureName, token->string); }
static boolean recurseUsingOpendir (const char *const dirName) { boolean resize = FALSE; DIR *const dir = opendir (dirName); if (dir == NULL) error (WARNING | PERROR, "cannot recurse into directory \"%s\"", dirName); else { struct dirent *entry; while ((entry = readdir (dir)) != NULL) { if (strcmp (entry->d_name, ".") != 0 && strcmp (entry->d_name, "..") != 0) { vString *filePath; if (strcmp (dirName, ".") == 0) filePath = vStringNewInit (entry->d_name); else filePath = combinePathAndFile (dirName, entry->d_name); resize |= createTagsForEntry (vStringValue (filePath)); vStringDelete (filePath); } } closedir (dir); } return resize; }
static void dropContext (tokenInfo *const token) { verbose ("current context %s; context kind %0d; nest level %0d\n", vStringValue (currentContext->name), currentContext->kind, currentContext->nestLevel); vString *endTokenName = vStringNewInit("end"); if ((currentContext->kind == K_COVERGROUP && strcmp (vStringValue (token->name), "endgroup") == 0) || (currentContext->kind == K_BLOCK && currentContext->nestLevel == 0 && strcmp (vStringValue (token->name), vStringValue (endTokenName)) == 0) ) { verbose ("Dropping context %s\n", vStringValue (currentContext->name)); currentContext = popToken (currentContext); } else { vStringCatS (endTokenName, kindFromKind (currentContext->kind)->name); if (strcmp (vStringValue (token->name), vStringValue (endTokenName)) == 0) { verbose ("Dropping context %s\n", vStringValue (currentContext->name)); currentContext = popToken (currentContext); if (currentContext->classScope) { verbose ("Dropping local context %s\n", vStringValue (currentContext->name)); currentContext = popToken (currentContext); } } } vStringDelete(endTokenName); }
extern void addLanguageExtensionMap ( const langType language, const char* extension) { vString* const str = vStringNewInit (extension); Assert (0 <= language && language < (int) LanguageCount); stringListAdd (LanguageTable [language]->currentExtensions, str); }
extern void addLanguagePatternMap (const langType language, const char* ptrn) { vString* const str = vStringNewInit (ptrn); Assert (0 <= language && language < (int) LanguageCount); if (LanguageTable [language]->currentPatterns == NULL) LanguageTable [language]->currentPatterns = stringListNew (); stringListAdd (LanguageTable [language]->currentPatterns, str); }
extern void addLanguageAlias (const langType language, const char* alias) { vString* const str = vStringNewInit (alias); parserDefinition* lang; Assert (0 <= language && language < (int) LanguageCount); lang = LanguageTable [language]; if (lang->currentAliaes == NULL) lang->currentAliaes = stringListNew (); stringListAdd (lang->currentAliaes, str); }
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); }
static void processEtagsInclude ( const char *const option, const char *const parameter) { if (! Option.etags) error (FATAL, "Etags must be enabled to use \"%s\" option", option); else { vString *const file = vStringNewInit (parameter); if (Option.etagsInclude == NULL) Option.etagsInclude = stringListNew (); stringListAdd (Option.etagsInclude, file); FilesRequired = FALSE; } }
static vString* determineZshAutoloadTag (const char *const modeline) { /* See "Autoloaded files" in zsh info. ------------------------------------- #compdef ... #autoload [ OPTIONS ] */ if (((strncmp (modeline, "#compdef", 8) == 0) && isspace (*(modeline + 8))) || ((strncmp (modeline, "#autoload", 9) == 0) && (isspace (*(modeline + 9)) || *(modeline + 9) == '\0'))) return vStringNewInit ("zsh"); else return NULL; }
static void plistFindTagsUnderKey (xmlNode *node, const struct sTagXpathRecurSpec *spec, xmlXPathContext *ctx, void *userData) { xmlNode *current; xmlNode *prev; stringList *queue; vString* path; vString* v; int c; queue = stringListNew (); current = node; for (current = node; current; current = current->parent) { if (isCompoundElement (current) && (prev = getPrevKeyElement (current))) { char* parent = (char *)xmlNodeGetContent (prev); if (parent) { v = vStringNewInit (parent); stringListAdd (queue, v); xmlFree (parent); } } } path = vStringNew (); while ((c = stringListCount (queue)) > 0) { v = stringListLast (queue); vStringCat (path, v); vStringDelete (v); stringListRemoveLast (queue); if (c != 1) vStringPut (path, '.'); } stringListDelete (queue); findXMLTags (ctx, node, plistXpathTableTable + TABLE_TEXT, PlistKinds, (vStringLength (path) > 0)? vStringValue (path): NULL); vStringDelete (path); }
static void setInputFileName (const char *const fileName) { const char *const head = fileName; const char *const tail = baseFilename (head); if (File.name != NULL) vStringDelete (File.name); File.name = vStringNewInit (fileName); if (File.path != NULL) vStringDelete (File.path); if (tail == head) File.path = NULL; else { const size_t length = tail - head - 1; File.path = vStringNew (); vStringNCopyS (File.path, fileName, length); } }
static void addExtensionList ( stringList *const slist, const char *const elist, const boolean clear) { char *const extensionList = eStrdup (elist); const char *extension = NULL; boolean first = TRUE; if (clear) { verbose (" clearing\n"); stringListClear (slist); } verbose (" adding: "); if (elist != NULL && *elist != '\0') { extension = extensionList; if (elist [0] == EXTENSION_SEPARATOR) ++extension; } while (extension != NULL) { char *separator = strchr (extension, EXTENSION_SEPARATOR); if (separator != NULL) *separator = '\0'; verbose ("%s%s", first ? "" : ", ", *extension == '\0' ? "(NONE)" : extension); stringListAdd (slist, vStringNewInit (extension)); first = FALSE; if (separator == NULL) extension = NULL; else extension = separator + 1; } if (Option.verbose) { printf ("\n now: "); stringListPrint (slist); putchar ('\n'); } eFree (extensionList); }
static boolean createTagsForWildcardArg (const char *const arg) { boolean resize = FALSE; vString *const pattern = vStringNewInit (arg); char *patternS = vStringValue (pattern); #if defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST) /* We must transform the "." and ".." forms into something that can * be expanded by the findfirst/_findfirst functions. */ if (Option.recurse && (strcmp (patternS, ".") == 0 || strcmp (patternS, "..") == 0)) { vStringPut (pattern, OUTPUT_PATH_SEPARATOR); vStringCatS (pattern, "*.*"); } resize |= createTagsForWildcardUsingFindfirst (patternS); #endif vStringDelete (pattern); return resize; }
extern void addCorpusFile (const langType language, const char* const spec, vString* const corpus_file, boolean pattern_p) { FILE *input; unsigned char* tg_table; vString* vspec; input = fopen (vStringValue (corpus_file), "rb"); if (input == NULL) error (FATAL, "failed in open %s as corpus", vStringValue (corpus_file)); tg_table = tg_create (); if (!tg_table) error (FATAL, "failed allocating memory for tg entry"); tg_load (tg_table, input); fclose (input); vspec = pattern_p? vStringNewInit (spec): ext2ptrnNew (spec); addTgEntryFull (language, vspec, tg_table, corpus_file); }
static boolean loadPathKind (xcmdPath *const path, char* line, char *args[]) { const char* backup = line; char* off; vString *desc; kindOption *kind; if (line[0] == '\0') return FALSE; else if (!isblank(line[1])) { error (WARNING, "[%s] a space after letter is not found in kind description line: %s", args[0], backup); return FALSE; } path->kinds = xRealloc (path->kinds, path->n_kinds + 1, kindOption); kind = &path->kinds [path->n_kinds]; memset (kind, 0, sizeof (*kind)); kind->enabled = TRUE; kind->letter = line[0]; kind->name = NULL; kind->description = NULL; kind->referenceOnly = FALSE; kind->nRoles = 0; kind->roles = NULL; verbose (" kind letter: <%c>\n", kind->letter); for (line++; isblank(*line); line++) ; /* do nothing */ if (*line == '\0') { error (WARNING, "[%s] unexpectedly a kind description line is terminated: %s", args[0], backup); return FALSE; } Assert (!isblank (*line)); off = strrstr(line, "[off]"); if (off == line) { error (WARNING, "[%s] [off] is given but no kind description is found: %s", args[0], backup); return FALSE; } else if (off) { if (!isblank (*(off - 1))) { error (WARNING, "[%s] a whitespace must precede [off] flag: %s", args[0], backup); return FALSE; } kind->enabled = FALSE; *off = '\0'; } desc = vStringNewInit (line); vStringStripTrailing (desc); Assert (vStringLength (desc) > 0); kind->description = vStringDeleteUnwrap (desc); /* TODO: This conversion should be part of protocol. */ { char *tmp = eStrdup (kind->description); char *c; for (c = tmp; *c != '\0'; c++) { if (*c == ' ' || *c == '\t') *c = '_'; } kind->name = tmp; } path->n_kinds += 1; return TRUE; }
static void enterUnnamedScope (void) { stringListAdd (nesting, vStringNewInit ("")); }
static boolean loadPathKinds (xcmdPath *const path, const langType language) { enum pcoproc_error r; FILE* pp = NULL; char * argv[3]; int status; vString * opt; opt = vStringNewInit(XCMD_LIST_KIND_OPTION); vStringCatS (opt, "="); vStringCatS (opt, getLanguageName(language)); argv[2] = NULL; argv[1] = vStringValue (opt); argv[0] = vStringValue (path->path); errno = 0; verbose ("loading path kinds of %s from [%s %s]\n", getLanguageName(language), argv[0], argv[1]); r = pcoproc_open (vStringValue (path->path), argv, &pp, NULL); switch (r) { case PCOPROC_ERROR_WPIPE: error (WARNING | PERROR, "failed to make pipe to write to command: [%s %s]", argv[0], argv[1]); break; case PCOPROC_ERROR_RPIPE: error (WARNING | PERROR, "failed to make pipe to read from command: [%s %s]", argv[0], argv[1]); break; case PCOPROC_ERROR_FORK: error (WARNING | PERROR, "failed to do fork: [%s %s]", argv[0], argv[1]); break; case PCOPROC_SUCCESSFUL: break; } if (pp) { vString* vline = vStringNew(); while (readLineWithNoSeek (vline, pp)) { char* line; vStringStripNewline (vline); line = vStringValue (vline); if (!loadPathKind (path, line, argv)) break; } vStringDelete (vline); status = pcoproc_close (pp); /* TODO: Decode status */ verbose(" status: %d\n", status); if (status != 0) { if (status > 0 && WIFEXITED (status) && (WEXITSTATUS (status) == XCMD_NOT_AVAILABLE_STATUS)) notice ("xcmd recognizes %s is not available", argv[0]); else error (WARNING, "xcmd exits abnormally status(%d): [%s %s]", status, argv[0], argv[1]); vStringDelete (opt); return FALSE; } } else { error (WARNING | PERROR, "cannot make pipe to xcmd: [%s %s]", argv[0], argv[1]); } vStringDelete (opt); return path->kinds == NULL? FALSE: TRUE; }
static boolean loadPathKinds (xcmdPath *const path, const langType language) { enum pcoprocError r; FILE* pp = NULL; char * argv[3]; int status; vString * opt; char file_kind = getLanguageFileKind (language)->letter; opt = vStringNewInit(XCMD_LIST_KIND_OPTION); vStringCatS (opt, "="); vStringCatS (opt, getLanguageName(language)); argv[2] = NULL; argv[1] = vStringValue (opt); argv[0] = vStringValue (path->path); errno = 0; if (getuid() == 0 || geteuid() == 0) { verbose ("all xcmd feature is disabled when running ctags in root privilege\n"); vStringDelete (opt); return FALSE; } if (! isSafeExecutable (argv [0])) { vStringDelete (opt); return FALSE; } verbose ("loading path kinds of %s from [%s %s]\n", getLanguageName(language), argv[0], argv[1]); r = pcoprocOpen (vStringValue (path->path), argv, &pp, NULL); switch (r) { case PCOPROC_ERROR_WPIPE: error (WARNING | PERROR, "failed to make pipe to write to command: [%s %s]", argv[0], argv[1]); break; case PCOPROC_ERROR_RPIPE: error (WARNING | PERROR, "failed to make pipe to read from command: [%s %s]", argv[0], argv[1]); break; case PCOPROC_ERROR_FORK: error (WARNING | PERROR, "failed to do fork: [%s %s]", argv[0], argv[1]); break; case PCOPROC_SUCCESSFUL: break; } if (pp) { vString* vline = vStringNew(); while (readLineRawWithNoSeek (vline, pp)) { char* line; char kind_letter; vStringStripNewline (vline); line = vStringValue (vline); if (!loadPathKind (path, line, argv)) break; kind_letter = path->kinds [path->n_kinds - 1].letter; if (kind_letter == file_kind) error (FATAL, "Kind letter \'%c\' returned from xcmd %s of %s language is reserved in ctags main", kind_letter, vStringValue (path->path), getLanguageName (language)); } vStringDelete (vline); status = pcoprocClose (pp); /* TODO: Decode status */ verbose(" status: %d\n", status); if (status != 0) { if (status > 0 && WIFEXITED (status) && (WEXITSTATUS (status) == path->not_available_status)) verbose ("xcmd: the %s backend is not available\n", argv[0]); else error (WARNING, "xcmd exits abnormally status(%d): [%s %s]", status, argv[0], argv[1]); vStringDelete (opt); return FALSE; } } else { error (WARNING | PERROR, "cannot make pipe to xcmd: [%s %s]", argv[0], argv[1]); } vStringDelete (opt); return path->kinds == NULL? FALSE: TRUE; }
static vString* ext2ptrnNew (const char *const ext) { vString * ptrn = vStringNewInit ("*."); vStringCatS (ptrn, ext); return ptrn; }
extern void addTgEntryForPattern (const langType language, const char* const ptrn, unsigned char* const tg_table) { addTgEntryFull (language, vStringNewInit (ptrn), tg_table, NULL); }
void cxxTagCommit(void) { if(g_oCXXTag.isFileScope) { if (isXtagEnabled(XTAG_FILE_SCOPE)) markTagExtraBit (&g_oCXXTag, XTAG_FILE_SCOPE); else return; } CXX_DEBUG_PRINT( "Emitting tag for symbol '%s', kind '%s', line %d", g_oCXXTag.name, g_oCXXTag.kind->name, g_oCXXTag.lineNumber ); if( g_oCXXTag.extensionFields.typeRef[0] && g_oCXXTag.extensionFields.typeRef[1] ) CXX_DEBUG_PRINT( "Tag has typeref %s %s", g_oCXXTag.extensionFields.typeRef[0], g_oCXXTag.extensionFields.typeRef[1] ); makeTagEntry(&g_oCXXTag); // Handle --extra=+q if(!isXtagEnabled(XTAG_QUALIFIED_TAGS)) return; else markTagExtraBit (&g_oCXXTag, XTAG_QUALIFIED_TAGS); if(!g_oCXXTag.extensionFields.scopeName) return; // WARNING: The following code assumes that the scope // didn't change between cxxTagBegin() and cxxTagCommit(). enum CXXTagKind eScopeKind = cxxScopeGetKind(); if(eScopeKind == CXXTagKindFUNCTION) { // old ctags didn't do this, and --extra=+q is mainly // for backward compatibility so... return; } // Same tag. Only the name changes. vString * x; if(eScopeKind == CXXTagKindENUM) { // If the scope kind is enumeration then we need to remove the // last scope part. This is what old ctags did. if(cxxScopeGetSize() < 2) return; // toplevel enum x = cxxScopeGetFullNameExceptLastComponentAsString(); CXX_DEBUG_ASSERT(x,"Scope with size >= 2 should have returned a value here"); } else { x = vStringNewInit(g_oCXXTag.extensionFields.scopeName); } vStringCatS(x,"::"); vStringCatS(x,g_oCXXTag.name); g_oCXXTag.name = vStringValue(x); CXX_DEBUG_PRINT( "Emitting extra tag for symbol '%s', kind '%s', line %d", g_oCXXTag.name, g_oCXXTag.kind->name, g_oCXXTag.lineNumber ); makeTagEntry(&g_oCXXTag); vStringDelete(x); }