[geany/geany] 92382d: Update to latest ctags main

Jiří Techet git-noreply at xxxxx
Sun Feb 7 21:32:14 UTC 2021


Branch:      refs/heads/master
Author:      Jiří Techet <techet at gmail.com>
Committer:   Jiří Techet <techet at gmail.com>
Date:        Wed, 18 Nov 2020 21:22:41 UTC
Commit:      92382dcdbcccb7f531569dc291c33e275a2a9e44
             https://github.com/geany/geany/commit/92382dcdbcccb7f531569dc291c33e275a2a9e44

Log Message:
-----------
Update to latest ctags main

See commit 2aa034a30dc54f5db18db2c9140821f64426283e upstream.


Modified Paths:
--------------
    configure.ac
    ctags/Makefile.am
    ctags/main/args.c
    ctags/main/args_p.h
    ctags/main/cmd.c
    ctags/main/colprint.c
    ctags/main/colprint_p.h
    ctags/main/ctags-api.c
    ctags/main/ctags-api.h
    ctags/main/ctags.h
    ctags/main/debug.c
    ctags/main/debug.h
    ctags/main/dependency.c
    ctags/main/dependency.h
    ctags/main/dependency_p.h
    ctags/main/e_msoft.h
    ctags/main/entry.c
    ctags/main/entry.h
    ctags/main/entry_p.h
    ctags/main/entry_private.c
    ctags/main/error.c
    ctags/main/error_p.h
    ctags/main/field.c
    ctags/main/field.h
    ctags/main/field_p.h
    ctags/main/flags.c
    ctags/main/flags_p.h
    ctags/main/fmt.c
    ctags/main/fmt_p.h
    ctags/main/gcc-attr.h
    ctags/main/general.h
    ctags/main/gvars.h
    ctags/main/htable.c
    ctags/main/htable.h
    ctags/main/interactive_p.h
    ctags/main/keyword.c
    ctags/main/keyword.h
    ctags/main/keyword_p.h
    ctags/main/kind.c
    ctags/main/kind.h
    ctags/main/kind_p.h
    ctags/main/lcpp.c
    ctags/main/lcpp.h
    ctags/main/lregex.c
    ctags/main/lregex.h
    ctags/main/lregex_p.h
    ctags/main/lxcmd.c
    ctags/main/lxpath.c
    ctags/main/lxpath.h
    ctags/main/lxpath_p.h
    ctags/main/main.c
    ctags/main/main.h
    ctags/main/main_p.h
    ctags/main/mbcs.c
    ctags/main/mbcs.h
    ctags/main/mbcs_p.h
    ctags/main/mini-geany.c
    ctags/main/mio.c
    ctags/main/mio.h
    ctags/main/nestlevel.c
    ctags/main/nestlevel.h
    ctags/main/numarray.c
    ctags/main/numarray.h
    ctags/main/objpool.c
    ctags/main/options.c
    ctags/main/options.h
    ctags/main/options_p.h
    ctags/main/output-ctags.c
    ctags/main/output.h
    ctags/main/param.c
    ctags/main/param.h
    ctags/main/param_p.h
    ctags/main/parse.c
    ctags/main/parse.h
    ctags/main/parse_p.h
    ctags/main/parsers.h
    ctags/main/parsers_p.h
    ctags/main/pcoproc.c
    ctags/main/pcoproc.h
    ctags/main/portable-dirent_p.h
    ctags/main/portable-scandir.c
    ctags/main/promise.c
    ctags/main/promise.h
    ctags/main/promise_p.h
    ctags/main/ptag.c
    ctags/main/ptag_p.h
    ctags/main/ptrarray.c
    ctags/main/ptrarray.h
    ctags/main/rbtree.c
    ctags/main/rbtree.h
    ctags/main/read.c
    ctags/main/read.h
    ctags/main/read_p.h
    ctags/main/repoinfo.h
    ctags/main/routines.c
    ctags/main/routines.h
    ctags/main/routines_p.h
    ctags/main/seccomp.c
    ctags/main/selectors.c
    ctags/main/selectors.h
    ctags/main/sort.c
    ctags/main/sort_p.h
    ctags/main/stats.c
    ctags/main/stats_p.h
    ctags/main/strlist.c
    ctags/main/strlist.h
    ctags/main/subparser.h
    ctags/main/subparser_p.h
    ctags/main/tokeninfo.c
    ctags/main/tokeninfo.h
    ctags/main/trace.c
    ctags/main/trace.h
    ctags/main/trashbox.h
    ctags/main/trashbox_p.h
    ctags/main/types.h
    ctags/main/unwindi.c
    ctags/main/unwindi.h
    ctags/main/vstring.c
    ctags/main/vstring.h
    ctags/main/writer-ctags.c
    ctags/main/writer-etags.c
    ctags/main/writer-json.c
    ctags/main/writer-xref.c
    ctags/main/writer.c
    ctags/main/writer_p.h
    ctags/main/xtag.c
    ctags/main/xtag.h
    ctags/main/xtag_p.h

Modified: configure.ac
3 lines changed, 1 insertions(+), 2 deletions(-)
===================================================================
@@ -43,8 +43,7 @@ AC_CHECK_HEADERS([fcntl.h glob.h stdlib.h sys/time.h errno.h limits.h])
 
 # Checks for dependencies needed by ctags
 AC_CHECK_HEADERS([fnmatch.h direct.h io.h sys/dir.h])
-AC_DEFINE([USE_STDBOOL_H], [1], [whether or not to use <stdbool.h>.])
-AC_DEFINE([CTAGS_LIB], [1], [compile ctags as a library.])
+AC_DEFINE([HAVE_STDBOOL_H], [1], [whether or not to use <stdbool.h>.])
 
 # Checks for typedefs, structures, and compiler characteristics.
 AC_TYPE_OFF_T


Modified: ctags/Makefile.am
81 lines changed, 61 insertions(+), 20 deletions(-)
===================================================================
@@ -1,6 +1,7 @@
 AM_CPPFLAGS = \
 	-I$(srcdir)/main \
 	-I$(srcdir)/parsers \
+	-DEXTERNAL_PARSER_LIST_FILE=\"$(top_srcdir)/src/tagmanager/tm_parsers.h\" \
 	-DG_LOG_DOMAIN=\"CTags\"
 AM_CFLAGS = \
 	$(GTK_CFLAGS) \
@@ -30,6 +31,8 @@ parsers = \
 	parsers/html.c \
 	parsers/jscript.c \
 	parsers/json.c \
+	parsers/lcpp.c \
+	parsers/lcpp.h \
 	parsers/lua.c \
 	parsers/make.c \
 	parsers/markdown.c \
@@ -53,44 +56,56 @@ parsers = \
 	parsers/verilog.c \
 	parsers/vhdl.c
 
+# skip cmd.c and mini-geany.c which define main()
 libctags_la_SOURCES = \
 	main/args.c \
-	main/args.h \
+	main/args_p.h \
+	main/colprint.c \
+	main/colprint_p.h \
 	main/ctags.h \
-	main/ctags-api.c \
-	main/ctags-api.h \
-	main/debug.h \
 	main/debug.c \
-	main/dependency.h \
+	main/debug.h \
 	main/dependency.c \
+	main/dependency.h \
+	main/dependency_p.h \
 	main/e_msoft.h \
 	main/entry.c \
 	main/entry.h \
+	main/entry_p.h \
+	main/entry_private.c \
 	main/error.c \
-	main/error.h \
+	main/error_p.h \
 	main/field.c \
 	main/field.h \
+	main/field_p.h \
 	main/flags.c \
-	main/flags.h \
+	main/flags_p.h \
 	main/fmt.c \
-	main/fmt.h \
+	main/fmt_p.h \
 	main/gcc-attr.h \
 	main/general.h \
+	main/gvars.h \
 	main/htable.c \
 	main/htable.h \
 	main/inline.h \
+	main/interactive_p.h \
 	main/keyword.c \
 	main/keyword.h \
+	main/keyword_p.h \
 	main/kind.c \
 	main/kind.h \
-	main/lcpp.c \
-	main/lcpp.h \
+	main/kind_p.h \
 	main/lregex.c \
-	main/lxcmd.c \
+	main/lregex.h \
+	main/lregex_p.h \
 	main/lxpath.c \
+	main/lxpath.h \
+	main/lxpath_p.h \
 	main/main.c \
-	main/main.h \
+	main/main_p.h \
+	main/mbcs.c \
 	main/mbcs.h \
+	main/mbcs_p.h \
 	main/mio.c \
 	main/mio.h \
 	main/nestlevel.c \
@@ -101,37 +116,63 @@ libctags_la_SOURCES = \
 	main/objpool.h \
 	main/options.c \
 	main/options.h \
-	main/output-ctags.c \
-	main/output.h \
+	main/options_p.h \
+	main/param.c \
+	main/param.h \
+	main/param_p.h \
 	main/parse.c \
 	main/parse.h \
-	main/parsers.h \
-	main/pcoproc.c \
-	main/pcoproc.h \
+	main/parse_p.h \
+	main/parsers_p.h \
+	main/portable-dirent_p.h \
+	main/portable-scandir.c \
 	main/promise.c \
 	main/promise.h \
+	main/promise_p.h \
 	main/ptag.c \
-	main/ptag.h \
+	main/ptag_p.h \
 	main/ptrarray.c \
 	main/ptrarray.h \
+	main/rbtree.c \
+	main/rbtree.h \
 	main/read.c \
 	main/read.h \
+	main/read_p.h \
 	main/repoinfo.c \
 	main/repoinfo.h \
 	main/routines.c \
 	main/routines.h \
+	main/routines_p.h \
+	main/seccomp.c \
 	main/selectors.c \
 	main/selectors.h \
 	main/sort.c \
-	main/sort.h \
+	main/sort_p.h \
+	main/stats.c \
+	main/stats_p.h \
 	main/strlist.c \
 	main/strlist.h \
+	main/subparser.h \
+	main/subparser_p.h \
+	main/tokeninfo.c \
+	main/tokeninfo.h \
+	main/trace.c \
 	main/trace.h \
 	main/trashbox.c \
 	main/trashbox.h \
+	main/trashbox_p.h \
 	main/types.h \
+	main/unwindi.c \
+	main/unwindi.h \
 	main/vstring.c \
 	main/vstring.h \
-	main/xtag.h \
+	main/writer-ctags.c \
+	main/writer-etags.c \
+	main/writer-json.c \
+	main/writer-xref.c \
+	main/writer.c \
+	main/writer_p.h \
 	main/xtag.c \
+	main/xtag.h \
+	main/xtag_p.h \
 	$(parsers)


Modified: ctags/main/args.c
6 lines changed, 4 insertions(+), 2 deletions(-)
===================================================================
@@ -16,9 +16,10 @@
 #include <string.h>
 #include <ctype.h>
 
-#include "args.h"
+#include "args_p.h"
 #include "debug.h"
 #include "routines.h"
+#include "vstring.h"
 
 /*
 *   FUNCTION DEFINITIONS
@@ -281,7 +282,8 @@ extern void argForth (Arguments* const current)
 extern void argDelete (Arguments* const current)
 {
 	Assert (current != NULL);
-	if (current->type ==  ARG_STRING  &&  current->item != NULL)
+	if ((current->type ==  ARG_STRING
+		 || current->type ==  ARG_FILE) &&  current->item != NULL)
 		eFree (current->item);
 	memset (current, 0, sizeof (Arguments));
 	eFree (current);


Modified: ctags/main/args_p.h
6 lines changed, 3 insertions(+), 3 deletions(-)
===================================================================
@@ -6,8 +6,8 @@
 *
 *   Defines external interface to command line argument reading.
 */
-#ifndef CTAGS_MAIN_ARGS_H
-#define CTAGS_MAIN_ARGS_H
+#ifndef CTAGS_MAIN_ARGS_PRIVATE_H
+#define CTAGS_MAIN_ARGS_PRIVATE_H
 
 /*
 *   INCLUDE FILES
@@ -54,4 +54,4 @@ extern void argSetLineMode (Arguments* const current);
 extern void argForth (Arguments* const current);
 extern void argDelete (Arguments* const current);
 
-#endif  /* CTAGS_MAIN_ARGS_H */
+#endif  /* CTAGS_MAIN_ARGS_PRIVATE_H */


Modified: ctags/main/cmd.c
22 lines changed, 22 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,22 @@
+/*
+*   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.
+*/
+
+/*
+*   INCLUDE FILES
+*/
+#include "general.h"  /* must always come first */
+
+#include "main_p.h"
+
+
+/*
+*   FUNCTION DEFINITIONS
+*/
+int main(int argc, char **argv)
+{
+	return ctags_cli_main (argc, argv);
+}


