static void findAwkTags (void) { vString *name = vStringNew (); const unsigned char *line; while ((line = readLineFromInputFile ()) != NULL) { if (strncmp ((const char*) line, "function", (size_t) 8) == 0 && isspace ((int) line [8])) { const unsigned char *cp = line + 8; while (isspace ((int) *cp)) ++cp; while (isalnum ((int) *cp) || *cp == '_') { vStringPut (name, (int) *cp); ++cp; } vStringTerminate (name); while (isspace ((int) *cp)) ++cp; if (*cp == '(') makeSimpleTag (name, AwkKinds, K_FUNCTION); vStringClear (name); if (*cp != '\0') ++cp; } } vStringDelete (name); }
/* in OCaml the file name is the module name used in the language * with it first letter put in upper case */ static void computeModuleName ( void ) { /* in Ocaml the file name define a module. * so we define a module =) */ const char *filename = getInputFileName (); int beginIndex = 0; int endIndex = strlen (filename) - 1; vString *moduleName = vStringNew (); while (filename[endIndex] != '.' && endIndex > 0) endIndex--; /* avoid problem with path in front of filename */ beginIndex = endIndex; while (beginIndex > 0) { if (filename[beginIndex] == '\\' || filename[beginIndex] == '/') { beginIndex++; break; } beginIndex--; } vStringNCopyS (moduleName, &filename[beginIndex], endIndex - beginIndex); vStringTerminate (moduleName); if (isLowerAlpha (moduleName->buffer[0])) moduleName->buffer[0] += ('A' - 'a'); addTag (moduleName, K_MODULE); vStringDelete (moduleName); }
static void makeClassTag (tokenInfo *const token, vString *const signature) { vString * fulltag; if ( ! token->ignoreTag ) { fulltag = vStringNew (); if (vStringLength (token->scope) > 0) { vStringCopy(fulltag, token->scope); vStringCatS (fulltag, "."); vStringCatS (fulltag, vStringValue(token->string)); } else { vStringCopy(fulltag, token->string); } vStringTerminate(fulltag); if ( ! stringListHas(ClassNames, vStringValue (fulltag)) ) { stringListAdd (ClassNames, vStringNewCopy (fulltag)); makeJsTag (token, JSTAG_CLASS, signature); } vStringDelete (fulltag); } }
static vString *parseNumeric (int c) { vString *string = vStringNew (); vString *integer = parseInteger (c); vStringCopy (string, integer); vStringDelete (integer); c = getcFromInputFile (); if (c == '.') { integer = parseInteger ('\0'); vStringPut (string, c); vStringCat (string, integer); vStringDelete (integer); c = getcFromInputFile (); } if (tolower (c) == 'e') { integer = parseInteger ('\0'); vStringPut (string, c); vStringCat (string, integer); vStringDelete (integer); } else if (!isspace (c)) ungetcToInputFile (c); vStringTerminate (string); return string; }
static vString *parseNumeric (int c) { static vString *string = NULL; if (string == NULL) string = vStringNew (); vStringCopy (string, parseInteger (c)); c = fileGetc (); if (c == '.') { vStringPut (string, c); vStringCat (string, parseInteger ('\0')); c = fileGetc (); } if (tolower (c) == 'e') { vStringPut (string, c); vStringCat (string, parseInteger ('\0')); } else if (!isspace (c)) fileUngetc (c); vStringTerminate (string); return string; }
/* If a numeric is passed in 'c', this is used as the first digit of the * numeric being parsed. */ static vString *parseInteger (int c) { static vString *string = NULL; if (string == NULL) string = vStringNew (); vStringClear (string); if (c == '\0') c = fileGetc (); if (c == '-') { vStringPut (string, c); c = fileGetc (); } else if (! isdigit (c)) c = fileGetc (); while (c != EOF && (isdigit (c) || c == '_')) { vStringPut (string, c); c = fileGetc (); } vStringTerminate (string); fileUngetc (c); return string; }
static const unsigned char *parseIdentifier ( const unsigned char *cp, vString *const identifier) { boolean stringLit = FALSE; vStringClear (identifier); while (*cp != '\0' && (!isIdentifier ((int) *cp) || stringLit)) { int oneback = *cp; cp++; if (oneback == '(' && *cp == '*' && stringLit == FALSE) { CommentLevel++; return ++cp; } if (*cp == '"' && oneback != '\\') { stringLit = TRUE; continue; } if (stringLit && *cp == '"' && oneback != '\\') stringLit = FALSE; } if (strcmp ((const char *) cp, "") == 0 || cp == NULL) return cp; while (isIdentifier ((int) *cp)) { vStringPut (identifier, (int) *cp); cp++; } vStringTerminate (identifier); return cp; }
/* Operator can be defined in OCaml as a function * so we must be ample enough to parse them normally */ static ocamlKeyword eatOperator (lexingState * st) { int count = 0; const unsigned char *root = st->cp; vStringClear (st->name); while (isOperator[st->cp[count]]) { vStringPut (st->name, st->cp[count]); count++; } vStringTerminate (st->name); st->cp += count; if (count <= 1) { switch (root[0]) { case '|': return Tok_Pipe; case '=': return Tok_EQ; default: return Tok_Op; } } else if (count == 2 && root[0] == '-' && root[1] == '>') return Tok_To; else return Tok_Op; }
/* * Emits a tag for the given 'name' of kind 'kind' at the current nesting. */ static void emitRubyTag (vString* name, rubyKind kind) { tagEntryInfo tag; vString* scope; if (!RubyKinds[kind].enabled) { return; } vStringTerminate (name); scope = stringListToScope (nesting); initTagEntry (&tag, vStringValue (name)); if (vStringLength (scope) > 0) { tag.extensionFields.scope [0] = "class"; tag.extensionFields.scope [1] = vStringValue (scope); } tag.kindName = RubyKinds [kind].name; tag.kind = RubyKinds [kind].letter; makeTagEntry (&tag); stringListAdd (nesting, vStringNewCopy (name)); vStringClear (name); vStringDelete (scope); }
static void parseLet (const unsigned char *line, int infunction) { vString *name = vStringNew (); const unsigned char *cp = line; const unsigned char *np = line; /* get the name */ if (isspace ((int) *cp)) { while (*cp && isspace ((int) *cp)) ++cp; /* * Ignore lets which set: * & - local buffer vim settings * @ - registers * [ - Lists or Dictionaries */ if (!*cp || *cp == '&' || *cp == '@' || *cp == '[' ) goto cleanUp; /* * Ignore vim variables which are read only * v: - Vim variables. */ np = cp; ++np; if ((int) *cp == 'v' && (int) *np == ':' ) goto cleanUp; /* Skip non-global vars in functions */ if (infunction && (int) *cp != 'g') goto cleanUp; /* deal with spaces, $, @ and & */ while (*cp && *cp != '$' && !isalnum ((int) *cp)) ++cp; if (!*cp) goto cleanUp; /* cp = skipPrefix (cp, &scope); */ do { if (!*cp) break; vStringPut (name, (int) *cp); ++cp; } while (isalnum ((int) *cp) || *cp == '_' || *cp == '#' || *cp == ':' || *cp == '$'); vStringTerminate (name); makeSimpleTag (name, VimKinds, K_VARIABLE); vStringClear (name); } cleanUp: vStringDelete (name); }
static void addContext (tokenInfo* const parent, const tokenInfo* const child) { if (vStringLength (parent->string) > 0) { vStringCatS (parent->string, "."); } vStringCatS (parent->string, vStringValue(child->string)); vStringTerminate(parent->string); }
static void addToScope (tokenInfo* const token, vString* const extra) { if (vStringLength (token->scope) > 0) { vStringCatS (token->scope, "."); } vStringCatS (token->scope, vStringValue(extra)); vStringTerminate(token->scope); }
/* Determines whether or not "name" should be ignored, per the ignore list. */ extern boolean isIgnoreToken (const char *const name, boolean *const pIgnoreParens, const char **const replacement) { boolean result = FALSE; if (c_tags_ignore != NULL) { const size_t nameLen = strlen (name); unsigned int i; guint len = g_strv_length (c_tags_ignore); vString *token = vStringNew(); if (pIgnoreParens != NULL) *pIgnoreParens = FALSE; for (i = 0 ; i < len ; ++i) { size_t tokenLen; vStringCopyS (token, c_tags_ignore[i]); vStringTerminate (token); tokenLen = vStringLength (token); if (tokenLen >= 2 && vStringChar (token, tokenLen - 1) == '*' && strncmp (vStringValue (token), name, tokenLen - 1) == 0) { result = TRUE; break; } if (strncmp (vStringValue (token), name, nameLen) == 0) { if (nameLen == tokenLen) { result = TRUE; break; } else if (tokenLen == nameLen + 1 && vStringChar (token, tokenLen - 1) == '+') { result = TRUE; if (pIgnoreParens != NULL) *pIgnoreParens = TRUE; break; } else if (vStringChar (token, nameLen) == '=') { if (replacement != NULL) *replacement = vStringValue (token) + nameLen + 1; break; } } } vStringDelete (token); } return result; }
/* Algorithm adapted from from GNU etags. * Scheme tag functions * look for (def... xyzzy * look for (def... (xyzzy * look for (def ... ((... (xyzzy .... * look for (set! xyzzy */ static void readIdentifier (vString *const name, const unsigned char *cp) { const unsigned char *p; vStringClear (name); /* Go till you get to white space or a syntactic break */ for (p = cp; *p != '\0' && *p != '(' && *p != ')' && !isspace (*p); p++) vStringPut (name, (int) *p); vStringTerminate (name); }
static void add_tag(const char *token, haskellKind kind, vString *name) { int i; for (i = 0; token[i] != '\0'; ++i) vStringPut(name, token[i]); vStringTerminate(name); makeSimpleTag(name, HaskellKinds, kind); vStringClear(name); }
static void pushScope (tokenInfo *const token, const tokenInfo *const parent, const jsonKind parentKind) { if (vStringLength (token->scope) > 0) vStringPut (token->scope, '.'); vStringCat (token->scope, parent->string); vStringTerminate (token->scope); token->scopeKind = parentKind; }
/* Match the name of a tag (function, variable, type, ...) starting at pos. */ static char const *extract_name (char const *pos, vString * name) { while (isspace (*pos)) pos++; vStringClear (name); for (; *pos && !isspace (*pos) && *pos != '(' && *pos != ',' && *pos != '='; pos++) vStringPut (name, *pos); vStringTerminate (name); return pos; }
/* * Emits a tag for the given 'name' of kind 'kind' at the current nesting. */ static void emitRubyTag (vString* name, rubyKind kind) { tagEntryInfo tag; vString* scope; tagEntryInfo *parent; rubyKind parent_kind = K_UNDEFINED; NestingLevel *lvl; const char *unqualified_name; const char *qualified_name; int r; if (!RubyKinds[kind].enabled) { return; } vStringTerminate (name); scope = nestingLevelsToScope (nesting); lvl = nestingLevelsGetCurrent (nesting); parent = getEntryOfNestingLevel (lvl); if (parent) parent_kind = parent->kind - RubyKinds; qualified_name = vStringValue (name); unqualified_name = strrchr (qualified_name, SCOPE_SEPARATOR); if (unqualified_name && unqualified_name[1]) { if (unqualified_name > qualified_name) { if (vStringLength (scope) > 0) vStringPut (scope, SCOPE_SEPARATOR); vStringNCatS (scope, qualified_name, unqualified_name - qualified_name); /* assume module parent type for a lack of a better option */ parent_kind = K_MODULE; } unqualified_name++; } else unqualified_name = qualified_name; initTagEntry (&tag, unqualified_name, &(RubyKinds [kind])); if (vStringLength (scope) > 0) { Assert (0 <= parent_kind && (size_t) parent_kind < (ARRAY_SIZE (RubyKinds))); tag.extensionFields.scopeKind = &(RubyKinds [parent_kind]); tag.extensionFields.scopeName = vStringValue (scope); } r = makeTagEntry (&tag); nestingLevelsPush (nesting, r); vStringClear (name); vStringDelete (scope); }
static void readAndEmitTag (const unsigned char** cp, rubyKind expected_kind) { if (isspace (**cp)) { vString *name = vStringNew (); vString *chunk = vStringNew (); rubyKind actual_kind; unsigned int i = 0; /* parse the identifier, allowing scoping like "class Foo::Bar::Baz" */ while (1) { actual_kind = parseIdentifier (cp, chunk, expected_kind); if (i++ > 0) vStringPut (name, '.'); vStringCat (name, chunk); vStringClear (chunk); if (actual_kind != K_UNDEFINED && (*cp)[0] == ':' && (*cp)[1] == ':') *cp += 2; else break; } vStringDelete (chunk); vStringTerminate (name); if (actual_kind == K_UNDEFINED || vStringLength (name) == 0) { /* * What kind of tags should we create for code like this? * * %w(self.clfloor clfloor).each do |name| * module_eval <<-"end;" * def #{name}(x, y=1) * q, r = x.divmod(y) * q = q.to_i * return q, r * end * end; * end * * Or this? * * class << HTTP * * For now, we don't create any. */ } else { emitRubyTag (name, actual_kind); } vStringDelete (name); } }
static void parseSelector (vString *const string, const int firstChar) { int c = firstChar; do { vStringPut (string, (char) c); c = fileGetc (); } while (isSelectorChar (c)); fileUngetc (c); vStringTerminate (string); }
static void parseIdentifier (vString *const string, const int firstChar) { int c = firstChar; do { vStringPut (string, c); c = getcFromInputFile (); } while (isIdentChar (c)); vStringTerminate (string); ungetcToInputFile (c); /* always unget, LF might add a semicolon */ }
/* * Copies the characters forming an identifier from *cp into * name, leaving *cp pointing to the character after the identifier. */ static rubyKind parseIdentifier ( const unsigned char** cp, vString* name, rubyKind kind) { /* Method names are slightly different to class and variable names. * A method name may optionally end with a question mark, exclamation * point or equals sign. These are all part of the name. * A method name may also contain a period if it's a singleton method. */ const char* also_ok = (kind == K_METHOD) ? "_.?!=" : "_"; skipWhitespace (cp); /* Check for an anonymous (singleton) class such as "class << HTTP". */ if (kind == K_CLASS && **cp == '<' && *(*cp + 1) == '<') { return K_UNDEFINED; } /* Check for operators such as "def []=(key, val)". */ if (kind == K_METHOD || kind == K_SINGLETON) { if (parseRubyOperator (name, cp)) { return kind; } } /* Copy the identifier into 'name'. */ while (**cp != 0 && (isalnum (**cp) || charIsIn (**cp, also_ok))) { char last_char = **cp; vStringPut (name, last_char); ++*cp; if (kind == K_METHOD) { /* Recognize singleton methods. */ if (last_char == '.') { vStringTerminate (name); vStringClear (name); return parseIdentifier (cp, name, K_SINGLETON); } /* Recognize characters which mark the end of a method name. */ if (charIsIn (last_char, "?!=")) { break; } } } return kind; }
static void initPhpEntry (tagEntryInfo *const e, const tokenInfo *const token, const phpKind kind, const accessType access) { int parentKind = -1; const char *rootsep; vStringClear (FullScope); if (vStringLength (CurrentNamesapce) > 0) { parentKind = K_NAMESPACE; rootsep = scopeSeparatorFor (PhpKinds + parentKind, KIND_NULL); vStringCatS (FullScope, rootsep); vStringCat (FullScope, CurrentNamesapce); } initTagEntry (e, vStringValue (token->string), &(PhpKinds[kind])); e->lineNumber = token->lineNumber; e->filePosition = token->filePosition; if (access != ACCESS_UNDEFINED) e->extensionFields.access = accessToString (access); if (vStringLength (token->scope) > 0) { parentKind = token->parentKind; if (vStringLength (FullScope) > 0) { const char* sep; sep = phpScopeSeparatorFor (parentKind, K_NAMESPACE); vStringCatS (FullScope, sep); } else { rootsep = scopeSeparatorFor (PhpKinds + parentKind, KIND_NULL); vStringCatS (FullScope, rootsep); } vStringCat (FullScope, token->scope); } if (vStringLength (FullScope) > 0) { Assert (parentKind >= 0); vStringTerminate (FullScope); e->extensionFields.scopeKind = &(PhpKinds[parentKind]); e->extensionFields.scopeName = vStringValue (FullScope); } }
static void parseFunction (const unsigned char *line) { vString *name = vStringNew (); /* boolean inFunction = FALSE; */ int scope; const unsigned char *cp = line + 1; if ((int) *++cp == 'n' && (int) *++cp == 'c' && (int) *++cp == 't' && (int) *++cp == 'i' && (int) *++cp == 'o' && (int) *++cp == 'n') ++cp; if ((int) *cp == '!') ++cp; if (isspace ((int) *cp)) { while (*cp && isspace ((int) *cp)) ++cp; if (*cp) { cp = skipPrefix (cp, &scope); if (isupper ((int) *cp) || scope == 's' || /* script scope */ scope == '<' || /* script scope */ scope == 'd' || /* dictionary */ scope == 'a') /* autoload */ { do { vStringPut (name, (int) *cp); ++cp; } while (isalnum ((int) *cp) || *cp == '_' || *cp == '.' || *cp == '#'); vStringTerminate (name); makeSimpleTag (name, VimKinds, K_FUNCTION); vStringClear (name); } } } /* TODO - update struct to indicate inside function */ while ((line = readVimLine ()) != NULL) { /* * Vim7 added the for/endfo[r] construct, so we must first * check for an "endfo", before a "endf" */ if ( (!strncmp ((const char*) line, "endfo", (size_t) 5) == 0) && (strncmp ((const char*) line, "endf", (size_t) 4) == 0) ) break; /* TODO - call parseVimLine */ } vStringDelete (name); }
static void parseIdentifier (vString *const string, const int firstChar) { int c = firstChar; do { vStringPut (string, (char) c); c = getcFromInputFile (); } while (isIdentChar (c)); ungetcToInputFile (c); vStringTerminate (string); }
static void readIdentifier (const int first, vString *const id) { int c = first; vStringClear (id); while (isIdentifier (c)) { vStringPut (id, c); c = nextChar (); } fileUngetc (c); vStringTerminate (id); }
/* Read a C identifier beginning with "firstChar" and places it into * "name". */ static void parseIdentifier (vString *const string, const int firstChar) { int c = firstChar; Assert (isIdentChar (c)); do { vStringPut (string, c); c = fileGetc (); } while (isIdentChar (c)); vStringTerminate (string); fileUngetc (c); /* unget non-identifier character */ }
static const unsigned char *parseIdentifier ( const unsigned char *cp, vString *const identifier) { vStringClear (identifier); while (isIdentifierCharacter ((int) *cp)) { vStringPut (identifier, (int) *cp); ++cp; } vStringTerminate (identifier); return cp; }
static vString* determineEmacsModeAtFirstLine (const char* const line) { vString* mode = vStringNew (); const char* p = strstr(line, "-*-"); if (p == NULL) return mode; p += strlen("-*-"); for ( ; isspace ((int) *p) ; ++p) ; /* no-op */ if (strncmp(p, "mode:", strlen("mode:")) == 0) { /* -*- mode: MODE; -*- */ p += strlen("mode:"); for ( ; isspace ((int) *p) ; ++p) ; /* no-op */ for ( ; *p != '\0' && isalnum ((int) *p) ; ++p) vStringPut (mode, (int) *p); vStringTerminate (mode); } else { /* -*- MODE -*- */ for ( ; *p != '\0' && isalnum ((int) *p) ; ++p) vStringPut (mode, (int) *p); vStringTerminate (mode); for ( ; isspace ((int) *p) ; ++p) ; /* no-op */ if (strncmp(p, "-*-", strlen("-*-")) != 0) vStringClear (mode); } return mode; }
static void addToScope (tokenInfo *const token, const vString *const extra, int kindOfUpperScope) { if (vStringLength (token->scope) > 0) { const char* sep; sep = phpScopeSeparatorFor(token->parentKind, kindOfUpperScope); vStringCatS (token->scope, sep); } vStringCat (token->scope, extra); vStringTerminate(token->scope); }