Branch: refs/heads/master Author: Jiřà Techet techet@gmail.com Committer: Jiřà Techet techet@gmail.com Date: Sat, 08 Oct 2016 13:48:42 UTC Commit: 2a9f473d782431c433c390dd002f9f3302b12d34 https://github.com/geany/geany/commit/2a9f473d782431c433c390dd002f9f3302b12d...
Log Message: ----------- Sync options.c/h (and introduce a lot of new garbage)
This commit started innocently as an attempt to grab options.c/h from uctags. However it started referencing other files (which started referencing other files) so the result is lots of new files are added.
When trying to make it compile, I run into many differences of existing code which would have to be resolved. As all the added code is more or less garbage for Geany, I just simply commented-out various function bodies so it compiles without additional modifications. Should get fixed once more files get synced with uctags.
Modified Paths: -------------- ctags/Makefile.am ctags/main/entry.c ctags/main/entry.h ctags/main/field.c ctags/main/field.h ctags/main/flags.c ctags/main/flags.h ctags/main/fmt.c ctags/main/fmt.h ctags/main/htable.c ctags/main/htable.h ctags/main/lcpp.c ctags/main/lregex.c ctags/main/lxcmd.c ctags/main/options.c ctags/main/options.h ctags/main/output-ctags.c ctags/main/output-etags.c ctags/main/output-json.c ctags/main/output-xref.c ctags/main/output.h ctags/main/parse.c ctags/main/parse.h ctags/main/pcoproc.c ctags/main/pcoproc.h ctags/main/ptag.c ctags/main/ptag.h ctags/main/types.h ctags/parsers/c.c ctags/parsers/fortran.c src/tagmanager/tm_ctags_wrappers.c
Modified: ctags/Makefile.am 18 lines changed, 18 insertions(+), 0 deletions(-) =================================================================== @@ -63,16 +63,25 @@ libctags_la_SOURCES = \ main/entry.h \ main/error.c \ main/error.h \ + main/field.c \ + main/field.h \ + main/flags.c \ + main/flags.h \ + main/fmt.c \ + main/fmt.h \ main/gcc-attr.h \ main/geany.c \ main/geany.h \ main/general.h \ + main/htable.c \ + main/htable.h \ main/keyword.c \ main/keyword.h \ main/kind.h \ main/lcpp.c \ main/lcpp.h \ main/lregex.c \ + main/lxcmd.c \ main/main.c \ main/main.h \ main/mio.c \ @@ -81,9 +90,18 @@ libctags_la_SOURCES = \ main/nestlevel.h \ main/options.c \ main/options.h \ + main/output-ctags.c \ + main/output-etags.c \ + main/output-json.c \ + main/output-xref.c \ + main/output.h \ main/parse.c \ main/parse.h \ main/parsers.h \ + main/pcoproc.c \ + main/pcoproc.h \ + main/ptag.c \ + main/ptag.h \ main/ptrarray.c \ main/ptrarray.h \ main/read.c \
Modified: ctags/main/entry.c 14 lines changed, 13 insertions(+), 1 deletions(-) =================================================================== @@ -43,6 +43,7 @@ #include "sort.h" #include "strlist.h" #include "routines.h" +#include "output.h"
/* * MACROS @@ -77,7 +78,7 @@ tagFile TagFile = { NULL, /* file pointer */ { 0, 0 }, /* numTags */ { 0, 0, 0 }, /* max */ - { NULL, NULL, 0 }, /* etags */ +/* { NULL, NULL, 0 },*/ /* etags */ NULL /* vLine */ };
@@ -113,6 +114,12 @@ extern const char *tagFileName (void) * Pseudo tag support */
+extern void abort_if_ferror(MIO *const mio) +{ + if (mio_error (mio)) + error (FATAL | PERROR, "cannot write tag file"); +} + static void rememberMaxLengths (const size_t nameLength, const size_t lineLength) { if (nameLength > TagFile.max.tag) @@ -410,3 +417,8 @@ extern void initTagEntry (tagEntryInfo *const e, const char *const name, const k e->name = name; e->kind = kind; } + +extern void setTagWriter (tagWriter *t) +{ +/* writer = t; */ +}
Modified: ctags/main/entry.h 13 lines changed, 9 insertions(+), 4 deletions(-) =================================================================== @@ -15,6 +15,7 @@ #include "general.h" /* must always come first */ #include "types.h"
+#include "field.h" #include "mio.h" #include "vstring.h" #include "kind.h" @@ -24,9 +25,15 @@ */ #define WHOLE_FILE -1L
+#define NO_PARSER_FIELD -1 + /* * DATA DECLARATIONS */ +typedef struct sTagField { + fieldType ftype; + const char* value; +} tagField;
/* Maintains the state of the tag file. */ @@ -36,11 +43,11 @@ typedef struct eTagFile { MIO *mio; struct sNumTags { unsigned long added, prev; } numTags; struct sMax { size_t line, tag, file; } max; - struct sEtags { +/* struct sEtags { char *name; MIO *mio; size_t byteCount; - } etags; + } etags;*/ vString *vLine; } tagFile;
@@ -91,8 +98,6 @@ extern void copyBytes (MIO* const fromMio, MIO* const toMio, const long size); extern void copyFile (const char *const from, const char *const to, const long size); extern void openTagFile (void); extern void closeTagFile (const bool resize); -extern void beginEtagsFile (void); -extern void endEtagsFile (const char *const name); extern void makeTagEntry (const tagEntryInfo *const tag); extern void initTagEntry (tagEntryInfo *const e, const char *const name, const kindOption *kind);
Modified: ctags/main/field.c 935 lines changed, 935 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,935 @@ +/* + * + * Copyright (c) 2015, Red Hat, Inc. + * Copyright (c) 2015, Masatake YAMATO + * + * Author: Masatake YAMATO yamato@redhat.com + * + * This source code is released for free distribution under the terms of the + * GNU General Public License version 2 or (at your option) any later version. + * + */ + +#include "general.h" /* must always come first */ + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "ctags.h" +#include "debug.h" +#include "entry.h" +#include "field.h" +#include "kind.h" +#include "options.h" +#include "read.h" +#include "routines.h" + + +struct sFieldDesc { + fieldSpec *spec; + unsigned int fixed: 1; /* fields which cannot be disabled. */ + vString *buffer; + const char* nameWithPrefix; + langType language; + fieldType sibling; +}; + +static const char *renderFieldName (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldInput (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldCompactInputLine (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldSignature (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldScope (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldTyperef (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldInherits (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldKindName (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldLineNumber (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldLanguage (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldAccess (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldKindLetter (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldImplementation (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldFile (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldPattern (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldRole (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldRefMarker (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldExtra (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldXpath (const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldScopeKindName(const tagEntryInfo *const tag, const char *value, vString* b); +static const char *renderFieldEnd (const tagEntryInfo *const tag, const char *value, vString* b); + +static bool isLanguageFieldAvailable (const tagEntryInfo *const tag); +static bool isTyperefFieldAvailable (const tagEntryInfo *const tag); +static bool isFileFieldAvailable (const tagEntryInfo *const tag); +static bool isInheritsFieldAvailable (const tagEntryInfo *const tag); +static bool isAccessFieldAvailable (const tagEntryInfo *const tag); +static bool isImplementationFieldAvailable (const tagEntryInfo *const tag); +static bool isSignatureFieldAvailable (const tagEntryInfo *const tag); +static bool isRoleFieldAvailable (const tagEntryInfo *const tag); +static bool isExtraFieldAvailable (const tagEntryInfo *const tag); +static bool isXpathFieldAvailable (const tagEntryInfo *const tag); +static bool isEndFieldAvailable (const tagEntryInfo *const tag); + + +#define DEFINE_FIELD_SPEC(L, N, V, H, F) \ + DEFINE_FIELD_SPEC_FULL (L, N, V, H, F, NULL) +#define DEFINE_FIELD_SPEC_FULL(L, N, V, H, F, A)\ + { \ + .letter = L, \ + .name = N, \ + .description = H, \ + .enabled = V, \ + .renderEscaped = F, \ + .isValueAvailable = A, \ + } + +#define WITH_DEFUALT_VALUE(str) ((str)?(str):"-") + +static fieldSpec fieldSpecsFixed [] = { + /* FIXED FIELDS */ + DEFINE_FIELD_SPEC ('N', "name", true, + "tag name (fixed field)", + renderFieldName), + DEFINE_FIELD_SPEC ('F', "input", true, + "input file (fixed field)", + renderFieldInput), + DEFINE_FIELD_SPEC ('P', "pattern", true, + "pattern (fixed field)", + renderFieldPattern), +}; + +static fieldSpec fieldSpecsExuberant [] = { + DEFINE_FIELD_SPEC ('C', "compact", false, + "compact input line (fixed field, only used in -x option)", + renderFieldCompactInputLine), + + /* EXTENSION FIELDS */ + DEFINE_FIELD_SPEC_FULL ('a', "access", false, + "Access (or export) of class members", + renderFieldAccess, isAccessFieldAvailable), + DEFINE_FIELD_SPEC_FULL ('f', "file", true, + "File-restricted scoping", + renderFieldFile, isFileFieldAvailable), + DEFINE_FIELD_SPEC_FULL ('i', "inherits", false, + "Inheritance information", + renderFieldInherits, isInheritsFieldAvailable), + DEFINE_FIELD_SPEC ('K', NULL, false, + "Kind of tag as full name", + renderFieldKindName), + DEFINE_FIELD_SPEC ('k', NULL, true, + "Kind of tag as a single letter", + renderFieldKindLetter), + DEFINE_FIELD_SPEC_FULL ('l', "language", false, + "Language of input file containing tag", + renderFieldLanguage, isLanguageFieldAvailable), + DEFINE_FIELD_SPEC_FULL ('m', "implementation", false, + "Implementation information", + renderFieldImplementation, isImplementationFieldAvailable), + DEFINE_FIELD_SPEC ('n', "line", false, + "Line number of tag definition", + renderFieldLineNumber), + DEFINE_FIELD_SPEC_FULL ('S', "signature", false, + "Signature of routine (e.g. prototype or parameter list)", + renderFieldSignature, isSignatureFieldAvailable), + DEFINE_FIELD_SPEC ('s', NULL, true, + "Scope of tag definition (`p' can be used for printing its kind)", + renderFieldScope), + DEFINE_FIELD_SPEC_FULL ('t', "typeref", true, + "Type and name of a variable or typedef", + renderFieldTyperef, isTyperefFieldAvailable), + DEFINE_FIELD_SPEC ('z', "kind", false, + "Include the "kind:" key in kind field (use k or K) in tags output, kind full name in xref output", + /* Following renderer is for handling --_xformat=%{kind}; + and is not for tags output. */ + renderFieldKindName), +}; + +static fieldSpec fieldSpecsUniversal [] = { + DEFINE_FIELD_SPEC_FULL ('r', "role", false, + "Role", + renderFieldRole, isRoleFieldAvailable), + DEFINE_FIELD_SPEC ('R', NULL, false, + "Marker (R or D) representing whether tag is definition or reference", + renderFieldRefMarker), + DEFINE_FIELD_SPEC ('Z', "scope", false, + "Include the "scope:" key in scope field (use s) in tags output, scope name in xref output", + /* Following renderer is for handling --_xformat=%{scope}; + and is not for tags output. */ + renderFieldScope), + DEFINE_FIELD_SPEC_FULL ('E', "extra", false, + "Extra tag type information", + renderFieldExtra, isExtraFieldAvailable), + DEFINE_FIELD_SPEC_FULL ('x', "xpath", false, + "xpath for the tag", + renderFieldXpath, isXpathFieldAvailable), + DEFINE_FIELD_SPEC ('p', "scopeKind", false, + "Kind of scope as full name", + renderFieldScopeKindName), + DEFINE_FIELD_SPEC_FULL ('e', "end", false, + "end lines of various items", + renderFieldEnd, isEndFieldAvailable), +}; + + +static unsigned int fieldDescUsed = 0; +static unsigned int fieldDescAllocated = 0; +static fieldDesc* fieldDescs = NULL; + +extern void initFieldDescs (void) +{ + int i; + fieldDesc *fdesc; + + Assert (fieldDescs == NULL); + + fieldDescAllocated + = ARRAY_SIZE (fieldSpecsFixed) + + ARRAY_SIZE (fieldSpecsExuberant) + + ARRAY_SIZE (fieldSpecsUniversal); + fieldDescs = xMalloc (fieldDescAllocated, fieldDesc); + + fieldDescUsed = 0; + + for (i = 0; i < ARRAY_SIZE (fieldSpecsFixed); i++) + { + fdesc = fieldDescs + i + fieldDescUsed; + fdesc->spec = fieldSpecsFixed + i; + fdesc->fixed = 1; + fdesc->buffer = NULL; + fdesc->nameWithPrefix = fdesc->spec->name; + fdesc->language = LANG_IGNORE; + fdesc->sibling = FIELD_UNKNOWN; + } + fieldDescUsed += ARRAY_SIZE (fieldSpecsFixed); + + for (i = 0; i < ARRAY_SIZE (fieldSpecsExuberant); i++) + { + fdesc = fieldDescs + i + fieldDescUsed; + fdesc->spec = fieldSpecsExuberant +i; + fdesc->fixed = 0; + fdesc->buffer = NULL; + fdesc->nameWithPrefix = fdesc->spec->name; + fdesc->language = LANG_IGNORE; + fdesc->sibling = FIELD_UNKNOWN; + } + fieldDescUsed += ARRAY_SIZE (fieldSpecsExuberant); + + for (i = 0; i < ARRAY_SIZE (fieldSpecsUniversal); i++) + { + char *nameWithPrefix; + + fdesc = fieldDescs + i + fieldDescUsed; + fdesc->spec = fieldSpecsUniversal + i; + fdesc->fixed = 0; + fdesc->buffer = NULL; + + if (fdesc->spec->name) + { + nameWithPrefix = eMalloc (sizeof CTAGS_FIELD_PREFIX + strlen (fdesc->spec->name) + 1); + nameWithPrefix [0] = '\0'; + strcat (nameWithPrefix, CTAGS_FIELD_PREFIX); + strcat (nameWithPrefix, fdesc->spec->name); + fdesc->nameWithPrefix = nameWithPrefix; + } + else + fdesc->nameWithPrefix = NULL; + fdesc->language = LANG_IGNORE; + fdesc->sibling = FIELD_UNKNOWN; + } + fieldDescUsed += ARRAY_SIZE (fieldSpecsUniversal); + + Assert ( fieldDescAllocated == fieldDescUsed ); +} + +static fieldDesc* getFieldDesc(fieldType type) +{ + Assert ((0 <= type) && (type < fieldDescUsed)); + return fieldDescs + type; +} + +extern fieldType getFieldTypeForOption (char letter) +{ + unsigned int i; + + for (i = 0; i < fieldDescUsed; i++) + { + if (fieldDescs [i].spec->letter == letter) + return i; + } + return FIELD_UNKNOWN; +} + +extern fieldType getFieldTypeForName (const char *name) +{ + return getFieldTypeForNameAndLanguage (name, LANG_IGNORE); +} + +extern fieldType getFieldTypeForNameAndLanguage (const char *fieldName, langType language) +{ + static bool initialized = false; + unsigned int i; + + if (fieldName == NULL) + return FIELD_UNKNOWN; + + if (language == LANG_AUTO && (initialized == false)) + { + initialized = true; + initializeParser (LANG_AUTO); + } + else if (language != LANG_IGNORE && (initialized == false)) + initializeParser (language); + + for (i = 0; i < fieldDescUsed; i++) + { + if (fieldDescs [i].spec->name + && strcmp (fieldDescs [i].spec->name, fieldName) == 0 + && ((language == LANG_AUTO) + || (fieldDescs [i].language == language))) + return i; + } + + return FIELD_UNKNOWN; +} + +extern const char* getFieldName(fieldType type) +{ + fieldDesc* fdesc; + + fdesc = getFieldDesc (type); + if (Option.putFieldPrefix) + return fdesc->nameWithPrefix; + else + return fdesc->spec->name; +} + +extern bool doesFieldHaveValue (fieldType type, const tagEntryInfo *tag) +{ + if (getFieldDesc(type)->spec->isValueAvailable) + return getFieldDesc(type)->spec->isValueAvailable(tag); + else + return true; +} + +#define PR_FIELD_WIDTH_LETTER 7 +#define PR_FIELD_WIDTH_NAME 15 +#define PR_FIELD_WIDTH_LANGUAGE 16 +#define PR_FIELD_WIDTH_DESC 30 +#define PR_FIELD_WIDTH_XFMT 6 +#define PR_FIELD_WIDTH_ENABLED 7 + +#define PR_FIELD_STR(X) PR_FIELD_WIDTH_##X +#define PR_FIELD_FMT(X,T) "%-" STRINGIFY(PR_FIELD_STR(X)) STRINGIFY(T) + +#define MAKE_FIELD_FMT(LETTER_SPEC) \ + PR_FIELD_FMT (LETTER,LETTER_SPEC) \ + " " \ + PR_FIELD_FMT (NAME,s) \ + " " \ + PR_FIELD_FMT (ENABLED,s) \ + " " \ + PR_FIELD_FMT (LANGUAGE,s) \ + " " \ + PR_FIELD_FMT (XFMT,s) \ + " " \ + PR_FIELD_FMT (DESC,s) \ + "\n" + +static void printField (fieldType i) +{ + unsigned char letter = fieldDescs[i].spec->letter; + const char *name; + const char *language; + + if (letter == FIELD_LETTER_NO_USE) + letter = '-'; + + if (! fieldDescs[i].spec->name) + name = "NONE"; + else + name = getFieldName (i); + + if (fieldDescs[i].language == LANG_IGNORE) + language = "NONE"; + else + language = getLanguageName (fieldDescs[i].language); + + printf((Option.machinable? "%c\t%s\t%s\t%s\t%s\t%s\n": MAKE_FIELD_FMT(c)), + letter, + name, + isFieldEnabled (i)? "on": "off", + language, + getFieldDesc (i)->spec->renderEscaped? "TRUE": "FALSE", + fieldDescs[i].spec->description? fieldDescs[i].spec->description: "NONE"); +} + +extern void printFields (int language) +{ + unsigned int i; + + if (Option.withListHeader) + printf ((Option.machinable? "%s\t%s\t%s\t%s\t%s\t%s\n": MAKE_FIELD_FMT(s)), + "#LETTER", "NAME", "ENABLED", "LANGUAGE", "XFMT", "DESCRIPTION"); + + for (i = 0; i < fieldDescUsed; i++) + { + if (language == LANG_AUTO || getFieldOwner (i) == language) + printField (i); + } +} + +static const char *renderAsIs (vString* b CTAGS_ATTR_UNUSED, const char *s) +{ + return s; +} + +static const char *renderEscapedString (const char *s, + const tagEntryInfo *const tag CTAGS_ATTR_UNUSED, + vString* b) +{ + vStringCatSWithEscaping (b, s); + return vStringValue (b); +} + +static const char *renderEscapedName (const char* s, + const tagEntryInfo *const tag, + vString* b) +{ + const char* base = s; + + for (; *s; s++) + { + int c = *s; + if ((c > 0x00 && c <= 0x1F) || c == 0x7F) + { + verbose ("Unexpected character (0 < *c && *c < 0x20) included in a tagEntryInfo: %s\n", base); + verbose ("File: %s, Line: %lu, Lang: %s, Kind: %c\n", + tag->sourceFileName, tag->lineNumber, tag->language, tag->kind->letter); + verbose ("Escape the character\n"); + break; + } + else if (c == '\') + break; + else + continue; + } + + if (*s == '\0') + return base; + + vStringNCatS (b, base, s - base); + + return renderEscapedString (s, tag, b); +} + +static const char *renderFieldName (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b) +{ + return renderEscapedName (tag->name, tag, b); +} + +static const char *renderFieldInput (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b) +{ + const char *f = tag->sourceFileName; + + if (Option.lineDirectives && tag->sourceFileName) + f = tag->sourceFileName; + return renderEscapedString (f, tag, b); +} + +static const char *renderFieldSignature (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b) +{ + return renderEscapedString (WITH_DEFUALT_VALUE (tag->extensionFields.signature), + tag, b); +} + +static const char *renderFieldScope (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b) +{ + const char* scope; + + /* getTagScopeInformation ((tagEntryInfo *const)tag, NULL, &scope); */ + return scope? renderEscapedName (scope, tag, b): NULL; +} + +static const char *renderFieldInherits (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b) +{ + return renderEscapedString (WITH_DEFUALT_VALUE (tag->extensionFields.inheritance), + tag, b); +} + +static const char *renderFieldTyperef (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b) +{ + /* return renderEscapedName (WITH_DEFUALT_VALUE (tag->extensionFields.typeRef [1]), tag, b); */ + return NULL; +} + + +extern const char* renderFieldEscaped (fieldType type, + const tagEntryInfo *tag, + int index) +{ + fieldDesc *fdesc = fieldDescs + type; + const char *value; + + Assert (tag); + Assert (fdesc->spec->renderEscaped); + + fdesc->buffer = vStringNewOrClear (fdesc->buffer); + + if (index >= 0) + { +/* + Assert ( tag->usedParserFields > index ); + value = tag->parserFields[ index ].value; +*/ + } + else + value = NULL; + + return fdesc->spec->renderEscaped (tag, value, fdesc->buffer); +} + +/* Writes "line", stripping leading and duplicate white space. + */ +static const char* renderCompactInputLine (vString *b, const char *const line) +{ + bool lineStarted = false; + const char *p; + int c; + + /* Write everything up to, but not including, the newline. + */ + for (p = line, c = *p ; c != NEWLINE && c != '\0' ; c = *++p) + { + if (lineStarted || ! isspace (c)) /* ignore leading spaces */ + { + lineStarted = true; + if (isspace (c)) + { + int next; + + /* Consume repeating white space. + */ + while (next = *(p+1) , isspace (next) && next != NEWLINE) + ++p; + c = ' '; /* force space character for any white space */ + } + if (c != CRETURN || *(p + 1) != NEWLINE) + vStringPut (b, c); + } + } + return vStringValue (b); +} + +static const char *renderFieldKindName (const tagEntryInfo *const tag, const char *value CTAGS_ATTR_UNUSED, vString* b) +{ + return renderAsIs (b, tag->kind->name); +} + +static const char *renderFieldCompactInputLine (const tagEntryInfo *const tag, + const char *value CTAGS_ATTR_UNUSED, + vString* b) +{ + const char *line; + static vString *tmp; + + tmp = vStringNewOrClear (tmp); + + line = NULL; +/* return renderEscapedName (WITH_DEFUALT_VALUE (tag->extensionFields.typeRef [1]), tag, b); */ + if (line) + renderCompactInputLine (b, line); + else + { + /* If no associated line for tag is found, we cannot prepare + * parameter to writeCompactInputLine(). In this case we + * use an empty string as LINE. + */ + vStringClear (b); + } + + return vStringValue (b); +} + +static const char *renderFieldLineNumber (const tagEntryInfo *const tag, + const char *value CTAGS_ATTR_UNUSED, + vString* b) +{ + long ln = tag->lineNumber; + char buf[32] = {[0] = '\0'}; +/* + if (Option.lineDirectives && (tag->sourceLineNumberDifference != 0)) + ln += tag->sourceLineNumberDifference; +*/ + snprintf (buf, sizeof(buf), "%ld", ln); + vStringCatS (b, buf); + return vStringValue (b); +} + +static const char *renderFieldRole (const tagEntryInfo *const tag, + const char *value CTAGS_ATTR_UNUSED, + vString* b) +{ +/* + int rindex = tag->extensionFields.roleIndex; + const roleDesc * role; + + if (rindex == ROLE_INDEX_DEFINITION) + vStringClear (b); + else + { + Assert (rindex < tag->kind->nRoles); + role = & (tag->kind->roles [rindex]); + return renderRole (role, b); + } + + return vStringValue (b); +*/ + return NULL; +} + +static const char *renderFieldLanguage (const tagEntryInfo *const tag, + const char *value CTAGS_ATTR_UNUSED, + vString* b) +{ + const char *l = tag->language; +/* + if (Option.lineDirectives && tag->sourceLanguage) + l = tag->sourceLanguage; +*/ + return renderAsIs (b, WITH_DEFUALT_VALUE(l)); +} + +static const char *renderFieldAccess (const tagEntryInfo *const tag, + const char *value, + vString* b) +{ + return renderAsIs (b, WITH_DEFUALT_VALUE (tag->extensionFields.access)); +} + +static const char *renderFieldKindLetter (const tagEntryInfo *const tag, + const char *value CTAGS_ATTR_UNUSED, + vString* b) +{ + static char c[2] = { [1] = '\0' }; + + c [0] = tag->kind->letter; + + return renderAsIs (b, c); +} + +static const char *renderFieldImplementation (const tagEntryInfo *const tag, + const char *value CTAGS_ATTR_UNUSED, + vString* b) +{ + return renderAsIs (b, WITH_DEFUALT_VALUE (tag->extensionFields.implementation)); +} + +static const char *renderFieldFile (const tagEntryInfo *const tag, + const char *value CTAGS_ATTR_UNUSED, + vString* b) +{ + return renderAsIs (b, tag->isFileScope? "file": "-"); +} + +static const char *renderFieldPattern (const tagEntryInfo *const tag, + const char *value CTAGS_ATTR_UNUSED, + vString* b) +{ +/* char* tmp = makePatternString (tag); */ + char* tmp = NULL; + vStringCatS (b, tmp); + eFree (tmp); + return vStringValue (b); +} + +static const char *renderFieldRefMarker (const tagEntryInfo *const tag, + const char *value CTAGS_ATTR_UNUSED, + vString* b) +{ + static char c[2] = { [1] = '\0' }; + +/* c [0] = tag->extensionFields.roleIndex == ROLE_INDEX_DEFINITION? 'D': 'R'; */ + + return renderAsIs (b, c); +} + +static const char *renderFieldExtra (const tagEntryInfo *const tag, + const char *value CTAGS_ATTR_UNUSED, + vString* b) +{ + int i; + bool hasExtra = false; +/* + for (i = 0; i < XTAG_COUNT; i++) + { + const char *name = getXtagName (i); + + if (!name) + continue; + + if (isTagExtraBitMarked (tag, i)) + { + + if (hasExtra) + vStringPut (b, ','); + vStringCatS (b, name); + hasExtra = true; + } + } +*/ + if (hasExtra) + return vStringValue (b); + else + return NULL; +} + +static const char *renderFieldXpath (const tagEntryInfo *const tag, + const char *value, + vString* b) +{ +#ifdef HAVE_LIBXML + if (tag->extensionFields.xpath) + return renderEscapedString (tag->extensionFields.xpath, + tag, b); +#endif + return NULL; +} + +static const char *renderFieldScopeKindName(const tagEntryInfo *const tag, + const char *value, + vString* b) +{ + const char* kind; + +/* getTagScopeInformation ((tagEntryInfo *const)tag, &kind, NULL); */ + return kind? renderAsIs (b, kind): NULL; +} + +static const char *renderFieldEnd (const tagEntryInfo *const tag, + const char *value, + vString* b) +{ + static char buf[16]; +/* + if (tag->extensionFields.endLine != 0) + { + sprintf (buf, "%ld", tag->extensionFields.endLine); + return renderAsIs (b, buf); + } + else */ + return NULL; +} + +static bool isLanguageFieldAvailable (const tagEntryInfo *const tag) +{ + return (tag->language != NULL)? true: false; +} + +static bool isTyperefFieldAvailable (const tagEntryInfo *const tag) +{ +/* + return (tag->extensionFields.typeRef [0] != NULL + && tag->extensionFields.typeRef [1] != NULL)? true: false; */ + return false; +} + +static bool isFileFieldAvailable (const tagEntryInfo *const tag) +{ + return tag->isFileScope? true: false; +} + +static bool isInheritsFieldAvailable (const tagEntryInfo *const tag) +{ + return (tag->extensionFields.inheritance != NULL)? true: false; +} + +static bool isAccessFieldAvailable (const tagEntryInfo *const tag) +{ + return (tag->extensionFields.access != NULL)? true: false; +} + +static bool isImplementationFieldAvailable (const tagEntryInfo *const tag) +{ + return (tag->extensionFields.implementation != NULL)? true: false; +} + +static bool isSignatureFieldAvailable (const tagEntryInfo *const tag) +{ + return (tag->extensionFields.signature != NULL)? true: false; +} + +static bool isRoleFieldAvailable (const tagEntryInfo *const tag) +{ + /* return (tag->extensionFields.roleIndex != ROLE_INDEX_DEFINITION)? true: false; */ + return false; +} + +static bool isExtraFieldAvailable (const tagEntryInfo *const tag) +{ + int i; +/* + for (i = 0; i < sizeof (tag->extra); i++) + { + if (tag->extra [i]) + return true; + } +*/ + return false; +} + +static bool isXpathFieldAvailable (const tagEntryInfo *const tag) +{ +#ifdef HAVE_LIBXML + return (tag->extensionFields.xpath != NULL)? true: false; +#else + return false; +#endif +} + +static bool isEndFieldAvailable (const tagEntryInfo *const tag) +{ +/* return (tag->extensionFields.endLine != 0)? true: false; */ + return false; +} + +extern bool isFieldEnabled (fieldType type) +{ + return getFieldDesc(type)->spec->enabled; +} + +static bool isFieldFixed (fieldType type) +{ + return getFieldDesc(type)->fixed? true: false; +} + +extern bool enableField (fieldType type, bool state, bool warnIfFixedField) +{ + fieldSpec *spec = getFieldDesc(type)->spec; + bool old = spec->enabled? true: false; + if (isFieldFixed (type)) + { + if ((!state) && warnIfFixedField) + { + if (spec->name && spec->letter != NUL_FIELD_LETTER) + error(WARNING, "Cannot disable fixed field: '%c'{%s}", + spec->letter, spec->name); + else if (spec->name) + error(WARNING, "Cannot disable fixed field: {%s}", + spec->name); + else if (spec->letter != NUL_FIELD_LETTER) + error(WARNING, "Cannot disable fixed field: '%c'", + getFieldDesc(type)->spec->letter); + else + AssertNotReached(); + } + } + else + { + getFieldDesc(type)->spec->enabled = state; + + if (isCommonField (type)) + verbose ("enable field "%s": %s\n", + getFieldDesc(type)->spec->name, + (state? "TRUE": "FALSE")); + else + verbose ("enable field "%s"<%s>: %s\n", + getFieldDesc(type)->spec->name, + getLanguageName (getFieldOwner(type)), + (state? "TRUE": "FALSE")); + } + return old; +} + +extern bool isCommonField (fieldType type) +{ + return (FIELD_BUILTIN_LAST < type)? false: true; +} + +extern int getFieldOwner (fieldType type) +{ + return getFieldDesc(type)->language; +} + +extern bool isFieldRenderable (fieldType type) +{ + return getFieldDesc(type)->spec->renderEscaped? true: false; +} + +extern int countFields (void) +{ + return fieldDescUsed; +} + +extern fieldType nextSiblingField (fieldType type) +{ + fieldDesc *fdesc; + + fdesc = fieldDescs + type; + return fdesc->sibling; +} + +static void updateSiblingField (fieldType type, const char* name) +{ + int i; + fieldDesc *fdesc; + + for (i = type; i > 0; i--) + { + fdesc = fieldDescs + i - 1; + if (fdesc->spec->name && (strcmp (fdesc->spec->name, name) == 0)) + { + Assert (fdesc->sibling == FIELD_UNKNOWN); + fdesc->sibling = type; + break; + } + } +} + +static const char* defaultRenderer (const tagEntryInfo *const tag, + const char *value, + vString * buffer) +{ + return value; +} + +extern int defineField (fieldSpec *spec, langType language) +{ + fieldDesc *fdesc; + char *nameWithPrefix; + size_t i; + + Assert (spec); + Assert (spec->name); + for (i = 0; i < strlen (spec->name); i++) + { + Assert ( isalnum (spec->name [i]) ); + } + spec->letter = NUL_FIELD_LETTER; + + if (fieldDescUsed == fieldDescAllocated) + { + fieldDescAllocated *= 2; + fieldDescs = xRealloc (fieldDescs, fieldDescAllocated, fieldDesc); + } + fdesc = fieldDescs + (fieldDescUsed); + spec->ftype = fieldDescUsed++; + + if (spec->renderEscaped == NULL) + spec->renderEscaped = defaultRenderer; + + fdesc->spec = spec; + + fdesc->fixed = 0; + fdesc->buffer = NULL; + + nameWithPrefix = eMalloc (sizeof CTAGS_FIELD_PREFIX + strlen (spec->name) + 1); + nameWithPrefix [0] = '\0'; + strcat (nameWithPrefix, CTAGS_FIELD_PREFIX); + strcat (nameWithPrefix, spec->name); + fdesc->nameWithPrefix = nameWithPrefix; + + fdesc->language = language; + fdesc->sibling = FIELD_UNKNOWN; + + updateSiblingField (spec->ftype, spec->name); + return spec->ftype; +}
Modified: ctags/main/field.h 111 lines changed, 111 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,111 @@ +/* + * + * Copyright (c) 2015, Red Hat, Inc. + * Copyright (c) 2015, Masatake YAMATO + * + * Author: Masatake YAMATO yamato@redhat.com + * + * This source code is released for free distribution under the terms of the + * GNU General Public License version 2 or (at your option) any later version. + * + */ +#ifndef CTAGS_MAIN_FIELD_H +#define CTAGS_MAIN_FIELD_H + +#include "general.h" +#include "types.h" + +#include "vstring.h" + +typedef enum eFieldType { /* extension field content control */ + FIELD_UNKNOWN = -1, + + /* BASIC FIELDS */ + FIELD_NAME, + FIELD_INPUT_FILE, + FIELD_PATTERN, + FIELD_COMPACT_INPUT_LINE, + + /* EXTENSION FIELDS */ + FIELD_EXTENSION_START, + FIELD_ACCESS = FIELD_EXTENSION_START, + FIELD_FILE_SCOPE, + FIELD_INHERITANCE, + FIELD_KIND_LONG, + FIELD_KIND, + FIELD_LANGUAGE, + FIELD_IMPLEMENTATION, + FIELD_LINE_NUMBER, + FIELD_SIGNATURE, + FIELD_SCOPE, + FIELD_TYPE_REF, + FIELD_KIND_KEY, + + /* EXTENSION FIELDS NEWLY INTRODUCED IN UCTAGS */ + FIELD_ROLE, + FIELD_REF_MARK, + FIELD_SCOPE_KEY, + FIELD_EXTRA, + FIELD_XPATH, + FIELD_SCOPE_KIND_LONG, + FIELD_END, + FIELD_BUILTIN_LAST = FIELD_END, +} fieldType ; + +typedef const char* (* renderEscaped) (const tagEntryInfo *const tag, + const char *value, + vString * buffer); +typedef bool (* isValueAvailable) (const struct sTagEntryInfo *const tag); + +#define FIELD_LETTER_NO_USE '\0' +typedef struct sFieldSpec { + /* lettern, and ftype are initialized in the main part, + not in a parser. */ +#define NUL_FIELD_LETTER '\0' + unsigned char letter; + const char* name; + const char* description; + bool enabled; + renderEscaped renderEscaped; + isValueAvailable isValueAvailable; + + unsigned int ftype; /* Given from the main part */ +} fieldSpec; + + +extern fieldType getFieldTypeForOption (char letter); + +/* + `getFieldTypeForName' is for looking for a field not owned by any parser, + + `getFieldTypeForNameAndLanguage' can be used for getting all fields having + the same name; specify `LANG_AUTO' as `language' parameter to get the first + field having the name. With the returned fieldType, `nextSiblingField' gets + the next field having the same name. `nextSiblingField' returns `FIELD_UNKNOWN' + at the end of iteration. + + Specifying `LANG_IGNORE' has the same effects as `LANG_AUTO'. However, + internally, each parser is not initialized. `LANG_IGNORE' is a bit faster. */ +extern fieldType getFieldTypeForName (const char *name); +extern fieldType getFieldTypeForNameAndLanguage (const char *fieldName, langType language); +extern bool isFieldEnabled (fieldType type); +extern bool enableField (fieldType type, bool state, bool warnIfFixedField); +extern bool isCommonField (fieldType type); +extern int getFieldOwner (fieldType type); +extern const char* getFieldName (fieldType type); +extern void printFields (int language); + +extern bool isFieldRenderable (fieldType type); + +extern bool doesFieldHaveValue (fieldType type, const tagEntryInfo *tag); +extern const char* renderFieldEscaped (fieldType type, const tagEntryInfo *tag, int index); + +extern void initFieldDescs (void); +extern int countFields (void); + +/* language should be typed to langType. + Use int here to avoid circular dependency */ +extern int defineField (fieldSpec *spec, langType language); +extern fieldType nextSiblingField (fieldType type); + +#endif /* CTAGS_MAIN_FIELD_H */
Modified: ctags/main/flags.c 107 lines changed, 107 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,107 @@ +/* +* +* Copyright (c) 2000-2003, Darren Hiebert +* +* This source code is released for free distribution under the terms of the +* GNU General Public License version 2 or (at your option) any later version. +* +* This module contains functions to process command line options. +*/ + +/* +* INCLUDE FILES +*/ +#include "general.h" /* must always come first */ + +#include <string.h> +#include <stdio.h> + +#include "flags.h" +#include "vstring.h" +#include "routines.h" + +void flagsEval (const char* flags_original, flagDefinition* defs, unsigned int ndefs, void* data) +{ + unsigned int i, j; + char *flags; + + if (!flags_original) + return; + if (!defs) + return; + + flags = eStrdup (flags_original); + for (i = 0 ; flags [i] != '\0' ; ++i) + { + if (flags [i] == LONG_FLAGS_OPEN) + { + const char* aflag = flags + i + 1; + char* needle_close_paren = strchr(aflag, LONG_FLAGS_CLOSE); + const char* param; + char* needle_eqaul; + + if (needle_close_paren == NULL) + { + error (WARNING, "long flags specifier opened with `%c' is not closed `%c'", + LONG_FLAGS_OPEN, LONG_FLAGS_CLOSE); + break; + } + + *needle_close_paren = '\0'; + needle_eqaul = strchr(aflag, '='); + if ((needle_eqaul == NULL || (needle_eqaul >= needle_close_paren))) + { + needle_eqaul = NULL; + param = NULL; + } + else + { + param = needle_eqaul + 1; + *needle_eqaul = '\0'; + } + + for ( j = 0 ; j < ndefs ; ++j ) + if (defs[j].longStr && (strcmp(aflag, defs[j].longStr) == 0)) + defs[j].longProc(aflag, param, data); + + if (needle_eqaul) + *needle_eqaul = '='; + *needle_close_paren = LONG_FLAGS_CLOSE; + + i = needle_close_paren - flags; + } + else for (j = 0 ; j < ndefs ; ++j) + if (flags[i] == defs[j].shortChar) + defs[j].shortProc(flags[i], data); + } + eFree (flags); +} + +void flagPrintHelp (flagDefinition* def, unsigned int ndefs) +{ + + unsigned int i; + const char *longStr; + const char *description; + const char *paramName; + char shortChar[3]; + for ( i = 0; i < ndefs; ++i ) + { + longStr = def[i].longStr? def[i].longStr: ""; + description = def[i].description? def[i].description: ""; + paramName = def[i].paramName; + + if (def[i].shortChar == '\0') + strcpy (shortChar, "\0"); + else + { + shortChar[0] = def[i].shortChar; + shortChar[1] = '\0'; + } + + if (paramName) + printf ("%s\t%s=%s\t%s\n", shortChar, longStr, paramName, description); + else + printf ("%s\t%s\t%s\n", shortChar, longStr, description); + } +}
Modified: ctags/main/flags.h 29 lines changed, 29 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,29 @@ +/* +* +* +* Copyright (c) 2000-2003, Darren Hiebert +* +* This source code is released for free distribution under the terms of the +* GNU General Public License version 2 or (at your option) any later version. +* +* Defines external interface to option processing. +*/ +#ifndef CTAGS_MAIN_FLAGS_H +#define CTAGS_MAIN_FLAGS_H + +#define LONG_FLAGS_OPEN '{' +#define LONG_FLAGS_CLOSE '}' + +typedef struct sFlagDefinition { + char shortChar; + const char *longStr; + void (* shortProc) (char c, void *data); + void (* longProc) (const char* const s, const char* const param, void *data); + const char *paramName; + const char *description; +} flagDefinition; + +extern void flagsEval (const char* flags, flagDefinition* defs, unsigned int ndefs, void* data); +extern void flagPrintHelp (flagDefinition* def, unsigned int ndefs); + +#endif /* CTAGS_MAIN_FLAGS_H */
Modified: ctags/main/fmt.c 355 lines changed, 355 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,355 @@ +/* + * + * Copyright (c) 2015, Red Hat, Inc. + * Copyright (c) 2015, Masatake YAMATO + * + * Author: Masatake YAMATO yamato@redhat.com + * + * This source code is released for free distribution under the terms of the + * GNU General Public License version 2 or (at your option) any later version. + * + */ + +#include "general.h" +#include "debug.h" +#include "fmt.h" +#include "field.h" +#include "options.h" +#include "parse.h" +#include "routines.h" +#include <string.h> +#include <errno.h> + +typedef union uFmtSpec { + char *const_str; + struct { + fieldType ftype; + int width; + } field; +} fmtSpec; + +struct sFmtElement { + union uFmtSpec spec; + int (* printer) (fmtSpec*, MIO* fp, const tagEntryInfo *); + struct sFmtElement *next; +}; + +static int printLiteral (fmtSpec* fspec, MIO* fp, const tagEntryInfo * tag CTAGS_ATTR_UNUSED) +{ + return mio_puts (fp, fspec->const_str); +} + +static bool isParserFieldCompatibleWithFtype (const tagField *pfield, int baseFtype) +{ + do { + if (pfield->ftype == baseFtype) + return true; + baseFtype = nextSiblingField (baseFtype); + } while (baseFtype != FIELD_UNKNOWN); + return false; +} + +static int printTagField (fmtSpec* fspec, MIO* fp, const tagEntryInfo * tag) +{ + int i; + int width = fspec->field.width; + int ftype; + const char* str = NULL; + + ftype = fspec->field.ftype; + + if (isCommonField (ftype)) + str = renderFieldEscaped (ftype, tag, NO_PARSER_FIELD); + else + { + unsigned int findex; +/* + for (findex = 0; findex < tag->usedParserFields; findex++) + { + if (isParserFieldCompatibleWithFtype (tag->parserFields + findex, ftype)) + break; + } + + if (findex == tag->usedParserFields) + str = ""; + else if (isFieldEnabled (tag->parserFields [findex].ftype)) + str = renderFieldEscaped (tag->parserFields [findex].ftype, + tag, findex); +*/ + } + + if (str == NULL) + str = ""; + + if (width < 0) + i = mio_printf (fp, "%-*s", -1 * width, str); + else if (width > 0) + i = mio_printf (fp, "%*s", width, str); + else + { + mio_puts (fp, str); + i = strlen (str); + } + return i; +} + +static fmtElement** queueLiteral (fmtElement **last, char *literal) +{ + fmtElement *cur = xMalloc (1, fmtElement); + + cur->spec.const_str = literal; + cur->printer = printLiteral; + cur->next = NULL; + *last = cur; + return &(cur->next); +} + +/* `getLanguageComponentInFieldName' is used as part of the option parameter + for --_xformat option. + + It splits the value of fullName into a language part and a field name part. + Here the two parts are combined with `.'. + + If it cannot find a period, it returns LANG_IGNORE and sets + fullname to *fieldName. + + If lang part if `*', it returns LANG_AUTO and sets the field + name part to *fieldName. + + Though a period is found but no parser (langType) is found for + the language parser, this function returns LANG_IGNORE and sets + NULL to *fieldName. + + A proper parser is found, this function returns langType for the + parser and sets the field name part to *fieldName. */ +static langType getLanguageComponentInFieldName (const char *fullName, + const char **fieldName) +{ + const char *tmp; + langType language; + + tmp = strchr (fullName, '.'); + if (tmp) + { + size_t len = tmp - fullName; + + if (len == 1 && fullName[0] == '*') + { + language = LANG_AUTO; + *fieldName = tmp + 1; + } + else if (len == 0) + { + language = LANG_IGNORE; + *fieldName = tmp + 1; + } + else + { + language = getNamedLanguage (fullName, len); + if (language == LANG_IGNORE) + *fieldName = NULL; + else + *fieldName = tmp + 1; + } + } + else + { + language = LANG_IGNORE; + *fieldName = fullName; + } + return language; +} + +static fmtElement** queueTagField (fmtElement **last, long width, char field_letter, + const char *field_name) +{ + fieldType ftype; + fmtElement *cur; + langType language; + + if (field_letter == NUL_FIELD_LETTER) + { + const char *f; + + language = getLanguageComponentInFieldName (field_name, &f); + if (f == NULL) + error (FATAL, "No suitable parser for field name: %s", field_name); + ftype = getFieldTypeForNameAndLanguage (f, language); + } + else + { + language = LANG_IGNORE; + ftype = getFieldTypeForOption (field_letter); + } + + if (ftype == FIELD_UNKNOWN) + { + if (field_letter == NUL_FIELD_LETTER) + error (FATAL, "No such field name: %s", field_name); + else + error (FATAL, "No such field letter: %c", field_letter); + } + + if (!isFieldRenderable (ftype)) + { + Assert (field_letter != NUL_FIELD_LETTER); + error (FATAL, "The field cannot be printed in format output: %c", field_letter); + } + + cur = xMalloc (1, fmtElement); + + cur->spec.field.width = width; + cur->spec.field.ftype = ftype; + + enableField (ftype, true, false); + if (language == LANG_AUTO) + { + fieldType ftype_next = ftype; + + while ((ftype_next = nextSiblingField (ftype_next)) != FIELD_UNKNOWN) + enableField (ftype_next, true, false); + } + + cur->printer = printTagField; + cur->next = NULL; + *last = cur; + return &(cur->next); +} + +extern fmtElement *fmtNew (const char* fmtString) +{ + int i; + vString *literal = NULL; + fmtElement *code = NULL; + fmtElement **last = &code; + bool found_percent = false; + long column_width; + const char* cursor; + + cursor = fmtString; + + for (i = 0; cursor[i] != '\0'; ++i) + { + if (found_percent) + { + found_percent = false; + if (cursor[i] == '%') + { + if (literal == NULL) + literal = vStringNew (); + vStringPut (literal, cursor[i]); + } + else + { + int justification_right = 1; + vString *width = NULL; + if (literal) + { + char* l = vStringDeleteUnwrap (literal); + literal = NULL; + last = queueLiteral (last, l); + } + if (cursor [i] == '-') + { + justification_right = -1; + i++; + + if (cursor [i] == '\0') + error (FATAL, "unexpectedly terminated just after '-': "%s"", fmtString); + + } + + while ( '0' <= cursor[i] && cursor[i] <= '9' ) + { + if (width == NULL) + width = vStringNew (); + vStringPut (width, cursor[i]); + i++; + + if (cursor [i] == '\0') + error (FATAL, "unexpectedly terminated during parsing column width: "%s"", fmtString); + } + + if (justification_right == -1 && width == NULL) + error (FATAL, "no column width given after '-': "%s"", fmtString); + + column_width = 0; + if (width) + { + if(!strToLong (vStringValue (width), 0, &column_width)) + error (FATAL | PERROR, "coverting failed: %s", vStringValue (width)); + vStringDelete (width); + width = NULL; + column_width *= justification_right; + } + + if (cursor[i] == '{') + { + vString *field_name = vStringNew (); + + i++; + for (; cursor[i] != '}'; i++) + vStringPut (field_name, cursor[i]); + + last = queueTagField (last, column_width, NUL_FIELD_LETTER, + vStringValue (field_name)); + + vStringDelete (field_name); + } + else + last = queueTagField (last, column_width, cursor[i], NULL); + } + + } + else + { + if (cursor[i] == '%') + found_percent = true; + else + { + if (literal == NULL) + literal = vStringNew (); + + vStringPut (literal, cursor[i]); + } + } + } + if (literal) + { + char* l = vStringDeleteUnwrap (literal); + literal = NULL; + last = queueLiteral (last, l); + } + return code; +} + +extern int fmtPrint (fmtElement * fmtelts, MIO* fp, const tagEntryInfo *tag) +{ + fmtElement *f = fmtelts; + int i = 0; + while (f) + { + i += f->printer (&(f->spec), fp, tag); + f = f->next; + } + return i; +} + +extern void fmtDelete (fmtElement * fmtelts) +{ + fmtElement *f = fmtelts; + fmtElement *next; + + while (f) + { + next = f->next; + if (f->printer == printLiteral) + { + eFree (f->spec.const_str); + f->spec.const_str = NULL; + } + f->next = NULL; + eFree (f); + f = next; + } +}
Modified: ctags/main/fmt.h 25 lines changed, 25 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,25 @@ +/* + * + * Copyright (c) 2015, Red Hat, Inc. + * Copyright (c) 2015, Masatake YAMATO + * + * Author: Masatake YAMATO yamato@redhat.com + * + * This source code is released for free distribution under the terms of the + * GNU General Public License version 2 or (at your option) any later version. + * + */ + +#ifndef FMT_H +#define FMT_H + +#include "general.h" +#include "entry.h" +#include "mio.h" + +typedef struct sFmtElement fmtElement; +extern fmtElement *fmtNew (const char* fmtString); +extern int fmtPrint (fmtElement * fmtelts, MIO* fp, const tagEntryInfo *tag); +extern void fmtDelete (fmtElement * fmtelts); + +#endif /* FMT_H */
Modified: ctags/main/htable.c 271 lines changed, 271 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,271 @@ +/* +* +* Copyright (c) 2014, Red Hat, Inc. +* Copyright (c) 2014, Masatake YAMATO +* +* This source code is released for free distribution under the terms of the +* GNU General Public License version 2 or (at your option) any later version. +* +* Defines hashtable +*/ + +#include "general.h" +#include "htable.h" + +#ifndef MAIN +#include <stdio.h> +#include "routines.h" +#else +#include <stdlib.h> +#ifndef xCalloc +#define xCalloc(n,Type) (Type *)calloc((size_t)(n), sizeof (Type)) +#endif +#ifndef xMalloc +#define xMalloc(n,Type) (Type *)malloc((size_t)(n) * sizeof (Type)) +#endif +#ifndef eFree +#define eFree(x) free(x) +#endif +#endif /* MAIN */ + +#include <string.h> + + +typedef struct sHashEntry hentry; +struct sHashEntry { + void *key; + void *value; + hentry *next; +}; + +struct sHashTable { + hentry** table; + unsigned int size; + hashTableHashFunc hashfn; + hashTableEqualFunc equalfn; + hashTableFreeFunc keyfreefn; + hashTableFreeFunc valfreefn; +}; + + +static hentry* entry_new (void *key, void *value, hentry* next) +{ + hentry* entry = xMalloc (1, hentry); + + entry->key = key; + entry->value = value; + entry->next = next; + + return entry; +} + +static hentry* entry_destroy (hentry* entry, + hashTableFreeFunc keyfreefn, + hashTableFreeFunc valfreefn) +{ + hentry* tmp; + + if (keyfreefn) + keyfreefn (entry->key); + if (valfreefn) + valfreefn (entry->value); + entry->key = NULL; + entry->value = NULL; + tmp = entry->next; + eFree (entry); + + return tmp; +} + +static void entry_reclaim (hentry* entry, + hashTableFreeFunc keyfreefn, + hashTableFreeFunc valfreefn) +{ + while (entry) + entry = entry_destroy (entry, keyfreefn, valfreefn); +} + +static void *entry_find (hentry* entry, void* key, hashTableEqualFunc equalfn) +{ + while (entry) + { + if (equalfn( key, entry->key)) + return entry->value; + entry = entry->next; + } + return NULL; +} + +static bool entry_delete (hentry **entry, void *key, hashTableEqualFunc equalfn, + hashTableFreeFunc keyfreefn, hashTableFreeFunc valfreefn) +{ + while (*entry) + { + if (equalfn (key, (*entry)->key)) + { + *entry = entry_destroy (*entry, keyfreefn, valfreefn); + return true; + } + + } + return false; +} + +static void entry_foreach (hentry *entry, hashTableForeachFunc proc, void *user_data) +{ + while (entry) + { + proc (entry->key, entry->value, user_data); + entry = entry->next; + } +} + +extern hashTable *hashTableNew (unsigned int size, + hashTableHashFunc hashfn, + hashTableEqualFunc equalfn, + hashTableFreeFunc keyfreefn, + hashTableFreeFunc valfreefn) +{ + hashTable *htable; + + htable = xMalloc (1, hashTable); + htable->size = size; + htable->table = xCalloc (size, hentry*); + + htable->hashfn = hashfn; + htable->equalfn = equalfn; + htable->keyfreefn = keyfreefn; + htable->valfreefn = valfreefn; + + return htable; +} + +extern void hashTableDelete (hashTable *htable) +{ + unsigned int i; + if (!htable) + return; + + for (i = 0; i < htable->size; i++) + { + hentry *entry; + + entry = htable->table[i]; + entry_reclaim (entry, htable->keyfreefn, htable->valfreefn); + htable->table[i] = NULL; + } + eFree (htable->table); + eFree (htable); +} + +extern void hashTablePutItem (hashTable *htable, void *key, void *value) +{ + unsigned int i; + + i = htable->hashfn (key) % htable->size; + htable->table[i] = entry_new(key, value, htable->table[i]); +} + +extern void* hashTableGetItem (hashTable *htable, void *key) +{ + unsigned int i; + + i = htable->hashfn (key) % htable->size; + return entry_find(htable->table[i], key, htable->equalfn); +} + +extern bool hashTableDeleteItem (hashTable *htable, void *key) +{ + unsigned int i; + + i = htable->hashfn (key) % htable->size; + return entry_delete(&htable->table[i], key, + htable->equalfn, htable->keyfreefn, htable->valfreefn); +} + +extern bool hashTableHasItem (hashTable *htable, void *key) +{ + return hashTableGetItem (htable, key)? true: false; +} + +extern void hashTableForeachItem (hashTable *htable, hashTableForeachFunc proc, void *user_data) +{ + unsigned int i; + + for (i = 0; i < htable->size; i++) + entry_foreach(htable->table[i], proc, user_data); +} + +static void count (void *key CTAGS_ATTR_UNUSED, void *value CTAGS_ATTR_UNUSED, void *data) +{ + int *c = data; + ++*c; +} + +extern int hashTableCountItem (hashTable *htable) +{ + int c = 0; + hashTableForeachItem (htable, count, &c); + return c; +} +unsigned int hashPtrhash (void * x) +{ + union { + void *ptr; + unsigned int ui; + } v; + + v.ui = 0; + v.ptr = x; + return v.ui; +} + +bool hashPtreq (void *a, void *b) +{ + return (a == b)? true: false; +} + + +/* http://www.cse.yorku.ca/~oz/hash.html */ +static unsigned long +djb2(unsigned char *str) +{ + unsigned long hash = 5381; + int c; + + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + + return hash; +} + +unsigned int hashCstrhash (void * x) +{ + char *s = x; + return (unsigned int)djb2((unsigned char *)s); +} + +bool hashCstreq (void *a, void *b) +{ + return !!(strcmp (a, b) == 0); +} + +unsigned int hashInthash (void *x) +{ + union tmp { + unsigned int u; + int i; + } x0; + + x0.u = 0; + x0.i = *(int *)x; + return x0.u; +} + +bool hashInteq (void *a, void *b) +{ + int ai = *(int *)a; + int bi = *(int *)b; + + return !!(ai == bi); +}
Modified: ctags/main/htable.h 47 lines changed, 47 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,47 @@ +/* +* +* Copyright (c) 2014, Red Hat, Inc. +* Copyright (c) 2014, Masatake YAMATO +* +* This source code is released for free distribution under the terms of the +* GNU General Public License version 2 or (at your option) any later version. +* +* Defines hashtable +*/ +#ifndef CTAGS_MAIN_HTABLE_H +#define CTAGS_MAIN_HTABLE_H + +#include "general.h" + +typedef struct sHashTable hashTable; +typedef unsigned int (* hashTableHashFunc) (void * key); +typedef bool (* hashTableEqualFunc) (void* a, void* b); +typedef void (* hashTableFreeFunc) (void * ptr); +typedef void (* hashTableForeachFunc) (void *key, void *value, void* user_data); + +unsigned int hashPtrhash (void * x); +bool hashPtreq (void *a, void *b); + +unsigned int hashCstrhash (void * x); +bool hashCstreq (void *a, void *b); + +unsigned int hashCstrhash (void * x); +bool hashCstreq (void *a, void *b); + +unsigned int hashInthash (void *x); +bool hashInteq (void *a, void *b); + +extern hashTable* hashTableNew (unsigned int size, + hashTableHashFunc hashfn, + hashTableEqualFunc equalfn, + hashTableFreeFunc keyfreefn, + hashTableFreeFunc valfreefn); +extern void hashTableDelete (hashTable *htable); +extern void hashTablePutItem (hashTable *htable, void *key, void *value); +extern void* hashTableGetItem (hashTable *htable, void *key); +extern bool hashTableHasItem (hashTable *htable, void *key); +extern bool hashTableDeleteItem (hashTable *htable, void *key); +extern void hashTableForeachItem (hashTable *htable, hashTableForeachFunc proc, void *user_data); +extern int hashTableCountItem (hashTable *htable); + +#endif /* CTAGS_MAIN_HTABLE_H */
Modified: ctags/main/lcpp.c 3 lines changed, 2 insertions(+), 1 deletions(-) =================================================================== @@ -23,6 +23,7 @@ #include "read.h" #include "vstring.h" #include "routines.h" +#include "xtag.h"
/* * MACROS @@ -309,7 +310,7 @@ static void makeDefineTag (const char *const name, bool parameterized) const bool isFileScope = (bool) (! isInputHeaderFile ());
if (includingDefineTags () && - (! isFileScope || Option.include.fileScope)) + (! isFileScope || isXtagEnabled(XTAG_FILE_SCOPE))) { tagEntryInfo e;
Modified: ctags/main/lregex.c 5 lines changed, 3 insertions(+), 2 deletions(-) =================================================================== @@ -592,7 +592,7 @@ extern bool processRegexOption (const char *const option, if (dash != NULL && strncmp (option, "regex", dash - option) == 0) { langType language; - language = getNamedLanguage (dash + 1); + language = getNamedLanguage (dash + 1, 0); if (language == LANG_IGNORE) printf ("regex: unknown language "%s" in --%s option\n", (dash + 1), option); else @@ -658,7 +658,8 @@ extern void freeRegexResources (void) }
/* Check for broken regcomp() on Cygwin */ -extern void checkRegex (void) +extern bool checkRegex (void) { /* not needed now we have GRegex */ + return true; }
Modified: ctags/main/lxcmd.c 1227 lines changed, 1227 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,1227 @@ +/* +* +* Copyright (c) 1996-2003, Darren Hiebert +* Copyright (c) 2014, Red Hat, Inc. +* Copyright (c) 2014, Masatake YAMATO +* +* This source code is released for free distribution under the terms of the +* GNU General Public License version 2 or (at your option) any later version. +* +* This module contains functions for invoking external command. +* Half of codes are derived from lregex.c. +* Core data structure is taken from readtags.h. +* +*/ + +/* + XCMD PROTOCOL (version 2.1) + ================================================================== + When invoking xcmd just only with --lint-kinds=LANG option, + xcmd must write lines matching one of following patterns + to stdout. + + patterns + -------- + + ^([^ \t])[ \t]+([^\t]+)([ \t]+([off]))?$ + \1 => letter + \2 => name + \4 => [off] is optional. + + + exit code + --------- + + If xcmd itself recognizes it cannot run, it should exit with + XCMD_NOT_AVAILABLE_STATUS exit code. ctags may ignore the xcmd. +*/ + +#define XCMD_NOT_AVAILABLE_STATUS 127 + +/* +* INCLUDE FILES +*/ +#include "general.h" /* must always come first */ + +#ifndef _GNU_SOURCE +# define _GNU_SOURCE /* for WIFEXITED and WEXITSTATUS */ +#endif +#include <errno.h> +#include <ctype.h> +#include <stdlib.h> /* for WIFEXITED and WEXITSTATUS */ +#include <string.h> +#include <sys/types.h> +#ifdef HAVE_SYS_WAIT_H +# include <sys/wait.h> /* for WIFEXITED and WEXITSTATUS */ +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + + +#include "debug.h" +#include "main.h" +#include "options.h" +#include "parse.h" +#include "ptag.h" +#include "read.h" +#include "routines.h" +#include "vstring.h" + +#include "pcoproc.h" + +#include "flags.h" +#include "xtag.h" +#include "ptag.h" + +/* +* MACROS +*/ + +#define XCMD_LIST_KIND_OPTION "--list-kinds" + +/* +* DATA DECLARATIONS +*/ + +typedef struct { + + /* the key of the extension field */ + const char *key; + + /* the value of the extension field (may be an empty string) */ + const char *value; + int pull_count; + +} tagExtensionField; + +/* This structure contains information about a specific tag. */ +typedef struct { + + /* name of tag */ + const char *name; + + /* path of input file containing definition of tag */ + const char *file; + + /* address for locating tag in input file */ + struct { + /* pattern for locating input line + * (may be NULL if not present) */ + const char *pattern; + + /* line number in input file of tag definition + * (may be zero if not known) */ + unsigned long lineNumber; + } address; + + + const kindOption* kind; + + /* is tag of file-limited scope? */ + short fileScope; + + /* miscellaneous extension fields */ + struct { + /* number of entries in `list' */ + unsigned short count; + + /* list of key value pairs */ + tagExtensionField *list; + } fields; + +} tagEntry; + +typedef struct { + vString *path; + kindOption *kinds; + unsigned int n_kinds; + bool available; + unsigned int id; /* not used yet */ + int not_available_status; +} xcmdPath; + +typedef struct { + xcmdPath *paths; + unsigned int count; +} pathSet; + +#ifdef HAVE_COPROC + +static pathSet* Sets = NULL; +static int SetUpper = -1; /* upper language index in list */ + +static void clearPathSet (const langType language) +{ + if (language <= SetUpper) + { + pathSet* const set = Sets + language; + unsigned int i, k; + for (i = 0 ; i < set->count ; ++i) + { + xcmdPath *p = &set->paths [i]; + + vStringDelete (p->path); + p->path = NULL; + p->available = false; + for (k = 0; k < p->n_kinds; k++) + { + kindOption* kind = &(p->kinds[k]); + + eFree ((void *)kind->name); + kind->name = NULL; + eFree ((void *)kind->description); + kind->description = NULL; + } + if (p->kinds) + { + eFree (p->kinds); + p->kinds = NULL; + } + } + if (set->paths != NULL) + eFree (set->paths); + set->paths = NULL; + set->count = 0; + } +} + +static bool 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 bool isSafeExecutable (const char* path) +{ + fileStatus *file; + bool r; + + Assert (path); + file = eStat (path); + + if (!file->exists) + { + /* The file doesn't exist. So I cannot say + it is unsafe. The caller should + handle this case. */ + r = true; + } + else if (file->isSetuid) + { + error (WARNING, "xcmd doesn't run a setuid executable: %s", path); + r = false; + } + else if (file->isSetgid) + { + error (WARNING, "xcmd doesn't run a setgid executable: %s", path); + r = false; + } + else + r = true; + + eStatFree (file); + return r; +} + +static bool 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; +} +#endif /* HAVE_COPROC */ + + +extern void foreachXcmdKinds (const langType language, + bool (*func) (kindOption *, void *), + void *data) +{ +#ifdef HAVE_COPROC + if (language <= SetUpper && Sets [language].count > 0) + { + pathSet* const set = Sets + language; + xcmdPath * path = set->paths; + unsigned int i; + for (i = 0 ; i < set->count ; ++i) + { + unsigned int k; + if (!path[i].available) + continue; + + for (k = 0; k < path[i].n_kinds; k++) + if (func (& (path[i].kinds[k]), data)) + break; + } + } +#endif +} + +static bool kind_reset_cb (kindOption *kind, void *data) +{ + kind->enabled = *(bool *)data; + return false; /* continue */ +} + +extern void resetXcmdKinds (const langType language, bool mode) +{ + foreachXcmdKinds (language, kind_reset_cb, &mode); +} + +struct kind_and_mode_and_result +{ + int kind; + const char *kindLong; + bool mode; + bool result; +}; + +static bool enable_kind_cb (kindOption *kind, void *data) +{ + struct kind_and_mode_and_result *kmr = data; + if ((kmr->kind != KIND_NULL + && kind->letter == kmr->kind) + || (kmr->kindLong && kind->name + && (strcmp (kmr->kindLong, kind->name) == 0))) + { + kind->enabled = kmr->mode; + kmr->result = true; + } + /* conitnue: + There can be more than one paths which deals this kind. + Consider /bin/X and /bin/Y are both parser for a language L. + ctags --langdef=L --xcmd-L=/bin/X --xcmd-L=/bin/Y ... */ + return false; + +} + +extern bool enableXcmdKind (const langType language, const int kind, + const bool mode) +{ + struct kind_and_mode_and_result kmr; + + kmr.kind = kind; + kmr.kindLong = NULL; + kmr.mode = mode; + kmr.result = false; + + foreachXcmdKinds (language, enable_kind_cb, &kmr); + return kmr.result; +} + +extern bool enableXcmdKindLong (const langType language, const char *kindLong, + const bool mode) +{ + struct kind_and_mode_and_result kmr; + + kmr.kind = KIND_NULL; + kmr.kindLong = kindLong; + kmr.mode = mode; + kmr.result = false; + + foreachXcmdKinds (language, enable_kind_cb, &kmr); + return kmr.result; +} + +struct kind_and_result +{ + int kind; + bool result; +}; + +static bool is_kind_enabled_cb (kindOption *kind, void *data) +{ + bool r = false; + struct kind_and_result *kr = data; + + if (kind->letter == kr->kind) + { + kr->result = kind->enabled; + r = true; + } + + return r; +} + +static bool does_kind_exist_cb (kindOption *kind, void *data) +{ + bool r = false; + struct kind_and_result *kr = data; + + if (kind->letter == kr->kind) + { + kr->result = true; + r = true; + } + + return r; +} + +extern bool isXcmdKindEnabled (const langType language, const int kind) +{ + struct kind_and_result d; + + d.kind = kind; + d.result = false; + + foreachXcmdKinds (language, is_kind_enabled_cb, &d); + + return d.result; +} + +extern bool hasXcmdKind (const langType language, const int kind) +{ + struct kind_and_result d; + + d.kind = kind; + d.result = false; + + foreachXcmdKinds (language, does_kind_exist_cb, &d); + + return d.result; +} + +struct printXcmdKindCBData { + const char *langName; + bool allKindFields; + bool indent; + bool tabSeparated; +}; + +#ifdef HAVE_COPROC +static bool printXcmdKind (kindOption *kind, void *user_data) +{ + struct printXcmdKindCBData *data = user_data; + + if (data->allKindFields && data->indent) + printf (Option.machinable? "%s": PR_KIND_FMT (LANG,s), data->langName); + + printKind (kind, data->allKindFields, data->indent, data->tabSeparated); + return false; +} +#endif + +extern void printXcmdKinds (const langType language CTAGS_ATTR_UNUSED, + bool allKindFields CTAGS_ATTR_UNUSED, + bool indent CTAGS_ATTR_UNUSED, + bool tabSeparated CTAGS_ATTR_UNUSED) +{ +#ifdef HAVE_COPROC + if (language <= SetUpper && Sets [language].count > 0) + { + const char* const langName = getLanguageName(language); + struct printXcmdKindCBData data = { + .langName = langName, + .allKindFields = allKindFields, + .indent = indent, + .tabSeparated = tabSeparated, + }; + foreachXcmdKinds (language, printXcmdKind, &data); + } +#endif +} + +extern void freeXcmdResources (void) +{ +#ifdef HAVE_COPROC + int i; + for (i = 0 ; i <= SetUpper ; ++i) + clearPathSet (i); + if (Sets != NULL) + eFree (Sets); + Sets = NULL; + SetUpper = -1; +#endif +} + +#ifdef HAVE_COPROC +static void xcmd_flag_not_avaible_status_long (const char* const s, const char* const v, void* data) +{ + xcmdPath *path = data; + + if(!strToInt(v, 0, &path->not_available_status)) + error (FATAL, "Could not parse the value for %s flag: %s", s, v); +} +#endif + +extern void addTagXcmd (const langType language, vString* pathvstr, const char* flags) +{ +#ifdef HAVE_COPROC + pathSet* set; + xcmdPath *path; + + flagDefinition xcmdFlagDefs[] = { + { '\0', "notAvailableStatus", NULL, xcmd_flag_not_avaible_status_long }, + }; + + Assert (pathvstr != NULL); + + if (language > SetUpper) + { + int i; + Sets = xRealloc (Sets, (language + 1), pathSet); + for (i = SetUpper + 1 ; i <= language ; ++i) + { + Sets [i].paths = NULL; + Sets [i].count = 0; + } + SetUpper = language; + } + set = Sets + language; + set->paths = xRealloc (set->paths, (set->count + 1), xcmdPath); + + path = &set->paths [set->count]; + path->path = pathvstr; + path->kinds = NULL; + path->n_kinds = 0; + path->id = set->count; + path->not_available_status = XCMD_NOT_AVAILABLE_STATUS; + + set->count += 1; + + flagsEval (flags, xcmdFlagDefs, ARRAY_SIZE(xcmdFlagDefs), path); + + path->available = (loadPathKinds (path, language)); + useXcmdMethod (language); + if (path->available) + notifyAvailabilityXcmdMethod (language); +#endif +} +extern void addLanguageXcmd ( + const langType language CTAGS_ATTR_UNUSED, const char* const parameter CTAGS_ATTR_UNUSED) +{ +#ifdef HAVE_COPROC + char *path; + vString* vpath; + const char* flags; + + flags = strchr (parameter, LONG_FLAGS_OPEN); + if (flags) + path = eStrndup (parameter, flags - parameter); + else + path = eStrdup (parameter); + + if (parameter [0] != '/' && parameter [0] != '.') + { + vpath = expandOnDriversPathList (path); + vpath = vpath? vpath: vStringNewInit(path); + } + else + vpath = vStringNewInit(path); + + eFree (path); + + addTagXcmd (language, vpath, flags); +#endif +} + +#ifdef HAVE_COPROC +static void processLanguageXcmd (const langType language, + const char* const parameter) +{ + if (parameter == NULL || parameter [0] == '\0') + clearPathSet (language); + else + addLanguageXcmd (language, parameter); +} +#endif + +extern bool processXcmdOption (const char *const option, const char *const parameter, + OptionLoadingStage stage) +{ + langType language; + + language = getLanguageComponentInOption (option, "xcmd-"); + if (language == LANG_IGNORE) + return false; + + if (stage == OptionLoadingStageCurrentRecursive) + { + error (WARNING, "Don't use --xcmd-<LANG> option in ./.ctags nor ./.ctags/*: %s", + option); + /* Consume it here. */ + return true; + } + else if (stage == OptionLoadingStageHomeRecursive && (!Option.allowXcmdInHomeDir)) + { + error (WARNING, "Don't use --xcmd-<LANG> option in ~/.ctags and/or ~/.ctags/*: %s", + option); + /* Consume it here. */ + return true; + } + +#ifdef HAVE_COPROC + processLanguageXcmd (language, parameter); +#else + error (WARNING, "coproc feature is not available; required for --%s option", + option); +#endif + + return true; +} + +#ifdef HAVE_COPROC +static const kindOption* lookupKindFromLetter (const xcmdPath* const path, char kind_letter) +{ + unsigned int k; + kindOption *kind; + + for (k = 0; k < path->n_kinds; k++) + { + kind = path->kinds + k; + if (kind->letter == kind_letter) + return kind; + } + return NULL; + +} + +static const kindOption* lookupKindFromName (const xcmdPath* const path, const char* const kind_name) +{ + unsigned int k; + kindOption *kind; + + for (k = 0; k < path->n_kinds; k++) + { + kind = path->kinds + k; + if (kind->name && (!strcmp(kind->name, kind_name))) + return kind; + + } + return NULL; + +} + +static const char* entryLookupField (tagEntry *const entry, const char *const kind, bool pulling) +{ + int i; + + for (i = 0; i < entry->fields.count; i++) + { + if (!strcmp (entry->fields.list [i].key, kind)) + { + if (pulling) + entry->fields.list [i].pull_count++; + return entry->fields.list [i].value; + } + } + return NULL; +} + +static const char* entryGetAnyUnpulledField (tagEntry *const entry, const char **const kind, bool pulling) +{ + int i; + + for (i = 0; i < entry->fields.count; i++) + { + if (entry->fields.list [i].pull_count == 0) + { + *kind = entry->fields.list [i].key; + if (pulling) + entry->fields.list [i].pull_count++; + return entry->fields.list [i].value; + } + } + return NULL; +} + +static bool isKindEnabled (xcmdPath* path, const char* value) +{ + unsigned int k; + kindOption *kind; + + Assert (path->kinds); + Assert (value); + Assert (*value); + + for (k = 0; k < path->n_kinds; k++) + { + kind = path->kinds + k; + if (!kind->enabled) + { + if (value[1] == '\0' && value[0] == kind->letter) + return false; + if (!strcmp(value, kind->name)) + return false; + if (!strcmp(value, kind->description)) + return false; + } + } + return true; +} + +static void entryAddField (tagEntry *const entry, const char *const key, const char *const value) +{ + entry->fields.list = xRealloc (entry->fields.list, + entry->fields.count + 1, + tagExtensionField); + entry->fields.list [entry->fields.count].key = key; + entry->fields.list [entry->fields.count].value = value; + entry->fields.list [entry->fields.count].pull_count = 0; + ++entry->fields.count; +} + +static bool parseExtensionFields (tagEntry *const entry, char *const string, xcmdPath* path) +{ + char *p = string; + + while (p != NULL && *p != '\0') + { + while (*p == TAB) + *p++ = '\0'; + if (*p != '\0') + { + char *colon; + char *field = p; + p = strchr (p, TAB); + if (p != NULL) + *p++ = '\0'; + colon = strchr (field, ':'); + if (colon == NULL) + { + if (isKindEnabled (path, field)) + { + if (entry->kind == NULL) + { + entry->kind = lookupKindFromLetter (path, field[0]); + if (entry->kind == NULL) + { + kindOption *fileKind = getInputLanguageFileKind (); + if (fileKind && fileKind->letter == field[0]) + /* ctags will make a tag for file. */ + goto reject; + + } + } + else { + ; /* TODO Handle warning */ + } + Assert (entry->kind); + + } + else + goto reject; + } + else + { + const char *key = field; + const char *value = colon + 1; + *colon = '\0'; + if (strcmp (key, "kind") == 0) + { + if (*value == '\0') + goto reject; + else if (isKindEnabled (path, value)) + { + if (entry->kind == NULL) + { + entry->kind = lookupKindFromName (path, value); + if (entry->kind == NULL) + { + kindOption *fileKind = getInputLanguageFileKind (); + if (fileKind && (strcmp(fileKind->name, value) == 0)) + /* ctags will make a tag for file. */ + goto reject; + + } + } + + else { + ; /*TODO Handle warning*/ + } + Assert (entry->kind); + } + else + goto reject; + } + else if (strcmp (key, "file") == 0) + entry->fileScope = 1; + else if (strcmp (key, "line") == 0) + entry->address.lineNumber = atol (value); + else if (strcmp (key, "language") == 0) + continue; + else + entryAddField (entry, key, value); + } + } + } + return true; + reject: + if (entry->fields.list) + { + eFree (entry->fields.list); + entry->fields.list = NULL; + } + entry->fields.count = 0; + return false; +} + +static bool hasPseudoTagPrefix (const char* const name) +{ + const size_t prefixLength = strlen (PSEUDO_TAG_PREFIX); + return !strncmp (name, PSEUDO_TAG_PREFIX, prefixLength); +} + +static bool parseXcmdPath (char* line, xcmdPath* path, tagEntry* entry) +{ + char *p = line; + char *tab = strchr (p, TAB); + bool pseudoTag = false; + + // verbose("<%s>line: %s\n", vStringValue (path->path), line); + + entry->name = p; + if (tab != NULL) + { + *tab = '\0'; + pseudoTag = hasPseudoTagPrefix (entry->name); + + p = tab + 1; + entry->file = p; + tab = strchr (p, TAB); + if (tab != NULL) + { + int fieldsPresent; + *tab = '\0'; + p = tab + 1; + if (*p == '/' || *p == '?') + { + /* parse pattern */ + int delimiter = *(unsigned char*) p; + entry->address.lineNumber = 0; + entry->address.pattern = p; + do + { + p = strchr (p + 1, delimiter); + } while (p != NULL && *(p - 1) == '\'); + if (p == NULL) + { + *tab = '\t'; + error (WARNING, "pattern from %s is not ended with `%c': %s", + vStringValue (path->path), + (char)delimiter, + line); + return false; + } + else + ++p; + } + else if (isdigit ((int) *(unsigned char*) p)) + { + /* parse line number */ + entry->address.pattern = p; + entry->address.lineNumber = atol (p); + while (isdigit ((int) *(unsigned char*) p)) + ++p; + } + else + { + *tab = '\t'; + error (WARNING, "cannot parse as ctags output from %s: %s", + vStringValue (path->path), line); + return false; + } + fieldsPresent = (strncmp (p, ";"", 2) == 0); + *p = '\0'; + + if (pseudoTag) + return true; + + if (fieldsPresent) + { + if (!parseExtensionFields (entry, p + 2, path)) + return false; + return true; + } + } + } + return false; +} + +static void freeTagEntry (tagEntry* entry) +{ + if (entry->fields.list) + { + eFree (entry->fields.list); + entry->fields.list = NULL; + } + entry->fields.count = 0; +} + +static bool makePseudoTagEntryFromTagEntry (tagEntry* entry) +{ + const char *tagName, *fileName, *pattern; + const size_t prefixLength = strlen (PSEUDO_TAG_PREFIX); + ptagType t = PTAG_UNKNOWN; + + tagName = entry->name + prefixLength; + fileName = entry->file; + pattern = entry->address.pattern; + + if (strcmp (tagName, "TAG_FILE_SORTED") == 0) + return false; + else if (strcmp (tagName, "TAG_FILE_FORMAT") == 0) + return false; /* ??? */ + else if (strcmp (tagName, "TAG_PROGRAM_AUTHOR") == 0) + t = PTAG_PROGRAM_AUTHOR; + else if (strcmp (tagName, "TAG_PROGRAM_NAME") == 0) + t = PTAG_PROGRAM_NAME; + else if (strcmp (tagName, "TAG_PROGRAM_URL") == 0) + t = PTAG_PROGRAM_URL; + else if (strcmp (tagName, "TAG_PROGRAM_VERSION") == 0) + t = PTAG_PROGRAM_VERSION; + + if (t == PTAG_UNKNOWN) + return false; + else + { + struct ptagXcmdData data = { + .fileName = fileName, + .pattern = pattern, + .language = entryLookupField(entry, + "language", + false), + }; + return makePtagIfEnabled (t, &data); + } +} + +static bool makeTagEntryFromTagEntry (xcmdPath* path, tagEntry* entry) +{ + tagEntryInfo tag; + MIOPos filePosition; + + if (hasPseudoTagPrefix (entry->name)) + { + if (isXtagEnabled (XTAG_PSEUDO_TAGS)) + return makePseudoTagEntryFromTagEntry (entry); + else + return false; + } + + memset(&filePosition, 0, sizeof(filePosition)); + + // pseudo if (entry->name...); + initTagEntryFull (&tag, entry->name, + entry->address.lineNumber, + entryLookupField(entry, "language", true), + filePosition, + entry->file, + entry->kind, + ROLE_INDEX_DEFINITION, + NULL, + NULL, + 0); + + tag.pattern = entry->address.pattern; + + tag.isFileScope = (bool)entry->fileScope; + tag.extensionFields.access = entryLookupField(entry, "access", true); + tag.extensionFields.implementation = entryLookupField(entry, "implementation", true); + tag.extensionFields.inheritance = entryLookupField(entry, "inherits", true); + tag.extensionFields.signature = entryLookupField(entry, "signature", true); + tag.extensionFields.typeRef[0] = entryLookupField(entry, "typeref", true); + if (tag.extensionFields.typeRef[0]) + { + char *tmp; + tmp = strchr (tag.extensionFields.typeRef[0], ':'); + if (tmp) + { + *tmp = '\0'; + tag.extensionFields.typeRef[1] = tmp + 1; + } + } + + const char *kindName = NULL; + tag.extensionFields.scopeName = entryGetAnyUnpulledField (entry, &kindName, true); + if (tag.extensionFields.scopeName && kindName) + tag.extensionFields.scopeKind = lookupKindFromName (path, kindName); + + /* TODO: role */ + + makeTagEntry (&tag); + return true; +} + +static bool invokeXcmdPath (const char* const fileName, xcmdPath* path, const langType language) +{ + enum pcoprocError r; + bool result = false; + char* argv[4]; + FILE* pp = NULL; + + if (!path->available) + return false; + + argv[2] = NULL; + argv[1] = (char * const)fileName; + argv[0] = vStringValue (path->path); + + Assert (!(getuid() == 0 || geteuid() == 0)); + if (! isSafeExecutable (argv [0])) + return false; + + verbose ("getting tags of %s language 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(); + int status; + + while (readLineRawWithNoSeek (vline, pp)) + { + char* line; + tagEntry entry; + + memset(&entry, 0, sizeof(entry)); + vStringStripNewline (vline); + line = vStringValue (vline); + + + if (parseXcmdPath (line, path, &entry) ) + { + entryAddField (&entry, "language", getLanguageName (language)); + + /* Throw away the input file name returned from the xcmd. + Instead we use the input file name arranged + (relative or absolute) by ctags main side. */ + entry.file = getInputFileTagPath (); + + if (makeTagEntryFromTagEntry (path, &entry)) + result = true; + freeTagEntry (&entry); + } + } + + vStringDelete (vline); + + status = pcoprocClose (pp); + verbose(" status: %d\n", status); + if (status) + { + error (WARNING | PERROR, "xcmd exits abnormally status(%d): [%s %s]", + status, argv[0], argv[1]); + return false; + } + } + else + { + error (WARNING | PERROR, "cannot make pipe to xcmd: [%s %s]", + argv[0], argv[1]); + } + + return result; +} + +#endif + +#ifdef HAVE_COPROC +extern bool invokeXcmd (const char* const fileName, const langType language) +{ + bool result = false; + + if (language != LANG_IGNORE && language <= SetUpper && + Sets [language].count > 0) + { + const pathSet* const set = Sets + language; + unsigned int i; + + for (i = 0; i < set->count ; ++i) + { + xcmdPath* path = set->paths + i; + if (invokeXcmdPath (fileName, path, language)) + result = true; + } + + } + return result; +} +#endif
Modified: ctags/main/options.c 3347 lines changed, 3298 insertions(+), 49 deletions(-) =================================================================== No diff available, check online
Modified: ctags/main/options.h 169 lines changed, 128 insertions(+), 41 deletions(-) =================================================================== @@ -23,73 +23,108 @@ #include <stdarg.h>
#include "args.h" +#include "field.h" +#include "fmt.h" #include "parse.h" #include "strlist.h" +#include "htable.h" #include "vstring.h"
/* * DATA DECLARATIONS */
+typedef enum { OPTION_NONE, OPTION_SHORT, OPTION_LONG } optionType; + +typedef struct sCookedArgs { + /* private */ + Arguments* args; + char *shortOptions; + char simple[2]; + bool isOption; + bool longOption; + const char* parameter; + /* public */ + char* item; +} cookedArgs; + +typedef enum eLocate { + EX_MIX, /* line numbers for defines, patterns otherwise */ + EX_LINENUM, /* -n only line numbers in tag file */ + EX_PATTERN /* -N only patterns in tag file */ +} exCmd; + typedef enum sortType { SO_UNSORTED, SO_SORTED, SO_FOLDSORTED } sortType;
+typedef struct sIgnoredTokenInfo { + bool ignoreFollowingParenthesis; /* -I SOMETHING+ */ + char * replacement; /* -I SOMETHING=REPLACEMENT */ +} ignoredTokenInfo; + /* This stores the command line options. */ typedef struct sOptionValues { - struct sInclude { - bool fileNames; /* include tags for source file names */ - bool fileScope; /* include tags of file scope only */ - } include; - struct sExtFields { /* extension field content control */ - bool access; - bool fileScope; - bool implementation; - bool inheritance; - bool kind; - bool kindKey; - bool kindLong; - bool language; - bool lineNumber; - bool scope; - bool filePosition; /* Write file position */ - bool argList; /* Write function and macro argumentlist */ - } extensionFields; - stringList* ignore; /* -I name of file containing tokens to ignore */ - bool append; /* -a append to "tags" file */ - bool backward; /* -B regexp patterns search backwards */ - enum eLocate { - EX_MIX, /* line numbers for defines, patterns otherwise */ - EX_LINENUM, /* -n only line numbers in tag file */ - EX_PATTERN /* -N only patterns in tag file */ - } locate; /* --excmd EX command used to locate tag */ - bool recurse; /* -R recurse into directories */ - bool sorted; /* -u,--sort sort tags */ - bool verbose; /* -V verbose */ - bool xref; /* -x generate xref output instead */ + hashTable * ignore; /* -I name of file containing tokens to ignore */ + bool append; /* -a append to "tags" file */ + bool backward; /* -B regexp patterns search backwards */ + bool etags; /* -e output Emacs style tags file */ + exCmd locate; /* --excmd EX command used to locate tag */ + bool recurse; /* -R recurse into directories */ + sortType sorted; /* -u,--sort sort tags */ + bool verbose; /* -V verbose */ + bool xref; /* -x generate xref output instead */ + fmtElement *customXfmt; /* compiled code for --xformat=XFMT */ char *fileList; /* -L name of file containing names of files */ char *tagFileName; /* -o name of tags file */ stringList* headerExt; /* -h header extensions */ + char* configFilename; /* --config-filename use instead of 'ctags' in option file names */ stringList* etagsInclude;/* --etags-include list of TAGS files to include*/ unsigned int tagFileFormat;/* --format tag file format (level) */ - bool if0; /* --if0 examine code within "#if 0" branch */ - bool kindLong; /* --kind-long */ +#ifdef HAVE_ICONV + char *inputEncoding; /* --input-encoding convert text into --output-encoding */ + char *outputEncoding; /* --output-encoding write tags file as this encoding */ +#endif + bool if0; /* --if0 examine code within "#if 0" branch */ langType language; /* --lang specified language override */ - bool followLinks; /* --link follow symbolic links? */ - bool filter; /* --filter behave as filter: files in, tags out */ + bool followLinks; /* --link follow symbolic links? */ + bool filter; /* --filter behave as filter: files in, tags out */ char* filterTerminator; /* --filter-terminator string to output */ - bool qualifiedTags; /* --qualified-tags include class-qualified tag */ - bool tagRelative; /* --tag-relative file paths relative to tag file */ - bool printTotals; /* --totals print cumulative statistics */ - bool lineDirectives; /* --linedirectives process #line directives */ - bool nestFunction; /* --nest Nest inside function blocks for tags */ - bool machinable; /* --machinable */ - bool withListHeader; /* --with-list-header */ + bool tagRelative; /* --tag-relative file paths relative to tag file */ + bool printTotals; /* --totals print cumulative statistics */ + bool lineDirectives; /* --linedirectives process #line directives */ + bool printLanguage; /* --print-language */ + bool guessLanguageEagerly; /* --guess-language-eagerly|-G */ + bool quiet; /* --quiet */ + bool allowXcmdInHomeDir; /* --_allow-xcmd-in-homedir */ + bool fatalWarnings; /* --_fatal-warnings */ + unsigned int patternLengthLimit; /* --pattern-length-limit=N */ + bool putFieldPrefix; /* --put-field-prefix */ + unsigned int maxRecursionDepth; /* --maxdepth=<max-recursion-depth> */ + bool machinable; /* --machinable */ + bool withListHeader; /* --with-list-header */ +#ifdef DEBUG + long debugLevel; /* -D debugging output */ + unsigned long breakLine;/* -b input line at which to call lineBreak() */ +#endif } optionValues;
+typedef enum eOptionLoadingStage { + OptionLoadingStageNone, + OptionLoadingStageCustom, + OptionLoadingStageDosCnf, + OptionLoadingStageEtc, + OptionLoadingStageLocalEtc, + OptionLoadingStageHomeRecursive, + OptionLoadingStageCurrentRecursive, + OptionLoadingStagePreload, + OptionLoadingStageEnvVar, + OptionLoadingStageCmdline, +} OptionLoadingStage; + /* * GLOBAL VARIABLES */ @@ -98,10 +133,62 @@ extern CONST_OPTION optionValues Option; /* * FUNCTION PROTOTYPES */ +extern void notice (const char *const format, ...) CTAGS_ATTR_PRINTF (1, 2); extern void verbose (const char *const format, ...) CTAGS_ATTR_PRINTF (1, 2); +#define BEGIN_VERBOSE(VFP) do { if (Option.verbose) { \ + FILE* VFP = stderr +#define END_VERBOSE() } } while (0) + extern void freeList (stringList** const pString); extern void setDefaultTagFileName (void); +extern void checkOptions (void); +extern bool filesRequired (void); +extern void testEtagsInvocation (void); + +extern cookedArgs* cArgNewFromString (const char* string); +extern cookedArgs* cArgNewFromArgv (char* const* const argv); +extern cookedArgs* cArgNewFromFile (FILE* const fp); +extern cookedArgs* cArgNewFromLineFile (FILE* const fp); +extern void cArgDelete (cookedArgs* const current); +extern bool cArgOff (cookedArgs* const current); +extern bool cArgIsOption (cookedArgs* const current); +extern const char* cArgItem (cookedArgs* const current); +extern void cArgForth (cookedArgs* const current);
+extern bool isExcludedFile (const char* const name); extern bool isIncludeFile (const char *const fileName); +/* +extern const ignoredTokenInfo * isIgnoreToken (const char *const name); +*/ +extern void parseCmdlineOptions (cookedArgs* const cargs); +extern void previewFirstOption (cookedArgs* const cargs); +extern void readOptionConfiguration (void); +extern void initOptions (void); +extern void freeOptionResources (void); +#ifdef HAVE_ICONV +extern void freeEncodingResources (void); +#endif + +/* Return vString must be freed by caller side. */ +extern vString* expandOnCorpusPathList (const char* leaf); +extern vString* expandOnDriversPathList (const char* leaf); + + +extern langType getLanguageComponentInOption (const char *const option, + const char *const prefix); + +extern void processLanguageDefineOption (const char *const option, const char *const parameter); +extern bool processMapOption (const char *const option, const char *const parameter); +extern bool processKindOption (const char *const option, const char *const parameter); +extern bool processCorpusOption (const char *const option, const char *const parameter); +extern bool processAliasOption (const char *const option, const char *const parameter); +#ifdef HAVE_ICONV +extern bool processLanguageEncodingOption (const char *const option, const char *const parameter); +#endif +extern bool processRegexOption (const char *const option, const char *const parameter); +extern bool processXcmdOption (const char *const option, const char *const parameter, OptionLoadingStage stage); + +typedef void (* mainLoopFunc) (cookedArgs *args, void *data); +extern void setMainLoop (mainLoopFunc func, void *data);
#endif /* CTAGS_MAIN_OPTIONS_H */
Modified: ctags/main/output-ctags.c 227 lines changed, 227 insertions(+), 0 deletions(-) =================================================================== @@ -0,0 +1,227 @@ +/* +* Copyright (c) 1998-2002, Darren Hiebert +* +* This source code is released for free distribution under the terms of the +* GNU General Public License version 2 or (at your option) any later version. +* +* External interface to entry.c +*/ + +#include "general.h" /* must always come first */ + +#include "entry.h" +#include "mio.h" +#include "options.h" +#include "output.h" +#include "read.h" +#include "ptag.h" + + +static int writeCtagsEntry (MIO * mio, const tagEntryInfo *const tag, void *data CTAGS_ATTR_UNUSED); +static int writeCtagsPtagEntry (MIO * mio, const ptagDesc *desc, + const char *const fileName, + const char *const pattern, + const char *const parserName, void *data CTAGS_ATTR_UNUSED); + +tagWriter ctagsWriter = { + .writeEntry = writeCtagsEntry, + .writePtagEntry = writeCtagsPtagEntry, + .preWriteEntry = NULL, + .postWriteEntry = NULL, + .useStdoutByDefault = false, +}; + +static const char* escapeFieldValue (const tagEntryInfo * tag, fieldType ftype) +{ + return renderFieldEscaped (ftype, tag, NO_PARSER_FIELD); +} + +static int renderExtensionFieldMaybe (int xftype, const tagEntryInfo *const tag, char sep[2], MIO *mio) +{ + if (isFieldEnabled (xftype) && doesFieldHaveValue (xftype, tag)) + { + int len; + len = mio_printf (mio, "%s\t%s:%s", sep, + getFieldName (xftype), + escapeFieldValue (tag, xftype)); + sep[0] = '\0'; + return len; + } + else + return 0; +} + +static int addParserFields (MIO * mio, const tagEntryInfo *const tag) +{ + unsigned int i; + unsigned int ftype; + int length = 0; +/* + for (i = 0; i < tag->usedParserFields; i++) + { + ftype = tag->parserFields [i].ftype; + if (! isFieldEnabled (ftype)) + continue; + + length += mio_printf(mio, "\t%s:%s", + getFieldName (ftype), + renderFieldEscaped (tag->parserFields [i].ftype, tag, i)); + } +*/ + return length; +} + +static int writeLineNumberEntry (MIO * mio, const tagEntryInfo *const tag) +{ + if (Option.lineDirectives) + return mio_printf (mio, "%s", escapeFieldValue (tag, FIELD_LINE_NUMBER)); + else + return mio_printf (mio, "%lu", tag->lineNumber); +} + +static int file_putc (char c, void *data) +{ + MIO *fp = data; + mio_putc (fp, c); + return 1; +} + +static int file_puts (const char* s, void *data) +{ + MIO *fp = data; + return mio_puts (fp, s); +} + +static int addExtensionFields (MIO *mio, const tagEntryInfo *const tag) +{ + bool isKindKeyEnabled = isFieldEnabled (FIELD_KIND_KEY); + bool isScopeEnabled = isFieldEnabled (FIELD_SCOPE_KEY); + + const char* const kindKey = isKindKeyEnabled + ?getFieldName (FIELD_KIND_KEY) + :""; + const char* const kindFmt = isKindKeyEnabled + ?"%s\t%s:%s" + :"%s\t%s%s"; + const char* const scopeKey = isScopeEnabled + ?getFieldName (FIELD_SCOPE_KEY) + :""; + const char* const scopeFmt = isScopeEnabled + ?"%s\t%s:%s:%s" + :"%s\t%s%s:%s"; + + char sep [] = {';', '"', '\0'}; + int length = 0; + + if (tag->kind->name != NULL && (isFieldEnabled (FIELD_KIND_LONG) || + (isFieldEnabled (FIELD_KIND) && tag->kind == '\0'))) + { + length += mio_printf (mio, kindFmt, sep, kindKey, tag->kind->name); + sep [0] = '\0'; + } + else if (tag->kind != '\0' && (isFieldEnabled (FIELD_KIND) || + (isFieldEnabled (FIELD_KIND_LONG) && tag->kind->name == NULL))) + { + char str[2] = {tag->kind->letter, '\0'}; + length += mio_printf (mio, kindFmt, sep, kindKey, str); + sep [0] = '\0'; + } + + if (isFieldEnabled (FIELD_LINE_NUMBER) && doesFieldHaveValue (FIELD_LINE_NUMBER, tag)) + { + length += mio_printf (mio, "%s\t%s:%ld", sep, + getFieldName (FIELD_LINE_NUMBER), + tag->lineNumber); + sep [0] = '\0'; + } + + length += renderExtensionFieldMaybe (FIELD_LANGUAGE, tag, sep, mio); + + if (isFieldEnabled (FIELD_SCOPE)) + { + const char* k = NULL, *v = NULL; + + k = escapeFieldValue (tag, FIELD_SCOPE_KIND_LONG); + v = escapeFieldValue (tag, FIELD_SCOPE); + if (k && v) + { + length += mio_printf (mio, scopeFmt, sep, scopeKey, k, v); + sep [0] = '\0'; + } + } + + if (isFieldEnabled (FIELD_TYPE_REF) && doesFieldHaveValue (FIELD_TYPE_REF, tag)) + { +/* + length += mio_printf (mio, "%s\t%s:%s:%s", sep, + getFieldName (FIELD_TYPE_REF), + tag->extensionFields.typeRef [0], + escapeFieldValue (tag, FIELD_TYPE_REF)); +*/ + sep [0] = '\0'; + } + + if (isFieldEnabled (FIELD_FILE_SCOPE) && doesFieldHaveValue (FIELD_FILE_SCOPE, tag)) + { + length += mio_printf (mio, "%s\t%s:", sep, + getFieldName (FIELD_FILE_SCOPE)); + sep [0] = '\0'; + } + + length += renderExtensionFieldMaybe (FIELD_INHERITANCE, tag, sep, mio); + length += renderExtensionFieldMaybe (FIELD_ACCESS, tag, sep, mio); + length += renderExtensionFieldMaybe (FIELD_IMPLEMENTATION, tag, sep, mio); + length += renderExtensionFieldMaybe (FIELD_SIGNATURE, tag, sep, mio); + length += renderExtensionFieldMaybe (FIELD_ROLE, tag, sep, mio); + length += renderExtensionFieldMaybe (FIELD_EXTRA, tag, sep, mio); + length += renderExtensionFieldMaybe (FIELD_XPATH, tag, sep, mio); + length += renderExtensionFieldMaybe (FIELD_END, tag, sep, mio); + + return length; +} + +static int writePatternEntry (MIO *mio, const tagEntryInfo *const tag) +{ + return makePatternStringCommon (tag, file_putc, file_puts, mio); +} + +static int writeCtagsEntry (MIO * mio, const tagEntryInfo *const tag, void *data CTAGS_ATTR_UNUSED) +{ + int length = mio_printf (mio, "%s\t%s\t", + escapeFieldValue (tag, FIELD_NAME), + escapeFieldValue (tag, FIELD_INPUT_FILE)); +/* + if (tag->lineNumberEntry) + length += writeLineNumberEntry (mio, tag); + else if (tag->pattern) + length += mio_printf(mio, "%s", tag->pattern); + else + length += writePatternEntry (mio, tag); + + if (includeExtensionFlags ()) + { + length += addExtensionFields (mio, tag); + length += addParserFields (mio, tag); + } +*/ + length += mio_printf (mio, "\n"); + + return length; +} + +static int writeCtagsPtagEntry (MIO * mio, const ptagDesc *desc, + const char *const fileName, + const char *const pattern, + const char *const parserName, void *data CTAGS_ATTR_UNUSED) +{ + return parserName + +#define OPT(X) ((X)?(X):"") + ? mio_printf (mio, "%s%s%s%s\t%s\t%s\n", + PSEUDO_TAG_PREFIX, desc->name, PSEUDO_TAG_SEPARATOR, parserName, + OPT(fileName), OPT(pattern)) + : mio_printf (mio, "%s%s\t%s\t/%s/\n", + PSEUDO_TAG_PREFIX, desc->name, + OPT(fileName), OPT(pattern)); +#undef OPT @@ Diff output truncated at 100000 characters. @@
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).