Modified: ctags/main/colprint.c
295 lines changed, 295 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,295 @@
+/*
+*   Copyright (c) 2017 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.
+*
+*/
+#include "general.h"  /* must always come first */
+
+#include "colprint_p.h"
+#include "ptrarray.h"
+#include "routines.h"
+#include "strlist.h"
+#include "vstring.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+
+enum colprintJustification {
+	COLPRINT_LEFT,				/* L:... */
+	COLPRINT_RIGHT,				/* R:... */
+	COLPRINT_LAST,
+};
+
+struct colprintHeaderColumn {
+	vString *value;
+	enum colprintJustification justification;
+	unsigned int maxWidth;
+	bool needPrefix;
+};
+
+struct colprintTable {
+	ptrArray *header;
+	ptrArray *lines;
+};
+
+static void fillWithWhitespaces (int i, FILE *fp)
+{
+	while (i-- > 0)
+	{
+		fputc(' ', fp);
+	}
+}
+
+static struct colprintHeaderColumn * colprintHeaderColumnNew (const char* spec)
+{
+	int offset = 2;
+	struct colprintHeaderColumn *headerCol = xCalloc (1, struct colprintHeaderColumn);
+
+	if (strstr(spec, "L:") == spec)
+		headerCol->justification = COLPRINT_LEFT;
+	else if (strstr(spec, "R:") == spec)
+		headerCol->justification = COLPRINT_RIGHT;
+	else
+	{
+		headerCol->justification = COLPRINT_LEFT;
+		offset = 0;
+	}
+
+	headerCol->value = vStringNewInit(spec + offset);
+	headerCol->maxWidth = vStringLength(headerCol->value);
+	return headerCol;
+}
+
+static void colprintHeaderColumnDelete (struct colprintHeaderColumn * headerCol)
+{
+	vStringDelete (headerCol->value);
+	eFree (headerCol);
+}
+
+struct colprintTable *colprintTableNew (const char* columnHeader, ... /* NULL TERMINATED */)
+{
+	char *tmp;
+	va_list ap;
+	struct colprintTable *table;
+	struct colprintHeaderColumn *headerCol;
+
+
+	table = xCalloc (1, struct colprintTable);
+	table->header = ptrArrayNew ((ptrArrayDeleteFunc)colprintHeaderColumnDelete);
+	table->lines  = ptrArrayNew ((ptrArrayDeleteFunc)stringListDelete);
+
+	headerCol = colprintHeaderColumnNew(columnHeader);
+	ptrArrayAdd (table->header, headerCol);
+
+	va_start(ap, columnHeader);
+	while (1)
+	{
+		tmp = va_arg(ap, char*);
+		if (tmp)
+		{
+			headerCol = colprintHeaderColumnNew(tmp);
+			ptrArrayAdd (table->header, headerCol);
+		}
+		else
+			break;
+	}
+	va_end(ap);
+
+	struct colprintHeaderColumn *last_col =	ptrArrayLast (table->header);
+	if (last_col)
+		last_col->justification = COLPRINT_LAST;
+
+	return table;
+}
+
+void colprintTableDelete (struct colprintTable *table)
+{
+	ptrArrayDelete(table->header);
+	table->header = NULL;
+
+	ptrArrayDelete(table->lines);
+	table->header = NULL;
+
+	eFree (table);
+}
+
+static void colprintColumnPrintGeneric (vString *column, struct colprintHeaderColumn *spec, bool machinable, FILE *fp)
+{
+	int maxWidth = spec->maxWidth + (spec->needPrefix? 1: 0);
+
+	if ((column == spec->value) && (spec->needPrefix))
+	{
+		fputc('#', fp);
+		maxWidth--;
+	}
+
+	if (machinable)
+	{
+		fputs (vStringValue (column), fp);
+		if (spec->justification != COLPRINT_LAST)
+			fputc ('\t', fp);
+	}
+	else
+	{
+		int padLen = maxWidth - vStringLength (column);
+		if (spec->justification == COLPRINT_LEFT
+			|| spec->justification == COLPRINT_LAST)
+		{
+			fputs (vStringValue (column), fp);
+			if (spec->justification != COLPRINT_LAST)
+			{
+				fillWithWhitespaces (padLen, fp);
+				fputc (' ', fp);
+			}
+		}
+		else
+		{
+			fillWithWhitespaces (padLen, fp);
+			fputs (vStringValue (column), fp);
+			fputc (' ', fp);
+		}
+	}
+}
+
+static void colprintHeaderColumnPrint (struct colprintHeaderColumn *headerCol, bool machinable, FILE* fp)
+{
+	colprintColumnPrintGeneric (headerCol->value, headerCol, machinable, fp);
+}
+
+static void colprintHeaderPrint (ptrArray *header, unsigned int startFrom, bool withHeader, bool machinable, FILE *fp)
+{
+	unsigned int i;
+
+	if (!withHeader)
+		return;
+
+	for (i = startFrom; i < ptrArrayCount(header); i++)
+	{
+		struct colprintHeaderColumn *headerCol = ptrArrayItem (header, i);
+		colprintHeaderColumnPrint (headerCol, machinable, fp);
+	}
+	fputc('\n', fp);
+}
+
+static void colprintLinePrint  (stringList *line, unsigned int startFrom, ptrArray *header, bool machinable, FILE *fp)
+{
+	unsigned int i;
+
+	for (i = startFrom; i < stringListCount (line); i++)
+	{
+		vString *value = stringListItem(line, i);
+		struct colprintHeaderColumn *spec = ptrArrayItem (header, i);
+		colprintColumnPrintGeneric(value, spec, machinable, fp);
+	}
+}
+static void colprintLinesPrint (ptrArray *lines, unsigned int startFrom, ptrArray *header, bool machinable, FILE *fp)
+{
+	unsigned int i;
+
+	for (i = 0; i < ptrArrayCount (lines); i++)
+	{
+		stringList *line = ptrArrayItem (lines, i);
+		colprintLinePrint (line, startFrom, header, machinable, fp);
+		fputc('\n', fp);
+	}
+}
+
+static void colprintUpdateMaxWidths (ptrArray *header, ptrArray *lines, unsigned int startFrom)
+{
+	for (unsigned int c = 0; c < ptrArrayCount(header); c++)
+	{
+		struct colprintHeaderColumn *spec = ptrArrayItem (header, c);
+
+		if (c == startFrom)
+			spec->needPrefix = true;
+		else
+			spec->needPrefix = false;
+	}
+
+	for (unsigned int c = 0; c < ptrArrayCount(header); c++)
+	{
+		struct colprintHeaderColumn *spec = ptrArrayItem (header, c);
+
+		for (unsigned int l = 0; l < ptrArrayCount(lines); l++)
+		{
+			struct colprintLine *line = ptrArrayItem(lines, l);
+			vString *column = ptrArrayItem((ptrArray *)line, c);
+			if (spec->maxWidth < vStringLength(column))
+				spec->maxWidth = vStringLength(column);
+		}
+	}
+}
+
+void colprintTablePrint (struct colprintTable *table, unsigned int startFrom, bool withHeader, bool machinable, FILE *fp)
+{
+	colprintUpdateMaxWidths (table->header, table->lines, startFrom);
+
+	colprintHeaderPrint (table->header, startFrom, withHeader, machinable, fp);
+	colprintLinesPrint (table->lines, startFrom, table->header, machinable, fp);
+}
+
+void colprintTableSort  (struct colprintTable *table, int (* compareFn) (struct colprintLine *, struct colprintLine *))
+{
+	ptrArraySort (table->lines, (int (*) (const void *, const void *))compareFn);
+}
+
+struct colprintLine *colprintTableGetNewLine (struct colprintTable *table)
+{
+	stringList *line = stringListNew ();
+
+	ptrArrayAdd (table->lines, line);
+	return (struct colprintLine *)line;
+}
+
+static void colprintLineAppendColumn (struct colprintLine *line, vString *column)
+{
+	stringList *slist = (stringList *)line;
+	stringListAdd (slist, column);
+}
+
+void colprintLineAppendColumnCString (struct colprintLine *line, const char *column)
+{
+	vString* vcol = vStringNewInit (column? column: "");
+	colprintLineAppendColumn (line, vcol);
+}
+
+void colprintLineAppendColumnVString (struct colprintLine *line, vString* column)
+{
+	colprintLineAppendColumnCString(line, vStringValue (column));
+}
+
+void colprintLineAppendColumnChar (struct colprintLine *line, char column)
+{
+	vString* vcol = vStringNew ();
+	vStringPut (vcol, column);
+	colprintLineAppendColumn (line, vcol);
+}
+
+void colprintLineAppendColumnInt  (struct colprintLine *line, unsigned int column)
+{
+	char buf[12];
+
+	snprintf(buf, 12, "%u", column);
+	colprintLineAppendColumnCString	(line, buf);
+}
+
+void colprintLineAppendColumnBool  (struct colprintLine *line, bool column)
+{
+	colprintLineAppendColumnCString	(line, column? "yes": "no");
+}
+
+const char *colprintLineGetColumn (struct colprintLine *line, unsigned int column)
+{
+	stringList *slist = (stringList *)line;
+	if (column <= stringListCount(slist))
+	{
+		vString *vstr = stringListItem (slist, column);
+		return vStringValue (vstr);
+	}
+	else
+		return NULL;
+}


Modified: ctags/main/colprint_p.h
37 lines changed, 37 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,37 @@
+/*
+*   Copyright (c) 2017 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.
+*
+*/
+#ifndef CTAGS_MAIN_COLPRINT_PRIVATE_H
+#define CTAGS_MAIN_COLPRINT_PRIVATE_H
+
+#include "general.h"
+
+#include "vstring.h"
+#include <stdio.h>
+
+struct colprintTable;
+struct colprintLine;
+
+/* Each column must have a prefix for specifying justification: "L:" or "R:". */
+struct colprintTable *colprintTableNew (const char* columnHeader, ... /* NULL TERMINATED */);
+void colprintTableDelete (struct colprintTable *table);
+void colprintTablePrint (struct colprintTable *table, unsigned int startFrom, bool withHeader, bool machinable, FILE *fp);
+void colprintTableSort  (struct colprintTable *table, int (* compareFn) (struct colprintLine *, struct colprintLine *));
+
+struct colprintLine *colprintTableGetNewLine (struct colprintTable *table);
+
+void colprintLineAppendColumnCString (struct colprintLine *line, const char* column);
+void colprintLineAppendColumnVString (struct colprintLine *line, vString* column);
+void colprintLineAppendColumnChar (struct colprintLine *line, char column);
+void colprintLineAppendColumnInt  (struct colprintLine *line, unsigned int column);
+
+/* Appends "yes" or "no". */
+void colprintLineAppendColumnBool (struct colprintLine *line, bool column);
+
+const char *colprintLineGetColumn (struct colprintLine *line, unsigned int column);
+
+#endif /* CTAGS_MAIN_COLPRINT_PRIVATE_H */


Modified: ctags/main/ctags-api.c
144 lines changed, 0 insertions(+), 144 deletions(-)
===================================================================
@@ -1,144 +0,0 @@
-/*
-*   Copyright (c) 2016, Jiri Techet
-*
-*   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 ctags API when compiled as a library.
-*/
-
-#include "general.h"  /* must always come first */
-
-#ifdef CTAGS_LIB
-
-#include "ctags-api.h"
-#include "types.h"
-#include "routines.h"
-#include "error.h"
-#include "output.h"
-#include "parse.h"
-#include "options.h"
-#include "trashbox.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-
-static bool nofatalErrorPrinter (const errorSelection selection,
-					  const char *const format,
-					  va_list ap, void *data CTAGS_ATTR_UNUSED)
-{
-	fprintf (stderr, "%s: ", (selection & WARNING) ? "Warning: " : "Error");
-	vfprintf (stderr, format, ap);
-	if (selection & PERROR)
-#ifdef HAVE_STRERROR
-		fprintf (stderr, " : %s", strerror (errno));
-#else
-		perror (" ");
-#endif
-	fputs ("\n", stderr);
-
-	return false;
-}
-
-extern void ctagsInit(void)
-{
-	setErrorPrinter (nofatalErrorPrinter, NULL);
-	setTagWriter (&ctagsWriter);
-
-	checkRegex ();
-	initFieldDescs ();
-
-	initializeParsing ();
-	initOptions ();
-
-	initDefaultTrashBox ();
-
-	/* make sure all parsers are initialized */
-	initializeParser (LANG_AUTO);
-}
-
-
-
-extern void ctagsParse(unsigned char *buffer, size_t bufferSize,
-	const char *fileName, const langType language,
-	tagEntryFunction tagCallback, passStartCallback passCallback,
-	void *userData)
-{
-	if (buffer == NULL && fileName == NULL)
-	{
-		error(FATAL, "Neither buffer nor file provided to ctagsParse()");
-		return;
-	}
-
-	createTagsWithFallback(buffer, bufferSize, fileName, language,
-		tagCallback, passCallback, userData);
-}
-
-
-extern const char *ctagsGetLangName(int lang)
-{
-	return getLanguageName(lang);
-}
-
-
-extern int ctagsGetNamedLang(const char *name)
-{
-	return getNamedLanguage(name, 0);
-}
-
-
-extern const char *ctagsGetLangKinds(int lang)
-{
-	const parserDefinition *def = getParserDefinition(lang);
-	unsigned int i;
-	static char kinds[257];
-
-	for (i = 0; i < def->kindCount; i++)
-		kinds[i] = def->kindTable[i].letter;
-	kinds[i] = '\0';
-
-	return kinds;
-}
-
-
-extern const char *ctagsGetKindName(char kind, int lang)
-{
-	const parserDefinition *def = getParserDefinition(lang);
-	unsigned int i;
-
-	for (i = 0; i < def->kindCount; i++)
-	{
-		if (def->kindTable[i].letter == kind)
-			return def->kindTable[i].name;
-	}
-	return "unknown";
-}
-
-
-extern char ctagsGetKindFromName(const char *name, int lang)
-{
-	const parserDefinition *def = getParserDefinition(lang);
-	unsigned int i;
-
-	for (i = 0; i < def->kindCount; i++)
-	{
-		if (strcmp(def->kindTable[i].name, name) == 0)
-			return def->kindTable[i].letter;
-	}
-	return '-';
-}
-
-
-extern bool ctagsIsUsingRegexParser(int lang)
-{
-	return getParserDefinition(lang)->method & METHOD_REGEX;
-}
-
-
-extern unsigned int ctagsGetLangCount(void)
-{
-	return countParsers();
-}
-
-#endif /* CTAGS_LIB */


Modified: ctags/main/ctags-api.h
57 lines changed, 0 insertions(+), 57 deletions(-)
===================================================================
@@ -1,57 +0,0 @@
-/*
-*   Copyright (c) 2016, Jiri Techet
-*
-*   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 ctags API when compiled as a library.
-*/
-#ifndef CTAGS_API_H
-#define CTAGS_API_H
-
-#include "general.h"  /* must always come first */
-
-#ifdef CTAGS_LIB
-
-#include <stdlib.h>
-#include <stdbool.h>
-
-typedef struct {
-	const char *name;
-	const char *signature;
-	const char *scopeName;
-	const char *inheritance;
-	const char *varType;
-	const char *access;
-	const char *implementation;
-	char kindLetter;
-	bool isFileScope;
-	unsigned long lineNumber;
-	int lang;
-} ctagsTag;
-
-/* Callback invoked for every tag found by the parser. The return value is
- * currently unused. */
-typedef bool (*tagEntryFunction) (const ctagsTag *const tag, void *userData);
-
-/* Callback invoked at the beginning of every parsing pass. The return value is
- * currently unused */
-typedef bool (*passStartCallback) (void *userData);
-
-
-extern void ctagsInit(void);
-extern void ctagsParse(unsigned char *buffer, size_t bufferSize,
-	const char *fileName, const int language,
-	tagEntryFunction tagCallback, passStartCallback passCallback,
-	void *userData);
-extern const char *ctagsGetLangName(int lang);
-extern int ctagsGetNamedLang(const char *name);
-extern const char *ctagsGetLangKinds(int lang);
-extern const char *ctagsGetKindName(char kind, int lang);
-extern char ctagsGetKindFromName(const char *name, int lang);
-extern bool ctagsIsUsingRegexParser(int lang);
-extern unsigned int ctagsGetLangCount(void);
-
-#endif /* CTAGS_LIB */
-
-#endif  /* CTAGS_API_H */


Modified: ctags/main/ctags.h
10 lines changed, 8 insertions(+), 2 deletions(-)
===================================================================
@@ -17,7 +17,7 @@
 #if defined (HAVE_CONFIG_H)
 # define PROGRAM_VERSION PACKAGE_VERSION
 #else
-# define PROGRAM_VERSION "0.0.0"
+# define PROGRAM_VERSION "5.9.0"
 #endif
 #define PROGRAM_NAME      "Universal Ctags"
 #define PROGRAM_URL       "https://ctags.io/"
@@ -30,5 +30,11 @@
 extern const char* ctags_repoinfo;
 #define CTAGS_FIELD_PREFIX "UCTAGS"
 
-
+/*
+ * Reserved words
+ */
+#define RSV_LANGMAP_DEFAULT "default"
+#define RSV_LANG_ALL "all"
+#define RSV_LANG_AUTO "auto"
+#define RSV_NONE "NONE"
 #endif	/* CTAGS_MAIN_CTAGS_H */


Modified: ctags/main/debug.c
103 lines changed, 99 insertions(+), 4 deletions(-)
===================================================================
@@ -16,16 +16,22 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include <string.h>
 
 #include "debug.h"
+#include "entry_p.h"
 #include "options.h"
+#include "parse_p.h"
 #include "read.h"
+#include "read_p.h"
 
 /*
 *   FUNCTION DEFINITIONS
 */
 
 #ifdef DEBUG
+#include "htable.h"
+
 
 extern void lineBreak (void) {}  /* provides a line-specified break point */
 
