[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