[geany/geany] 2a9f47: Sync options.c/h (and introduce a lot of new garbage)
Jiří Techet
git-noreply at xxxxx
Mon Dec 17 21:05:43 UTC 2018
Branch: refs/heads/master
Author: Jiří Techet <techet at gmail.com>
Committer: Jiří Techet <techet at gmail.com>
Date: Sat, 08 Oct 2016 13:48:42 UTC
Commit: 2a9f473d782431c433c390dd002f9f3302b12d34
https://github.com/geany/geany/commit/2a9f473d782431c433c390dd002f9f3302b12d34
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 at 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 at 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 at 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 at 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).
More information about the Commits
mailing list