@@ -74,11 +80,16 @@ extern void debugEntry (const tagEntryInfo *const tag)
 
 	if (debug (DEBUG_PARSE))
 	{
-		printf ("<#%s%s:%s", scope, tag->kind->name, tag->name);
-
-		if (tag->extensionFields.scopeKind != NULL  &&
+		langType lang = (tag->extensionFields.scopeLangType == LANG_AUTO)
+			? tag->langType
+			: tag->extensionFields.scopeLangType;
+		kindDefinition *scopeKindDef = getLanguageKind(lang,
+													   tag->extensionFields.scopeKindIndex);
+		printf ("<#%s%s:%s", scope, getTagKindName(tag), tag->name);
+
+		if (tag->extensionFields.scopeKindIndex != KIND_GHOST_INDEX  &&
 				tag->extensionFields.scopeName != NULL)
-			printf (" [%s:%s]", tag->extensionFields.scopeKind->name,
+			printf (" [%s:%s]", scopeKindDef->name,
 					tag->extensionFields.scopeName);
 
 		if (isFieldEnabled (FIELD_INHERITANCE) &&
@@ -125,4 +136,88 @@ extern void debugAssert (const char *assertion, const char *file, unsigned int l
 	abort();
 }
 
+static int debugScopeDepth;
+#define DEBUG_INDENT_UNIT 4
+
+static char debugPrefix[DEBUG_INDENT_UNIT + 1];
+
+extern void debugInit (void)
+{
+	memset(debugPrefix, ' ', DEBUG_INDENT_UNIT);
+	debugPrefix[DEBUG_INDENT_UNIT] = '\0';
+}
+
+extern void debugIndent(void)
+{
+	for(int i=0;i< debugScopeDepth;i++)
+		fputs(debugPrefix, stderr);
+}
+
+extern void debugInc(void)
+{
+	debugScopeDepth++;
+}
+
+extern void debugDec(void)
+{
+	debugScopeDepth--;
+	if(debugScopeDepth < 0)
+		debugScopeDepth = 0;
+}
+
+
+
+struct circularRefChecker {
+	hashTable *visitTable;
+	int counter;
+};
+
+extern void circularRefCheckerDestroy (struct circularRefChecker * checker)
+{
+	hashTableDelete (checker->visitTable);
+	checker->visitTable = NULL;
+	eFree (checker);
+}
+
+extern struct circularRefChecker * circularRefCheckerNew (void)
+{
+	Assert (sizeof(void *) >= sizeof(int));
+
+	struct circularRefChecker *c = xMalloc (1, struct circularRefChecker);
+
+	c->visitTable = hashTableNew (17, hashPtrhash, hashPtreq, NULL, NULL);
+	c->counter = 0;
+
+	return c;
+}
+
+extern int circularRefCheckerCheck (struct circularRefChecker *c, void *ptr)
+{
+	union conv {
+		int i;
+		void *ptr;
+	} v;
+
+	v.ptr = hashTableGetItem(c->visitTable, ptr);
+	if (v.ptr)
+		return v.i;
+	else
+	{
+		v.i = ++c->counter;
+		hashTablePutItem (c->visitTable, ptr, v.ptr);
+		return 0;
+	}
+}
+
+extern int circularRefCheckerGetCurrent (struct circularRefChecker *c)
+{
+	return c->counter;
+}
+
+extern void circularRefCheckClear (struct circularRefChecker *c)
+{
+	hashTableClear (c->visitTable);
+	c->counter = 0;
+}
+
 #endif


Modified: ctags/main/debug.h
32 lines changed, 26 insertions(+), 6 deletions(-)
===================================================================
@@ -14,27 +14,26 @@
 */
 #include "general.h"  /* must always come first */
 
+#include "gvars.h"
+#include "types.h"
 #ifdef DEBUG
 # include <assert.h>
 #endif
-#include "entry.h"
 
 /*
 *   Macros
 */
 
 #ifdef DEBUG
-# define debug(level)      ((Option.debugLevel & (long)(level)) != 0)
+# define debug(level)      ((ctags_debugLevel & (long)(level)) != 0)
 # define DebugStatement(x) x
 # define PrintStatus(x)    if (debug(DEBUG_STATUS)) printf x;
 # ifdef NDEBUG
 #  define Assert(c) do {} while(0)
 #  define AssertNotReached() do {} while(0)
 # else
-   /* based on glibc's assert.h __ASSERT_FUNCTION */
-#  if defined (__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 4))
-#   define ASSERT_FUNCTION __PRETTY_FUNCTION__
-#  elif defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
+   /* We expect cc supports c99 standard. */
+#  if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
 #   define ASSERT_FUNCTION __func__
 #  else
 #   define ASSERT_FUNCTION ((const char*)0)
@@ -52,6 +51,10 @@
 # endif
 #endif
 
+#ifdef DEBUG
+/* This makes valgrind report an error earlier. */
+#define DISABLE_OBJPOOL
+#endif
 /*
 *   Data declarations
 */
@@ -79,4 +82,21 @@ extern void debugCppIgnore (const bool ignore);
 extern void debugEntry (const tagEntryInfo *const tag);
 extern void debugAssert (const char *assertion, const char *file, unsigned int line, const char *function) attr__noreturn;
 
+#ifdef DEBUG
+#define DEBUG_INIT() debugInit()
+extern void debugInit (void);
+extern void debugIndent(void);
+extern void debugInc(void);
+extern void debugDec(void);
+
+struct circularRefChecker;
+extern struct circularRefChecker * circularRefCheckerNew (void);
+extern void circularRefCheckerDestroy (struct circularRefChecker * checker);
+extern int circularRefCheckerCheck (struct circularRefChecker *c, void *ptr);
+extern int circularRefCheckerGetCurrent (struct circularRefChecker *c);
+extern void circularRefCheckClear (struct circularRefChecker *c);
+
+#else
+#define DEBUG_INIT() do { } while(0)
+#endif	/* DEBUG */
 #endif  /* CTAGS_MAIN_DEBUG_H */


Modified: ctags/main/dependency.c
353 lines changed, 303 insertions(+), 50 deletions(-)
===================================================================
@@ -12,91 +12,344 @@
 
 #include "general.h"  /* must always come first */
 
+#include "debug.h"
 #include "dependency.h"
-#include "parse.h"
+#include "options.h"
+#include "parse_p.h"
+#include "read.h"
+#include "read_p.h"
+#include "routines.h"
+#include "subparser.h"
+#include "subparser_p.h"
+#include "xtag.h"
 
 #include <string.h>
 
+struct slaveControlBlock {
+	slaveParser *slaveParsers;	/* The parsers on this list must be initialized when
+								   this parser is initialized. */
+	subparser   *subparsersDefault;
+	subparser   *subparsersInUse;
+	langType     owner;
+};
 
-static void linkKinds (kindDefinition *masterKind, kindDefinition *slaveKind)
+extern void linkDependencyAtInitializeParsing (depType dtype,
+						   parserDefinition *const master,
+						   struct slaveControlBlock *masterSCB,
+						   struct kindControlBlock *masterKCB,
+						   parserDefinition *const slave,
+						   struct kindControlBlock *slaveKCB,
+						   void *data)
 {
-	kindDefinition *tail;
+	if (dtype == DEPTYPE_KIND_OWNER)
+		linkKindDependency (masterKCB, slaveKCB);
+	else if (dtype == DEPTYPE_SUBPARSER)
+	{
+		slaveParser *s = xMalloc (1, slaveParser);
 
-	slaveKind->master = masterKind;
+		s->type = dtype;
+		s->id = slave->id;
+		s->data = data;
 
-	tail = slaveKind;
-	while (tail->slave)
-	{
-		tail->enabled = masterKind->enabled;
-		tail = tail->slave;
+		s->next = masterSCB->slaveParsers;
+		masterSCB->slaveParsers = s;
 	}
+}
 
-	tail->slave = masterKind->slave;
-	masterKind->slave = slaveKind;
+static void attachSubparser (struct slaveControlBlock *base_sb, subparser *subparser)
+{
+	   subparser->next = base_sb->subparsersDefault;
+	   base_sb->subparsersDefault = subparser;
 }
 
-static void linkKindDependency (parserDefinition *const masterParser,
-				parserDefinition *const slaveParser)
+
+extern struct slaveControlBlock *allocSlaveControlBlock (parserDefinition *parser)
 {
-	unsigned int k_slave, k_master;
-	kindDefinition *kind_slave, *kind_master;
+	struct slaveControlBlock *cb;
 
-	for (k_slave = 0; k_slave < slaveParser->kindCount; k_slave++)
+	cb = xMalloc (1, struct slaveControlBlock);
+	cb->slaveParsers = NULL;
+	cb->subparsersDefault = NULL;
+	cb->subparsersInUse = NULL;
+	cb->owner = parser->id;
+
+	return cb;
+}
+
+extern void freeSlaveControlBlock (struct slaveControlBlock *cb)
+{
+	eFree (cb);
+}
+
+extern void initializeDependencies (parserDefinition *parser,
+									struct slaveControlBlock *cb)
+{
+	unsigned int i;
+	slaveParser *sp;
+
+	/* Initialize slaves */
+	sp = cb->slaveParsers;
+	while (sp != NULL)
 	{
-		if (slaveParser->kindTable [k_slave].syncWith == LANG_AUTO)
+		if (sp->type == DEPTYPE_SUBPARSER)
 		{
-			kind_slave = slaveParser->kindTable + k_slave;
-			for (k_master = 0; k_master < masterParser->kindCount; k_master++)
+			subparser *sub;
+
+			sub = (subparser *)sp->data;
+			sub->slaveParser = sp;
+		}
+
+		if (sp->type == DEPTYPE_KIND_OWNER
+			|| (sp->type == DEPTYPE_SUBPARSER &&
+				(((subparser *)sp->data)->direction & SUBPARSER_BASE_RUNS_SUB)))
+		{
+			initializeParser (sp->id);
+			if (sp->type == DEPTYPE_SUBPARSER
+				&& isXtagEnabled (XTAG_SUBPARSER))
 			{
-				kind_master = masterParser->kindTable + k_master;
-				if ((kind_slave->letter == kind_master->letter)
-				    && (strcmp (kind_slave->name, kind_master->name) == 0))
-				{
-					linkKinds (kind_master, kind_slave);
-					kind_slave->syncWith = masterParser->id;
-					kind_master->syncWith = masterParser->id;
-					break;
-				}
+				subparser *subparser = sp->data;
+				attachSubparser (cb, subparser);
 			}
 		}
+		sp = sp->next;
+	}
+
+	/* Initialize masters that act as base parsers. */
+	for (i = 0; i < parser->dependencyCount; i++)
+	{
+		parserDependency *d = parser->dependencies + i;
+		if (d->type == DEPTYPE_SUBPARSER &&
+			((subparser *)(d->data))->direction & SUBPARSER_SUB_RUNS_BASE)
+		{
+			langType baseParser;
+			baseParser = getNamedLanguage (d->upperParser, 0);
+			Assert (baseParser != LANG_IGNORE);
+			initializeParser (baseParser);
+		}
 	}
 }
 
-extern void linkDependencyAtInitializeParsing (depType dtype,
-					       parserDefinition *const masterParser,
-					       parserDefinition *const slaveParser)
+extern void finalizeDependencies (parserDefinition *parser,
+								  struct slaveControlBlock *cb)
 {
-	if (dtype == DEPTYPE_KIND_OWNER)
-		linkKindDependency (masterParser, slaveParser);
-	else if (dtype == DEPTYPE_SUBPARSER)
+	while (cb->slaveParsers)
 	{
-		subparser *s = xMalloc (1, subparser);
+		slaveParser *sp = cb->slaveParsers;
+		cb->slaveParsers = sp->next;
+		sp->next = NULL;
+		eFree (sp);
+	}
+}
+
+extern void notifyInputStart (void)
+{
+	subparser *s;
 
-		s->id = slaveParser->id;
-		s->next = masterParser->subparsers;
-		masterParser->subparsers = s;
+	foreachSubparser(s, false)
+	{
+		langType lang = getSubparserLanguage (s);
+		notifyLanguageRegexInputStart (lang);
+
+		if (s->inputStart)
+		{
+			enterSubparser(s);
+			s->inputStart (s);
+			leaveSubparser();
+		}
 	}
 }
 
-extern void initializeSubparsers (const parserDefinition *parser)
+extern void notifyInputEnd   (void)
 {
-	subparser *sp;
+	subparser *s;
+
+	foreachSubparser(s, false)
+	{
+		if (s->inputEnd)
+		{
+			enterSubparser(s);
+			s->inputEnd (s);
+			leaveSubparser();
+		}
+
+		langType lang = getSubparserLanguage (s);
+		notifyLanguageRegexInputEnd (lang);
+	}
+}
 
-	for (sp = parser->subparsers; sp; sp = sp->next)
-		initializeParser (sp->id);
+extern void notifyMakeTagEntry (const tagEntryInfo *tag, int corkIndex)
+{
+	subparser *s;
+
+	foreachSubparser(s, false)
+	{
+		if (s->makeTagEntryNotify)
+		{
+			enterSubparser(s);
+			s->makeTagEntryNotify (s, tag, corkIndex);
+			leaveSubparser();
+		}
+	}
+}
+
+extern langType getSubparserLanguage (subparser *s)
+{
+	return s->slaveParser->id;
+}
+
+extern void chooseExclusiveSubparser (subparser *s, void *data)
+{
+	if (s->exclusiveSubparserChosenNotify)
+	{
+		s->chosenAsExclusiveSubparser = true;
+		enterSubparser(s);
+		s->exclusiveSubparserChosenNotify (s, data);
+		verbose ("%s is chosen as exclusive subparser\n",
+				 getLanguageName (getSubparserLanguage (s)));
+		leaveSubparser();
+	}
 }
 
-extern void finalizeSubparsers (parserDefinition *parser)
+extern subparser *getFirstSubparser(struct slaveControlBlock *controlBlock)
+{
+	if (controlBlock)
+		return controlBlock->subparsersInUse;
+	return NULL;
+}
+
+extern void useDefaultSubparsers (struct slaveControlBlock *controlBlock)
+{
+	controlBlock->subparsersInUse = controlBlock->subparsersDefault;
+}
+
+extern void useSpecifiedSubparser (struct slaveControlBlock *controlBlock, subparser *s)
+{
+	s->schedulingBaseparserExplicitly = true;
+	controlBlock->subparsersInUse = s;
+}
+
+extern void setupSubparsersInUse (struct slaveControlBlock *controlBlock)
+{
+	if (!controlBlock->subparsersInUse)
+		useDefaultSubparsers(controlBlock);
+}
+
+extern subparser* teardownSubparsersInUse (struct slaveControlBlock *controlBlock)
 {
-	subparser *sp;
 	subparser *tmp;
+	subparser *s = NULL;
 
-	for (sp = parser->subparsers; sp;)
+	tmp = controlBlock->subparsersInUse;
+	controlBlock->subparsersInUse = NULL;
+
+	if (tmp && tmp->schedulingBaseparserExplicitly)
 	{
-		tmp = sp;
-		sp = sp->next;
-		tmp->next = NULL;
-		eFree (tmp);
+		tmp->schedulingBaseparserExplicitly = false;
+		s = tmp;
 	}
-	parser->subparsers = NULL;
+
+	if (s)
+		return s;
+
+	while (tmp)
+	{
+		if (tmp->chosenAsExclusiveSubparser)
+		{
+			s = tmp;
+		}
+		tmp = tmp->next;
+	}
+
+	return s;
+}
+
+
+static int subparserDepth;
+
+extern void enterSubparser(subparser *subparser)
+{
+	subparserDepth++;
+	pushLanguage (getSubparserLanguage (subparser));
+}
+
+extern void leaveSubparser(void)
+{
+	popLanguage ();
+	subparserDepth--;
+}
+
+extern bool doesSubparserRun (void)
+{
+	if (getLanguageForBaseParser () == getInputLanguage())
+		return false;
+	return subparserDepth;
+}
+
+extern slaveParser *getFirstSlaveParser (struct slaveControlBlock *scb)
+{
+	if (scb)
+		return scb->slaveParsers;
+	return NULL;
+}
+
+extern struct colprintTable * subparserColprintTableNew (void)
+{
+	return colprintTableNew ("L:NAME", "L:BASEPARSER", "L:DIRECTIONS", NULL);
+}
+
+extern void subparserColprintAddSubparsers (struct colprintTable *table,
+											struct slaveControlBlock *scb)
+{
+	slaveParser *tmp;
+
+	pushLanguage (scb->owner);
+	foreachSlaveParser(tmp)
+	{
+		struct colprintLine *line = colprintTableGetNewLine(table);
+
+		colprintLineAppendColumnCString (line, getLanguageName (tmp->id));
+		colprintLineAppendColumnCString (line, getLanguageName (scb->owner));
+
+		const char *direction;
+		switch (((subparser *)tmp->data)->direction)
+		{
+		case SUBPARSER_BASE_RUNS_SUB:
+			direction = "base => sub {shared}";
+			break;
+		case SUBPARSER_SUB_RUNS_BASE:
+			direction = "base <= sub {dedicated}";
+			break;
+		case SUBPARSER_BI_DIRECTION:
+			direction = "base <> sub {bidirectional}";
+			break;
+		default:
+			direction  = "UNKNOWN(INTERNAL BUG)";
+			break;
+		}
+		colprintLineAppendColumnCString (line, direction);
+	}
+	popLanguage ();
+}
+
+static int subparserColprintCompareLines (struct colprintLine *a , struct colprintLine *b)
+{
+	const char *a_name = colprintLineGetColumn (a, 0);
+	const char *b_name = colprintLineGetColumn (b, 0);
+
+	int r;
+	r = strcmp (a_name, b_name);
+	if (r != 0)
+		return r;
+
+	const char *a_baseparser = colprintLineGetColumn (a, 1);
+	const char *b_baseparser = colprintLineGetColumn (b, 1);
+
+	return strcmp(a_baseparser, b_baseparser);
+}
+
+extern void subparserColprintTablePrint (struct colprintTable *table,
+										 bool withListHeader, bool machinable, FILE *fp)
+{
+	colprintTableSort (table, subparserColprintCompareLines);
+	colprintTablePrint (table, 0, withListHeader, machinable, fp);
 }


Modified: ctags/main/dependency.h
26 lines changed, 13 insertions(+), 13 deletions(-)
===================================================================
@@ -12,34 +12,34 @@
 #ifndef CTAGS_MAIN_DEPENDENCY_H
 #define CTAGS_MAIN_DEPENDENCY_H
 
-#include "general.h"
+/*
+*   INCLUDE FILES
+*/
+#include "general.h"  /* must always come first */
 
 #include "types.h"
 
 
+/*
+*   DATA DECLARATIONS
+*/
 typedef enum eDepType {
 	DEPTYPE_KIND_OWNER,
 	DEPTYPE_SUBPARSER,
 	COUNT_DEPTYPES,
 } depType;
 
-typedef struct sParserDependency {
+struct sParserDependency {
 	depType type;
 	const char *upperParser;
 	void *data;
-} parserDependency;
-
-extern void linkDependencyAtInitializeParsing (depType dtype,
-					       parserDefinition *const masterParser,
-					       parserDefinition *const slaveParser);
+};
 
-typedef struct sSubparser subparser;
-struct sSubparser {
+struct sSlaveParser {
+	depType type;
 	langType id;
-	subparser *next;
+	void *data;
+	slaveParser *next;
 };
 
-extern void initializeSubparsers (const parserDefinition *parser);
-extern void finalizeSubparsers (parserDefinition *parser);
-
 #endif	/* CTAGS_MAIN_DEPENDENCY_H */


Modified: ctags/main/dependency_p.h
58 lines changed, 58 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,58 @@
+/*
+ *
+ *  Copyright (c) 2016, Red Hat, Inc.
+ *  Copyright (c) 2016, 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_DEPENDENCY_PRIVATE_H
+#define CTAGS_MAIN_DEPENDENCY_PRIVATE_H
+
+/*
+*   INCLUDE FILES
+*/
+#include "general.h"  /* must always come first */
+
+#include "dependency.h"
+#include "kind.h"
+#include "types.h"
+
+/*
+*   MACROS
+*/
+#define foreachSlaveParser(VAR)			\
+	VAR = NULL;								\
+	while ((VAR = getNextSlaveParser (VAR)) != NULL)
+
+
+/*
+*   DATA DECLARATIONS
+*/
+struct slaveControlBlock;	/* Opaque data type for parse.c */
+
+/*
+*   FUNCTION PROTOTYPES
+*/
+extern void linkDependencyAtInitializeParsing (depType dtype,
+						   parserDefinition *const master,
+						   struct slaveControlBlock *masterSCB,
+						   struct kindControlBlock *masterKCB,
+						   parserDefinition *const slave,
+						   struct kindControlBlock *slaveKCB,
+						   void *data);
+
+extern struct slaveControlBlock *allocSlaveControlBlock (parserDefinition *parser);
+extern void freeSlaveControlBlock (struct slaveControlBlock *cb);
+extern void initializeDependencies (parserDefinition *parser,
+									struct slaveControlBlock *cb);
+extern void finalizeDependencies (parserDefinition *parser,
+								  struct slaveControlBlock *cb);
+
+extern slaveParser *getFirstSlaveParser(struct slaveControlBlock *controlBlock);
+extern slaveParser *getNextSlaveParser(slaveParser *last);
+
+#endif	/* CTAGS_MAIN_DEPENDENCY_PRIVATE_H */


Modified: ctags/main/e_msoft.h
23 lines changed, 10 insertions(+), 13 deletions(-)
===================================================================
@@ -14,34 +14,30 @@
 #define MSDOS_STYLE_PATH 1
 #define HAVE_FCNTL_H 1
 #define HAVE_IO_H 1
-#define HAVE_LIMITS_H 1
-#define HAVE_STDLIB_H 1
 #define HAVE_SYS_STAT_H 1
 #define HAVE_SYS_TYPES_H 1
-#define HAVE_TIME_H 1
-#define HAVE_CLOCK 1
 #define HAVE_CHSIZE 1
-#define HAVE_FGETPOS 1
+#define HAVE_DIRECT_H 1
 #define HAVE_STRICMP 1
 #define HAVE_STRNICMP 1
 #define HAVE_STRSTR 1
 #define HAVE_STRERROR 1
+#define HAVE__FINDFIRST 1
 #define HAVE_FINDNEXT 1
-#define HAVE_TEMPNAM 1
+#define findfirst_t intptr_t
+#define HAVE_MKSTEMP 1
 #define HAVE_FNMATCH 1
 #define HAVE_FNMATCH_H 1
 #define HAVE_PUTENV 1
-#define tempnam(dir,pfx) _tempnam(dir,pfx)
 #define TMPDIR "\\"
 
+int mkstemp (char *template_name);
+
 #ifdef _MSC_VER
 
-# define HAVE__FINDFIRST 1
-# define HAVE_DIRECT_H 1
 # if _MSC_VER < 1900
 #  define snprintf _snprintf
 # endif
-# define findfirst_t intptr_t
 
 #if (_MSC_VER >= 1800) // Visual Studio 2013 or newer
 #define HAVE_STDBOOL_H 1
@@ -58,14 +54,15 @@ typedef enum { false, true } bool;
 
 # include <_mingw.h>
 # define HAVE_STDBOOL_H 1
-# define HAVE_DIR_H 1
 # define HAVE_DIRENT_H 1
-# define HAVE__FINDFIRST 1
-# define findfirst_t long
 # define ffblk _finddata_t
 # define FA_DIREC _A_SUBDIR
 # define ff_name name
 
+# if defined(__USE_MINGW_ANSI_STDIO) && defined(__MINGW64_VERSION_MAJOR)
+#  define HAVE_ASPRINTF 1
+# endif
+
 #endif
 
 #endif


Modified: ctags/main/entry.c
1190 lines changed, 880 insertions(+), 310 deletions(-)
===================================================================
@@ -36,20 +36,30 @@
 # include <io.h>
 #endif
 
+#include <stdint.h>
+#include <limits.h>  /* to define INT_MAX */
+
 #include "debug.h"
-#include "entry.h"
+#include "entry_p.h"
 #include "field.h"
-#include "fmt.h"
+#include "fmt_p.h"
 #include "kind.h"
-#include "main.h"
-#include "options.h"
-#include "output.h"
-#include "ptag.h"
+#include "nestlevel.h"
+#include "options_p.h"
+#include "ptag_p.h"
+#include "rbtree.h"
 #include "read.h"
+#include "read_p.h"
 #include "routines.h"
-#include "sort.h"
+#include "routines_p.h"
+#include "parse_p.h"
+#include "ptrarray.h"
+#include "sort_p.h"
 #include "strlist.h"
-#include "xtag.h"
+#include "subparser_p.h"
+#include "trashbox.h"
+#include "writer_p.h"
+#include "xtag_p.h"
 
 /*
 *   MACROS
@@ -82,43 +92,38 @@ typedef struct eTagFile {
 	struct sMax { size_t line, tag; } max;
 	vString *vLine;
 
-	unsigned int cork;
-	struct sCorkQueue {
-		struct sTagEntryInfo* queue;
-		unsigned int length;
-		unsigned int count;
-	} corkQueue;
+	int cork;
+	unsigned int corkFlags;
+	ptrArray *corkQueue;
 
 	bool patternCacheValid;
 } tagFile;
 
+typedef struct sTagEntryInfoX  {
+	tagEntryInfo slot;
+	int corkIndex;
+	struct rb_root symtab;
+	struct rb_node symnode;
+} tagEntryInfoX;
+
 /*
 *   DATA DEFINITIONS
 */
 
-tagFile TagFile = {
+static tagFile TagFile = {
     NULL,               /* tag file name */
     NULL,               /* tag file directory (absolute) */
     NULL,               /* file pointer */
     { 0, 0 },           /* numTags */
     { 0, 0 },        /* max */
     NULL,                /* vLine */
     .cork = false,
-    .corkQueue = {
-	    .queue = NULL,
-	    .length = 0,
-	    .count  = 0
-    },
+    .corkQueue = NULL,
     .patternCacheValid = false,
 };
 
 static bool TagsToStdout = false;
 
-#ifdef CTAGS_LIB
-static tagEntryFunction TagEntryFunction = NULL;
-static void *TagEntryUserData = NULL;
-#endif
-
 /*
 *   FUNCTION PROTOTYPES
 */
@@ -152,10 +157,8 @@ extern const char *tagFileName (void)
 
 extern void abort_if_ferror(MIO *const mio)
 {
-#ifndef CTAGS_LIB
-	if (mio_error (mio))
+	if (mio != NULL && mio_error (mio))
 		error (FATAL | PERROR, "cannot write tag file");
-#endif
 }
 
 static void rememberMaxLengths (const size_t nameLength, const size_t lineLength)
@@ -169,52 +172,38 @@ static void rememberMaxLengths (const size_t nameLength, const size_t lineLength
 
 static void addCommonPseudoTags (void)
 {
-	int i;
-
-	for (i = 0; i < PTAG_COUNT; i++)
+	for (int i = 0; i < PTAG_COUNT; i++)
 	{
 		if (isPtagCommonInParsers (i))
-			makePtagIfEnabled (i, NULL);
+			makePtagIfEnabled (i, LANG_IGNORE, &Option);
 	}
 }
 
 extern void makeFileTag (const char *const fileName)
 {
-	xtagType     xtag = XTAG_UNKNOWN;
-
-	if (isXtagEnabled(XTAG_FILE_NAMES))
-		xtag = XTAG_FILE_NAMES;
-
-	if (xtag != XTAG_UNKNOWN)
-	{
-		tagEntryInfo tag;
-		kindDefinition  *kind;
-
-		kind = getInputLanguageFileKind();
-		Assert (kind);
-		kind->enabled = isXtagEnabled(XTAG_FILE_NAMES);
-
-		/* TODO: you can return here if enabled == false. */
+	tagEntryInfo tag;
 
-		initTagEntry (&tag, baseFilename (fileName), KIND_FILE_INDEX);
+	if (!isXtagEnabled(XTAG_FILE_NAMES))
+		return;
 
-		tag.isFileEntry     = true;
-		tag.lineNumberEntry = true;
-		markTagExtraBit (&tag, xtag);
+	initTagEntry (&tag, baseFilename (fileName), KIND_FILE_INDEX);
 
-		tag.lineNumber = 1;
-		if (isFieldEnabled (FIELD_END))
-		{
-			/* isFieldEnabled is called again in the rendering
-			   stage. However, it is called here for avoiding
-			   unnecessary read line loop. */
-			while (readLineFromInputFile () != NULL)
-				; /* Do nothing */
-			tag.extensionFields.endLine = getInputLineNumber ();
-		}
+	tag.isFileEntry     = true;
+	tag.lineNumberEntry = true;
+	markTagExtraBit (&tag, XTAG_FILE_NAMES);
 
-		makeTagEntry (&tag);
+	tag.lineNumber = 1;
+	if (isFieldEnabled (FIELD_END_LINE))
+	{
+		/* isFieldEnabled is called again in the rendering
+		   stage. However, it is called here for avoiding
+		   unnecessary read line loop. */
+		while (readLineFromInputFile () != NULL)
+			; /* Do nothing */
+		tag.extensionFields.endLine = getInputLineNumber ();
 	}
+
+	makeTagEntry (&tag);
 }
 
 static void updateSortedFlag (
@@ -382,7 +371,7 @@ static bool isTagFile (const char *const filename)
 			ok = true;
 		else
 			ok = (bool) (isCtagsLine (line) || isEtagsLine (line));
-		mio_free (mio);
+		mio_unref (mio);
 	}
 	return ok;
 }
@@ -399,9 +388,13 @@ extern void openTagFile (void)
 	 */
 	if (TagsToStdout)
 	{
-		/* Open a tempfile with read and write mode. Read mode is used when
-		 * write the result to stdout. */
-		TagFile.mio = tempFile ("w+", &TagFile.name);
+		if (Option.interactive == INTERACTIVE_SANDBOX)
+		{
+			TagFile.mio = mio_new_memory (NULL, 0, eRealloc, eFreeNoNullCheck);
+			TagFile.name = NULL;
+		}
+		else
+			TagFile.mio = tempFile ("w+", &TagFile.name);
 		if (isXtagEnabled (XTAG_PSEUDO_TAGS))
 			addCommonPseudoTags ();
 	}
@@ -431,7 +424,7 @@ extern void openTagFile (void)
 				if (TagFile.mio != NULL)
 				{
 					TagFile.numTags.prev = updatePseudoTags (TagFile.mio);
-					mio_free (TagFile.mio);
+					mio_unref (TagFile.mio);
 					TagFile.mio = mio_new_file (TagFile.name, "a+");
 				}
 			}
@@ -445,10 +438,14 @@ extern void openTagFile (void)
 		if (TagFile.mio == NULL)
 			error (FATAL | PERROR, "cannot open tag file");
 	}
-	if (TagsToStdout)
-		TagFile.directory = eStrdup (CurrentDirectory);
-	else
-		TagFile.directory = absoluteDirname (TagFile.name);
+
+	if (TagFile.directory == NULL)
+	{
+		if (TagsToStdout)
+			TagFile.directory = eStrdup (CurrentDirectory);
+		else
+			TagFile.directory = absoluteDirname (TagFile.name);
+	}
 }
 
 #ifdef USE_REPLACEMENT_TRUNCATE
@@ -485,19 +482,20 @@ static void copyFile (const char *const from, const char *const to, const long s
 		else
 		{
 			copyBytes (fromMio, toMio, size);
-			mio_free (toMio);
+			mio_unref (toMio);
 		}
-		mio_free (fromMio);
+		mio_unref (fromMio);
 	}
 }
 
 /*  Replacement for missing library function.
  */
 static int replacementTruncate (const char *const name, const long size)
 {
+#define WHOLE_FILE  -1L
 	char *tempName = NULL;
 	MIO *mio = tempFile ("w", &tempName);
-	mio_free (mio);
+	mio_unref (mio);
 	copyFile (name, tempName, size);
 	copyFile (tempName, name, WHOLE_FILE);
 	remove (tempName);
@@ -532,7 +530,7 @@ static void internalSortTagFile (void)
 			  TagFile.numTags.added + TagFile.numTags.prev);
 
 	if (! TagsToStdout)
-		mio_free (mio);
+		mio_unref (mio);
 }
 #endif
 
@@ -558,6 +556,12 @@ static void resizeTagFile (const long newSize)
 {
 	int result;
 
+	if (!TagFile.name)
+	{
+		mio_try_resize (TagFile.mio, newSize);
+		return;
+	}
+
 #ifdef USE_REPLACEMENT_TRUNCATE
 	result = replacementTruncate (TagFile.name, newSize);
 #else
@@ -605,30 +609,35 @@ extern void closeTagFile (const bool resize)
 	if (Option.etags)
 		writeEtagsIncludes (TagFile.mio);
 	mio_flush (TagFile.mio);
+
 	abort_if_ferror (TagFile.mio);
 	desiredSize = mio_tell (TagFile.mio);
 	mio_seek (TagFile.mio, 0L, SEEK_END);
 	size = mio_tell (TagFile.mio);
 	if (! TagsToStdout)
 		/* The tag file should be closed before resizing. */
-		if (mio_free (TagFile.mio) != 0)
+		if (mio_unref (TagFile.mio) != 0)
 			error (FATAL | PERROR, "cannot close tag file");
 
 	if (resize  &&  desiredSize < size)
 	{
 		DebugStatement (
 			debugPrintf (DEBUG_STATUS, "shrinking %s from %ld to %ld bytes\n",
-				TagFile.name, size, desiredSize); )
+				TagFile.name? TagFile.name: "<mio>", size, desiredSize); )
 		resizeTagFile (desiredSize);
 	}
 	sortTagFile ();
 	if (TagsToStdout)
 	{
-		if (mio_free (TagFile.mio) != 0)
+		if (mio_unref (TagFile.mio) != 0)
 			error (FATAL | PERROR, "cannot close tag file");
-		remove (tagFileName ());  /* remove temporary file */
+		if (TagFile.name)
+			remove (TagFile.name);  /* remove temporary file */
 	}
-	eFree (TagFile.name);
+
+	TagFile.mio = NULL;
+	if (TagFile.name)
+		eFree (TagFile.name);
 	TagFile.name = NULL;
 }
 
@@ -641,10 +650,13 @@ extern void closeTagFile (const bool resize)
  *  are doubled and a leading '^' or trailing '$' is also quoted. End of line
  *  characters (line feed or carriage return) are dropped.
  */
-static size_t appendInputLine (int putc_func (char , void *), const char *const line, void * data, bool *omitted)
+static size_t appendInputLine (int putc_func (char , void *), const char *const line,
+							   unsigned int patternLengthLimit,
+							   void * data, bool *omitted)
 {
 	size_t length = 0;
 	const char *p;
+	int extraLength = 0;
 
 	/*  Write everything up to, but not including, a line end character.
 	 */
@@ -657,7 +669,11 @@ static size_t appendInputLine (int putc_func (char , void *), const char *const
 		if (c == CRETURN  ||  c == NEWLINE)
 			break;
 
-		if (Option.patternLengthLimit != 0 && length >= Option.patternLengthLimit)
+		if (patternLengthLimit != 0 && length >= patternLengthLimit &&
+			/* Do not cut inside a multi-byte UTF-8 character, but safe-guard it not to
+			 * allow more than one extra valid UTF-8 character in case it's not actually
+			 * UTF-8.  To do that, limit to an extra 3 UTF-8 sub-bytes (0b10xxxxxx). */
+			((((unsigned char) c) & 0xc0) != 0x80 || ++extraLength > 3))
 		{
 			*omitted = true;
 			break;
@@ -687,11 +703,12 @@ static int vstring_putc (char c, void *data)
 static int vstring_puts (const char* s, void *data)
 {
 	vString *str = data;
-	int len = vStringLength (str);
+	size_t len = vStringLength (str);
 	vStringCatS (str, s);
-	return vStringLength (str) - len;
+	return (int) (vStringLength (str) - len);
 }
 
+#ifdef DEBUG
 static bool isPosSet(MIOPos pos)
 {
 	char * p = (char *)&pos;
@@ -702,26 +719,23 @@ static bool isPosSet(MIOPos pos)
 		r |= p[i];
 	return r;
 }
+#endif
 
-extern char *readLineFromBypassAnyway (vString *const vLine, const tagEntryInfo *const tag,
+extern char *readLineFromBypassForTag (vString *const vLine, const tagEntryInfo *const tag,
 				   long *const pSeekValue)
 {
-	char * line;
-
-	if (isPosSet (tag->filePosition) || (tag->pattern == NULL))
-		line = 	readLineFromBypass (vLine, tag->filePosition, pSeekValue);
-	else
-		line = readLineFromBypassSlow (vLine, tag->lineNumber, tag->pattern, pSeekValue);
-
-	return line;
+	Assert (isPosSet (tag->filePosition) || (tag->pattern == NULL));
+	return readLineFromBypass (vLine, tag->filePosition, pSeekValue);
 }
 
 /*  Truncates the text line containing the tag at the character following the
  *  tag, providing a character which designates the end of the tag.
+ *  Returns the length of the truncated line (or 0 if it doesn't truncate).
  */
-extern void truncateTagLine (
+extern size_t truncateTagLineAfterTag (
 		char *const line, const char *const token, const bool discardNewline)
 {
+	size_t len = 0;
 	char *p = strstr (line, token);
 
 	if (p != NULL)
@@ -730,7 +744,10 @@ extern void truncateTagLine (
 		if (*p != '\0'  &&  ! (*p == '\n'  &&  discardNewline))
 			++p;    /* skip past character terminating character */
 		*p = '\0';
+		len = p - line;
 	}
+
+	return len;
 }
 
 static char* getFullQualifiedScopeNameFromCorkQueue (const tagEntryInfo * inner_scope)
@@ -739,6 +756,7 @@ static char* getFullQualifiedScopeNameFromCorkQueue (const tagEntryInfo * inner_
 	int kindIndex = KIND_GHOST_INDEX;
 	langType lang;
 	const tagEntryInfo *scope = inner_scope;
+	const tagEntryInfo *root_scope = NULL;
 	stringList *queue = stringListNew ();
 	vString *v;
 	vString *n;
@@ -760,11 +778,16 @@ static char* getFullQualifiedScopeNameFromCorkQueue (const tagEntryInfo * inner_
 			stringListAdd (queue, v);
 			kindIndex = scope->kindIndex;
 			lang = scope->langType;
+			root_scope = scope;
 		}
 		scope =  getEntryInCorkQueue (scope->extensionFields.scopeIndex);
 	}
 
 	n = vStringNew ();
+	sep = root_scope? scopeSeparatorFor (root_scope->langType, root_scope->kindIndex, KIND_GHOST_INDEX): NULL;
+	if (sep)
+		vStringCatS(n, sep);
+
 	while ((c = stringListCount (queue)) > 0)
 	{
 		v = stringListLast (queue);
@@ -785,16 +808,13 @@ extern void getTagScopeInformation (tagEntryInfo *const tag,
 	if (name)
 		*name = NULL;
 
+	const tagEntryInfo * scope = getEntryInCorkQueue (tag->extensionFields.scopeIndex);
 	if (tag->extensionFields.scopeKindIndex == KIND_GHOST_INDEX
 	    && tag->extensionFields.scopeName == NULL
-	    && tag->extensionFields.scopeIndex != CORK_NIL
-	    && TagFile.corkQueue.count > 0)
+	    && scope
+	    && ptrArrayCount (TagFile.corkQueue) > 0)
 	{
-		const tagEntryInfo * scope = NULL;
-		char *full_qualified_scope_name = NULL;
-
-		scope = getEntryInCorkQueue (tag->extensionFields.scopeIndex);
-		full_qualified_scope_name = getFullQualifiedScopeNameFromCorkQueue(scope);
+		char *full_qualified_scope_name = getFullQualifiedScopeNameFromCorkQueue(scope);
 		Assert (full_qualified_scope_name);
 
 		/* Make the information reusable to generate full qualified entry, and xformat output*/
@@ -821,9 +841,9 @@ extern void getTagScopeInformation (tagEntryInfo *const tag,
 }
 
 
-extern int   makePatternStringCommon (const tagEntryInfo *const tag,
-				      int putc_func (char , void *),
-				      int puts_func (const char* , void *),
+static int   makePatternStringCommon (const tagEntryInfo *const tag,
+				      int (* putc_func) (char , void *),
+				      int (* puts_func) (const char* , void *),
 				      void *output)
 {
 	int length = 0;
@@ -845,20 +865,33 @@ extern int   makePatternStringCommon (const tagEntryInfo *const tag,
 	    && (memcmp (&tag->filePosition, &cached_location, sizeof(MIOPos)) == 0))
 		return puts_func (vStringValue (cached_pattern), output);
 
-	line = readLineFromBypass (TagFile.vLine, tag->filePosition, NULL);
+	line = readLineFromBypassForTag (TagFile.vLine, tag, NULL);
 	if (line == NULL)
-		error (FATAL, "could not read tag line from %s at line %lu", getInputFileName (),tag->lineNumber);
+	{
+		/* This can be occurs if the size of input file is zero, and
+		   an empty regex pattern (//) matches to the input. */
+		line = "";
+		line_len = 0;
+	}
+	else
+		line_len = vStringLength (TagFile.vLine);
+
 	if (tag->truncateLineAfterTag)
-		truncateTagLine (line, tag->name, false);
+	{
+		size_t truncted_len;
+
+		truncted_len = truncateTagLineAfterTag (line, tag->name, false);
+		if (truncted_len > 0)
+			line_len = truncted_len;
+	}
 
-	line_len = strlen (line);
 	searchChar = Option.backward ? '?' : '/';
-	terminator = (bool) (line [line_len - 1] == '\n') ? "$": "";
+	terminator = (line_len > 0 && (line [line_len - 1] == '\n')) ? "$": "";
 
 	if (!tag->truncateLineAfterTag)
 	{
 		making_cache = true;
-		cached_pattern = vStringNewOrClear (cached_pattern);
+		cached_pattern = vStringNewOrClearWithAutoRelease (cached_pattern);
 
 		puts_o_func = puts_func;
 		o_output    = output;
@@ -870,7 +903,8 @@ extern int   makePatternStringCommon (const tagEntryInfo *const tag,
 	length += putc_func(searchChar, output);
 	if ((tag->boundaryInfo & BOUNDARY_START) == 0)
 		length += putc_func('^', output);
-	length += appendInputLine (putc_func, line, output, &omitted);
+	length += appendInputLine (putc_func, line, Option.patternLengthLimit,
+							   output, &omitted);
 	length += puts_func (omitted? "": terminator, output);
 	length += putc_func (searchChar, output);
 
@@ -891,30 +925,97 @@ extern char* makePatternString (const tagEntryInfo *const tag)
 	return vStringDeleteUnwrap (pattern);
 }
 
-extern void attachParserField (tagEntryInfo *const tag, fieldType ftype, const char * value)
+static tagField * tagFieldNew(fieldType ftype, const char *value, bool valueOwner)
 {
-	Assert (tag->usedParserFields < PRE_ALLOCATED_PARSER_FIELDS);
+	tagField *f = xMalloc (1, tagField);
 
-	tag->parserFields [tag->usedParserFields].ftype = ftype;
-	tag->parserFields [tag->usedParserFields].value = value;
-	tag->usedParserFields++;
+	f->ftype = ftype;
+	f->value = value;
+	f->valueOwner = valueOwner;
+	return f;
 }
 
-extern void attachParserFieldToCorkEntry (int index,
-					 fieldType type,
-					 const char *value)
+static void tagFieldDelete (tagField * f)
 {
-	tagEntryInfo * tag;
-	const char * v;
+	if (f->valueOwner)
+		eFree((void *)f->value);
+	eFree (f);
+}
 
-	if (index == CORK_NIL)
-		return;
+static void attachParserFieldGeneric (tagEntryInfo *const tag, fieldType ftype, const char * value,
+									  bool valueOwner)
+{
+	if (tag->usedParserFields < PRE_ALLOCATED_PARSER_FIELDS)
+	{
+		tag->parserFields [tag->usedParserFields].ftype = ftype;
+		tag->parserFields [tag->usedParserFields].value = value;
+		tag->parserFields [tag->usedParserFields].valueOwner = valueOwner;
+		tag->usedParserFields++;
+	}
+	else if (tag->parserFieldsDynamic == NULL)
+	{
+		tag->parserFieldsDynamic = ptrArrayNew((ptrArrayDeleteFunc)tagFieldDelete);
+		PARSER_TRASH_BOX(tag->parserFieldsDynamic, ptrArrayDelete);
+		attachParserFieldGeneric (tag, ftype, value, valueOwner);
+	}
+	else
+	{
+		tagField *f = tagFieldNew (ftype, value, valueOwner);
+		ptrArrayAdd(tag->parserFieldsDynamic, f);
+		tag->usedParserFields++;
+	}
+}
 
-	tag = getEntryInCorkQueue(index);
+extern void attachParserField (tagEntryInfo *const tag, bool inCorkQueue, fieldType ftype, const char * value)
+{
 	Assert (tag != NULL);
 
-	v = eStrdup (value);
-	attachParserField (tag, type, v);
+	if (inCorkQueue)
+	{
+		const char * v;
+		v = eStrdup (value);
+
+		bool dynfields_allocated = tag->parserFieldsDynamic? true: false;
+		attachParserFieldGeneric (tag, ftype, v, true);
+		if (!dynfields_allocated && tag->parserFieldsDynamic)
+			PARSER_TRASH_BOX_TAKE_BACK(tag->parserFieldsDynamic);
+	}
+	else
+		attachParserFieldGeneric (tag, ftype, value, false);
+}
+
+extern void attachParserFieldToCorkEntry (int index,
+					 fieldType ftype,
+					 const char *value)
+{
+	tagEntryInfo * tag = getEntryInCorkQueue (index);
+	if (tag)
+		attachParserField (tag, true, ftype, value);
+}
+
+extern const tagField* getParserFieldForIndex (const tagEntryInfo * tag, int index)
+{
+	if (index < 0
+		|| tag->usedParserFields <= ((unsigned int)index) )
+		return NULL;
+	else if (index < PRE_ALLOCATED_PARSER_FIELDS)
+		return tag->parserFields + index;
+	else
+	{
+		unsigned int n = index - PRE_ALLOCATED_PARSER_FIELDS;
+		return ptrArrayItem(tag->parserFieldsDynamic, n);
+	}
+}
+
+extern const char* getParserFieldValueForType (tagEntryInfo *const tag, fieldType ftype)
+{
+	for (int i = 0; i < tag->usedParserFields; i++)
+	{
+		const tagField *f = getParserFieldForIndex (tag, i);
+		if (f && f->ftype == ftype)
+			return f->value;
+	}
+	return NULL;
 }
 
 static void copyParserFields (const tagEntryInfo *const tag, tagEntryInfo* slot)
@@ -924,24 +1025,42 @@ static void copyParserFields (const tagEntryInfo *const tag, tagEntryInfo* slot)
 
 	for (i = 0; i < tag->usedParserFields; i++)
 	{
-		value = tag->parserFields [i].value;
+		const tagField *f = getParserFieldForIndex (tag, i);
+		Assert(f);
+
+		value = f->value;
 		if (value)
 			value = eStrdup (value);
 
-		attachParserField (slot,
-				   tag->parserFields [i].ftype,
-				   value);
+		attachParserFieldGeneric (slot,
+								  f->ftype,
+								  value,
+								  true);
 	}
+
 }
 
-static void recordTagEntryInQueue (const tagEntryInfo *const tag, tagEntryInfo* slot)
+static tagEntryInfo *newNilTagEntry (unsigned int corkFlags)
 {
+	tagEntryInfoX *x = xCalloc (1, tagEntryInfoX);
+	x->corkIndex = CORK_NIL;
+	x->symtab = RB_ROOT;
+	x->slot.kindIndex = KIND_FILE_INDEX;
+	return &(x->slot);
+}
+
+static tagEntryInfoX *copyTagEntry (const tagEntryInfo *const tag,
+								   unsigned int corkFlags)
+{
+	tagEntryInfoX *x = xMalloc (1, tagEntryInfoX);
+	x->symtab = RB_ROOT;
+	x->corkIndex = CORK_NIL;
+	tagEntryInfo  *slot = (tagEntryInfo *)x;
+
 	*slot = *tag;
 
 	if (slot->pattern)
 		slot->pattern = eStrdup (slot->pattern);
-	else if (!slot->lineNumberEntry)
-		slot->pattern = makePatternString (slot);
 
 	slot->inputFileName = eStrdup (slot->inputFileName);
 	slot->name = eStrdup (slot->name);
@@ -961,39 +1080,63 @@ static void recordTagEntryInQueue (const tagEntryInfo *const tag, tagEntryInfo*
 		slot->extensionFields.typeRef[0] = eStrdup (slot->extensionFields.typeRef[0]);
 	if (slot->extensionFields.typeRef[1])
 		slot->extensionFields.typeRef[1] = eStrdup (slot->extensionFields.typeRef[1]);
-/* GEANY DIFF */
-	if (slot->extensionFields.varType)
-		slot->extensionFields.varType = eStrdup (slot->extensionFields.varType);
-/* GEANY DIFF END */
 #ifdef HAVE_LIBXML
 	if (slot->extensionFields.xpath)
 		slot->extensionFields.xpath = eStrdup (slot->extensionFields.xpath);
 #endif
 
+	if (slot->extraDynamic)
+	{
+		int n = countXtags () - XTAG_COUNT;
+		slot->extraDynamic = xCalloc ((n / 8) + 1, uint8_t);
+		memcpy (slot->extraDynamic, tag->extraDynamic, (n / 8) + 1);
+	}
+
 	if (slot->sourceFileName)
 		slot->sourceFileName = eStrdup (slot->sourceFileName);
 
+
 	slot->usedParserFields = 0;
+	slot->parserFieldsDynamic = NULL;
 	copyParserFields (tag, slot);
+	if (slot->parserFieldsDynamic)
+		PARSER_TRASH_BOX_TAKE_BACK(slot->parserFieldsDynamic);
+
+	return x;
 }
 
 static void clearParserFields (tagEntryInfo *const tag)
 {
-	unsigned int i;
+	unsigned int i, n;
 	const char* value;
 
-	for (i = 0; i < tag->usedParserFields; i++)
+	if ( tag->usedParserFields < PRE_ALLOCATED_PARSER_FIELDS )
+		n = tag->usedParserFields;
+	else
+		n = PRE_ALLOCATED_PARSER_FIELDS;
+
+	for (i = 0; i < n; i++)
 	{
 		value = tag->parserFields[i].value;
-		if (value)
+		if (value && tag->parserFields[i].valueOwner)
 			eFree ((char *)value);
 		tag->parserFields[i].value = NULL;
 		tag->parserFields[i].ftype = FIELD_UNKNOWN;
 	}
+	if (tag->parserFieldsDynamic)
+	{
+		ptrArrayDelete (tag->parserFieldsDynamic);
+		tag->parserFieldsDynamic = NULL;
+	}
 }
 
-static void clearTagEntryInQueue (tagEntryInfo* slot)
+static void deleteTagEnry (void *data)
 {
+	tagEntryInfo *slot = data;
+
+	if (slot->kindIndex == KIND_FILE_INDEX)
+		goto out;
+
 	if (slot->pattern)
 		eFree ((char *)slot->pattern);
 	eFree ((char *)slot->inputFileName);
@@ -1015,139 +1158,409 @@ static void clearTagEntryInQueue (tagEntryInfo* slot)
 		eFree ((char *)slot->extensionFields.typeRef[0]);
 	if (slot->extensionFields.typeRef[1])
 		eFree ((char *)slot->extensionFields.typeRef[1]);
-/* GEANY DIFF */
-	if (slot->extensionFields.varType)
-		eFree ((char *)slot->extensionFields.varType);
-/* GEANY DIFF END */
 #ifdef HAVE_LIBXML
 	if (slot->extensionFields.xpath)
 		eFree ((char *)slot->extensionFields.xpath);
 #endif
 
+	if (slot->extraDynamic)
+		eFree (slot->extraDynamic);
+
 	if (slot->sourceFileName)
 		eFree ((char *)slot->sourceFileName);
 
 	clearParserFields (slot);
+
+ out:
+	eFree (slot);
 }
 
-static unsigned int queueTagEntry(const tagEntryInfo *const tag)
+static void corkSymtabPut (tagEntryInfoX *scope, const char* name, tagEntryInfoX *item)
 {
-	unsigned int i;
-	void *tmp;
-	tagEntryInfo * slot;
+	struct rb_root *root = &scope->symtab;
+
+	struct rb_node **new = &(root->rb_node), *parent = NULL;
 
-	if (! (TagFile.corkQueue.count < TagFile.corkQueue.length))
+	while (*new)
 	{
-		if (!TagFile.corkQueue.length)
-			TagFile.corkQueue.length = 1;
+		tagEntryInfoX *this = container_of(*new, tagEntryInfoX, symnode);
+		int result = strcmp(item->slot.name, this->slot.name);
+
+		parent = *new;
 
-		tmp = eRealloc (TagFile.corkQueue.queue,
-				sizeof (*TagFile.corkQueue.queue) * TagFile.corkQueue.length * 2);
+		if (result < 0)
+			new = &((*new)->rb_left);
+		else if (result > 0)
+			new = &((*new)->rb_right);
+		else
+		{
+			unsigned long lthis = this->slot.lineNumber;
+			unsigned long litem = item->slot.lineNumber;
+
+			/* Comparing lineNumber */
+			if (litem < lthis)
+				new = &((*new)->rb_left);
+			else if (litem > lthis)
+				new = &((*new)->rb_right);
+			else
+			{
+				/* Comparing memory address */
+				if (item < this)
+					new = &((*new)->rb_left);
+				else if (item > this)
+					new = &((*new)->rb_right);
+				else
+				{
+					AssertNotReached(); /* registering the same object twice. */
+					return;
+				}
+			}
+		}
+	}
 
-		TagFile.corkQueue.length *= 2;
-		TagFile.corkQueue.queue = tmp;
+	verbose ("symtbl[:=] %s<-%s/%p (line: %lu)\n",
+			*new? container_of(*new, tagEntryInfoX, symnode)->slot.name: "*root*",
+			 item->slot.name, &item->slot, item->slot.lineNumber);
+	/* Add new node and rebalance tree. */
+	rb_link_node(&item->symnode, parent, new);
+	rb_insert_color(&item->symnode, root);
+}
+
+extern bool foreachEntriesInScope (int corkIndex,
+								   const char *name,
+								   entryForeachFunc func,
+								   void *data)
+{
+	tagEntryInfoX *x = ptrArrayItem (TagFile.corkQueue, corkIndex);
+
+	struct rb_root *root = &x->symtab;
+	tagEntryInfoX *rep = NULL;
+
+	/* More than one tag can have a same name.
+	 * Visit them from the last.
+	 *
+	 * 1. find one of them as the representative,
+	 * 2. find the last one of them from the representative with rb_next,
+	 * 3. call FUNC iteratively from the last to the first.
+	 */
+	if (name)
+	{
+		struct rb_node *node = root->rb_node;
+		while (node)
+		{
+			tagEntryInfoX *entry = container_of(node, tagEntryInfoX, symnode);
+			int result;
+
+			result = strcmp(name, entry->slot.name);
+
+			if (result < 0)
+				node = node->rb_left;
+			else if (result > 0)
+				node = node->rb_right;
+			else
+			{
+				rep = entry;
+				break;
+			}
+		}
+		if (rep == NULL)
+			return true;
+
+		verbose("symtbl[<>] %s->%p\n", name, &rep->slot);
+	}
+
+	struct rb_node *last;
+
+	if (name)
+	{
+		struct rb_node *tmp = &rep->symnode;
+		last = tmp;
+
+		while ((tmp = rb_next (tmp)))
+		{
+			tagEntryInfoX *entry = container_of(tmp, tagEntryInfoX, symnode);
+			if (strcmp(name, entry->slot.name) == 0)
+			{
+				verbose ("symtbl[ >] %s->%p\n", name, &container_of(tmp, tagEntryInfoX, symnode)->slot);
+				last = tmp;
+			}
+			else
+				break;
+		}
+	}
+	else
+	{
+		last = rb_last(root);
+		verbose ("last for %d<%p>: %p\n", corkIndex, root, last);
 	}
 
-	i = TagFile.corkQueue.count;
-	TagFile.corkQueue.count++;
+	if (!last)
+	{
+		verbose ("symtbl[>V] %s->%p\n", name? name: "(null)", NULL);
+		return true;			/* Nothing here in this node. */
+	}
 
+	verbose ("symtbl[>|] %s->%p\n", name, &container_of(last, tagEntryInfoX, symnode)->slot);
 
-	slot = TagFile.corkQueue.queue + i;
-	recordTagEntryInQueue (tag, slot);
+	struct rb_node *cursor = last;
+	bool revisited_rep = false;
+	do
+	{
+		tagEntryInfoX *entry = container_of(cursor, tagEntryInfoX, symnode);
+		if (!revisited_rep || !name || strcmp(name, entry->slot.name))
+		{
+			verbose ("symtbl[< ] %s->%p\n", name, &entry->slot);
+			if (!func (entry->corkIndex, &entry->slot, data))
+				return false;
+			if (cursor == &rep->symnode)
+				revisited_rep = true;
+		}
+		else if (name)
+			break;
+	}
+	while ((cursor = rb_prev(cursor)));
 
-	return i;
+	return true;
 }
 
+static bool findName (int corkIndex, tagEntryInfo *entry, void *data)
+{
+	int *index = data;
 
-static void *writerData;
-static tagWriter *writer;
+	*index =  corkIndex;
+	return false;
+}
 
-extern void setTagWriter (tagWriter *t)
+int anyEntryInScope (int corkIndex, const char *name)
 {
-	writer = t;
+	int index = CORK_NIL;
+
+	if (foreachEntriesInScope (corkIndex, name, findName, &index) == false)
+		return index;
+
+	return CORK_NIL;
 }
 
-extern bool outpuFormatUsedStdoutByDefault (void)
+struct anyKindsEntryInScopeData {
+	int  index;
+	const int *kinds;
+	int  count;
+};
+
+static bool findNameOfKinds (int corkIndex, tagEntryInfo *entry, void *data)
 {
-	return writer->useStdoutByDefault;
+	struct anyKindsEntryInScopeData * kdata = data;
+
+	for (int i = 0; i < kdata->count; i++)
+	{
+		int k = kdata->kinds [i];
+		if (entry->kindIndex == k)
+		{
+			kdata->index = corkIndex;
+			return false;
+		}
+	}
+	return true;
 }
 
-extern void setupWriter (void)
+int anyKindEntryInScope (int corkIndex,
+						 const char *name, int kind)
 {
-	if (writer->preWriteEntry)
-		writerData = writer->preWriteEntry (TagFile.mio);
-	else
-		writerData = NULL;
+	return anyKindsEntryInScope (corkIndex, name, &kind, 1);
 }
 
-extern void teardownWriter (const char *filename)
+int anyKindsEntryInScope (int corkIndex,
+						  const char *name,
+						  const int *kinds, int count)
 {
-	if (writer->postWriteEntry)
-		writer->postWriteEntry (TagFile.mio, filename, writerData);
+	struct anyKindsEntryInScopeData data = {
+		.index = CORK_NIL,
+		.kinds = kinds,
+		.count = count,
+	};
+
+	if (foreachEntriesInScope (corkIndex, name, findNameOfKinds, &data) == false)
+		return data.index;
+
+	return CORK_NIL;
 }
 
-static void buildFqTagCache (const tagEntryInfo *const tag)
+int anyKindsEntryInScopeRecursive (int corkIndex,
+								   const char *name,
+								   const int *kinds, int count)
 {
-	renderFieldEscaped (FIELD_SCOPE_KIND_LONG, tag, NO_PARSER_FIELD);
-	renderFieldEscaped (FIELD_SCOPE, tag, NO_PARSER_FIELD);
+	struct anyKindsEntryInScopeData data = {
+		.index = CORK_NIL,
+		.kinds = kinds,
+		.count = count,
+	};
+
+	tagEntryInfo *e;
+	do
+	{
+		if (foreachEntriesInScope (corkIndex, name, findNameOfKinds, &data) == false)
+			return data.index;
+
+		if (corkIndex == CORK_NIL)
+			break;
+
+		e = getEntryInCorkQueue (corkIndex);
+		if (!e)
+			break;
+		corkIndex = e->extensionFields.scopeIndex;
+	}
+	while (1);
+
+	return CORK_NIL;
 }
 
-#ifdef CTAGS_LIB
-static void initCtagsTag(ctagsTag *tag, const tagEntryInfo *info)
+extern void registerEntry (int corkIndex)
 {
-	tag->name = info->name;
-	tag->signature = info->extensionFields.signature;
-	tag->scopeName = info->extensionFields.scopeName;
-	tag->inheritance = info->extensionFields.inheritance;
-	tag->varType = info->extensionFields.varType;
-	tag->access = info->extensionFields.access;
-	tag->implementation = info->extensionFields.implementation;
-	tag->kindLetter = getLanguageKind(info->langType, info->kindIndex)->letter;
-	tag->isFileScope = info->isFileScope;
-	tag->lineNumber = info->lineNumber;
-	tag->lang = info->langType;
+	Assert (TagFile.corkFlags & CORK_SYMTAB);
+	Assert (corkIndex != CORK_NIL);
+
+	tagEntryInfoX *e = ptrArrayItem (TagFile.corkQueue, corkIndex);
+	{
+		tagEntryInfoX *scope = ptrArrayItem (TagFile.corkQueue, e->slot.extensionFields.scopeIndex);
+		corkSymtabPut (scope, e->slot.name, e);
+	}
+}
+
+static int queueTagEntry(const tagEntryInfo *const tag)
+{
+	static bool warned;
+
+	int corkIndex;
+	tagEntryInfoX * entry = copyTagEntry (tag,
+										TagFile.corkFlags);
+
+	if (ptrArrayCount (TagFile.corkQueue) == (size_t)INT_MAX)
+	{
+		if (!warned)
+		{
+			warned = true;
+			error (WARNING,
+				   "The tag entry queue overflows; drop the tag entry at %lu in %s",
+				   tag->lineNumber,
+				   tag->inputFileName);
+		}
+		return CORK_NIL;
+	}
+	warned = false;
+
+	corkIndex = (int)ptrArrayAdd (TagFile.corkQueue, entry);
+	entry->corkIndex = corkIndex;
+
+	return corkIndex;
+}
+
+extern void setupWriter (void *writerClientData)
+{
+	writerSetup (TagFile.mio, writerClientData);
+}
+
+extern bool teardownWriter (const char *filename)
+{
+	return writerTeardown (TagFile.mio, filename);
+}
+
+static bool isTagWritable(const tagEntryInfo *const tag)
+{
+	if (tag->placeholder)
+		return false;
+
+	if (! isLanguageKindEnabled(tag->langType, tag->kindIndex))
+		return false;
+
+	if (tag->extensionFields.roleBits)
+	{
+		size_t available_roles;
+
+		if (!isXtagEnabled (XTAG_REFERENCE_TAGS))
+			return false;
+
+		available_roles = countLanguageRoles(tag->langType,
+											 tag->kindIndex);
+		if (tag->extensionFields.roleBits >=
+			(makeRoleBit(available_roles)))
+			return false;
+
+		/* TODO: optimization
+		   A Bitmasks representing all enabled roles can be calculated at the
+		   end of initializing the parser. Calculating each time when checking
+		   a tag entry is not needed. */
+		for (unsigned int roleIndex = 0; roleIndex < available_roles; roleIndex++)
+		{
+			if (isRoleAssigned(tag, roleIndex))
+			{
+				if (isLanguageRoleEnabled (tag->langType, tag->kindIndex,
+											 roleIndex))
+					return true;
+			}
+
+		}
+		return false;
+	}
+	else if (isLanguageKindRefOnly(tag->langType, tag->kindIndex))
+	{
+		error (WARNING, "definition tag for refonly kind(%s) is made: %s",
+			   getLanguageKind(tag->langType, tag->kindIndex)->name,
+			   tag->name);
+		/* This one is not so critical. */
+	}
+
+	if (!isXtagEnabled(XTAG_ANONYMOUS)
+		&& isTagExtraBitMarked(tag, XTAG_ANONYMOUS))
+		return false;
+
+	return true;
+}
+
+static void buildFqTagCache (tagEntryInfo *const tag)
+{
+	getTagScopeInformation (tag, NULL, NULL);
 }
-#endif
 
 static void writeTagEntry (const tagEntryInfo *const tag)
 {
 	int length = 0;
 
-	if (tag->placeholder)
-		return;
-#ifndef CTAGS_LIB
-	if (! tag->kind->enabled)
-		return;
-#endif
-	if (tag->extensionFields.roleIndex != ROLE_INDEX_DEFINITION
-	    && ! isXtagEnabled (XTAG_REFERENCE_TAGS))
-		return;
+	Assert (tag->kindIndex != KIND_GHOST_INDEX);
 
 	DebugStatement ( debugEntry (tag); )
-	Assert (writer);
+
+#ifdef WIN32
+	if (getFilenameSeparator(Option.useSlashAsFilenameSeparator) == FILENAME_SEP_USE_SLASH)
+	{
+		Assert (((const tagEntryInfo *)tag)->inputFileName);
+		char *c = (char *)(((tagEntryInfo *const)tag)->inputFileName);
+		while (*c)
+		{
+			if (*c == PATH_SEPARATOR)
+				*c = OUTPUT_PATH_SEPARATOR;
+			c++;
+		}
+	}
+#endif
 
 	if (includeExtensionFlags ()
 	    && isXtagEnabled (XTAG_QUALIFIED_TAGS)
-	    && doesInputLanguageRequestAutomaticFQTag ())
-		buildFqTagCache (tag);
+	    && doesInputLanguageRequestAutomaticFQTag ()
+		&& !isTagExtraBitMarked (tag, XTAG_QUALIFIED_TAGS)
+		&& !tag->skipAutoFQEmission)
+	{
+		/* const is discarded to update the cache field of TAG. */
+		buildFqTagCache ( (tagEntryInfo *const)tag);
+	}
 
-#ifdef CTAGS_LIB
-	getTagScopeInformation((tagEntryInfo *)tag, NULL, NULL);
+	length = writerWriteTag (TagFile.mio, tag);
 
-	if (TagEntryFunction != NULL)
+	if (length > 0)
 	{
-		ctagsTag t;
-
-		initCtagsTag(&t, tag);
-		length = TagEntryFunction(&t, TagEntryUserData);
+		++TagFile.numTags.added;
+		rememberMaxLengths (strlen (tag->name), (size_t) length);
 	}
-#else
-	length = writer->writeEntry (TagFile.mio, tag, writerData);
-#endif
-
-	++TagFile.numTags.added;
-	rememberMaxLengths (strlen (tag->name), (size_t) length);
-	DebugStatement ( mio_flush (TagFile.mio); )
+	DebugStatement ( if (TagFile.mio) mio_flush (TagFile.mio); )
 
 	abort_if_ferror (TagFile.mio);
 }
@@ -1159,11 +1572,11 @@ extern bool writePseudoTag (const ptagDesc *desc,
 {
 	int length;
 
-	if (writer->writePtagEntry == NULL)
+	length = writerWritePtag (TagFile.mio, desc, fileName,
+							  pattern, parserName);
+	if (length < 0)
 		return false;
 
-	length = writer->writePtagEntry (TagFile.mio, desc, fileName,
-									 pattern, parserName, writerData);
 	abort_if_ferror (TagFile.mio);
 
 	++TagFile.numTags.added;
@@ -1172,15 +1585,15 @@ extern bool writePseudoTag (const ptagDesc *desc,
 	return true;
 }
 
-extern void corkTagFile(void)
+extern void corkTagFile(unsigned int corkFlags)
 {
 	TagFile.cork++;
 	if (TagFile.cork == 1)
 	{
-		  TagFile.corkQueue.length = 1;
-		  TagFile.corkQueue.count = 1;
-		  TagFile.corkQueue.queue = eMalloc (sizeof (*TagFile.corkQueue.queue));
-		  memset (TagFile.corkQueue.queue, 0, sizeof (*TagFile.corkQueue.queue));
+		TagFile.corkFlags = corkFlags;
+		TagFile.corkQueue = ptrArrayNew (deleteTagEnry);
+		tagEntryInfo *nil = newNilTagEntry (corkFlags);
+		ptrArrayAdd (TagFile.corkQueue, nil);
 	}
 }
 
@@ -1193,32 +1606,36 @@ extern void uncorkTagFile(void)
 	if (TagFile.cork > 0)
 		return ;
 
-	for (i = 1; i < TagFile.corkQueue.count; i++)
+	for (i = 1; i < ptrArrayCount (TagFile.corkQueue); i++)
 	{
-		tagEntryInfo *tag = TagFile.corkQueue.queue + i;
+		tagEntryInfo *tag = ptrArrayItem (TagFile.corkQueue, i);
+
+		if (!isTagWritable(tag))
+			continue;
+
 		writeTagEntry (tag);
+
 		if (doesInputLanguageRequestAutomaticFQTag ()
 		    && isXtagEnabled (XTAG_QUALIFIED_TAGS)
-		    && (tag->extensionFields.scopeKindIndex != KIND_GHOST_INDEX)
-		    && tag->extensionFields.scopeName
-		    && tag->extensionFields.scopeIndex)
+			&& !isTagExtraBitMarked (tag, XTAG_QUALIFIED_TAGS)
+			&& !tag->skipAutoFQEmission
+			&& ((tag->extensionFields.scopeKindIndex != KIND_GHOST_INDEX
+				 && tag->extensionFields.scopeName != NULL
+				 && tag->extensionFields.scopeIndex != CORK_NIL)
+				|| (tag->extensionFields.scopeKindIndex == KIND_GHOST_INDEX
+					&& tag->extensionFields.scopeName == NULL
+					&& tag->extensionFields.scopeIndex == CORK_NIL)))
 			makeQualifiedTagEntry (tag);
 	}
-	for (i = 1; i < TagFile.corkQueue.count; i++)
-		clearTagEntryInQueue (TagFile.corkQueue.queue + i);
 
-	memset (TagFile.corkQueue.queue, 0,
-		sizeof (*TagFile.corkQueue.queue) * TagFile.corkQueue.count);
-	TagFile.corkQueue.count = 0;
-	eFree (TagFile.corkQueue.queue);
-	TagFile.corkQueue.queue = NULL;
-	TagFile.corkQueue.length = 0;
+	ptrArrayDelete (TagFile.corkQueue);
+	TagFile.corkQueue = NULL;
 }
 
-extern tagEntryInfo *getEntryInCorkQueue   (unsigned int n)
+extern tagEntryInfo *getEntryInCorkQueue   (int n)
 {
-	if ((CORK_NIL < n) && (n < TagFile.corkQueue.count))
-		return TagFile.corkQueue.queue + n;
+	if ((CORK_NIL < n) && (((size_t)n) < ptrArrayCount (TagFile.corkQueue)))
+		return ptrArrayItem (TagFile.corkQueue, n);
 	else
 		return NULL;
 }
@@ -1232,25 +1649,38 @@ extern tagEntryInfo *getEntryOfNestingLevel (const NestingLevel *nl)
 
 extern size_t        countEntryInCorkQueue (void)
 {
-	return TagFile.corkQueue.count;
+	return ptrArrayCount (TagFile.corkQueue);
+}
+
+extern int makePlaceholder (const char *const name)
+{
+	tagEntryInfo e;
+
+	initTagEntry (&e, name, KIND_GHOST_INDEX);
+	e.placeholder = 1;
+
+	/*
+	 * makePlaceholder may be called even before reading any bytes
+	 * from the input stream. In such case, initTagEntry fills
+	 * the lineNumber field of the placeholder tag with 0.
+	 * This breaks an assertion in makeTagEntry. Following adjustment
+	 * is for avoiding it.
+	 */
+	if (e.lineNumber == 0)
+		e.lineNumber = 1;
+
+	return makeTagEntry (&e);
 }
 
 extern int makeTagEntry (const tagEntryInfo *const tag)
 {
 	int r = CORK_NIL;
 	Assert (tag->name != NULL);
+	Assert(tag->lineNumber > 0);
 
-#ifndef CTAGS_LIB
-	if (getInputLanguageFileKind() != tag->kind)
-	{
-		if (! isInputLanguageKindEnabled (tag->kind->letter) &&
-		    (tag->extensionFields.roleIndex == ROLE_INDEX_DEFINITION))
-			return CORK_NIL;
-		if ((tag->extensionFields.roleIndex != ROLE_INDEX_DEFINITION)
-		    && (! tag->kind->roles[tag->extensionFields.roleIndex].enabled))
-			return CORK_NIL;
-	}
-#endif
+	if (!TagFile.cork)
+		if (!isTagWritable (tag))
+			goto out;
 
 	if (tag->name [0] == '\0' && (!tag->placeholder))
 	{
@@ -1264,6 +1694,10 @@ extern int makeTagEntry (const tagEntryInfo *const tag)
 		r = queueTagEntry (tag);
 	else
 		writeTagEntry (tag);
+
+	if (r != CORK_NIL)
+		notifyMakeTagEntry (tag, r);
+
 out:
 	return r;
 }
@@ -1272,7 +1706,7 @@ extern int makeQualifiedTagEntry (const tagEntryInfo *const e)
 {
 	int r = CORK_NIL;
 	tagEntryInfo x;
-	char xk;
+	int xk;
 	const char *sep;
 	static vString *fqn;
 
@@ -1281,7 +1715,7 @@ extern int makeQualifiedTagEntry (const tagEntryInfo *const e)
 		x = *e;
 		markTagExtraBit (&x, XTAG_QUALIFIED_TAGS);
 
-		fqn = vStringNewOrClear (fqn);
+		fqn = vStringNewOrClearWithAutoRelease (fqn);
 
 		if (e->extensionFields.scopeName)
 		{
@@ -1298,7 +1732,7 @@ extern int makeQualifiedTagEntry (const tagEntryInfo *const e)
 			if (sep == NULL)
 			{
 				/* No root separator. The name of the
-				   oritinal tag and that of full qualified tag
+				   optional tag and that of full qualified tag
 				   are the same; recording the full qualified tag
 				   is meaningless. */
 				return r;
@@ -1310,53 +1744,35 @@ extern int makeQualifiedTagEntry (const tagEntryInfo *const e)
 
 		x.name = vStringValue (fqn);
 		/* makeExtraTagEntry of c.c doesn't clear scope
-		   releated fields. */
+		   related fields. */
 #if 0
 		x.extensionFields.scopeKind = NULL;
 		x.extensionFields.scopeName = NULL;
+		x.extensionFields.scopeIndex = CORK_NIL;
 #endif
+
+		bool in_subparser
+			= isTagExtraBitMarked (&x,
+								   XTAG_SUBPARSER);
+
+		if (in_subparser)
+			pushLanguage(x.langType);
+
 		r = makeTagEntry (&x);
+
+		if (in_subparser)
+			popLanguage();
 	}
 	return r;
 }
 
-extern void initTagEntry (tagEntryInfo *const e, const char *const name,
-			  int kindIndex)
-{
-	initTagEntryFull(e, name,
-			 getInputLineNumber (),
-			 getInputLanguage (),
-			 getInputFilePosition (),
-			 getInputFileTagPath (),
-			 kindIndex,
-			 ROLE_INDEX_DEFINITION,
-			 getSourceFileTagPath(),
-			 getSourceLanguage(),
-			 getSourceLineNumber() - getInputLineNumber ());
-}
-
-extern void initRefTagEntry (tagEntryInfo *const e, const char *const name,
-			     int kindIndex, int roleIndex)
-{
-	initTagEntryFull(e, name,
-			 getInputLineNumber (),
-			 getInputLanguage (),
-			 getInputFilePosition (),
-			 getInputFileTagPath (),
-			 kindIndex,
-			 roleIndex,
-			 getSourceFileTagPath(),
-			 getSourceLanguage(),
-			 getSourceLineNumber() - getInputLineNumber ());
-}
-
-extern void initTagEntryFull (tagEntryInfo *const e, const char *const name,
+static void initTagEntryFull (tagEntryInfo *const e, const char *const name,
 			      unsigned long lineNumber,
 			      langType langType_,
 			      MIOPos      filePosition,
 			      const char *inputFileName,
 			      int kindIndex,
-			      int roleIndex,
+			      roleBitsType roleBits,
 			      const char *sourceFileName,
 			      langType sourceLangType,
 			      long sourceLineNumberDifference)
@@ -1380,12 +1796,17 @@ extern void initTagEntryFull (tagEntryInfo *const e, const char *const name,
 	Assert (kindIndex < 0 || kindIndex < (int)countLanguageKinds(langType_));
 	e->kindIndex = kindIndex;
 
-	Assert (roleIndex >= ROLE_INDEX_DEFINITION);
-	Assert (kind == NULL || roleIndex < kind->nRoles);
-	e->extensionFields.roleIndex = roleIndex;
-	if (roleIndex > ROLE_INDEX_DEFINITION)
+	Assert (roleBits == 0
+			|| (roleBits < (makeRoleBit(countLanguageRoles(langType_, kindIndex)))));
+	e->extensionFields.roleBits = roleBits;
+	if (roleBits)
 		markTagExtraBit (e, XTAG_REFERENCE_TAGS);
 
+	if (doesParserRunAsGuest ())
+		markTagExtraBit (e, XTAG_GUEST);
+	if (doesSubparserRun ())
+		markTagExtraBit (e, XTAG_SUBPARSER);
+
 	e->sourceLangType = sourceLangType;
 	e->sourceFileName = sourceFileName;
 	e->sourceLineNumberDifference = sourceLineNumberDifference;
@@ -1394,30 +1815,163 @@ extern void initTagEntryFull (tagEntryInfo *const e, const char *const name,
 
 	for ( i = 0; i < PRE_ALLOCATED_PARSER_FIELDS; i++ )
 		e->parserFields[i].ftype = FIELD_UNKNOWN;
+
+	if (isParserMarkedNoEmission ())
+		e->placeholder = 1;
 }
 
-extern void    markTagExtraBit     (tagEntryInfo *const tag, xtagType extra)
+extern void initTagEntry (tagEntryInfo *const e, const char *const name,
+						  int kindIndex)
+{
+	initTagEntryFull(e, name,
+			 getInputLineNumber (),
+			 getInputLanguage (),
+			 getInputFilePosition (),
+			 getInputFileTagPath (),
+			 kindIndex,
+			 0,
+			 getSourceFileTagPath(),
+			 getSourceLanguage(),
+			 getSourceLineNumber() - getInputLineNumber ());
+}
+
+extern void initRefTagEntry (tagEntryInfo *const e, const char *const name,
+			     int kindIndex, int roleIndex)
+{
+	initForeignRefTagEntry (e, name, getInputLanguage (), kindIndex, roleIndex);
+}
+
+extern void initForeignRefTagEntry (tagEntryInfo *const e, const char *const name,
+									langType langType,
+									int kindIndex, int roleIndex)
+{
+	initTagEntryFull(e, name,
+			 getInputLineNumber (),
+			 langType,
+			 getInputFilePosition (),
+			 getInputFileTagPath (),
+			 kindIndex,
+			 makeRoleBit(roleIndex),
+			 getSourceFileTagPath(),
+			 getSourceLanguage(),
+			 getSourceLineNumber() - getInputLineNumber ());
+}
+
+static void    markTagExtraBitFull     (tagEntryInfo *const tag, xtagType extra, bool mark)
 {
 	unsigned int index;
 	unsigned int offset;
+	uint8_t *slot;
 
-	Assert (extra < XTAG_COUNT);
 	Assert (extra != XTAG_UNKNOWN);
 
-	index = (extra / 8);
-	offset = (extra % 8);
-	tag->extra [ index ] |= (1 << offset);
+	if (extra < XTAG_COUNT)
+	{
+		index = (extra / 8);
+		offset = (extra % 8);
+		slot = tag->extra;
+	}
+	else if (tag->extraDynamic)
+	{
+		Assert (extra < countXtags ());
+
+		index = ((extra - XTAG_COUNT) / 8);
+		offset = ((extra - XTAG_COUNT) % 8);
+		slot = tag->extraDynamic;
+	}
+	else
+	{
+		Assert (extra < countXtags ());
+
+		int n = countXtags () - XTAG_COUNT;
+		tag->extraDynamic = xCalloc ((n / 8) + 1, uint8_t);
+		PARSER_TRASH_BOX(tag->extraDynamic, eFree);
+		markTagExtraBit (tag, extra);
+		return;
+	}
+
+	if (mark)
+		slot [ index ] |= (1 << offset);
+	else
+		slot [ index ] &= ~(1 << offset);
+}
+
+extern void    markTagExtraBit     (tagEntryInfo *const tag, xtagType extra)
+{
+	markTagExtraBitFull (tag, extra, true);
 }
 
 extern bool isTagExtraBitMarked (const tagEntryInfo *const tag, xtagType extra)
 {
-	unsigned int index = (extra / 8);
-	unsigned int offset = (extra % 8);
+	unsigned int index;
+	unsigned int offset;
+	const uint8_t *slot;
 
-	Assert (extra < XTAG_COUNT);
 	Assert (extra != XTAG_UNKNOWN);
 
-	return !! ((tag->extra [ index ]) & (1 << offset));
+	if (extra < XTAG_COUNT)
+	{
+		index = (extra / 8);
+		offset = (extra % 8);
+		slot = tag->extra;
+
+	}
+	else if (!tag->extraDynamic)
+		return false;
+	else
+	{
+		Assert (extra < countXtags ());
+		index = ((extra - XTAG_COUNT) / 8);
+		offset = ((extra - XTAG_COUNT) % 8);
+		slot = tag->extraDynamic;
+
+	}
+	return !! ((slot [ index ]) & (1 << offset));
+}
+
+extern bool isTagExtra (const tagEntryInfo *const tag)
+{
+	for (unsigned int i = 0; i < XTAG_COUNT; i++)
+		if (isTagExtraBitMarked (tag, i))
+			return true;
+	return false;
+}
+
+static void assignRoleFull(tagEntryInfo *const e, int roleIndex, bool assign)
+{
+	if (roleIndex == ROLE_DEFINITION_INDEX)
+	{
+		if (assign)
+		{
+			e->extensionFields.roleBits = 0;
+			markTagExtraBitFull (e, XTAG_REFERENCE_TAGS, false);
+		}
+	}
+	else if (roleIndex > ROLE_DEFINITION_INDEX)
+	{
+		Assert (roleIndex < (int)countLanguageRoles(e->langType, e->kindIndex));
+
+		if (assign)
+			e->extensionFields.roleBits |= (makeRoleBit(roleIndex));
+		else
+			e->extensionFields.roleBits &= ~(makeRoleBit(roleIndex));
+		markTagExtraBitFull (e, XTAG_REFERENCE_TAGS, e->extensionFields.roleBits);
+	}
+	else
+		AssertNotReached();
+}
+
+extern void assignRole(tagEntryInfo *const e, int roleIndex)
+{
+	assignRoleFull(e, roleIndex, true);
+}
+
+extern bool isRoleAssigned(const tagEntryInfo *const e, int roleIndex)
+{
+	if (roleIndex == ROLE_DEFINITION_INDEX)
+		return (!e->extensionFields.roleBits);
+	else
+		return (e->extensionFields.roleBits & makeRoleBit(roleIndex));
 }
 
 extern unsigned long numTagsAdded(void)
@@ -1447,23 +2001,39 @@ extern void invalidatePatternCache(void)
 
 extern void tagFilePosition (MIOPos *p)
 {
-	mio_getpos (TagFile.mio, p);
+	/* mini-geany doesn't set TagFile.mio. */
+	if 	(TagFile.mio == NULL)
+		return;
+
+	if (mio_getpos (TagFile.mio, p) == -1)
+		error (FATAL|PERROR,
+			   "failed to get file position of the tag file\n");
 }
 
 extern void setTagFilePosition (MIOPos *p)
 {
-	mio_setpos (TagFile.mio, p);
+	/* mini-geany doesn't set TagFile.mio. */
+	if 	(TagFile.mio == NULL)
+		return;
+
+	if (mio_setpos (TagFile.mio, p) == -1)
+		error (FATAL|PERROR,
+			   "failed to set file position of the tag file\n");
 }
 
 extern const char* getTagFileDirectory (void)
 {
 	return TagFile.directory;
 }
 
-#ifdef CTAGS_LIB
-extern void setTagEntryFunction(tagEntryFunction entry_function, void *user_data)
+static bool markAsPlaceholder  (int index, tagEntryInfo *e, void *data CTAGS_ATTR_UNUSED)
 {
-	TagEntryFunction = entry_function;
-	TagEntryUserData = user_data;
+	e->placeholder = 1;
+	markAllEntriesInScopeAsPlaceholder (index);
+	return true;
+}
+
+extern void markAllEntriesInScopeAsPlaceholder (int index)
+{
+	foreachEntriesInScope (index, NULL, markAsPlaceholder, NULL);
 }
-#endif


Modified: ctags/main/entry.h
207 lines changed, 146 insertions(+), 61 deletions(-)
===================================================================
@@ -16,30 +16,28 @@
 #include "types.h"
 
 #include <stdint.h>
-#include <stdio.h>
 
 #include "field.h"
-#include "kind.h"
-#include "vstring.h"
 #include "xtag.h"
 #include "mio.h"
+#include "ptrarray.h"
 #include "nestlevel.h"
-#include "ctags-api.h"
 
 /*
 *   MACROS
 */
-#define WHOLE_FILE  -1L
-#define includeExtensionFlags()         (Option.tagFileFormat > 1)
 
 /*
 *   DATA DECLARATIONS
 */
 typedef struct sTagField {
 	fieldType  ftype;
 	const char* value;
+	bool valueOwner;			/* used only in parserFieldsDynamic */
 } tagField;
 
+typedef uint64_t roleBitsType;
+
 /*  Information about the current tag candidate.
  */
 struct sTagEntryInfo {
@@ -50,6 +48,10 @@ struct sTagEntryInfo {
 	unsigned int placeholder    :1;	 /* This is just a part of scope context.
 					    Put this entry to cork queue but
 					    don't print it to tags file. */
+	unsigned int skipAutoFQEmission:1; /* If a parser makes a fq tag for the
+										  current tag by itself, set this. */
+	unsigned int isPseudoTag:1;	/* Used only in xref output.
+								   If a tag is a pseudo, set this. */
 
 	unsigned long lineNumber;     /* line number of tag */
 	const char* pattern;	      /* pattern for locating input line
@@ -60,7 +62,8 @@ struct sTagEntryInfo {
 	const char *inputFileName;   /* name of input file */
 	const char *name;             /* name of the tag */
 	int kindIndex;	      /* kind descriptor */
-	unsigned char extra[ ((XTAG_COUNT) / 8) + 1 ];
+	uint8_t extra[ ((XTAG_COUNT) / 8) + 1 ];
+	uint8_t *extraDynamic;		/* Dynamically allocated but freed by per parser TrashBox */
 
 	struct {
 		const char* access;
@@ -84,23 +87,27 @@ struct sTagEntryInfo {
 		/* type (union/struct/etc.) and name for a variable or typedef. */
 		const char* typeRef [2];  /* e.g., "struct" and struct name */
 
-/* GEANY DIFF */
-		const char *varType;
-/* GEANY DIFF END */
-
-#define ROLE_INDEX_DEFINITION -1
-		int roleIndex; /* for role of reference tag */
+#define ROLE_DEFINITION_INDEX -1
+#define ROLE_DEFINITION_NAME "def"
+#define ROLE_MAX_COUNT (sizeof(roleBitsType) * 8)
+		roleBitsType roleBits; /* for role of reference tag */
 
 #ifdef HAVE_LIBXML
 		const char* xpath;
 #endif
 		unsigned long endLine;
 	} extensionFields;  /* list of extension fields*/
 
+	/* `usedParserFields' tracks how many parser own fields are
+	   used. If it is a few (less than PRE_ALLOCATED_PARSER_FIELDS),
+	   statically allocated parserFields is used. If more fields than
+	   PRE_ALLOCATED_PARSER_FIELDS is defined and attached, parserFieldsDynamic
+	   is used. */
+	unsigned int usedParserFields;
 #define PRE_ALLOCATED_PARSER_FIELDS 5
 #define NO_PARSER_FIELD -1
-	unsigned int usedParserFields;
 	tagField     parserFields [PRE_ALLOCATED_PARSER_FIELDS];
+	ptrArray *   parserFieldsDynamic;
 
 	/* Following source* fields are used only when #line is found
 	   in input and --line-directive is given in ctags command line. */
@@ -109,6 +116,9 @@ struct sTagEntryInfo {
 	unsigned long sourceLineNumberDifference;
 };
 
+typedef bool (* entryForeachFunc) (int corkIndex,
+								   tagEntryInfo * entry,
+								   void * data);
 
 /*
 *   GLOBAL VARIABLES
@@ -118,71 +128,146 @@ struct sTagEntryInfo {
 /*
 *   FUNCTION PROTOTYPES
 */
-extern void freeTagFileResources (void);
-extern const char *tagFileName (void);
-extern void openTagFile (void);
-extern void closeTagFile (const bool resize);
-extern void  setupWriter (void);
-extern void  teardownWriter (const char *inputFilename);
 extern int makeTagEntry (const tagEntryInfo *const tag);
 extern void initTagEntry (tagEntryInfo *const e, const char *const name,
 			  int kindIndex);
 extern void initRefTagEntry (tagEntryInfo *const e, const char *const name,
 			     int kindIndex, int roleIndex);
-extern void initTagEntryFull (tagEntryInfo *const e, const char *const name,
-			      unsigned long lineNumber,
-			      langType langType_,
-			      MIOPos      filePosition,
-			      const char *inputFileName,
-			      int kindIndex,
-			      int roleIndex,
-			      const char *sourceFileName,
-			      langType sourceLangType,
-			      long sourceLineNumberDifference);
+extern void initForeignRefTagEntry (tagEntryInfo *const e, const char *const name,
+									langType type,
+									int kindIndex, int roleIndex);
+extern void assignRole(tagEntryInfo *const e, int roleIndex);
+extern bool isRoleAssigned(const tagEntryInfo *const e, int roleIndex);
+
 extern int makeQualifiedTagEntry (const tagEntryInfo *const e);
 
-extern unsigned long numTagsAdded(void);
-extern void setNumTagsAdded (unsigned long nadded);
-extern unsigned long numTagsTotal(void);
-extern unsigned long maxTagsLine(void);
-extern void invalidatePatternCache(void);
-extern void tagFilePosition (MIOPos *p);
-extern void setTagFilePosition (MIOPos *p);
-extern const char* getTagFileDirectory (void);
-extern void getTagScopeInformation (tagEntryInfo *const tag,
-				    const char **kind, const char **name);
 
-/* Getting line associated with tag */
-extern char *readLineFromBypassAnyway (vString *const vLine, const tagEntryInfo *const tag,
-				   long *const pSeekValue);
+#define CORK_NIL 0
+tagEntryInfo *getEntryInCorkQueue   (int n);
+tagEntryInfo *getEntryOfNestingLevel (const NestingLevel *nl);
+size_t        countEntryInCorkQueue (void);
+
+/* If a parser sets (CORK_QUEUE and )CORK_SYMTAB to useCork,
+ * the parsesr can use symbol lookup tables for the current input.
+ * Each scope has a symbol lookup table.
+ * To register an tag to the table, use registerEntry().
+ * registerEntry registers CORKINDEX to a symbol table of a parent tag
+ * specified in the scopeIndex field of the tag specified with CORKINDEX.
+ */
+void          registerEntry (int corkIndex);
 
-/* Generating pattern associated tag, caller must do eFree for the returned value. */
-extern char* makePatternString (const tagEntryInfo *const tag);
+/* foreachEntriesInScope is for traversing the symbol table for a table
+ * specified with CORKINDEX. If CORK_NIL is given, this function traverses
+ * top-level entries. If name is NULL, this function traverses all entries
+ * under the scope.
+ *
+ * If FUNC returns false, this function returns false.
+ * If FUNC never returns false, this func returns true.
+ * If FUNC is not called because no node for NAME in the symbol table.
+ */
+bool          foreachEntriesInScope (int corkIndex,
+									 const char *name, /* or NULL */
+									 entryForeachFunc func,
+									 void *data);
 
+/* Return the cork index for NAME in the scope specified with CORKINDEX.
+ * Even if more than one entries for NAME are in the scope, this function
+ * just returns one of them. Returning CORK_NIL means there is no entry
+ * for NAME.
+ */
+int           anyEntryInScope       (int corkIndex,
+									 const char *name);
 
-/* language is optional: can be NULL. */
-extern bool writePseudoTag (const ptagDesc *pdesc,
-			       const char *const fileName,
-			       const char *const pattern,
-			       const char *const parserName);
+int           anyKindEntryInScope (int corkIndex,
+								   const char *name, int kind);
 
-#define CORK_NIL 0
-void          corkTagFile(void);
-void          uncorkTagFile(void);
-tagEntryInfo *getEntryInCorkQueue   (unsigned int n);
-tagEntryInfo *getEntryOfNestingLevel (const NestingLevel *nl);
-size_t        countEntryInCorkQueue (void);
+int           anyKindsEntryInScope (int corkIndex,
+									const char *name,
+									const int * kinds, int count);
 
-extern void makeFileTag (const char *const fileName);
+int           anyKindsEntryInScopeRecursive (int corkIndex,
+											 const char *name,
+											 const int * kinds, int count);
 
 extern void    markTagExtraBit     (tagEntryInfo *const tag, xtagType extra);
 extern bool isTagExtraBitMarked (const tagEntryInfo *const tag, xtagType extra);
 
-extern void attachParserField (tagEntryInfo *const tag, fieldType ftype, const char* value);
+/* If any extra bit is on, return true. */
+extern bool isTagExtra (const tagEntryInfo *const tag);
+
+/* Functions for attaching parser specific fields
+ *
+ * Which function you should use?
+ * ------------------------------
+ * Case A:
+ *
+ * If your parser uses the Cork API, and your parser called
+ * makeTagEntry () already, you can use both
+ * attachParserFieldToCorkEntry () and attachParserField ().  Your
+ * parser has the cork index returned from makeTagEntry ().  With the
+ * cork index, your parser can call attachParserFieldToCorkEntry ().
+ * If your parser already call getEntryInCorkQueue () to get the tag
+ * entry for the cork index, your parser can call attachParserField ()
+ * with passing true for `inCorkQueue' parameter. attachParserField ()
+ * is a bit faster than attachParserFieldToCorkEntry ().
+ *
+ * attachParserField () and attachParserFieldToCorkEntry () duplicates
+ * the memory object specified with `value' and stores the duplicated
+ * object to the entry on the cork queue. So the parser must/can free
+ * the original one passed to the functions after calling. The cork
+ * queue manages the life of the duplicated object. It is not the
+ * parser's concern.
+ *
+ *
+ * Case B:
+ *
+ * If your parser called one of initTagEntry () family but didn't call
+ * makeTagEntry () for a tagEntry yet, use attachParserField () with
+ * false for `inCorkQueue' whether your parser uses the Cork API or
+ * not.
+ *
+ * The parser (== caller) keeps the memory object specified with `value'
+ * till calling makeTagEntry (). The parser must free the memory object
+ * after calling makeTagEntry () if it is allocated dynamically in the
+ * parser side.
+ *
+ * Interpretation of VALUE
+ * -----------------------
+ * For FIELDTYPE_STRING:
+ * Both json writer and xref writer prints it as-is.
+ *
+ * For FIELDTYPE_STRING|FIELDTYPE_BOOL:
+ * If VALUE points "" (empty C string), the json writer prints it as
+ * false, and the xref writer prints it as -.
+ * If VALUE points a non-empty C string, Both json writer and xref
+ * writer print it as-is.
+ *
+ * For FIELDTYPE_BOOL
+ * The json writer always prints true.
+ * The xref writer always prints the name of field.
+ * Set "" explicitly though the value pointed by VALUE is not referred,
+ *
+ *
+ * The other data type and the combination of types are not implemented yet.
+ *
+ */
+extern void attachParserField (tagEntryInfo *const tag, bool inCorkQueue, fieldType ftype, const char* value);
 extern void attachParserFieldToCorkEntry (int index, fieldType ftype, const char* value);
+extern const char* getParserFieldValueForType (tagEntryInfo *const tag@@ 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