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 int makeDefineTag (const char *const name, bool parameterized, bool undef) { const bool isFileScope = (bool) (! isInputHeaderFile ()); if (!Cpp.defineMacroKind) return CORK_NIL; if (isFileScope && !isXtagEnabled(XTAG_FILE_SCOPE)) return CORK_NIL; if ( /* condition for definition tag */ ((!undef) && Cpp.defineMacroKind->enabled) || /* condition for reference tag */ (undef && isXtagEnabled(XTAG_REFERENCE_TAGS))) { tagEntryInfo e; initTagEntry (&e, name, Cpp.defineMacroKind); e.lineNumberEntry = (bool) (Option.locate == EX_LINENUM); e.isFileScope = isFileScope; e.truncateLine = true; if (parameterized) e.extensionFields.signature = cppGetSignature (); makeTagEntry (&e); if (parameterized) eFree((char *) e.extensionFields.signature); } return CORK_NIL; }
static void makeTag (tokenInfo *const token, const goKind kind, tokenInfo *const parent_token, const goKind parent_kind, const char *argList) { const char *const name = vStringValue (token->string); tagEntryInfo e; initTagEntry (&e, name, &(GoKinds [kind])); if (!GoKinds [kind].enabled) return; e.lineNumber = token->lineNumber; e.filePosition = token->filePosition; if (argList) e.extensionFields.signature = argList; if (parent_kind != GOTAG_UNDEFINED && parent_token != NULL) { e.extensionFields.scopeKind = &(GoKinds[parent_kind]); e.extensionFields.scopeName = vStringValue (parent_token->string); } makeTagEntry (&e); if (scope && isXtagEnabled(XTAG_QUALIFIED_TAGS)) { vString *qualifiedName = vStringNew (); vStringCopy (qualifiedName, scope); vStringCatS (qualifiedName, "."); vStringCat (qualifiedName, token->string); e.name = vStringValue (qualifiedName); makeTagEntry (&e); vStringDelete (qualifiedName); } }
/* `end' points to the equal sign. Parse from right to left to get the * identifier. Assume we're dealing with something of form \s*\w+\s*=> */ static void makeTagFromLeftSide (const char *begin, const char *end, vString *name, vString *package) { tagEntryInfo entry; const char *b, *e; if (! PerlKinds[K_CONSTANT].enabled) return; for (e = end - 1; e > begin && isspace(*e); --e) ; if (e < begin) return; for (b = e; b >= begin && isIdentifier(*b); --b) ; /* Identifier must be either beginning of line of have some whitespace * on its left: */ if (b < begin || isspace(*b) || ',' == *b) ++b; else if (b != begin) return; if (e - b + 1 <= 0) return; /* Left side of => has an invalid identifier. */ vStringClear(name); vStringNCatS(name, b, e - b + 1); initTagEntry(&entry, vStringValue(name), &(PerlKinds[K_CONSTANT])); makeTagEntry(&entry); if (isXtagEnabled (XTAG_QUALIFIED_TAGS) && package && vStringLength(package)) { vStringClear(name); vStringCopy(name, package); vStringNCatS(name, b, e - b + 1); initTagEntry(&entry, vStringValue(name), &(PerlKinds[K_CONSTANT])); markTagExtraBit (&entry, XTAG_QUALIFIED_TAGS); makeTagEntry(&entry); } }
static void directiveUndef (const int c) { if (isXtagEnabled (XTAG_REFERENCE_TAGS)) { directiveDefine (c, true); } else { Cpp.directive.state = DRCTV_NONE; } }
extern void makeFileTag (const char *const fileName) { boolean via_line_directive = (strcmp (fileName, getInputFileName()) != 0); xtagType xtag = XTAG_UNKNOWN; if (isXtagEnabled(XTAG_FILE_NAMES)) xtag = XTAG_FILE_NAMES; if (isXtagEnabled(XTAG_FILE_NAMES_WITH_TOTAL_LINES)) xtag = XTAG_FILE_NAMES_WITH_TOTAL_LINES; if (xtag != XTAG_UNKNOWN) { tagEntryInfo tag; kindOption *kind; kind = getInputLanguageFileKind(); Assert (kind); kind->enabled = isXtagEnabled(XTAG_FILE_NAMES); /* TODO: you can return here if enabled == FALSE. */ initTagEntry (&tag, baseFilename (fileName), kind); tag.isFileEntry = TRUE; tag.lineNumberEntry = TRUE; markTagExtraBit (&tag, xtag); if (via_line_directive || (!isXtagEnabled(XTAG_FILE_NAMES_WITH_TOTAL_LINES))) { tag.lineNumber = 1; } else { while (readLineFromInputFile () != NULL) ; /* Do nothing */ tag.lineNumber = getInputLineNumber (); } makeTagEntry (&tag); } }
static void parsePackage (tokenInfo *const token) { readToken (token); if (isType (token, TOKEN_IDENTIFIER)) { makeTag (token, GOTAG_PACKAGE, NULL, GOTAG_UNDEFINED, NULL); if (!scope && isXtagEnabled(XTAG_QUALIFIED_TAGS)) { scope = vStringNew (); vStringCopy (scope, token->string); } } }
static void simpleXpathMakeTag (xmlNode *node, const tagXpathMakeTagSpec *spec, const kindOption* const kinds, void *userData) { tagEntryInfo tag; xmlChar* str; const kindOption *kind; char *path; str = xmlNodeGetContent(node); if (str == NULL) return; kind = kinds + spec->kind; if (spec->role == ROLE_INDEX_DEFINITION) initTagEntry (&tag, (char *)str, kind); else if (isXtagEnabled(XTAG_REFERENCE_TAGS)) initRefTagEntry (&tag, (char *)str, kind, spec->role); else goto out; tag.lineNumber = xmlGetLineNo (node); tag.filePosition = getInputFilePositionForLine (tag.lineNumber); path = (char *)xmlGetNodePath (node); tag.extensionFields.xpath = path; if (spec->make) spec->make (node, spec, &tag, userData); else makeTagEntry (&tag); if (path) xmlFree (path); out: xmlFree (str); }
static void makeEiffelLocalTag (tokenInfo *const token) { if (EiffelKinds [EKIND_LOCAL].enabled && isXtagEnabled(XTAG_FILE_SCOPE)) { const char *const name = vStringValue (token->string); vString* scope = vStringNew (); tagEntryInfo e; initTagEntry (&e, name, &(EiffelKinds [EKIND_LOCAL])); e.isFileScope = TRUE; vStringCopy (scope, token->className); vStringPut (scope, '.'); vStringCat (scope, token->featureName); e.extensionFields.scopeKind = &(EiffelKinds [EKIND_FEATURE]); e.extensionFields.scopeName = vStringValue (scope); makeTagEntry (&e); vStringDelete (scope); } }
static int makeSimplePythonRefTag (const tokenInfo *const token, const vString *const altName, pythonKind const kind, int roleIndex, xtagType xtag) { if (isXtagEnabled (XTAG_REFERENCE_TAGS) && PythonKinds[kind].roles[roleIndex].enabled) { tagEntryInfo e; initRefTagEntry (&e, vStringValue (altName ? altName : token->string), kind, roleIndex); e.lineNumber = token->lineNumber; e.filePosition = token->filePosition; if (xtag != XTAG_UNKNOWN) markTagExtraBit (&e, xtag); return makeTagEntry (&e); } return CORK_NIL; }
extern void openTagFile (void) { setDefaultTagFileName (); TagsToStdout = isDestinationStdout (); if (TagFile.vLine == NULL) TagFile.vLine = vStringNew (); /* Open the tags file. */ if (TagsToStdout) { /* Open a tempfile with read and write mode. Read mode is used when * write the result to stdout. */ TagFile.fp = tempFile ("w+", &TagFile.name); if (isXtagEnabled (XTAG_PSEUDO_TAGS)) addCommonPseudoTags (); } else { boolean fileExists; TagFile.name = eStrdup (Option.tagFileName); fileExists = doesFileExist (TagFile.name); if (fileExists && ! isTagFile (TagFile.name)) error (FATAL, "\"%s\" doesn't look like a tag file; I refuse to overwrite it.", TagFile.name); if (Option.etags) { if (Option.append && fileExists) TagFile.fp = fopen (TagFile.name, "a+b"); else TagFile.fp = fopen (TagFile.name, "w+b"); } else { if (Option.append && fileExists) { TagFile.fp = fopen (TagFile.name, "r+"); if (TagFile.fp != NULL) { TagFile.numTags.prev = updatePseudoTags (TagFile.fp); fclose (TagFile.fp); TagFile.fp = fopen (TagFile.name, "a+"); } } else { TagFile.fp = fopen (TagFile.name, "w"); if (TagFile.fp != NULL && isXtagEnabled (XTAG_PSEUDO_TAGS)) addCommonPseudoTags (); } } if (TagFile.fp == NULL) error (FATAL | PERROR, "cannot open tag file"); } if (TagsToStdout) TagFile.directory = eStrdup (CurrentDirectory); else TagFile.directory = absoluteDirname (TagFile.name); }
/* Algorithm adapted from from GNU etags. * Perl support by Bart Robinson <*****@*****.**> * Perl sub names: look for /^ [ \t\n]sub [ \t\n]+ [^ \t\n{ (]+/ */ static void findPerlTags (void) { vString *name = vStringNew (); vString *package = NULL; bool skipPodDoc = false; const unsigned char *line; unsigned long podStart = 0UL; /* Core modules AutoLoader and SelfLoader support delayed compilation * by allowing Perl code that follows __END__ and __DATA__ tokens, * respectively. When we detect that one of these modules is used * in the file, we continue processing even after we see the * corresponding token that would usually terminate parsing of the * file. */ enum { RESPECT_END = (1 << 0), RESPECT_DATA = (1 << 1), } respect_token = RESPECT_END | RESPECT_DATA; while ((line = readLineFromInputFile ()) != NULL) { bool spaceRequired = false; bool qualified = false; const unsigned char *cp = line; perlKind kind = K_NONE; tagEntryInfo e; if (skipPodDoc) { if (strncmp ((const char*) line, "=cut", (size_t) 4) == 0) { skipPodDoc = false; if (podStart != 0UL) { makePromise ("Pod", podStart, 0, getInputLineNumber(), 0, getSourceLineNumber()); podStart = 0UL; } } continue; } else if (line [0] == '=') { skipPodDoc = isPodWord ((const char*)line + 1); if (skipPodDoc) podStart = getSourceLineNumber (); continue; } else if (strcmp ((const char*) line, "__DATA__") == 0) { if (respect_token & RESPECT_DATA) break; else continue; } else if (strcmp ((const char*) line, "__END__") == 0) { if (respect_token & RESPECT_END) break; else continue; } else if (line [0] == '#') continue; while (isspace (*cp)) cp++; if (strncmp((const char*) cp, "sub", (size_t) 3) == 0) { TRACE("this looks like a sub\n"); cp += 3; kind = K_SUBROUTINE; spaceRequired = true; qualified = true; } else if (strncmp((const char*) cp, "use", (size_t) 3) == 0) { cp += 3; if (!isspace(*cp)) continue; while (*cp && isspace (*cp)) ++cp; if (strncmp((const char*) cp, "AutoLoader", (size_t) 10) == 0) { respect_token &= ~RESPECT_END; continue; } if (strncmp((const char*) cp, "SelfLoader", (size_t) 10) == 0) { respect_token &= ~RESPECT_DATA; continue; } if (strncmp((const char*) cp, "constant", (size_t) 8) != 0) continue; cp += 8; /* Skip up to the first non-space character, skipping empty * and comment lines. */ while (isspace(*cp)) cp++; while (!*cp || '#' == *cp) { cp = readLineFromInputFile (); if (!cp) goto END_MAIN_WHILE; while (isspace (*cp)) cp++; } if ('{' == *cp) { ++cp; if (0 == parseConstantsFromHashRef(cp, name, package)) { vStringClear(name); continue; } else goto END_MAIN_WHILE; } kind = K_CONSTANT; spaceRequired = false; qualified = true; } else if (strncmp((const char*) cp, "package", (size_t) 7) == 0 && ('\0' == cp[7] || isspace(cp[7]))) { cp += 7; while (isspace (*cp)) cp++; while (!*cp || '#' == *cp) { cp = readLineFromInputFile (); if (!cp) goto END_MAIN_WHILE; while (isspace (*cp)) cp++; } if (package == NULL) package = vStringNew (); else vStringClear (package); const unsigned char *const first = cp; while (*cp && (int) *cp != ';' && !isspace ((int) *cp)) { vStringPut (package, (int) *cp); cp++; } vStringCatS (package, "::"); cp = first; /* Rewind */ kind = K_PACKAGE; spaceRequired = false; qualified = true; } else if (strncmp((const char*) cp, "format", (size_t) 6) == 0) { cp += 6; kind = K_FORMAT; spaceRequired = true; qualified = true; } else { if (isIdentifier1 (*cp)) { const unsigned char *p = cp; while (isIdentifier (*p)) ++p; while (isspace (*p)) ++p; if ((int) *p == ':' && (int) *(p + 1) != ':') kind = K_LABEL; } } if (kind != K_NONE) { TRACE("cp0: %s\n", (const char *) cp); if (spaceRequired && *cp && !isspace (*cp)) continue; TRACE("cp1: %s\n", (const char *) cp); while (isspace (*cp)) cp++; while (!*cp || '#' == *cp) { /* Gobble up empty lines and comments */ cp = readLineFromInputFile (); if (!cp) goto END_MAIN_WHILE; while (isspace (*cp)) cp++; } while (isIdentifier (*cp) || (K_PACKAGE == kind && ':' == *cp)) { vStringPut (name, (int) *cp); cp++; } if (K_FORMAT == kind && vStringLength (name) == 0 && /* cp did not advance */ '=' == *cp) { /* format's name is optional. If it's omitted, 'STDOUT' is assumed. */ vStringCatS (name, "STDOUT"); } TRACE("name: %s\n", name->buffer); if (0 == vStringLength(name)) { vStringClear(name); continue; } if (K_SUBROUTINE == kind) { /* * isSubroutineDeclaration() may consume several lines. So * we record line positions. */ initTagEntry(&e, vStringValue(name), NULL); if (true == isSubroutineDeclaration(cp)) { if (true == PerlKinds[K_SUBROUTINE_DECLARATION].enabled) { kind = K_SUBROUTINE_DECLARATION; } else { vStringClear (name); continue; } } else if (! PerlKinds[kind].enabled) { continue; } e.kind = &(PerlKinds[kind]); makeTagEntry(&e); if (isXtagEnabled (XTAG_QUALIFIED_TAGS) && qualified && package != NULL && vStringLength (package) > 0) { vString *const qualifiedName = vStringNew (); vStringCopy (qualifiedName, package); vStringCat (qualifiedName, name); e.name = vStringValue(qualifiedName); markTagExtraBit (&e, XTAG_QUALIFIED_TAGS); makeTagEntry(&e); vStringDelete (qualifiedName); } } else if (vStringLength (name) > 0) { makeSimpleTag (name, PerlKinds, kind); if (isXtagEnabled(XTAG_QUALIFIED_TAGS) && qualified && K_PACKAGE != kind && package != NULL && vStringLength (package) > 0) { tagEntryInfo fqe; vString *const qualifiedName = vStringNew (); vStringCopy (qualifiedName, package); vStringCat (qualifiedName, name); initTagEntry (&fqe, vStringValue (qualifiedName), PerlKinds + kind); markTagExtraBit (&fqe, XTAG_QUALIFIED_TAGS); vStringDelete (qualifiedName); } } vStringClear (name); } } END_MAIN_WHILE: vStringDelete (name); if (package != NULL) vStringDelete (package); }
/* Algorithm adapted from from GNU etags. * Perl support by Bart Robinson <*****@*****.**> * Perl sub names: look for /^ [ \t\n]sub [ \t\n]+ [^ \t\n{ (]+/ */ static void findPerlTags (void) { vString *name = vStringNew (); vString *package = NULL; bool skipPodDoc = false; const unsigned char *line; while ((line = readLineFromInputFile ()) != NULL) { bool spaceRequired = false; bool qualified = false; const unsigned char *cp = line; perlKind kind = K_NONE; tagEntryInfo e; if (skipPodDoc) { if (strncmp ((const char*) line, "=cut", (size_t) 4) == 0) skipPodDoc = false; continue; } else if (line [0] == '=') { skipPodDoc = isPodWord ((const char*)line + 1); continue; } else if (strcmp ((const char*) line, "__DATA__") == 0) break; else if (strcmp ((const char*) line, "__END__") == 0) break; else if (line [0] == '#') continue; while (isspace (*cp)) cp++; if (strncmp((const char*) cp, "sub", (size_t) 3) == 0) { TRACE("this looks like a sub\n"); cp += 3; kind = K_SUBROUTINE; spaceRequired = true; qualified = true; } else if (strncmp((const char*) cp, "use", (size_t) 3) == 0) { cp += 3; if (!isspace(*cp)) continue; while (*cp && isspace (*cp)) ++cp; if (strncmp((const char*) cp, "constant", (size_t) 8) != 0) continue; cp += 8; kind = K_CONSTANT; spaceRequired = true; qualified = true; } else if (strncmp((const char*) cp, "package", (size_t) 7) == 0) { /* This will point to space after 'package' so that a tag can be made */ const unsigned char *space = cp += 7; if (package == NULL) package = vStringNew (); else vStringClear (package); while (isspace (*cp)) cp++; while ((int) *cp != ';' && !isspace ((int) *cp)) { vStringPut (package, (int) *cp); cp++; } vStringCatS (package, "::"); cp = space; /* Rewind */ kind = K_PACKAGE; spaceRequired = true; qualified = true; } else if (strncmp((const char*) cp, "format", (size_t) 6) == 0) { cp += 6; kind = K_FORMAT; spaceRequired = true; qualified = true; } else { if (isIdentifier1 (*cp)) { const unsigned char *p = cp; while (isIdentifier (*p)) ++p; while (isspace (*p)) ++p; if ((int) *p == ':' && (int) *(p + 1) != ':') kind = K_LABEL; } } if (kind != K_NONE) { TRACE("cp0: %s\n", (const char *) cp); if (spaceRequired && *cp && !isspace (*cp)) continue; TRACE("cp1: %s\n", (const char *) cp); while (isspace (*cp)) cp++; while (!*cp || '#' == *cp) { /* Gobble up empty lines and comments */ cp = readLineFromInputFile (); if (!cp) goto END_MAIN_WHILE; while (isspace (*cp)) cp++; } while (isIdentifier (*cp) || (K_PACKAGE == kind && ':' == *cp)) { vStringPut (name, (int) *cp); cp++; } if (K_FORMAT == kind && vStringLength (name) == 0 && /* cp did not advance */ '=' == *cp) { /* format's name is optional. If it's omitted, 'STDOUT' is assumed. */ vStringCatS (name, "STDOUT"); } TRACE("name: %s\n", name->buffer); if (0 == vStringLength(name)) { vStringClear(name); continue; } if (K_SUBROUTINE == kind) { /* * isSubroutineDeclaration() may consume several lines. So * we record line positions. */ initTagEntry(&e, vStringValue(name), &(PerlKinds[kind])); if (true == isSubroutineDeclaration(cp)) { if (true == PerlKinds[K_SUBROUTINE_DECLARATION].enabled) { kind = K_SUBROUTINE_DECLARATION; } else { vStringClear (name); continue; } } makeTagEntry(&e); if (isXtagEnabled(XTAG_QUALIFIED_TAGS) && qualified && package != NULL && vStringLength (package) > 0) { vString *const qualifiedName = vStringNew (); vStringCopy (qualifiedName, package); vStringCat (qualifiedName, name); e.name = vStringValue(qualifiedName); makeTagEntry(&e); vStringDelete (qualifiedName); } } else if (vStringLength (name) > 0) { makeSimpleTag (name, PerlKinds, kind); if (isXtagEnabled(XTAG_QUALIFIED_TAGS) && qualified && K_PACKAGE != kind && package != NULL && vStringLength (package) > 0) { vString *const qualifiedName = vStringNew (); vStringCopy (qualifiedName, package); vStringCat (qualifiedName, name); makeSimpleTag (qualifiedName, PerlKinds, kind); vStringDelete (qualifiedName); } } vStringClear (name); } } END_MAIN_WHILE: vStringDelete (name); if (package != NULL) vStringDelete (package); }
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); }
static void createTag (tokenInfo *const token) { tagEntryInfo tag; verilogKind kind; /* Determine if kind is prototype */ if (currentContext->prototype) { kind = K_PROTOTYPE; } else { kind = token->kind; } /* Do nothing it tag name is empty or tag kind is disabled */ if (vStringLength (token->name) == 0 || ! kindEnabled (kind)) { return; } /* Create tag */ initTagEntry (&tag, vStringValue (token->name), kindFromKind (kind)); tag.lineNumber = token->lineNumber; tag.filePosition = token->filePosition; verbose ("Adding tag %s (kind %d)", vStringValue (token->name), kind); if (currentContext->kind != K_UNDEFINED) { verbose (" to context %s\n", vStringValue (currentContext->name)); currentContext->lastKind = kind; tag.extensionFields.scopeKind = kindFromKind (currentContext->kind); tag.extensionFields.scopeName = vStringValue (currentContext->name); } verbose ("\n"); if (vStringLength (token->inheritance) > 0) { tag.extensionFields.inheritance = vStringValue (token->inheritance); verbose ("Class %s extends %s\n", vStringValue (token->name), tag.extensionFields.inheritance); } makeTagEntry (&tag); if (isXtagEnabled(XTAG_QUALIFIED_TAGS) && currentContext->kind != K_UNDEFINED) { vString *const scopedName = vStringNew (); vStringCopy (scopedName, currentContext->name); vStringPut (scopedName, '.'); vStringCatS (scopedName, vStringValue (token->name)); tag.name = vStringValue (scopedName); markTagExtraBit (&tag, XTAG_QUALIFIED_TAGS); makeTagEntry (&tag); vStringDelete (scopedName); } /* Push token as context if it is a container */ if (isContainer (token)) { tokenInfo *newScope = newToken (); vStringCopy (newScope->name, token->name); newScope->kind = kind; createContext (newScope); } /* Clear no longer required inheritance information */ vStringClear (token->inheritance); }
static void findShTags (void) { vString *name = vStringNew (); const unsigned char *line; vString *hereDocDelimiter = NULL; boolean hereDocIndented = FALSE; boolean (* check_char)(int); while ((line = readLineFromInputFile ()) != NULL) { const unsigned char* cp = line; shKind found_kind = K_NOTHING; if (hereDocDelimiter) { if (hereDocIndented) { while (*cp == '\t') cp++; } if (strcmp ((const char *) cp, vStringValue (hereDocDelimiter)) == 0) { vStringDelete (hereDocDelimiter); hereDocDelimiter = NULL; } continue; } while (*cp != '\0') { /* jump over whitespace */ while (isspace ((int)*cp)) cp++; /* jump over strings */ if (*cp == '"') cp = skipDoubleString (cp); else if (*cp == '\'') cp = skipSingleString (cp); /* jump over comments */ else if (*cp == '#') break; /* jump over here-documents */ else if (cp[0] == '<' && cp[1] == '<') { const unsigned char *start, *end; boolean trimEscapeSequences = FALSE; boolean quoted = FALSE; cp += 2; /* an optional "-" strips leading tabulations from the heredoc lines */ if (*cp != '-') hereDocIndented = FALSE; else { hereDocIndented = TRUE; cp++; } while (isspace (*cp)) cp++; start = end = cp; /* the delimiter can be surrounded by quotes */ if (*cp == '"') { start++; end = cp = skipDoubleString (cp); /* we need not to worry about variable substitution, they * don't happen in heredoc delimiter definition */ trimEscapeSequences = TRUE; quoted = TRUE; } else if (*cp == '\'') { start++; end = cp = skipSingleString (cp); quoted = TRUE; } else { while (isIdentChar ((int) *cp)) cp++; end = cp; } if (end > start || quoted) { /* The input may be broken as a shell script but we need to avoid memory leaking. */ if (hereDocDelimiter) vStringClear(hereDocDelimiter); else hereDocDelimiter = vStringNew (); for (; end > start; start++) { if (trimEscapeSequences && *start == '\\') start++; vStringPut (hereDocDelimiter, *start); } } } if (strncmp ((const char*) cp, "function", (size_t) 8) == 0 && isspace ((int) cp [8])) { found_kind = K_FUNCTION; cp += 8; } else if (strncmp ((const char*) cp, "alias", (size_t) 5) == 0 && isspace ((int) cp [5])) { found_kind = K_ALIAS; cp += 5; } else if (isXtagEnabled (XTAG_REFERENCE_TAGS) && ShKinds [K_SOURCE].enabled) { if (cp [0] == '.' && isspace((int) cp [1])) { found_kind = K_SOURCE; ++cp; } else if (strncmp ((const char*) cp, "source", (size_t) 6) == 0 && isspace((int) cp [6])) { found_kind = K_SOURCE; cp += 6; } } if (found_kind != K_NOTHING) while (isspace ((int) *cp)) ++cp; // Get the name of the function, alias or file to be read by source check_char = isIdentChar; if (found_kind == K_SOURCE) check_char = isFileChar; if (! check_char ((int) *cp)) { found_kind = K_NOTHING; if (*cp != '\0') ++cp; continue; } while (check_char ((int) *cp)) { vStringPut (name, (int) *cp); ++cp; } vStringTerminate (name); while (isspace ((int) *cp)) ++cp; if ((found_kind != K_SOURCE) && *cp == '(') { ++cp; while (isspace ((int) *cp)) ++cp; if (*cp == ')') { found_kind = K_FUNCTION; ++cp; } } if (found_kind != K_NOTHING) { if (found_kind == K_SOURCE) makeSimpleRefTag (name, ShKinds, K_SOURCE, R_SOURCE_GENERIC); else makeSimpleTag (name, ShKinds, found_kind); found_kind = K_NOTHING; } vStringClear (name); } } vStringDelete (name); if (hereDocDelimiter) vStringDelete (hereDocDelimiter); }