Branch: refs/heads/master Author: Jiří Techet techet@gmail.com Committer: Jiří Techet techet@gmail.com Date: Wed, 18 Nov 2020 21:22:41 UTC Commit: 92382dcdbcccb7f531569dc291c33e275a2a9e44 https://github.com/geany/geany/commit/92382dcdbcccb7f531569dc291c33e275a2a9e...
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@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).