commit 1476cf9b97c5742051974179e96a9aedad289615 Author: Adrian Schröter Date: Mon Oct 14 14:06:01 2024 +0200 Sync from SUSE:ALP:Source:Standard:1.0 ctags revision 54c266584b1171503298880781f3af63 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..fecc750 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,23 @@ +## Default LFS +*.7z filter=lfs diff=lfs merge=lfs -text +*.bsp filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.gem filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.jar filter=lfs diff=lfs merge=lfs -text +*.lz filter=lfs diff=lfs merge=lfs -text +*.lzma filter=lfs diff=lfs merge=lfs -text +*.obscpio filter=lfs diff=lfs merge=lfs -text +*.oxt filter=lfs diff=lfs merge=lfs -text +*.pdf filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.rpm filter=lfs diff=lfs merge=lfs -text +*.tbz filter=lfs diff=lfs merge=lfs -text +*.tbz2 filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.ttf filter=lfs diff=lfs merge=lfs -text +*.txz filter=lfs diff=lfs merge=lfs -text +*.whl filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text diff --git a/0001-Mixing-with-anjuta-tags-https-git.gnome.org-browse-a.patch b/0001-Mixing-with-anjuta-tags-https-git.gnome.org-browse-a.patch new file mode 100644 index 0000000..ee9d3cd --- /dev/null +++ b/0001-Mixing-with-anjuta-tags-https-git.gnome.org-browse-a.patch @@ -0,0 +1,2868 @@ +From 504c9e52393b1a3620de00878043271812adb887 Mon Sep 17 00:00:00 2001 +From: Federico Fissore +Date: Fri, 23 Jan 2015 15:36:29 +0100 +Subject: [PATCH 01/19] Mixing with anjuta-tags + https://git.gnome.org/browse/anjuta/tree/plugins/symbol-db/anjuta-tags + +--- + .gitignore | 5 + + acconfig.h | 127 +++++++++++++++++ + ant.c | 4 +- + c.c | 145 +++++++++++++++++-- + config.h | 275 ++++++++++++++++++++++++++++++++++++ + ctags-utils.c | 41 ++++++ + ctags-utils.h | 38 +++++ + ctags-visitor.vala | 400 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + ctags.h | 2 +- + eiffel.c | 20 ++- + entry.c | 6 + + entry.h | 3 +- + falcon.c | 149 ++++++++++++++++++++ + flex.c | 55 +++++++- + gir.c | 216 +++++++++++++++++++++++++++++ + lregex.c | 4 +- + make.c | 4 +- + options.c | 6 +- + options.h | 1 + + parsers.h | 47 +++++++ + php.c | 24 ++-- + python.c | 8 +- + sort.c | 4 +- + sql.c | 278 ++++++++++++++++++++++++++++++++----- + test-cmd-line | 1 + + tex.c | 35 ++--- + vala.c | 103 ++++++++++++++ + verilog.c | 3 +- + 28 files changed, 1900 insertions(+), 104 deletions(-) + create mode 100644 .gitignore + create mode 100644 acconfig.h + create mode 100644 config.h + create mode 100644 ctags-utils.c + create mode 100644 ctags-utils.h + create mode 100644 ctags-visitor.vala + create mode 100644 falcon.c + create mode 100644 gir.c + create mode 100644 test-cmd-line + create mode 100644 vala.c + +diff --git a/.gitignore b/.gitignore +new file mode 100644 +index 0000000..868b69d +--- /dev/null ++++ b/.gitignore +@@ -0,0 +1,5 @@ ++*.o ++Makefile ++config.log ++config.status ++ctags +diff --git a/acconfig.h b/acconfig.h +new file mode 100644 +index 0000000..8431027 +--- /dev/null ++++ b/acconfig.h +@@ -0,0 +1,127 @@ ++/* ++* $Id: acconfig.h 318 2003-04-01 05:02:21Z darren $ ++* ++* Copyright (c) 1998-2003, Darren Hiebert ++* ++* This source code is released for free distribution under the terms of the ++* GNU General Public License. ++* ++* This module contains input source for generating config.h.in ++*/ ++ ++/* Package name. ++ */ ++#undef PACKAGE ++ ++/* Package version. ++ */ ++#undef VERSION ++ ++/* Define to the appropriate type if does not define this. ++ */ ++#undef clock_t ++ ++/* Define to long if does not define this. ++ */ ++#undef fpos_t ++ ++/* Define to the appropriate size for tmpnam() if does not define ++ * this. ++ */ ++#undef L_tmpnam ++ ++/* Define this macro if the field "st_ino" exists in struct stat in ++ * . ++ * */ ++#undef HAVE_STAT_ST_INO ++ ++/* Define remove to unlink if you have unlink(), but not remove(). ++ */ ++#undef remove ++ ++/* Define this value used by fseek() appropriately if ++ * (or on SunOS 4.1.x) does not define them. ++ */ ++#undef SEEK_SET ++ ++/* Define as the maximum integer on your system if not defined . ++ */ ++#undef INT_MAX ++ ++/* You can define this label to be a string containing the name of a ++ * site-specific configuration file containing site-wide default options. The ++ * files /etc/ctags.conf and /usr/local/etc/ctags.conf are already checked, ++ * so only define one here if you need a file somewhere else. ++ */ ++#undef CUSTOM_CONFIGURATION_FILE ++ ++/* Define this label if you want macro tags (defined lables) to use patterns ++ * in the EX command by default (original ctags behavior is to use line ++ * numbers). ++ */ ++#undef MACROS_USE_PATTERNS ++ ++/* Define this as desired. ++ * 1: Original ctags format ++ * 2: Extended ctags format with extension flags in EX-style comment. ++ */ ++#define DEFAULT_FILE_FORMAT 2 ++ ++/* Define this label if your system supports starting scripts with a line of ++ * the form "#! /bin/sh" to select the interpreter to use for the script. ++ */ ++#undef SYS_INTERPRETER ++ ++/* Define this label if your system uses case-insensitive file names ++ */ ++#undef CASE_INSENSITIVE_FILENAMES ++ ++/* Define this label to use the system sort utility (which is probably more ++ * efficient) over the internal sorting algorithm. ++ */ ++#ifndef INTERNAL_SORT ++# undef EXTERNAL_SORT ++#endif ++ ++/* If you wish to change the directory in which temporary files are stored, ++ * define this label to the directory desired. ++ */ ++#undef TMPDIR ++ ++/* Define this label if regcomp() is broken. ++ */ ++#undef REGCOMP_BROKEN ++ ++/* Define this label if you wish to check the regcomp() function at run time ++ * for correct behavior. This function is currently broken on Cygwin. ++ */ ++#undef CHECK_REGCOMP ++ ++/* This corrects the problem of missing prototypes for certain functions ++ * in some GNU installations (e.g. SunOS 4.1.x). ++ */ ++#undef __USE_FIXED_PROTOTYPES__ ++ ++/* Define this is you have a prototype for putenv() in , but ++ * doesn't declare its argument as "const char *". ++ */ ++#undef NON_CONST_PUTENV_PROTOTYPE ++ ++/* If you receive error or warning messages indicating that you are missing ++ * a prototype for, or a type mismatch using, one of the following functions, ++ * define the appropriate label and remake. ++ */ ++#undef NEED_PROTO_REMOVE ++#undef NEED_PROTO_UNLINK ++#undef NEED_PROTO_MALLOC ++#undef NEED_PROTO_GETENV ++#undef NEED_PROTO_FGETPOS ++#undef NEED_PROTO_STAT ++#undef NEED_PROTO_LSTAT ++#undef NEED_PROTO_TRUNCATE ++#undef NEED_PROTO_FTRUNCATE ++ ++/*---------------------------------------------------------------------------- ++- Lines below this are automatically generated by autoheader ++----------------------------------------------------------------------------*/ ++/* @TOP@ */ +diff --git a/ant.c b/ant.c +index eedfcec..bd01de4 100644 +--- a/ant.c ++++ b/ant.c +@@ -24,9 +24,9 @@ + static void installAntRegex (const langType language) + { + addTagRegex (language, +- "^[ \t]*<[ \t]*project.*name=\"([^\"]+)\".*", "\\1", "p,project,projects", NULL); ++ "^[ \t]*<[ \t]*project[^>]+name=\"([^\"]+)\".*", "\\1", "p,project,projects", NULL); + addTagRegex (language, +- "^[ \t]*<[ \t]*target.*name=\"([^\"]+)\".*", "\\1", "t,target,targets", NULL); ++ "^[ \t]*<[ \t]*target[^>]+name=\"([^\"]+)\".*", "\\1", "t,target,targets", NULL); + } + + extern parserDefinition* AntParser () +diff --git a/c.c b/c.c +index 0cf0a14..ccca3a4 100644 +--- a/c.c ++++ b/c.c +@@ -48,7 +48,7 @@ + * DATA DECLARATIONS + */ + +-enum { NumTokens = 3 }; ++enum { NumTokens = 15 }; + + typedef enum eException { + ExceptionNone, ExceptionEOF, ExceptionFormattingError, +@@ -119,6 +119,8 @@ typedef enum eTokenType { + TOKEN_PAREN_NAME, /* a single name in parentheses */ + TOKEN_SEMICOLON, /* the semicolon character */ + TOKEN_SPEC, /* a storage class specifier, qualifier, type, etc. */ ++ TOKEN_STAR, /* pointer * detection */ ++ TOKEN_AMPERSAND, /* ampersand & detection */ + TOKEN_COUNT + } tokenType; + +@@ -259,6 +261,7 @@ static langType Lang_java; + static langType Lang_vera; + static vString *Signature; + static boolean CollectingSignature; ++static vString *ReturnType; + + /* Number used to uniquely identify anonymous structs and unions. */ + static int AnonymousID = 0; +@@ -564,7 +567,7 @@ static const char *implementationString (const impType imp) + /* + * Debugging functions + */ +- ++#define DEBUG + #ifdef DEBUG + + #define boolString(c) ((c) ? "TRUE" : "FALSE") +@@ -573,7 +576,7 @@ static const char *tokenString (const tokenType type) + { + static const char *const names [] = { + "none", "args", "}", "{", "colon", "comma", "double colon", "keyword", +- "name", "package", "paren-name", "semicolon", "specifier" ++ "name", "package", "paren-name", "semicolon", "specifier", "star", "ampersand" + }; + Assert (sizeof (names) / sizeof (names [0]) == TOKEN_COUNT); + Assert ((int) type < TOKEN_COUNT); +@@ -637,13 +640,13 @@ static void __unused__ pt (tokenInfo *const token) + static void __unused__ ps (statementInfo *const st) + { + unsigned int i; +- printf ("scope: %s decl: %s gotName: %s gotParenName: %s\n", ++ printf ("scope: %s decl: %s gotName: %s gotParenName: %s isPointer: %s\n", + scopeString (st->scope), declString (st->declaration), +- boolString (st->gotName), boolString (st->gotParenName)); ++ boolString (st->gotName), boolString (st->gotParenName), boolString (st->isPointer)); + printf ("haveQualifyingName: %s\n", boolString (st->haveQualifyingName)); + printf ("access: %s default: %s\n", accessString (st->member.access), + accessString (st->member.accessDefault)); +- printf ("token : "); ++ printf ("active token : "); + pt (activeToken (st)); + for (i = 1 ; i < (unsigned int) NumTokens ; ++i) + { +@@ -982,8 +985,15 @@ static void addOtherFields (tagEntryInfo* const tag, const tagType type, + case TAG_FUNCTION: + case TAG_METHOD: + case TAG_PROTOTYPE: +- if (vStringLength (Signature) > 0) ++ if (vStringLength (Signature) > 0) ++ { + tag->extensionFields.signature = vStringValue (Signature); ++ } ++ ++ if (vStringLength (ReturnType) > 0) ++ { ++ tag->extensionFields.returnType = vStringValue (ReturnType); ++ } + case TAG_CLASS: + case TAG_ENUM: + case TAG_ENUMERATOR: +@@ -1156,7 +1166,7 @@ static void makeTag (const tokenInfo *const token, + + findScopeHierarchy (scope, st); + addOtherFields (&e, type, st, scope, typeRef); +- ++ + makeTagEntry (&e); + makeExtraTagEntry (type, &e, scope); + vStringDelete (scope); +@@ -1377,6 +1387,8 @@ static void skipToMatch (const char *const pair) + { + if (CollectingSignature) + vStringPut (Signature, c); ++ ++ + if (c == begin) + { + ++matchLevel; +@@ -2073,7 +2085,7 @@ static void processAngleBracket (void) + cppUngetc (c); + } + } else { +- cppUngetc (c); ++ cppUngetc (c); + } + } + +@@ -2102,6 +2114,106 @@ static void parseJavaAnnotation (statementInfo *const st) + } + } + ++static void parseReturnType (statementInfo *const st) ++{ ++ int i; ++ int lower_bound; ++ tokenInfo * finding_tok; ++ ++ /* FIXME TODO: if java language must be supported then impement this here ++ * removing the current FIXME */ ++ if (!isLanguage (Lang_c) && !isLanguage (Lang_cpp)) ++ { ++ return; ++ } ++ ++ vStringClear (ReturnType); ++ ++ finding_tok = prevToken (st, 1); ++ ++ if (isType (finding_tok, TOKEN_NONE)) ++ return; ++ ++ finding_tok = prevToken (st, 2); ++ ++ if (finding_tok->type == TOKEN_DOUBLE_COLON) ++ { ++ /* get the total number of double colons */ ++ int j; ++ int num_colons = 0; ++ ++ /* we already are at 2nd token */ ++ /* the +=2 means that colons are usually found at even places */ ++ for (j = 2; j < NumTokens; j+=2) ++ { ++ tokenInfo *curr_tok; ++ curr_tok = prevToken (st, j); ++ if (curr_tok->type == TOKEN_DOUBLE_COLON) ++ num_colons++; ++ else ++ break; ++ } ++ ++ /*printf ("FOUND colons %d\n", num_colons);*/ ++ lower_bound = 2 * num_colons + 1; ++ } ++ else ++ lower_bound = 1; ++ ++ for (i = (unsigned int) NumTokens; i > lower_bound; i--) ++ { ++ tokenInfo * curr_tok; ++ curr_tok = prevToken (st, i); ++ ++ switch (curr_tok->type) ++ { ++ case TOKEN_PAREN_NAME: ++ case TOKEN_NONE: ++ continue; ++ break; ++ ++ case TOKEN_DOUBLE_COLON: ++ /* usually C++ class scope */ ++ vStringCatS (ReturnType, "::"); ++ break; ++ ++ case TOKEN_STAR: ++ /* pointers */ ++ vStringPut (ReturnType, '*'); ++ break; ++ ++ case TOKEN_AMPERSAND: ++ /* references */ ++ vStringPut (ReturnType, '&'); ++ break; ++ ++ case TOKEN_KEYWORD: ++ vStringPut (ReturnType, ' '); ++ ++ default: ++ vStringCat (ReturnType, curr_tok->name); ++ break; ++ } ++ } ++ ++ /* clear any white space from the front */ ++ vStringStripLeading (ReturnType); ++ ++ /* .. and from the tail too */ ++ vStringStripTrailing (ReturnType); ++ ++ /* put and end marker */ ++ vStringTerminate (ReturnType); ++ ++ /*/ ++ printf ("~~~~~ statement ---->\n"); ++ ps (st); ++ printf ("NumTokens: %d\n", NumTokens); ++ printf ("FOUND ReturnType: %s\n", vStringValue (ReturnType)); ++ printf ("<~~~~~\n"); ++ //*/ ++} ++ + static int parseParens (statementInfo *const st, parenInfo *const info) + { + tokenInfo *const token = activeToken (st); +@@ -2301,6 +2413,7 @@ static void analyzeParens (statementInfo *const st) + + initParenInfo (&info); + parseParens (st, &info); ++ parseReturnType (st); + c = skipToNonWhite (); + cppUngetc (c); + if (info.invalidContents) +@@ -2536,9 +2649,15 @@ static void nextToken (statementInfo *const st) + switch (c) + { + case EOF: longjmp (Exception, (int) ExceptionEOF); break; +- case '(': analyzeParens (st); break; ++ /* analyze functions and co */ ++ case '(': analyzeParens (st); break; + case '<': processAngleBracket (); break; +- case '*': st->haveQualifyingName = FALSE; break; ++ case '*': ++ st->haveQualifyingName = FALSE; ++ setToken (st, TOKEN_STAR); ++ break; ++ case '&': setToken (st, TOKEN_AMPERSAND); break; ++ + case ',': setToken (st, TOKEN_COMMA); break; + case ':': processColon (st); break; + case ';': setToken (st, TOKEN_SEMICOLON); break; +@@ -2654,6 +2773,7 @@ static void nest (statementInfo *const st, const unsigned int nestLevel) + case DECL_FUNCTION: + case DECL_TASK: + st->inFunction = TRUE; ++ + /* fall through */ + default: + if (includeTag (TAG_LOCAL, FALSE)) +@@ -2765,6 +2885,7 @@ static void createTags (const unsigned int nestLevel, + + nextToken (st); + token = activeToken (st); ++ + if (isType (token, TOKEN_BRACE_CLOSE)) + { + if (nestLevel > 0) +@@ -2801,6 +2922,7 @@ static boolean findCTags (const unsigned int passCount) + Assert (passCount < 3); + cppInit ((boolean) (passCount > 1), isLanguage (Lang_csharp)); + Signature = vStringNew (); ++ ReturnType = vStringNew (); + + exception = (exception_t) setjmp (Exception); + retry = FALSE; +@@ -2817,6 +2939,7 @@ static boolean findCTags (const unsigned int passCount) + } + } + vStringDelete (Signature); ++ vStringDelete (ReturnType); + cppTerminate (); + return retry; + } +diff --git a/config.h b/config.h +new file mode 100644 +index 0000000..d33e48b +--- /dev/null ++++ b/config.h +@@ -0,0 +1,275 @@ ++/* config.h. Generated from config.h.in by configure. */ ++/* config.h.in. Generated from configure.in by autoheader. */ ++/* ++* $Id: acconfig.h 318 2003-04-01 05:02:21Z darren $ ++* ++* Copyright (c) 1998-2003, Darren Hiebert ++* ++* This source code is released for free distribution under the terms of the ++* GNU General Public License. ++* ++* This module contains input source for generating config.h.in ++*/ ++ ++/* Package name. ++ */ ++/* #undef PACKAGE */ ++ ++/* Package version. ++ */ ++/* #undef VERSION */ ++ ++/* Define to the appropriate type if does not define this. ++ */ ++/* #undef clock_t */ ++ ++/* Define to long if does not define this. ++ */ ++/* #undef fpos_t */ ++ ++/* Define to the appropriate size for tmpnam() if does not define ++ * this. ++ */ ++/* #undef L_tmpnam */ ++ ++/* Define this macro if the field "st_ino" exists in struct stat in ++ * . ++ * */ ++#define HAVE_STAT_ST_INO 1 ++ ++/* Define remove to unlink if you have unlink(), but not remove(). ++ */ ++/* #undef remove */ ++ ++/* Define this value used by fseek() appropriately if ++ * (or on SunOS 4.1.x) does not define them. ++ */ ++/* #undef SEEK_SET */ ++ ++/* Define as the maximum integer on your system if not defined . ++ */ ++/* #undef INT_MAX */ ++ ++/* You can define this label to be a string containing the name of a ++ * site-specific configuration file containing site-wide default options. The ++ * files /etc/ctags.conf and /usr/local/etc/ctags.conf are already checked, ++ * so only define one here if you need a file somewhere else. ++ */ ++/* #undef CUSTOM_CONFIGURATION_FILE */ ++ ++/* Define this label if you want macro tags (defined lables) to use patterns ++ * in the EX command by default (original ctags behavior is to use line ++ * numbers). ++ */ ++/* #undef MACROS_USE_PATTERNS */ ++ ++/* Define this as desired. ++ * 1: Original ctags format ++ * 2: Extended ctags format with extension flags in EX-style comment. ++ */ ++#define DEFAULT_FILE_FORMAT 2 ++ ++/* Define this label if your system supports starting scripts with a line of ++ * the form "#! /bin/sh" to select the interpreter to use for the script. ++ */ ++#define SYS_INTERPRETER 1 ++ ++/* Define this label if your system uses case-insensitive file names ++ */ ++/* #undef CASE_INSENSITIVE_FILENAMES */ ++ ++/* Define this label to use the system sort utility (which is probably more ++ * efficient) over the internal sorting algorithm. ++ */ ++#ifndef INTERNAL_SORT ++# define EXTERNAL_SORT 1 ++#endif ++ ++/* If you wish to change the directory in which temporary files are stored, ++ * define this label to the directory desired. ++ */ ++#define TMPDIR "/tmp" ++ ++/* Define this label if regcomp() is broken. ++ */ ++/* #undef REGCOMP_BROKEN */ ++ ++/* Define this label if you wish to check the regcomp() function at run time ++ * for correct behavior. This function is currently broken on Cygwin. ++ */ ++/* #undef CHECK_REGCOMP */ ++ ++/* This corrects the problem of missing prototypes for certain functions ++ * in some GNU installations (e.g. SunOS 4.1.x). ++ */ ++/* #undef __USE_FIXED_PROTOTYPES__ */ ++ ++/* Define this is you have a prototype for putenv() in , but ++ * doesn't declare its argument as "const char *". ++ */ ++/* #undef NON_CONST_PUTENV_PROTOTYPE */ ++ ++/* If you receive error or warning messages indicating that you are missing ++ * a prototype for, or a type mismatch using, one of the following functions, ++ * define the appropriate label and remake. ++ */ ++/* #undef NEED_PROTO_REMOVE */ ++/* #undef NEED_PROTO_UNLINK */ ++/* #undef NEED_PROTO_MALLOC */ ++/* #undef NEED_PROTO_GETENV */ ++/* #undef NEED_PROTO_FGETPOS */ ++/* #undef NEED_PROTO_STAT */ ++/* #undef NEED_PROTO_LSTAT */ ++/* #undef NEED_PROTO_TRUNCATE */ ++/* #undef NEED_PROTO_FTRUNCATE */ ++ ++/*---------------------------------------------------------------------------- ++- Lines below this are automatically generated by autoheader ++----------------------------------------------------------------------------*/ ++ ++/* Define to 1 if you have the `chmod' function. */ ++/* #undef HAVE_CHMOD */ ++ ++/* Define to 1 if you have the `chsize' function. */ ++/* #undef HAVE_CHSIZE */ ++ ++/* Define to 1 if you have the `clock' function. */ ++#define HAVE_CLOCK 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_DIRENT_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_FCNTL_H 1 ++ ++/* Define to 1 if you have the `fgetpos' function. */ ++#define HAVE_FGETPOS 1 ++ ++/* Define to 1 if you have the `findfirst' function. */ ++/* #undef HAVE_FINDFIRST */ ++ ++/* Define to 1 if you have the `fnmatch' function. */ ++#define HAVE_FNMATCH 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_FNMATCH_H 1 ++ ++/* Define to 1 if you have the `ftruncate' function. */ ++/* #undef HAVE_FTRUNCATE */ ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_INTTYPES_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_MEMORY_H 1 ++ ++/* Define to 1 if you have the `mkstemp' function. */ ++#define HAVE_MKSTEMP 1 ++ ++/* Define to 1 if you have the `opendir' function. */ ++#define HAVE_OPENDIR 1 ++ ++/* Define to 1 if you have the `putenv' function. */ ++/* #undef HAVE_PUTENV */ ++ ++/* Define to 1 if you have the `regcomp' function. */ ++#define HAVE_REGCOMP 1 ++ ++/* Define to 1 if you have the `remove' function. */ ++#define HAVE_REMOVE 1 ++ ++/* Define to 1 if you have the `setenv' function. */ ++#define HAVE_SETENV 1 ++ ++/* Define to 1 if you have the header file. */ ++/* #undef HAVE_STAT_H */ ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_STDINT_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_STDLIB_H 1 ++ ++/* Define to 1 if you have the `strcasecmp' function. */ ++#define HAVE_STRCASECMP 1 ++ ++/* Define to 1 if you have the `strerror' function. */ ++#define HAVE_STRERROR 1 ++ ++/* Define to 1 if you have the `stricmp' function. */ ++/* #undef HAVE_STRICMP */ ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_STRINGS_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_STRING_H 1 ++ ++/* Define to 1 if you have the `strncasecmp' function. */ ++#define HAVE_STRNCASECMP 1 ++ ++/* Define to 1 if you have the `strnicmp' function. */ ++/* #undef HAVE_STRNICMP */ ++ ++/* Define to 1 if you have the `strstr' function. */ ++#define HAVE_STRSTR 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_SYS_DIR_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_SYS_STAT_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_SYS_TIMES_H 1 ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_SYS_TYPES_H 1 ++ ++/* Define to 1 if you have the `tempnam' function. */ ++/* #undef HAVE_TEMPNAM */ ++ ++/* Define to 1 if you have the `times' function. */ ++/* #undef HAVE_TIMES */ ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_TIME_H 1 ++ ++/* Define to 1 if you have the `truncate' function. */ ++#define HAVE_TRUNCATE 1 ++ ++/* Define to 1 if you have the header file. */ ++/* #undef HAVE_TYPES_H */ ++ ++/* Define to 1 if you have the header file. */ ++#define HAVE_UNISTD_H 1 ++ ++/* Define to 1 if you have the `_findfirst' function. */ ++/* #undef HAVE__FINDFIRST */ ++ ++/* Define to the address where bug reports for this package should be sent. */ ++#define PACKAGE_BUGREPORT "" ++ ++/* Define to the full name of this package. */ ++#define PACKAGE_NAME "" ++ ++/* Define to the full name and version of this package. */ ++#define PACKAGE_STRING "" ++ ++/* Define to the one symbol short name of this package. */ ++#define PACKAGE_TARNAME "" ++ ++/* Define to the version of this package. */ ++#define PACKAGE_VERSION "" ++ ++/* Define to 1 if you have the ANSI C header files. */ ++#define STDC_HEADERS 1 ++ ++/* Define to empty if `const' does not conform to ANSI C. */ ++/* #undef const */ ++ ++/* Define to `long int' if does not define. */ ++/* #undef off_t */ ++ ++/* Define to `unsigned int' if does not define. */ ++/* #undef size_t */ +diff --git a/ctags-utils.c b/ctags-utils.c +new file mode 100644 +index 0000000..0db7745 +--- /dev/null ++++ b/ctags-utils.c +@@ -0,0 +1,41 @@ ++/* ++ * Copyright (C) Massimo Cora' 2010 ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA ++ */ ++ ++#include "ctags-utils.h" ++ ++void ++get_file_pos (gint line, fpos_t *fpos, FILE *f) ++{ ++ vString * str = vStringNew (); ++ gint i; ++ g_assert (fseek (f, 0, SEEK_SET) == 0); ++ ++ for (i = 0;i < line - 1; i++) ++ { ++ if (readLine (str, f) == NULL) ++ { ++ vStringDelete (str); ++ return; ++ } ++ } ++ ++ vStringDelete (str); ++ g_assert (fgetpos (f, fpos) == 0); ++} ++ ++ +diff --git a/ctags-utils.h b/ctags-utils.h +new file mode 100644 +index 0000000..41283bf +--- /dev/null ++++ b/ctags-utils.h +@@ -0,0 +1,38 @@ ++/* ++ * Copyright (C) Massimo Cora' 2010 ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA ++ */ ++ ++#include "general.h" /* must always come first */ ++#include "read.h" ++#include ++#include ++#include ++ ++ ++/** ++ * IMPORTANT NOTE ++ * ++ * This file should contain functions/helpers that aren't strictly ++ * ctags-standardized and that can be used in extra parsers (i.e. parser ++ * not included with ctags distribution). ++ * Doing so and keeping separate standard/extra files should make ++ * an upgrade of ctags easier. ++ */ ++ ++ ++void get_file_pos (gint line, fpos_t *fpos, FILE *f); ++ +diff --git a/ctags-visitor.vala b/ctags-visitor.vala +new file mode 100644 +index 0000000..f7c050a +--- /dev/null ++++ b/ctags-visitor.vala +@@ -0,0 +1,400 @@ ++/* ++ * ctags-visitor.vala ++ * ++ * Copyright 2008, 2010 Abderrahim Kitouni ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ++ * MA 02110-1301, USA. ++ */ ++ ++using Vala; ++ ++public struct CTagsEntry { ++ public int line_number; ++ public string name; ++ public string kind_name; ++ public char kind; ++ public string access; ++ public string implementation; ++ public string inheritance; ++ public string scope[2]; ++ public string signature; ++ public string typeref; ++ public string returntype; ++} ++ ++class DummyReport : Report { ++ public override void warn (SourceReference? source, string message) {} ++ public override void err (SourceReference? source, string message) {} ++} ++ ++[CCode (has_target=false)] ++public delegate void CTagsEntryMaker (CTagsEntry entry); ++ ++public class CTagsVisitor : CodeVisitor { ++ Parser vala_parser; ++ Genie.Parser genie_parser; ++ GLib.List taglist; ++ public CTagsVisitor () { ++ vala_parser = new Parser(); ++ genie_parser = new Genie.Parser(); ++ } ++ /* helper functions */ ++ static string get_access (Symbol sym) { ++ switch (sym.access) { ++ case SymbolAccessibility.PRIVATE : return "private"; ++ case SymbolAccessibility.INTERNAL : return "internal"; ++ case SymbolAccessibility.PROTECTED : return "protected"; ++ case SymbolAccessibility.PUBLIC : return "public"; ++ } ++ assert_not_reached (); ++ } ++ static string to_string (Iterable seq, string sep = ",") { ++ var str = new StringBuilder(); ++ var first = true; ++ foreach (var type in seq) { ++ if(first) { ++ first = false; ++ } else { ++ str.append(sep); ++ } ++ str.append(type.to_qualified_string()); ++ } ++ return str.str; ++ } ++ static string? implementation (Symbol sym) { ++ var list = new GLib.List(); ++ ++ if (sym is Vala.Signal) { ++ var sig = (Vala.Signal)sym; ++ if (sig.is_virtual) ++ list.append("virtual"); ++ } else if (sym is Class) { ++ var cls = (Class)sym; ++ if (cls.is_abstract) ++ list.append("abstract"); ++ } else if (sym is Method) { ++ var meth = (Method)sym; ++ if (meth.is_abstract) ++ list.append("abstract"); ++ else if (meth.is_virtual) ++ list.append("virtual"); ++ } else if (sym is Property) { ++ var prop = (Property)sym; ++ if (prop.is_abstract) ++ list.append("abstract"); ++ else if (prop.is_virtual) ++ list.append("virtual"); ++ } else ++ return_val_if_reached(null); ++ ++ var ret = new StringBuilder(); ++ var first = true; ++ foreach (var str in list) { ++ if(first) { ++ first = false; ++ } else { ++ ret.append(","); ++ } ++ ret.append(str); ++ } ++ return ret.str; ++ } ++ static string signature (Vala.List parameter) { ++ var ret = new StringBuilder("("); ++ var first = true; ++ foreach (var p in parameter) { ++ if(first) { ++ first = false; ++ } else { ++ ret.append(","); ++ } ++ if (p.ellipsis) { ++ ret.append("..."); ++ } else { ++ ret.append (p.variable_type.to_qualified_string()); ++ ret.append (" "); ++ ret.append (p.name); ++ } ++ } ++ ret.append (")"); ++ return ret.str; ++ } ++ static string[] scope (Symbol s) { ++ string scope[2]; ++ var par = s.parent_symbol; ++ if (par != null && par.name != null) { ++ if (par is Class) ++ scope[0] = "class"; ++ else if (par is Struct) ++ scope[0] = "struct"; ++ else if (par is Interface) ++ scope[0] = "interface"; ++ else ++ return scope; ++ scope[1] = par.name; ++ } ++ return scope; ++ } ++ /*static void print_tag(CTagsEntry en) { ++ stdout.printf("%s: %s at %d\n", en.name, en.kind_name, en.line_number); ++ }*/ ++ ++ public override void visit_source_file (SourceFile source_file) { ++ source_file.accept_children (this); ++ } ++ ++ public override void visit_class (Class cl) { ++ var entry = CTagsEntry(); ++ ++ entry.line_number = cl.source_reference.begin.line; ++ entry.name = cl.name; ++ entry.kind_name = "class"; ++ entry.kind = 'c'; ++ entry.access = get_access (cl); ++ entry.implementation = implementation(cl); ++ entry.inheritance = to_string(cl.get_base_types(), ","); ++ entry.scope = scope (cl); ++ ++ taglist.append(entry); ++// print_tag(entry); ++ cl.accept_children(this); ++ } ++ public override void visit_struct (Struct st) { ++ var entry = CTagsEntry(); ++ entry.line_number = st.source_reference.begin.line; ++ entry.name = st.name; ++ entry.kind_name = "struct"; ++ entry.kind = 's'; ++ entry.access = get_access (st); ++ entry.scope = scope (st); ++ ++ taglist.append(entry); ++// print_tag(entry); ++ st.accept_children(this); ++ } ++ public override void visit_interface (Interface iface) { ++ var entry = CTagsEntry(); ++ ++ entry.line_number = iface.source_reference.begin.line; ++ entry.name = iface.name; ++ entry.kind_name = "interface"; ++ entry.kind = 'i'; ++ entry.access = get_access (iface); ++ entry.inheritance = to_string(iface.get_prerequisites()); ++ entry.scope = scope (iface); ++ ++ taglist.append(entry); ++// print_tag(entry); ++ iface.accept_children(this); ++ } ++ ++ public override void visit_enum (Vala.Enum en) { ++ var entry = CTagsEntry(); ++ ++ entry.line_number = en.source_reference.begin.line; ++ entry.name = en.name; ++ entry.kind_name = "enum"; ++ entry.kind = 'e'; ++ entry.access = get_access (en); ++ entry.scope = scope (en); ++ ++ taglist.append(entry); ++// print_tag(entry); ++ en.accept_children(this); ++ } ++ public override void visit_error_domain (ErrorDomain edomain) { ++ var entry = CTagsEntry(); ++ ++ entry.line_number = edomain.source_reference.begin.line; ++ entry.name = edomain.name; ++ entry.kind_name = "errordomain"; ++ entry.kind = 'E'; ++ entry.access = get_access (edomain); ++ entry.scope = scope (edomain); ++ ++ taglist.append(entry); ++// print_tag(entry); ++ edomain.accept_children(this); ++ } ++ ++ public override void visit_enum_value (Vala.EnumValue ev) { ++ var entry = CTagsEntry(); ++ ++ entry.line_number = ev.source_reference.begin.line; ++ entry.name = ev.name; ++ entry.kind_name = "enumvalue"; ++ entry.kind = 'v'; ++ entry.access = get_access (ev); ++ entry.scope = scope (ev); ++ ++ taglist.append(entry); ++// print_tag(entry); ++ } ++ public override void visit_error_code (ErrorCode ecode) { ++ var entry = CTagsEntry(); ++ ++ //entry.line_number = ecode.source_reference.begin.line; ++ entry.name = ecode.name; ++ entry.kind_name = "errorcode"; ++ entry.kind = 'r'; ++ entry.access = get_access (ecode); ++ entry.scope = scope (ecode); ++ ++ taglist.append(entry); ++// print_tag(entry); ++ } ++ ++ public override void visit_delegate (Delegate d) { ++ var entry = CTagsEntry(); ++ ++ entry.line_number = d.source_reference.begin.line; ++ entry.name = d.name; ++ entry.kind_name = "delegate"; ++ entry.kind = 'd'; ++ entry.access = get_access (d); ++ entry.scope = scope (d); ++ entry.returntype = d.return_type.to_qualified_string(); ++ entry.signature = signature(d.get_parameters()); ++ ++ taglist.append(entry); ++// print_tag(entry); ++ } ++ public override void visit_signal (Vala.Signal sig) { ++ var entry = CTagsEntry(); ++ ++ entry.line_number = sig.source_reference.begin.line; ++ entry.name = sig.name; ++ entry.kind_name = "signal"; ++ entry.kind = 'S'; ++ entry.access = get_access (sig); ++ entry.implementation = implementation(sig); ++ entry.scope = scope (sig); ++ entry.returntype = sig.return_type.to_qualified_string(); ++ entry.signature = signature(sig.get_parameters()); ++ ++ taglist.append(entry); ++// print_tag(entry); ++ } ++ public override void visit_field (Field f) { ++ var entry = CTagsEntry(); ++ ++ entry.line_number = f.source_reference.begin.line; ++ entry.name = f.name; ++ entry.kind_name = "field"; ++ entry.kind = 'f'; ++ entry.access = get_access (f); ++ entry.scope = scope (f); ++ entry.typeref = f.variable_type.to_qualified_string(); ++ ++ taglist.append(entry); ++// print_tag(entry); ++ } ++ public override void visit_constant (Constant c) { ++ var entry = CTagsEntry(); ++ ++ entry.line_number = c.source_reference.begin.line; ++ entry.name = c.name; ++ entry.kind_name = "field"; ++ entry.kind = 'f'; ++ entry.access = get_access (c); ++ entry.scope = scope (c); ++ entry.typeref = c.type_reference.to_qualified_string(); ++ ++ taglist.append(entry); ++// print_tag(entry); ++ } ++ public override void visit_property (Property prop) { ++ var entry = CTagsEntry(); ++ ++ entry.line_number = prop.source_reference.begin.line; ++ entry.name = prop.name; ++ entry.kind_name = "property"; ++ entry.kind = 'p'; ++ entry.access = get_access (prop); ++ entry.implementation = implementation(prop); ++ entry.scope = scope (prop); ++ entry.typeref = prop.property_type.to_qualified_string(); ++ ++ taglist.append(entry); ++// print_tag(entry); ++ } ++ ++ public override void visit_method (Method m) { ++ var entry = CTagsEntry(); ++ ++ entry.line_number = m.source_reference.begin.line; ++ entry.name = m.name; ++ entry.kind_name = "method"; ++ entry.kind = 'm'; ++ entry.access = get_access (m); ++ entry.implementation = implementation(m); ++ entry.scope = scope (m); ++ entry.returntype = m.return_type.to_qualified_string(); ++ entry.signature = signature(m.get_parameters()); ++ ++ taglist.append(entry); ++// print_tag(entry); ++ } ++ ++ public override void visit_local_variable (LocalVariable local) { ++ var entry = CTagsEntry(); ++ ++ entry.line_number = local.source_reference.begin.line; ++ entry.name = local.name; ++ entry.kind_name = "local"; ++ entry.kind = 'l'; ++ entry.access = get_access (local); ++ ++ taglist.append(entry); ++// print_tag(entry); ++ } ++ ++ public void parse_vala (string filename, CTagsEntryMaker maker ) { ++ taglist = new GLib.List(); ++ /* We create a context for every source file so that Parser.parse(context) ++ * don't parse a file multiple times causing errors. Parser.parse_file(source_file) ++ * assumes that Parser.context is the same as source_file.context anyway */ ++ var context = new CodeContext(); ++ context.report = new DummyReport(); ++ var source_file = new SourceFile(context, filename.has_suffix("vapi") ? SourceFileType.PACKAGE : SourceFileType.SOURCE, filename); ++ ++ CodeContext.push(context); ++ context.add_source_file(source_file); ++ vala_parser.parse(context); ++ context.accept(this); ++ foreach (var tagentry in taglist) { ++ maker(tagentry); ++ } ++ taglist = null; ++ CodeContext.pop(); ++ } ++ public void parse_genie (string filename, CTagsEntryMaker maker ) { ++ taglist = new GLib.List(); ++ var context = new CodeContext(); ++ context.report = new DummyReport(); ++ var source_file = new SourceFile(context, SourceFileType.SOURCE, filename); ++ context.add_source_file(source_file); ++ ++ CodeContext.push(context); ++ genie_parser.parse(context); ++ context.accept(this); ++ foreach (var tagentry in taglist) { ++ maker(tagentry); ++ } ++ taglist = null; ++ CodeContext.pop(); ++ } ++} +diff --git a/ctags.h b/ctags.h +index f8884af..fb5ca5b 100644 +--- a/ctags.h ++++ b/ctags.h +@@ -15,7 +15,7 @@ + * MACROS + */ + #ifndef PROGRAM_VERSION +-# define PROGRAM_VERSION "5.8" ++# define PROGRAM_VERSION "Development" + #endif + #define PROGRAM_NAME "Exuberant Ctags" + #define PROGRAM_URL "http://ctags.sourceforge.net" +diff --git a/eiffel.c b/eiffel.c +index b504ac3..e2f5a5c 100644 +--- a/eiffel.c ++++ b/eiffel.c +@@ -1,5 +1,5 @@ + /* +-* $Id: eiffel.c 706 2009-06-28 23:09:30Z dhiebert $ ++* $Id: eiffel.c 748 2009-11-06 02:44:42Z dhiebert $ + * + * Copyright (c) 1998-2002, Darren Hiebert + * +@@ -53,13 +53,15 @@ typedef enum eException { ExceptionNone, ExceptionEOF } exception_t; + */ + typedef enum eKeywordId { + KEYWORD_NONE = -1, +- KEYWORD_alias, KEYWORD_all, KEYWORD_and, KEYWORD_as, KEYWORD_assign, ++ KEYWORD_alias, KEYWORD_all, KEYWORD_and, ++ KEYWORD_as, KEYWORD_assign, KEYWORD_attached, + KEYWORD_check, KEYWORD_class, KEYWORD_convert, KEYWORD_create, + KEYWORD_creation, KEYWORD_Current, +- KEYWORD_debug, KEYWORD_deferred, KEYWORD_do, KEYWORD_else, +- KEYWORD_elseif, KEYWORD_end, KEYWORD_ensure, KEYWORD_expanded, +- KEYWORD_export, KEYWORD_external, KEYWORD_false, KEYWORD_feature, +- KEYWORD_from, KEYWORD_frozen, KEYWORD_if, KEYWORD_implies, ++ KEYWORD_debug, KEYWORD_deferred, KEYWORD_detachable, KEYWORD_do, ++ KEYWORD_else, KEYWORD_elseif, KEYWORD_end, KEYWORD_ensure, ++ KEYWORD_expanded, KEYWORD_export, KEYWORD_external, ++ KEYWORD_false, KEYWORD_feature, KEYWORD_from, KEYWORD_frozen, ++ KEYWORD_if, KEYWORD_implies, + KEYWORD_indexing, KEYWORD_infix, KEYWORD_inherit, KEYWORD_inspect, + KEYWORD_invariant, KEYWORD_is, KEYWORD_like, KEYWORD_local, + KEYWORD_loop, KEYWORD_not, KEYWORD_obsolete, KEYWORD_old, KEYWORD_once, +@@ -154,6 +156,7 @@ static const keywordDesc EiffelKeywordTable [] = { + { "and", KEYWORD_and }, + { "as", KEYWORD_as }, + { "assign", KEYWORD_assign }, ++ { "attached", KEYWORD_attached }, + { "check", KEYWORD_check }, + { "class", KEYWORD_class }, + { "convert", KEYWORD_convert }, +@@ -162,6 +165,7 @@ static const keywordDesc EiffelKeywordTable [] = { + { "current", KEYWORD_Current }, + { "debug", KEYWORD_debug }, + { "deferred", KEYWORD_deferred }, ++ { "detachable", KEYWORD_detachable }, + { "do", KEYWORD_do }, + { "else", KEYWORD_else }, + { "elseif", KEYWORD_elseif }, +@@ -870,7 +874,9 @@ static boolean parseType (tokenInfo *const token) + } + else + { +- if (isKeyword (id, KEYWORD_expanded)) ++ if (isKeyword (id, KEYWORD_attached) || ++ isKeyword (id, KEYWORD_detachable) || ++ isKeyword (id, KEYWORD_expanded)) + { + copyToken (id, token); + readToken (token); +diff --git a/entry.c b/entry.c +index 3890e50..28bfe07 100644 +--- a/entry.c ++++ b/entry.c +@@ -761,6 +761,11 @@ static int addExtensionFields (const tagEntryInfo *const tag) + length += fprintf (TagFile.fp, "%s\tsignature:%s", sep, + tag->extensionFields.signature); + ++ if (Option.extensionFields.returnType && ++ tag->extensionFields.returnType != NULL) ++ length += fprintf (TagFile.fp, "%s\treturntype:%s", sep, ++ tag->extensionFields.returnType); ++ + return length; + #undef sep + } +@@ -836,6 +841,7 @@ extern void initTagEntry (tagEntryInfo *const e, const char *const name) + { + Assert (File.source.name != NULL); + memset (e, 0, sizeof (tagEntryInfo)); ++ + e->lineNumberEntry = (boolean) (Option.locate == EX_LINENUM); + e->lineNumber = getSourceLineNumber (); + e->language = getSourceLanguageName (); +diff --git a/entry.h b/entry.h +index 2365c50..323c1c5 100644 +--- a/entry.h ++++ b/entry.h +@@ -72,7 +72,8 @@ typedef struct sTagEntryInfo { + const char* inheritance; + const char* scope [2]; /* value and key */ + const char* signature; +- ++ const char* returnType; ++ + /* type (union/struct/etc.) and name for a variable or typedef. */ + const char* typeRef [2]; /* e.g., "struct" and struct name */ + +diff --git a/falcon.c b/falcon.c +new file mode 100644 +index 0000000..2730462 +--- /dev/null ++++ b/falcon.c +@@ -0,0 +1,149 @@ ++/* ++ * $Id$ ++ * ++ * Copyright (c) 2011, 2012 Steven Oliver ++ * ++ * This source code is released for free distribution under the terms of the ++ * GNU General Public License. ++ * ++ * This module contains functions for generating tags for Falcon language ++ * files. ++ */ ++ ++ ++/* ++ * INCLUDE FILES ++ */ ++#include "general.h" ++ ++#include ++#include ++ ++#include "parse.h" ++#include "read.h" ++ ++/* ++ * Data Definitions ++ */ ++typedef enum eFalconKinds { ++ K_CLASS, ++ K_FUNCTION, ++ K_MEMBER, ++ K_VARIABLE, ++ K_NAMESPACE ++} falconKind; ++ ++static kindOption FalconKinds [] = { ++ {TRUE, 'c', "class", "classes" }, ++ {TRUE, 'f', "function", "functions"}, ++ {TRUE, 'm', "member", "class members"}, ++ {TRUE, 'v', "variable", "variables"}, ++ {TRUE, 'i', "namespace", "imports"} ++}; ++ ++/* ++ * Function Definitions ++ */ ++ ++static boolean isIdentifierChar (int c) ++{ ++ return (boolean) (isalnum (c) || c == '_'); ++} ++ ++static const char *skipSpace (const char *cp) ++{ ++ while (isspace ((int) *cp)) ++ ++cp; ++ ++ return cp; ++} ++ ++static const char *skipString (const char *cp) ++{ ++ const char *start = cp; ++ int escaped = 0; ++ ++ for (cp++; *cp; cp++) ++ { ++ if (escaped) ++ escaped--; ++ else if (*cp == '\\') ++ escaped++; ++ else if (*cp == *start) ++ return cp + 1; ++ } ++ ++ return cp; ++} ++ ++static void findFalconTags (void) ++{ ++ vString *name = vStringNew (); ++ const unsigned char *line; ++ ++ while ((line = fileReadLine ()) != NULL) ++ { ++ const unsigned char *cp = line; ++ ++ if (*cp == '#') ++ continue; ++ ++ if (strncmp ((const char*) cp, "function", (size_t) 8) == 0) ++ { ++ cp += 8; ++ cp = skipSpace (cp); ++ ++ while (isIdentifierChar ((int) *cp)) ++ { ++ vStringPut (name, (int) *cp); ++ ++cp; ++ } ++ vStringTerminate (name); ++ makeSimpleTag (name, FalconKinds, K_FUNCTION); ++ vStringClear (name); ++ } ++ else if (strncmp ((const char*) cp, "class", (size_t) 5) == 0) ++ { ++ cp += 5; ++ cp = skipSpace (cp); ++ ++ while (isIdentifierChar ((int) *cp)) ++ { ++ vStringPut (name, (int) *cp); ++ ++cp; ++ } ++ vStringTerminate (name); ++ makeSimpleTag (name, FalconKinds, K_CLASS); ++ vStringClear (name); ++ } ++ else if (strncmp ((const char*) cp, "load", (size_t) 4) == 0) ++ { ++ cp += 4; ++ cp = skipSpace (cp); ++ ++ while (isIdentifierChar ((int) *cp)) ++ { ++ vStringPut (name, (int) *cp); ++ ++cp; ++ } ++ vStringTerminate (name); ++ makeSimpleTag (name, FalconKinds, K_NAMESPACE); ++ vStringClear (name); ++ } ++ } ++ vStringDelete (name); ++} ++ ++/* ++ * Parser definition structure ++ */ ++extern parserDefinition* FalconParser (void) ++{ ++ static const char *const extensions [] = { "fal", "ftd", NULL }; ++ parserDefinition *def = parserNew ("Falcon"); ++ def->kinds = FalconKinds; ++ def->kindCount = KIND_COUNT (FalconKinds); ++ def->extensions = extensions; ++ def->parser = findFalconTags; ++ return def; ++} +diff --git a/flex.c b/flex.c +index 06ca243..038ac4e 100644 +--- a/flex.c ++++ b/flex.c +@@ -80,7 +80,8 @@ typedef enum eKeywordId { + KEYWORD_id, + KEYWORD_script, + KEYWORD_cdata, +- KEYWORD_mx ++ KEYWORD_mx, ++ KEYWORD_override + } keywordId; + + /* Used to determine whether keyword is valid for the token language and +@@ -184,7 +185,8 @@ static const keywordDesc FlexKeywordTable [] = { + { "id", KEYWORD_id }, + { "script", KEYWORD_script }, + { "cdata", KEYWORD_cdata }, +- { "mx", KEYWORD_mx } ++ { "mx", KEYWORD_mx }, ++ { "override", KEYWORD_override } + }; + + /* +@@ -726,7 +728,7 @@ static void skipArgumentList (tokenInfo *const token) + * Other databases can have arguments with fully declared + * datatypes: + * ( name varchar(30), text binary(10) ) +- * So we must check for nested open and closing parantheses ++ * So we must check for nested open and closing parentheses + */ + + if (isType (token, TOKEN_OPEN_PAREN)) /* arguments? */ +@@ -1780,7 +1782,7 @@ static boolean parseStatement (tokenInfo *const token) + if (isType (token, TOKEN_CLOSE_CURLY)) + { + /* +- * Assume the closing parantheses terminates ++ * Assume the closing parenthesis terminates + * this statements. + */ + is_terminated = TRUE; +@@ -2154,6 +2156,33 @@ static boolean parseActionScript (tokenInfo *const token) + { + if (isType(token, TOKEN_KEYWORD)) + { ++ if (isKeyword (token, KEYWORD_private) || ++ isKeyword (token, KEYWORD_public) || ++ isKeyword (token, KEYWORD_override) ) ++ { ++ /* ++ * Methods can be defined as: ++ * private function f_name ++ * public override function f_name ++ * override private function f_name ++ * Ignore these keywords if present. ++ */ ++ readToken (token); ++ } ++ if (isKeyword (token, KEYWORD_private) || ++ isKeyword (token, KEYWORD_public) || ++ isKeyword (token, KEYWORD_override) ) ++ { ++ /* ++ * Methods can be defined as: ++ * private function f_name ++ * public override function f_name ++ * override private function f_name ++ * Ignore these keywords if present. ++ */ ++ readToken (token); ++ } ++ + switch (token->keyword) + { + case KEYWORD_function: parseFunction (token); break; +@@ -2178,11 +2207,14 @@ static void parseFlexFile (tokenInfo *const token) + { + parseMXML (token); + } +- if (isType (token, TOKEN_LESS_THAN)) ++ else if (isType (token, TOKEN_LESS_THAN)) + { + readToken (token); + if (isType (token, TOKEN_QUESTION_MARK)) + { ++ /* ++ * ++ */ + readToken (token); + while (! isType (token, TOKEN_QUESTION_MARK) ) + { +@@ -2190,6 +2222,19 @@ static void parseFlexFile (tokenInfo *const token) + } + readToken (token); + } ++ else if (isKeyword (token, KEYWORD_NONE)) ++ { ++ /* ++ * This is a simple XML tag, read until the closing statement ++ * ++ * ++ */ ++ readToken (token); ++ while (! isType (token, TOKEN_GREATER_THAN) ) ++ { ++ readToken (token); ++ } ++ } + } + else + { +diff --git a/gir.c b/gir.c +new file mode 100644 +index 0000000..517472b +--- /dev/null ++++ b/gir.c +@@ -0,0 +1,216 @@ ++#include "general.h" /* must always come first */ ++#include "debug.h" ++#include "entry.h" ++#include "keyword.h" ++#include "parse.h" ++#include "read.h" ++#include "routines.h" ++#include "string.h" ++#include "vstring.h" ++#include ++#include ++#include ++#include ++#include ++#include "ctags-utils.h" ++ ++static kindOption Kinds [] = { ++ { TRUE, 'f', "function", "functions"}, ++ { TRUE, 'c', "class", "classes"}, ++ { TRUE, 'm', "method", "methods"}, ++ { TRUE, 'p', "property", "properties"}, ++ { TRUE, 'v', "variable", "global variables"} ++}; ++ ++static void ++initialize (const langType language) ++{ ++} ++ ++static void ++parse_function (xmlNode *node, const gchar *parent) ++{ ++ xmlNode *i, *k; ++ gchar *name; ++ tagEntryInfo *tag; ++ ++ g_assert (node != NULL); ++ ++ name = (gchar*)xmlGetProp (node, (xmlChar*)"name"); ++ if (!name) ++ return; ++ ++ tag = (tagEntryInfo*)malloc (sizeof (tagEntryInfo)); ++ initTagEntry (tag, name); ++ get_file_pos (node->line, &tag->filePosition, File.fp); ++ tag->lineNumber = node->line; ++ tag->isFileScope = 1; ++ tag->kindName = "function"; ++ tag->kind = 'f'; ++ if (parent) { ++ tag->kindName = "member"; ++ tag->kind = 'm'; ++ tag->extensionFields.scope[0] = "class"; ++ tag->extensionFields.scope[1] = parent; ++ } ++ ++ for (i = node->children; i; i = i->next) ++ { ++ if (!i->name) ++ continue; ++ if (strcmp ((const gchar*)i->name, "return-value") == 0) ++ { ++ for (k = i->children; k; k = k->next) ++ { ++ const gchar *tmp; ++ if (!k->name) ++ continue; ++ tmp = (const gchar*)xmlGetProp (k, (const xmlChar*)"name"); ++ if (!tmp) ++ continue; ++ tag->extensionFields.returnType = tmp; ++ } ++ } ++ if (strcmp ((const gchar*)i->name, "parameters") == 0) ++ { ++ for (k = i->children; k; k = k->next) ++ { ++/*TODO: const gchar *name; ++ if (!k->name) ++ continue; ++ name = (const gchar*)xmlGetProp (node, (const xmlChar*)"name"); ++ if (!name) ++ continue; ++ tmp = g_new (Argument, 1); ++ tmp->name = g_strdup (name); ++ tmp->types = NULL; ++ ret->args = g_list_append (ret->args, tmp);*/ ++ } ++ } ++ } ++ makeTagEntry (tag); ++} ++ ++static void makeTags (xmlNode *node, const gchar *parent); ++ ++static void ++parse_class (xmlNode *node) ++{ ++ xmlNode *i; ++ gchar *name; ++ ++ g_assert (node); ++ ++ name = (gchar*)xmlGetProp (node, (const xmlChar*)"name"); ++ if (!name) ++ return; ++ ++ tagEntryInfo *tag = (tagEntryInfo*)malloc (sizeof (tagEntryInfo)); ++ initTagEntry (tag, name); ++ tag->isFileScope = 1; ++ tag->kindName = "class"; ++ tag->kind = 'c'; ++ get_file_pos (node->line, &tag->filePosition, File.fp); ++ tag->lineNumber = node->line; ++ makeTagEntry (tag); ++ ++ for (i = node->children; i; i = i->next) ++ { ++ makeTags (i, name); ++ } ++} ++ ++static void ++makeTags (xmlNode *node, const gchar *parent) ++{ ++ g_assert (node != NULL); ++ g_assert (node->name != NULL); ++ ++ if (strcmp ((const gchar*)node->name, "text") == 0 ++ || strcmp ((const gchar*)node->name, "implements") == 0) ++ return; ++ if (strcmp ((const gchar*)node->name, "enumeration") == 0 ++ || strcmp ((const gchar*)node->name, "union") == 0 ++ || strcmp ((const gchar*)node->name, "namespace") == 0 ++ || strcmp ((const gchar*)node->name, "class") == 0 ++ || strcmp ((const gchar*)node->name, "record") == 0 ++ || strcmp ((const gchar*)node->name, "bitfield") == 0 ++ || strcmp ((const gchar*)node->name, "interface") == 0) ++ { ++ parse_class (node); ++ return; ++ } ++ if (strcmp ((const gchar*)node->name, "function") == 0 || strcmp ((const gchar*)node->name, "method") == 0 ++ || strcmp ((const gchar*)node->name, "callback") == 0 ++ || strcmp ((const gchar*)node->name, "constructor") == 0) ++ { ++ parse_function (node, parent); ++ return; ++ } ++ if (strcmp ((const gchar*)node->name, "alias") == 0 || ++ strcmp ((const gchar*)node->name, "constant") == 0 || ++ strcmp ((const gchar*)node->name, "signal") == 0 || ++ strcmp ((const gchar*)node->name, "field") == 0 || ++ strcmp ((const gchar*)node->name, "property") == 0 || ++ strcmp ((const gchar*)node->name, "member") == 0) ++ { ++ gchar *name = (gchar*)xmlGetProp (node, (const xmlChar*)"name"); ++ if (!name) ++ return; ++ tagEntryInfo *tag = (tagEntryInfo*)malloc (sizeof (tagEntryInfo)); ++ initTagEntry (tag, name); ++ tag->isFileScope = 1; ++ tag->kindName = "variable"; ++ tag->kind = 'v'; ++ get_file_pos (node->line, &tag->filePosition, File.fp); ++ tag->lineNumber = node->line; ++ if (parent) { ++ tag->kindName = "member"; ++ tag->kind = 'm'; ++ tag->extensionFields.scope[0] = "class"; ++ tag->extensionFields.scope[1] = parent; ++ } ++ makeTagEntry (tag); ++ return; ++ } ++} ++ ++static void ++findTags (void) ++{ ++ xmlNode *i; ++ xmlDocPtr doc = xmlParseFile(getInputFileName()); ++ xmlNode *root; ++ ++ if (doc == NULL) { ++ g_warning ("could not parse file"); ++ } ++ root = xmlDocGetRootElement(doc); ++ for (i = root->children; i; i = i->next) ++ { ++ xmlNode *j; ++ if (!i->name) ++ continue; ++ if (strcmp ((const char*)i->name, "namespace") !=0) ++ continue; ++ for (j = i->children; j; j = j->next) ++ { ++ makeTags (j, NULL); ++ } ++ } ++} ++ ++extern parserDefinition* ++GirParser (void) ++{ ++ static const char *const extensions [] = { "gir", NULL }; ++ parserDefinition *const def = parserNew ("GObject-Introspection"); ++ def->extensions = extensions; ++ ++ def->kinds = Kinds; ++ def->kindCount = KIND_COUNT (Kinds); ++ def->parser = findTags; ++ def->initialize = initialize; ++ ++ return def; ++} +diff --git a/lregex.c b/lregex.c +index 59f5df6..37d7ea0 100644 +--- a/lregex.c ++++ b/lregex.c +@@ -1,5 +1,5 @@ + /* +-* $Id: lregex.c 576 2007-06-30 04:16:23Z elliotth $ ++* $Id: lregex.c 747 2009-11-06 02:33:37Z dhiebert $ + * + * Copyright (c) 2000-2003, Darren Hiebert + * +@@ -408,7 +408,7 @@ static void processLanguageRegex (const langType language, + const char* regexfile = parameter + 1; + FILE* const fp = fopen (regexfile, "r"); + if (fp == NULL) +- error (WARNING | PERROR, regexfile); ++ error (WARNING | PERROR, "%s", regexfile); + else + { + vString* const regex = vStringNew (); +diff --git a/make.c b/make.c +index f468b5a..7b56830 100644 +--- a/make.c ++++ b/make.c +@@ -1,5 +1,5 @@ + /* +-* $Id: make.c 681 2008-10-12 22:43:00Z dhiebert $ ++* $Id: make.c 751 2010-02-27 17:41:57Z elliotth $ + * + * Copyright (c) 2000-2005, Darren Hiebert + * +@@ -100,7 +100,7 @@ static void skipToMatch (const char *const pair) + ++matchLevel; + else if (c == end) + --matchLevel; +- else if (c == '\n') ++ else if (c == '\n' || c == EOF) + break; + } + if (c == EOF) +diff --git a/options.c b/options.c +index d26627f..1bee61d 100644 +--- a/options.c ++++ b/options.c +@@ -119,6 +119,7 @@ optionValues Option = { + FALSE, /* -fields=n */ + TRUE, /* -fields=s */ + FALSE, /* -fields=S */ ++ FALSE, /* -fields=T */ + TRUE /* -fields=t */ + }, + NULL, /* -I */ +@@ -208,7 +209,7 @@ static optionDescription LongOptionDescription [] = { + {1," --extra=[+|-]flags"}, + {1," Include extra tag entries for selected information (flags: \"fq\")."}, + {1," --fields=[+|-]flags"}, +- {1," Include selected extension fields (flags: \"afmikKlnsStz\") [fks]."}, ++ {1," Include selected extension fields (flags: \"afmikKlnsStTz\") [fks]."}, + {1," --file-scope=[yes|no]"}, + {1," Should tags scoped only for a single file (e.g. \"static\" tags"}, + {1," be included in the output [yes]?"}, +@@ -291,7 +292,7 @@ static const char* const License2 = + "\n" + "You should have received a copy of the GNU General Public License\n" + "along with this program; if not, write to the Free Software\n" +-"Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\n"; ++"Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n"; + + /* Contains a set of strings describing the set of "features" compiled into + * the code. +@@ -859,6 +860,7 @@ static void processFieldsOption ( + case 'S': field->signature = mode; break; + case 'z': field->kindKey = mode; break; + case 't': field->typeRef = mode; break; ++ case 'T': field->returnType = mode; break; + + default: error(WARNING, "Unsupported parameter '%c' for \"%s\" option", + c, option); +diff --git a/options.h b/options.h +index 34150e7..28b276f 100644 +--- a/options.h ++++ b/options.h +@@ -77,6 +77,7 @@ struct sExtFields { /* extension field content control */ + boolean lineNumber; + boolean scope; + boolean signature; ++ boolean returnType; + boolean typeRef; + }; + +diff --git a/parsers.h b/parsers.h +index 3dcc8ae..e4a50e1 100644 +--- a/parsers.h ++++ b/parsers.h +@@ -15,6 +15,7 @@ + #define _PARSERS_H + + /* Add the name of any new parser definition function here */ ++#ifndef ENABLE_VALA + #define PARSER_LIST \ + AntParser, \ + AsmParser, \ +@@ -57,6 +58,52 @@ + VhdlParser, \ + VimParser, \ + YaccParser ++#else ++#define PARSER_LIST \ ++ AntParser, \ ++ AsmParser, \ ++ AspParser, \ ++ AwkParser, \ ++ BasicParser, \ ++ BetaParser, \ ++ CParser, \ ++ CppParser, \ ++ CsharpParser, \ ++ CobolParser, \ ++ DosBatchParser, \ ++ EiffelParser, \ ++ ErlangParser, \ ++ FlexParser, \ ++ FortranParser, \ ++ GenieParser, \ ++ HtmlParser, \ ++ JavaParser, \ ++ JavaScriptParser, \ ++ LispParser, \ ++ LuaParser, \ ++ MakefileParser, \ ++ MatLabParser, \ ++ OcamlParser, \ ++ PascalParser, \ ++ PerlParser, \ ++ PhpParser, \ ++ PythonParser, \ ++ RexxParser, \ ++ RubyParser, \ ++ SchemeParser, \ ++ ShParser, \ ++ SlangParser, \ ++ SmlParser, \ ++ SqlParser, \ ++ TclParser, \ ++ TexParser, \ ++ ValaParse, \ ++ VeraParser, \ ++ VerilogParser, \ ++ VhdlParser, \ ++ VimParser, \ ++ YaccParser ++#endif + + #endif /* _PARSERS_H */ + +diff --git a/php.c b/php.c +index 0dd60c5..90e096a 100644 +--- a/php.c ++++ b/php.c +@@ -1,5 +1,5 @@ + /* +-* $Id: php.c 624 2007-09-15 22:53:31Z jafl $ ++* $Id: php.c 734 2009-08-20 23:33:54Z jafl $ + * + * Copyright (c) 2000, Jesus Castagnetto + * +@@ -64,17 +64,17 @@ static kindOption PhpKinds [] = { + + static void installPHPRegex (const langType language) + { +- addTagRegex(language, "(^|[ \t])class[ \t]+([" ALPHA "_][" ALNUM "_]*)", +- "\\2", "c,class,classes", NULL); +- addTagRegex(language, "(^|[ \t])interface[ \t]+([" ALPHA "_][" ALNUM "_]*)", +- "\\2", "i,interface,interfaces", NULL); +- addTagRegex(language, "(^|[ \t])define[ \t]*\\([ \t]*['\"]?([" ALPHA "_][" ALNUM "_]*)", +- "\\2", "d,define,constant definitions", NULL); +- addTagRegex(language, "(^|[ \t])function[ \t]+&?[ \t]*([" ALPHA "_][" ALNUM "_]*)", +- "\\2", "f,function,functions", NULL); +- addTagRegex(language, "(^|[ \t])(\\$|::\\$|\\$this->)([" ALPHA "_][" ALNUM "_]*)[ \t]*=", +- "\\3", "v,variable,variables", NULL); +- addTagRegex(language, "(^|[ \t])(var|public|protected|private|static)[ \t]+\\$([" ALPHA "_][" ALNUM "_]*)[ \t]*[=;]", ++ addTagRegex(language, "^[ \t]*((final|abstract)[ \t]+)*class[ \t]+([" ALPHA "_][" ALNUM "_]*)", ++ "\\3", "c,class,classes", NULL); ++ addTagRegex(language, "^[ \t]*interface[ \t]+([" ALPHA "_][" ALNUM "_]*)", ++ "\\1", "i,interface,interfaces", NULL); ++ addTagRegex(language, "^[ \t]*define[ \t]*\\([ \t]*['\"]?([" ALPHA "_][" ALNUM "_]*)", ++ "\\1", "d,define,constant definitions", NULL); ++ addTagRegex(language, "^[ \t]*((static|public|protected|private)[ \t]+)*function[ \t]+&?[ \t]*([" ALPHA "_][" ALNUM "_]*)", ++ "\\3", "f,function,functions", NULL); ++ addTagRegex(language, "^[ \t]*(\\$|::\\$|\\$this->)([" ALPHA "_][" ALNUM "_]*)[ \t]*=", ++ "\\2", "v,variable,variables", NULL); ++ addTagRegex(language, "^[ \t]*((var|public|protected|private|static)[ \t]+)+\\$([" ALPHA "_][" ALNUM "_]*)[ \t]*[=;]", + "\\3", "v,variable,variables", NULL); + + /* function regex is covered by PHP regex */ +diff --git a/python.c b/python.c +index 5fdf31b..a90d072 100644 +--- a/python.c ++++ b/python.c +@@ -1,5 +1,5 @@ + /* +-* $Id: python.c 720 2009-07-07 03:55:23Z dhiebert $ ++* $Id: python.c 752 2010-02-27 17:52:46Z elliotth $ + * + * Copyright (c) 2000-2003, Darren Hiebert + * +@@ -240,7 +240,7 @@ static const char *skipEverything (const char *cp) + { + for (; *cp; cp++) + { +- if (*cp == '"' || *cp == '\'') ++ if (*cp == '"' || *cp == '\'' || *cp == '#') + { + cp = skipString(cp); + if (!*cp) break; +@@ -398,7 +398,9 @@ static void parseFunction (const char *cp, vString *const def, + cp = parseIdentifier (cp, def); + arglist = parseArglist (cp); + makeFunctionTag (def, parent, is_class_parent, arglist); +- eFree (arglist); ++ if (arglist != NULL) { ++ eFree (arglist); ++ } + } + + /* Get the combined name of a nested symbol. Classes are separated with ".", +diff --git a/sort.c b/sort.c +index 09ba87a..c58defc 100644 +--- a/sort.c ++++ b/sort.c +@@ -1,5 +1,5 @@ + /* +-* $Id: sort.c 498 2007-02-17 22:43:15Z dhiebert $ ++* $Id: sort.c 747 2009-11-06 02:33:37Z dhiebert $ + * + * Copyright (c) 1996-2002, Darren Hiebert + * +@@ -109,7 +109,7 @@ static void failedSort (FILE *const fp, const char* msg) + if (fp != NULL) + fclose (fp); + if (msg == NULL) +- error (FATAL | PERROR, cannotSort); ++ error (FATAL | PERROR, "%s", cannotSort); + else + error (FATAL, "%s: %s", msg, cannotSort); + } +diff --git a/sql.c b/sql.c +index efe7e5d..6c0c76a 100644 +--- a/sql.c ++++ b/sql.c +@@ -1,5 +1,5 @@ + /* +- * $Id: sql.c 703 2009-03-14 22:06:12Z dfishburn $ ++ * $Id: sql.c 745 2009-10-27 02:42:55Z dfishburn $ + * + * Copyright (c) 2002-2003, Darren Hiebert + * +@@ -65,9 +65,14 @@ typedef enum eKeywordId { + KEYWORD_end, + KEYWORD_function, + KEYWORD_if, ++ KEYWORD_else, ++ KEYWORD_elseif, ++ KEYWORD_endif, + KEYWORD_loop, ++ KEYWORD_while, + KEYWORD_case, + KEYWORD_for, ++ KEYWORD_do, + KEYWORD_call, + KEYWORD_package, + KEYWORD_pragma, +@@ -114,6 +119,7 @@ typedef enum eKeywordId { + KEYWORD_ml_conn_dnet, + KEYWORD_ml_conn_java, + KEYWORD_ml_conn_chk, ++ KEYWORD_ml_prop, + KEYWORD_local, + KEYWORD_temporary, + KEYWORD_drop, +@@ -140,6 +146,7 @@ typedef enum eTokenType { + TOKEN_BLOCK_LABEL_END, + TOKEN_CHARACTER, + TOKEN_CLOSE_PAREN, ++ TOKEN_COLON, + TOKEN_SEMICOLON, + TOKEN_COMMA, + TOKEN_IDENTIFIER, +@@ -154,7 +161,8 @@ typedef enum eTokenType { + TOKEN_OPEN_SQUARE, + TOKEN_CLOSE_SQUARE, + TOKEN_TILDE, +- TOKEN_FORWARD_SLASH ++ TOKEN_FORWARD_SLASH, ++ TOKEN_EQUAL + } tokenType; + + typedef struct sTokenInfoSQL { +@@ -198,6 +206,7 @@ typedef enum { + SQLTAG_SYNONYM, + SQLTAG_MLTABLE, + SQLTAG_MLCONN, ++ SQLTAG_MLPROP, + SQLTAG_COUNT + } sqlKind; + +@@ -223,7 +232,8 @@ static kindOption SqlKinds [] = { + { TRUE, 'V', "view", "views" }, + { TRUE, 'n', "synonym", "synonyms" }, + { TRUE, 'x', "mltable", "MobiLink Table Scripts" }, +- { TRUE, 'y', "mlconn", "MobiLink Conn Scripts" } ++ { TRUE, 'y', "mlconn", "MobiLink Conn Scripts" }, ++ { TRUE, 'z', "mlprop", "MobiLink Properties " } + }; + + static const keywordDesc SqlKeywordTable [] = { +@@ -237,9 +247,14 @@ static const keywordDesc SqlKeywordTable [] = { + { "end", KEYWORD_end }, + { "function", KEYWORD_function }, + { "if", KEYWORD_if }, ++ { "else", KEYWORD_else }, ++ { "elseif", KEYWORD_elseif }, ++ { "endif", KEYWORD_endif }, + { "loop", KEYWORD_loop }, ++ { "while", KEYWORD_while }, + { "case", KEYWORD_case }, + { "for", KEYWORD_for }, ++ { "do", KEYWORD_do }, + { "call", KEYWORD_call }, + { "package", KEYWORD_package }, + { "pragma", KEYWORD_pragma }, +@@ -286,6 +301,7 @@ static const keywordDesc SqlKeywordTable [] = { + { "ml_add_dnet_connection_script", KEYWORD_ml_conn_dnet }, + { "ml_add_java_connection_script", KEYWORD_ml_conn_java }, + { "ml_add_lang_conn_script_chk", KEYWORD_ml_conn_chk }, ++ { "ml_add_property", KEYWORD_ml_prop }, + { "local", KEYWORD_local }, + { "temporary", KEYWORD_temporary }, + { "drop", KEYWORD_drop }, +@@ -303,6 +319,7 @@ static const keywordDesc SqlKeywordTable [] = { + + /* Recursive calls */ + static void parseBlock (tokenInfo *const token, const boolean local); ++static void parseDeclare (tokenInfo *const token, const boolean local); + static void parseKeywords (tokenInfo *const token); + static void parseSqlFile (tokenInfo *const token); + +@@ -541,6 +558,7 @@ getNextChar: + case EOF: longjmp (Exception, (int)ExceptionEOF); break; + case '(': token->type = TOKEN_OPEN_PAREN; break; + case ')': token->type = TOKEN_CLOSE_PAREN; break; ++ case ':': token->type = TOKEN_COLON; break; + case ';': token->type = TOKEN_SEMICOLON; break; + case '.': token->type = TOKEN_PERIOD; break; + case ',': token->type = TOKEN_COMMA; break; +@@ -549,6 +567,7 @@ getNextChar: + case '~': token->type = TOKEN_TILDE; break; + case '[': token->type = TOKEN_OPEN_SQUARE; break; + case ']': token->type = TOKEN_CLOSE_SQUARE; break; ++ case '=': token->type = TOKEN_EQUAL; break; + + case '\'': + case '"': +@@ -770,7 +789,7 @@ static void skipArgumentList (tokenInfo *const token) + * Other databases can have arguments with fully declared + * datatypes: + * ( name varchar(30), text binary(10) ) +- * So we must check for nested open and closing parantheses ++ * So we must check for nested open and closing parentheses + */ + + if (isType (token, TOKEN_OPEN_PAREN)) /* arguments? */ +@@ -848,7 +867,7 @@ static void parseSubProgram (tokenInfo *const token) + /* + * Read token after which could be the + * command terminator if a prototype +- * or an open parantheses ++ * or an open parenthesis + */ + readToken (token); + if (isType (token, TOKEN_OPEN_PAREN)) +@@ -870,6 +889,7 @@ static void parseSubProgram (tokenInfo *const token) + isKeyword (token, KEYWORD_internal) || + isKeyword (token, KEYWORD_external) || + isKeyword (token, KEYWORD_url) || ++ isType (token, TOKEN_EQUAL) || + isCmdTerm (token) + ) + ) +@@ -900,6 +920,12 @@ static void parseSubProgram (tokenInfo *const token) + + vStringClear (token->scope); + } ++ if ( isType (token, TOKEN_EQUAL) ) ++ readToken (token); ++ ++ if ( isKeyword (token, KEYWORD_declare) ) ++ parseDeclare (token, FALSE); ++ + if (isKeyword (token, KEYWORD_is) || + isKeyword (token, KEYWORD_begin) ) + { +@@ -1066,18 +1092,18 @@ static void parseDeclare (tokenInfo *const token, const boolean local) + case KEYWORD_type: parseType (token); break; + + default: +- if (isType (token, TOKEN_IDENTIFIER)) +- { +- if (local) +- { +- makeSqlTag (token, SQLTAG_LOCAL_VARIABLE); +- } +- else +- { +- makeSqlTag (token, SQLTAG_VARIABLE); +- } +- } +- break; ++ if (isType (token, TOKEN_IDENTIFIER)) ++ { ++ if (local) ++ { ++ makeSqlTag (token, SQLTAG_LOCAL_VARIABLE); ++ } ++ else ++ { ++ makeSqlTag (token, SQLTAG_VARIABLE); ++ } ++ } ++ break; + } + findToken (token, TOKEN_SEMICOLON); + readToken (token); +@@ -1164,12 +1190,13 @@ static void parseLabel (tokenInfo *const token) + } + } + +-static void parseStatements (tokenInfo *const token) ++static void parseStatements (tokenInfo *const token, const boolean exit_on_endif ) + { + boolean isAnsi = TRUE; + boolean stmtTerm = FALSE; + do + { ++ + if (isType (token, TOKEN_BLOCK_LABEL_BEGIN)) + parseLabel (token); + else +@@ -1210,6 +1237,7 @@ static void parseStatements (tokenInfo *const token) + */ + while (! isKeyword (token, KEYWORD_then)) + readToken (token); ++ + readToken (token); + continue; + +@@ -1220,6 +1248,15 @@ static void parseStatements (tokenInfo *const token) + * IF...THEN + * END IF; + * ++ * IF...THEN ++ * ELSE ++ * END IF; ++ * ++ * IF...THEN ++ * ELSEIF...THEN ++ * ELSE ++ * END IF; ++ * + * or non-ANSI + * IF ... + * BEGIN +@@ -1248,7 +1285,22 @@ static void parseStatements (tokenInfo *const token) + else + { + readToken (token); +- parseStatements (token); ++ ++ while( ! (isKeyword (token, KEYWORD_end ) || ++ isKeyword (token, KEYWORD_endif ) ) ++ ) ++ { ++ if ( isKeyword (token, KEYWORD_else) || ++ isKeyword (token, KEYWORD_elseif) ) ++ readToken (token); ++ ++ parseStatements (token, TRUE); ++ ++ if ( isCmdTerm(token) ) ++ readToken (token); ++ ++ } ++ + /* + * parseStatements returns when it finds an END, an IF + * should follow the END for ANSI anyway. +@@ -1258,7 +1310,13 @@ static void parseStatements (tokenInfo *const token) + if( isKeyword (token, KEYWORD_end ) ) + readToken (token); + +- if( ! isKeyword (token, KEYWORD_if ) ) ++ if( isKeyword (token, KEYWORD_if ) || isKeyword (token, KEYWORD_endif ) ) ++ { ++ readToken (token); ++ if ( isCmdTerm(token) ) ++ stmtTerm = TRUE; ++ } ++ else + { + /* + * Well we need to do something here. +@@ -1284,14 +1342,64 @@ static void parseStatements (tokenInfo *const token) + * END CASE; + * + * FOR loop_name AS cursor_name CURSOR FOR ... ++ * DO + * END FOR; + */ ++ if( isKeyword (token, KEYWORD_for ) ) ++ { ++ /* loop name */ ++ readToken (token); ++ /* AS */ ++ readToken (token); ++ ++ while ( ! isKeyword (token, KEYWORD_is) ) ++ { ++ /* ++ * If this is not an AS keyword this is ++ * not a proper FOR statement and should ++ * simply be ignored ++ */ ++ return; ++ } ++ ++ while ( ! isKeyword (token, KEYWORD_do) ) ++ readToken (token); ++ } ++ ++ + readToken (token); +- parseStatements (token); ++ while( ! isKeyword (token, KEYWORD_end ) ) ++ { ++ /* ++ if ( isKeyword (token, KEYWORD_else) || ++ isKeyword (token, KEYWORD_elseif) ) ++ readToken (token); ++ */ ++ ++ parseStatements (token, FALSE); ++ ++ if ( isCmdTerm(token) ) ++ readToken (token); ++ } ++ + + if( isKeyword (token, KEYWORD_end ) ) + readToken (token); + ++ /* ++ * Typically ended with ++ * END LOOP [loop name]; ++ * END CASE ++ * END FOR [loop name]; ++ */ ++ if ( isKeyword (token, KEYWORD_loop) || ++ isKeyword (token, KEYWORD_case) || ++ isKeyword (token, KEYWORD_for) ) ++ readToken (token); ++ ++ if ( isCmdTerm(token) ) ++ stmtTerm = TRUE; ++ + break; + + case KEYWORD_create: +@@ -1324,11 +1432,36 @@ static void parseStatements (tokenInfo *const token) + * + * So we must read to the first semi-colon or an END block + */ +- while ( ! stmtTerm && +- ! ( isKeyword (token, KEYWORD_end) || +- (isCmdTerm(token)) ) ++ while ( ! stmtTerm && ++ ! ( isKeyword (token, KEYWORD_end) || ++ (isCmdTerm(token)) ) + ) + { ++ if ( isKeyword (token, KEYWORD_endif) && ++ exit_on_endif ) ++ return; ++ ++ if (isType (token, TOKEN_COLON) ) ++ { ++ /* ++ * A : can signal a loop name ++ * myloop: ++ * LOOP ++ * LEAVE myloop; ++ * END LOOP; ++ * Unfortunately, labels do not have a ++ * cmd terminator, therefore we have to check ++ * if the next token is a keyword and process ++ * it accordingly. ++ */ ++ readToken (token); ++ if ( isKeyword (token, KEYWORD_loop) || ++ isKeyword (token, KEYWORD_while) || ++ isKeyword (token, KEYWORD_for) ) ++ /* parseStatements (token); */ ++ return; ++ } ++ + readToken (token); + + if (isType (token, TOKEN_OPEN_PAREN) || +@@ -1336,6 +1469,20 @@ static void parseStatements (tokenInfo *const token) + isType (token, TOKEN_OPEN_SQUARE) ) + skipToMatched (token); + ++ /* ++ * Since we know how to parse various statements ++ * if we detect them, parse them to completion ++ */ ++ if (isType (token, TOKEN_BLOCK_LABEL_BEGIN) || ++ isKeyword (token, KEYWORD_exception) || ++ isKeyword (token, KEYWORD_loop) || ++ isKeyword (token, KEYWORD_case) || ++ isKeyword (token, KEYWORD_for) || ++ isKeyword (token, KEYWORD_begin) ) ++ parseStatements (token, FALSE); ++ else if (isKeyword (token, KEYWORD_if)) ++ parseStatements (token, TRUE); ++ + } + } + /* +@@ -1343,11 +1490,12 @@ static void parseStatements (tokenInfo *const token) + * See comment above, now, only read if the current token + * is not a command terminator. + */ +- if ( isCmdTerm(token) ) +- { +- readToken (token); +- } +- } while (! isKeyword (token, KEYWORD_end) && ! stmtTerm ); ++ if ( isCmdTerm(token) && ! stmtTerm ) ++ stmtTerm = TRUE; ++ ++ } while (! isKeyword (token, KEYWORD_end) && ++ ! (exit_on_endif && isKeyword (token, KEYWORD_endif) ) && ++ ! stmtTerm ); + } + + static void parseBlock (tokenInfo *const token, const boolean local) +@@ -1378,7 +1526,10 @@ static void parseBlock (tokenInfo *const token, const boolean local) + token->begin_end_nest_lvl++; + while (! isKeyword (token, KEYWORD_end)) + { +- parseStatements (token); ++ parseStatements (token, FALSE); ++ ++ if ( isCmdTerm(token) ) ++ readToken (token); + } + token->begin_end_nest_lvl--; + +@@ -1994,6 +2145,70 @@ static void parseMLConn (tokenInfo *const token) + deleteToken (event); + } + ++static void parseMLProp (tokenInfo *const token) ++{ ++ tokenInfo *const component = newToken (); ++ tokenInfo *const prop_set_name = newToken (); ++ tokenInfo *const prop_name = newToken (); ++ ++ /* ++ * This deals with these formats ++ * ml_add_property ( ++ * 'comp_name', ++ * 'prop_set_name', ++ * 'prop_name', ++ * 'prop_value' ++ * ) ++ */ ++ ++ readToken (token); ++ if ( isType (token, TOKEN_OPEN_PAREN) ) ++ { ++ readToken (component); ++ readToken (token); ++ while (!(isType (token, TOKEN_COMMA) || ++ isType (token, TOKEN_CLOSE_PAREN) ++ )) ++ { ++ readToken (token); ++ } ++ ++ if (isType (token, TOKEN_COMMA)) ++ { ++ readToken (prop_set_name); ++ readToken (token); ++ while (!(isType (token, TOKEN_COMMA) || ++ isType (token, TOKEN_CLOSE_PAREN) ++ )) ++ { ++ readToken (token); ++ } ++ ++ if (isType (token, TOKEN_COMMA)) ++ { ++ readToken (prop_name); ++ ++ if (isType (component, TOKEN_STRING) && ++ isType (prop_set_name, TOKEN_STRING) && ++ isType (prop_name, TOKEN_STRING) ) ++ { ++ addToScope(component, prop_set_name->string); ++ addToScope(component, prop_name->string); ++ makeSqlTag (component, SQLTAG_MLPROP); ++ } ++ } ++ if( !isType (token, TOKEN_CLOSE_PAREN) ) ++ findToken (token, TOKEN_CLOSE_PAREN); ++ } ++ } ++ ++ findCmdTerm (token, TRUE); ++ ++ deleteToken (component); ++ deleteToken (prop_set_name); ++ deleteToken (prop_name); ++} ++ + static void parseComment (tokenInfo *const token) + { + /* +@@ -2039,7 +2254,7 @@ static void parseKeywords (tokenInfo *const token) + case KEYWORD_drop: parseDrop (token); break; + case KEYWORD_event: parseEvent (token); break; + case KEYWORD_function: parseSubProgram (token); break; +- case KEYWORD_if: parseStatements (token); break; ++ case KEYWORD_if: parseStatements (token, FALSE); break; + case KEYWORD_index: parseIndex (token); break; + case KEYWORD_ml_table: parseMLTable (token); break; + case KEYWORD_ml_table_lang: parseMLTable (token); break; +@@ -2051,6 +2266,7 @@ static void parseKeywords (tokenInfo *const token) + case KEYWORD_ml_conn_dnet: parseMLConn (token); break; + case KEYWORD_ml_conn_java: parseMLConn (token); break; + case KEYWORD_ml_conn_chk: parseMLConn (token); break; ++ case KEYWORD_ml_prop: parseMLProp (token); break; + case KEYWORD_package: parsePackage (token); break; + case KEYWORD_procedure: parseSubProgram (token); break; + case KEYWORD_publication: parsePublication (token); break; +diff --git a/test-cmd-line b/test-cmd-line +new file mode 100644 +index 0000000..980f6b9 +--- /dev/null ++++ b/test-cmd-line +@@ -0,0 +1 @@ ++./anjuta_tags --sort=no --fields=afmiKlnsStTz --c++-kinds=+p foo.cpp ; cat tags +diff --git a/tex.c b/tex.c +index a285797..0c6714e 100644 +--- a/tex.c ++++ b/tex.c +@@ -53,7 +53,8 @@ typedef enum eKeywordId { + KEYWORD_subsubsection, + KEYWORD_part, + KEYWORD_paragraph, +- KEYWORD_subparagraph ++ KEYWORD_subparagraph, ++ KEYWORD_include + } keywordId; + + /* Used to determine whether keyword is valid for the token language and +@@ -68,27 +69,15 @@ typedef enum eTokenType { + TOKEN_UNDEFINED, + TOKEN_CHARACTER, + TOKEN_CLOSE_PAREN, +- TOKEN_SEMICOLON, +- TOKEN_COLON, + TOKEN_COMMA, + TOKEN_KEYWORD, + TOKEN_OPEN_PAREN, +- TOKEN_OPERATOR, + TOKEN_IDENTIFIER, + TOKEN_STRING, +- TOKEN_PERIOD, + TOKEN_OPEN_CURLY, + TOKEN_CLOSE_CURLY, +- TOKEN_EQUAL_SIGN, +- TOKEN_EXCLAMATION, +- TOKEN_FORWARD_SLASH, + TOKEN_OPEN_SQUARE, + TOKEN_CLOSE_SQUARE, +- TOKEN_OPEN_MXML, +- TOKEN_CLOSE_MXML, +- TOKEN_CLOSE_SGML, +- TOKEN_LESS_THAN, +- TOKEN_GREATER_THAN, + TOKEN_QUESTION_MARK, + TOKEN_STAR + } tokenType; +@@ -118,6 +107,7 @@ typedef enum { + TEXTAG_PART, + TEXTAG_PARAGRAPH, + TEXTAG_SUBPARAGRAPH, ++ TEXTAG_INCLUDE, + TEXTAG_COUNT + } texKind; + +@@ -128,7 +118,8 @@ static kindOption TexKinds [] = { + { TRUE, 'b', "subsubsection", "subsubsections" }, + { TRUE, 'p', "part", "parts" }, + { TRUE, 'P', "paragraph", "paragraphs" }, +- { TRUE, 'G', "subparagraph", "subparagraphs" } ++ { TRUE, 'G', "subparagraph", "subparagraphs" }, ++ { TRUE, 'i', "include", "includes" } + }; + + static const keywordDesc TexKeywordTable [] = { +@@ -139,7 +130,8 @@ static const keywordDesc TexKeywordTable [] = { + { "subsubsection", KEYWORD_subsubsection }, + { "part", KEYWORD_part }, + { "paragraph", KEYWORD_paragraph }, +- { "subparagraph", KEYWORD_subparagraph } ++ { "subparagraph", KEYWORD_subparagraph }, ++ { "include", KEYWORD_include } + }; + + /* +@@ -150,7 +142,7 @@ static boolean isIdentChar (const int c) + { + return (boolean) + (isalpha (c) || isdigit (c) || c == '$' || +- c == '_' || c == '#'); ++ c == '_' || c == '#' || c == '-' || c == '.'); + } + + static void buildTexKeywordHash (void) +@@ -297,16 +289,11 @@ getNextChar: + case EOF: longjmp (Exception, (int)ExceptionEOF); break; + case '(': token->type = TOKEN_OPEN_PAREN; break; + case ')': token->type = TOKEN_CLOSE_PAREN; break; +- case ';': token->type = TOKEN_SEMICOLON; break; + case ',': token->type = TOKEN_COMMA; break; +- case '.': token->type = TOKEN_PERIOD; break; +- case ':': token->type = TOKEN_COLON; break; + case '{': token->type = TOKEN_OPEN_CURLY; break; + case '}': token->type = TOKEN_CLOSE_CURLY; break; +- case '=': token->type = TOKEN_EQUAL_SIGN; break; + case '[': token->type = TOKEN_OPEN_SQUARE; break; + case ']': token->type = TOKEN_CLOSE_SQUARE; break; +- case '?': token->type = TOKEN_QUESTION_MARK; break; + case '*': token->type = TOKEN_STAR; break; + + case '\'': +@@ -427,7 +414,8 @@ static boolean parseTag (tokenInfo *const token, texKind kind) + readToken (token); + while (! isType (token, TOKEN_CLOSE_CURLY) ) + { +- if (isType (token, TOKEN_IDENTIFIER) && useLongName) ++ /* if (isType (token, TOKEN_IDENTIFIER) && useLongName) */ ++ if (useLongName) + { + if (fullname->length > 0) + vStringCatS (fullname, " "); +@@ -479,6 +467,9 @@ static void parseTexFile (tokenInfo *const token) + case KEYWORD_subparagraph: + parseTag (token, TEXTAG_SUBPARAGRAPH); + break; ++ case KEYWORD_include: ++ parseTag (token, TEXTAG_INCLUDE); ++ break; + default: + break; + } +diff --git a/vala.c b/vala.c +new file mode 100644 +index 0000000..555ffc5 +--- /dev/null ++++ b/vala.c +@@ -0,0 +1,103 @@ ++/* ++ * vala.c ++ * ++ * Copyright 2008 Abderrahim Kitouni ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, ++ * MA 02110-1301, USA. ++ */ ++ ++/* ++ * INCLUDE FILES ++ */ ++#include "general.h" /* must always come first */ ++#include "parse.h" ++#include "read.h" ++ ++#include "entry.h" ++#include "ctags-vala.h" ++ ++CTagsVisitor *visitor; ++/* using different data structure because fpos_t isn't available in Vala*/ ++static void make_ctags_entry (CTagsEntry* entry) { ++ tagEntryInfo tag; ++ initTagEntry(&tag, entry->name); ++ ++ tag.lineNumberEntry = TRUE; ++ tag.lineNumber = entry->line_number; ++ tag.kindName = entry->kind_name; ++ tag.kind = entry->kind; ++ /* FIXME: add filePosition */ ++ tag.extensionFields.access = entry->access; ++ tag.extensionFields.implementation = entry->implementation; ++ tag.extensionFields.inheritance = entry->inheritance; ++ tag.extensionFields.scope[0] = entry->scope[0]; ++ tag.extensionFields.scope[1] = entry->scope[1]; ++ tag.extensionFields.typeRef[0] = entry->typeref; ++ tag.extensionFields.returnType = entry->returntype; ++ tag.extensionFields.signature = entry->signature; ++ makeTagEntry(&tag); ++} ++ ++static kindOption ValaKinds [] = { ++ { TRUE, 'c', "class", "Classes" }, ++ { TRUE, 's', "struct", "Structures" }, ++ { TRUE, 'i', "interface", "Interfaces" }, ++ { TRUE, 'e', "enum", "Enumerations" }, ++ { TRUE, 'v', "enumvalue", "Enumeration Values" }, ++ { TRUE, 'E', "errordomain", "Error domains" }, ++ { TRUE, 'r', "errorcode", "Error codes" }, ++ { TRUE, 'd', "delegate", "Delegates" }, ++ { TRUE, 'S', "signal", "Signals" }, ++ { TRUE, 'f', "field", "Fields" }, ++ { TRUE, 'p', "property", "Properties" }, ++ { TRUE, 'm', "method", "Methods" }, ++ { FALSE, 'l', "local", "Local variables" }, ++}; ++ ++static void findValaTags (void) { ++ if (visitor == NULL) { ++ visitor = ctags_visitor_new(); ++ } ++ ctags_visitor_parse_vala (visitor, getSourceFileName(), (CTagsEntryMaker) make_ctags_entry); ++} ++ ++extern parserDefinition *ValaParse(void) { ++ g_type_init(); ++ static const char *const extensions [] = { "vala", "vapi", NULL }; ++ parserDefinition* def = parserNew ("Vala"); ++ def->kinds = ValaKinds; ++ def->kindCount = KIND_COUNT (ValaKinds); ++ def->extensions = extensions; ++ def->parser = findValaTags; ++ return def; ++} ++ ++static void findGenieTags (void) { ++ if (visitor == NULL) { ++ visitor = ctags_visitor_new(); ++ } ++ ctags_visitor_parse_genie (visitor, getSourceFileName(), (CTagsEntryMaker) make_ctags_entry); ++} ++ ++extern parserDefinition *GenieParser(void) { ++ static const char *const extensions [] = { "gs", NULL }; ++ parserDefinition* def = parserNew ("Genie"); ++ def->kinds = ValaKinds; ++ def->kindCount = KIND_COUNT (ValaKinds); ++ def->extensions = extensions; ++ def->parser = findGenieTags; ++ return def; ++} +diff --git a/verilog.c b/verilog.c +index 814f5b0..52afc31 100644 +--- a/verilog.c ++++ b/verilog.c +@@ -1,5 +1,5 @@ + /* +-* $Id: verilog.c 573 2007-06-26 05:41:27Z elliotth $ ++* $Id: verilog.c 753 2010-02-27 17:53:32Z elliotth $ + * + * Copyright (c) 2003, Darren Hiebert + * +@@ -232,6 +232,7 @@ static void tagNameList (const verilogKind kind, int c) + c = skipWhite (c); + if (c == '=') + { ++ c = skipWhite (vGetc ()); + if (c == '{') + skipPastMatch ("{}"); + else +-- +2.11.0 + diff --git a/0002-Making-inline-behave-like-an-attribute.-Fixes-1.patch b/0002-Making-inline-behave-like-an-attribute.-Fixes-1.patch new file mode 100644 index 0000000..69f3761 --- /dev/null +++ b/0002-Making-inline-behave-like-an-attribute.-Fixes-1.patch @@ -0,0 +1,26 @@ +From 9362fa70eaa37250afd5b36adb68295b54ae5c99 Mon Sep 17 00:00:00 2001 +From: Federico Fissore +Date: Mon, 5 Oct 2015 11:27:36 +0200 +Subject: [PATCH 02/19] Making "inline" behave like an attribute. Fixes #1 + +--- + c.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/c.c b/c.c +index ccca3a4..af46dc4 100644 +--- a/c.c ++++ b/c.c +@@ -1732,7 +1732,8 @@ static void processToken (tokenInfo *const token, statementInfo *const st) + + case KEYWORD_NONE: processName (st); break; + case KEYWORD_ABSTRACT: st->implementation = IMP_ABSTRACT; break; +- case KEYWORD_ATTRIBUTE: skipParens (); initToken (token); break; ++ case KEYWORD_ATTRIBUTE: ++ case KEYWORD_INLINE: skipParens (); initToken (token); break; + case KEYWORD_BIND: st->declaration = DECL_BASE; break; + case KEYWORD_BIT: st->declaration = DECL_BASE; break; + case KEYWORD_CATCH: skipParens (); skipBraces (); break; +-- +2.11.0 + diff --git a/0003-Treat-typename-as-an-attribute.patch b/0003-Treat-typename-as-an-attribute.patch new file mode 100644 index 0000000..02f0832 --- /dev/null +++ b/0003-Treat-typename-as-an-attribute.patch @@ -0,0 +1,28 @@ +From 8c205231b591e954f763df794fc59a9f6a7e983b Mon Sep 17 00:00:00 2001 +From: Chris--A +Date: Thu, 8 Oct 2015 22:38:26 +1000 +Subject: [PATCH 03/19] Treat 'typename' as an attribute. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Relates to #1 +--- + c.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/c.c b/c.c +index af46dc4..ef81067 100644 +--- a/c.c ++++ b/c.c +@@ -1733,6 +1733,7 @@ static void processToken (tokenInfo *const token, statementInfo *const st) + case KEYWORD_NONE: processName (st); break; + case KEYWORD_ABSTRACT: st->implementation = IMP_ABSTRACT; break; + case KEYWORD_ATTRIBUTE: ++ case KEYWORD_TYPENAME: + case KEYWORD_INLINE: skipParens (); initToken (token); break; + case KEYWORD_BIND: st->declaration = DECL_BASE; break; + case KEYWORD_BIT: st->declaration = DECL_BASE; break; +-- +2.11.0 + diff --git a/0004-parseReturnType-should-start-from-the-first-non-brac.patch b/0004-parseReturnType-should-start-from-the-first-non-brac.patch new file mode 100644 index 0000000..9b75c34 --- /dev/null +++ b/0004-parseReturnType-should-start-from-the-first-non-brac.patch @@ -0,0 +1,57 @@ +From 3b6e9256061bfcb70d2540c49b074b4be0ace4be Mon Sep 17 00:00:00 2001 +From: Federico Fissore +Date: Wed, 4 Nov 2015 12:48:02 +0100 +Subject: [PATCH 04/19] parseReturnType should start from the first non-brace + token + +--- + c.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/c.c b/c.c +index ef81067..727d6bb 100644 +--- a/c.c ++++ b/c.c +@@ -567,7 +567,6 @@ static const char *implementationString (const impType imp) + /* + * Debugging functions + */ +-#define DEBUG + #ifdef DEBUG + + #define boolString(c) ((c) ? "TRUE" : "FALSE") +@@ -2120,6 +2119,7 @@ static void parseReturnType (statementInfo *const st) + { + int i; + int lower_bound; ++ int upper_bound; + tokenInfo * finding_tok; + + /* FIXME TODO: if java language must be supported then impement this here +@@ -2161,8 +2161,21 @@ static void parseReturnType (statementInfo *const st) + } + else + lower_bound = 1; +- +- for (i = (unsigned int) NumTokens; i > lower_bound; i--) ++ ++ upper_bound = -1; ++ for (i = 0; i < NumTokens; i++) { ++ tokenInfo *curr_tok; ++ curr_tok = prevToken (st, i); ++ if (curr_tok->type == TOKEN_BRACE_CLOSE || curr_tok->type == TOKEN_BRACE_OPEN) { ++ upper_bound = i - 1; ++ break; ++ } ++ } ++ if (upper_bound < 0) { ++ upper_bound = NumTokens - 1; ++ } ++ ++ for (i = upper_bound; i > lower_bound; i--) + { + tokenInfo * curr_tok; + curr_tok = prevToken (st, i); +-- +2.11.0 + diff --git a/0005-Ensuring-a-space-is-printed-in-return-type-AFTER-the.patch b/0005-Ensuring-a-space-is-printed-in-return-type-AFTER-the.patch new file mode 100644 index 0000000..66cd72c --- /dev/null +++ b/0005-Ensuring-a-space-is-printed-in-return-type-AFTER-the.patch @@ -0,0 +1,32 @@ +From b27f1a9c3468618eb6b2a02b33a9058f3ca567e6 Mon Sep 17 00:00:00 2001 +From: Federico Fissore +Date: Mon, 23 Nov 2015 10:47:18 +0100 +Subject: [PATCH 05/19] Ensuring a space is printed in return type AFTER the + keyword + +--- + c.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/c.c b/c.c +index 727d6bb..c40cc42 100644 +--- a/c.c ++++ b/c.c +@@ -2202,11 +2202,11 @@ static void parseReturnType (statementInfo *const st) + vStringPut (ReturnType, '&'); + break; + +- case TOKEN_KEYWORD: +- vStringPut (ReturnType, ' '); +- + default: + vStringCat (ReturnType, curr_tok->name); ++ if (curr_tok->type == TOKEN_KEYWORD) { ++ vStringPut (ReturnType, ' '); ++ } + break; + } + } +-- +2.11.0 + diff --git a/0006-Prevent-C-static_assert-from-stopping-parsing.patch b/0006-Prevent-C-static_assert-from-stopping-parsing.patch new file mode 100644 index 0000000..49ed780 --- /dev/null +++ b/0006-Prevent-C-static_assert-from-stopping-parsing.patch @@ -0,0 +1,42 @@ +From ef67b47e61a1a5f6258e7034ddb520a57b0a477e Mon Sep 17 00:00:00 2001 +From: Ivan Grokhotkov +Date: Wed, 20 Jan 2016 12:19:13 +0300 +Subject: [PATCH 06/19] Prevent C++ static_assert from stopping parsing + +Manual cherry-pick of https://github.com/geany/geany/commit/fa0f92def2bf584ed1f6ae836e509f38324f8b6c +--- + c.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/c.c b/c.c +index c40cc42..6bc8b76 100644 +--- a/c.c ++++ b/c.c +@@ -83,7 +83,7 @@ typedef enum eKeywordId { + KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PUBLIC, + KEYWORD_REGISTER, KEYWORD_RETURN, + KEYWORD_SHADOW, KEYWORD_STATE, +- KEYWORD_SHORT, KEYWORD_SIGNED, KEYWORD_STATIC, KEYWORD_STRING, ++ KEYWORD_SHORT, KEYWORD_SIGNED, KEYWORD_STATIC, KEYWORD_STATIC_ASSERT, KEYWORD_STRING, + KEYWORD_STRUCT, KEYWORD_SWITCH, KEYWORD_SYNCHRONIZED, + KEYWORD_TASK, KEYWORD_TEMPLATE, KEYWORD_THIS, KEYWORD_THROW, + KEYWORD_THROWS, KEYWORD_TRANSIENT, KEYWORD_TRANS, KEYWORD_TRANSITION, +@@ -437,6 +437,7 @@ static const keywordDesc KeywordTable [] = { + { "signed", KEYWORD_SIGNED, { 1, 1, 0, 0, 0 } }, + { "state", KEYWORD_STATE, { 0, 0, 0, 0, 1 } }, + { "static", KEYWORD_STATIC, { 1, 1, 1, 1, 1 } }, ++ { "static_assert", KEYWORD_STATIC_ASSERT, { 0, 1, 0, 0, 0} }, + { "string", KEYWORD_STRING, { 0, 0, 1, 0, 1 } }, + { "struct", KEYWORD_STRUCT, { 1, 1, 1, 0, 0 } }, + { "switch", KEYWORD_SWITCH, { 1, 1, 1, 1, 0 } }, +@@ -1764,6 +1765,7 @@ static void processToken (tokenInfo *const token, statementInfo *const st) + case KEYWORD_RETURN: skipStatement (st); break; + case KEYWORD_SHORT: st->declaration = DECL_BASE; break; + case KEYWORD_SIGNED: st->declaration = DECL_BASE; break; ++ case KEYWORD_STATIC_ASSERT: skipParens(); break; + case KEYWORD_STRING: st->declaration = DECL_BASE; break; + case KEYWORD_STRUCT: st->declaration = DECL_STRUCT; break; + case KEYWORD_TASK: st->declaration = DECL_TASK; break; +-- +2.11.0 + diff --git a/0007-c-Handle-C-11-noexcept.patch b/0007-c-Handle-C-11-noexcept.patch new file mode 100644 index 0000000..b4f2837 --- /dev/null +++ b/0007-c-Handle-C-11-noexcept.patch @@ -0,0 +1,42 @@ +From 3a843374f200b80b7e155059cd4e73171597880d Mon Sep 17 00:00:00 2001 +From: Ivan Grokhotkov +Date: Wed, 20 Jan 2016 12:21:26 +0300 +Subject: [PATCH 07/19] c++: Handle C++11 noexcept + +Manual cherry-pick of https://github.com/geany/geany/commit/f60b31385e4da74d3b926c8e0c8f97c00a508d7b +--- + c.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/c.c b/c.c +index 6bc8b76..0dd84d7 100644 +--- a/c.c ++++ b/c.c +@@ -77,7 +77,7 @@ typedef enum eKeywordId { + KEYWORD_LOCAL, KEYWORD_LONG, + KEYWORD_M_BAD_STATE, KEYWORD_M_BAD_TRANS, KEYWORD_M_STATE, KEYWORD_M_TRANS, + KEYWORD_MUTABLE, +- KEYWORD_NAMESPACE, KEYWORD_NEW, KEYWORD_NEWCOV, KEYWORD_NATIVE, ++ KEYWORD_NAMESPACE, KEYWORD_NEW, KEYWORD_NEWCOV, KEYWORD_NATIVE, KEYWORD_NOEXCEPT, + KEYWORD_OPERATOR, KEYWORD_OUTPUT, KEYWORD_OVERLOAD, KEYWORD_OVERRIDE, + KEYWORD_PACKED, KEYWORD_PORT, KEYWORD_PACKAGE, KEYWORD_PRIVATE, + KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PUBLIC, +@@ -419,6 +419,7 @@ static const keywordDesc KeywordTable [] = { + { "native", KEYWORD_NATIVE, { 0, 0, 0, 1, 0 } }, + { "new", KEYWORD_NEW, { 0, 1, 1, 1, 0 } }, + { "newcov", KEYWORD_NEWCOV, { 0, 0, 0, 0, 1 } }, ++ { "noexcept", KEYWORD_NOEXCEPT, { 0, 1, 0, 0, 0 } }, + { "operator", KEYWORD_OPERATOR, { 0, 1, 1, 0, 0 } }, + { "output", KEYWORD_OUTPUT, { 0, 0, 0, 0, 1 } }, + { "overload", KEYWORD_OVERLOAD, { 0, 1, 0, 0, 0 } }, +@@ -1967,6 +1968,7 @@ static boolean skipPostArgumentStuff ( + case KEYWORD_NAMESPACE: + case KEYWORD_NEW: + case KEYWORD_NEWCOV: ++ case KEYWORD_NOEXCEPT: + case KEYWORD_OPERATOR: + case KEYWORD_OVERLOAD: + case KEYWORD_PRIVATE: +-- +2.11.0 + diff --git a/0008-c-Properly-parse-C-11-override-and-final-members.patch b/0008-c-Properly-parse-C-11-override-and-final-members.patch new file mode 100644 index 0000000..f4f641d --- /dev/null +++ b/0008-c-Properly-parse-C-11-override-and-final-members.patch @@ -0,0 +1,56 @@ +From ce27db2946ae2ebc2766138af451d7d981201134 Mon Sep 17 00:00:00 2001 +From: Ivan Grokhotkov +Date: Wed, 20 Jan 2016 12:25:18 +0300 +Subject: [PATCH 08/19] c++: Properly parse C++11 override and final members + +Manual cherry-pick of +- https://github.com/geany/geany/commit/95a0d4db7e2188a62cf7770496ee2a51591f1962 +- https://github.com/geany/geany/commit/641863c2647c21abb36aedc40ac93e6cc478f920 +--- + c.c | 22 ++++++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +diff --git a/c.c b/c.c +index 0dd84d7..6e8b5aa 100644 +--- a/c.c ++++ b/c.c +@@ -1986,7 +1986,13 @@ static boolean skipPostArgumentStuff ( + break; + + default: +- if (isType (token, TOKEN_NONE)) ++ /* "override" and "final" are only keywords in the declaration of a virtual ++ * member function, so need to be handled specially, not as keywords */ ++ if (isLanguage(Lang_cpp) && isType (token, TOKEN_NAME) && ++ (strcmp ("override", vStringValue (token->name)) == 0 || ++ strcmp ("final", vStringValue (token->name)) == 0)) ++ ; ++ else if (isType (token, TOKEN_NONE)) + ; + else if (info->isKnrParamList && info->parameterCount > 0) + ++elementCount; +@@ -2839,8 +2845,20 @@ static void tagCheck (statementInfo *const st) + st->declaration == DECL_NAMESPACE || + st->declaration == DECL_PROGRAM) + { +- if (isType (prev, TOKEN_NAME)) ++ tokenInfo *name_token = (tokenInfo *)prev; ++ ++ /* C++ 11 allows class final { ... } */ ++ if (isLanguage (Lang_cpp) && isType (prev, TOKEN_NAME) && ++ strcmp("final", vStringValue(prev->name)) == 0 && ++ isType(prev2, TOKEN_NAME)) ++ { ++ name_token = (tokenInfo *)prev2; ++ copyToken (st->blockName, name_token); ++ } ++ else if (isType (name_token, TOKEN_NAME)) ++ { + copyToken (st->blockName, prev); ++ } + else + { + /* For an anonymous struct or union we use a unique ID +-- +2.11.0 + diff --git a/0009-Parse-C-11-enums-with-type-specifier.patch b/0009-Parse-C-11-enums-with-type-specifier.patch new file mode 100644 index 0000000..b4a572b --- /dev/null +++ b/0009-Parse-C-11-enums-with-type-specifier.patch @@ -0,0 +1,33 @@ +From cf9442ccad73448ff22ee96fa743893b29df5cfc Mon Sep 17 00:00:00 2001 +From: Ivan Grokhotkov +Date: Thu, 4 Feb 2016 19:36:35 +0300 +Subject: [PATCH 09/19] Parse C++11 enums with type specifier + +Manual cherry-pick of https://github.com/geany/geany/commit/f2f22d34ab9063852279bc6c5a45c8d3cfafdc0a +--- + c.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/c.c b/c.c +index 6e8b5aa..ff7aa24 100644 +--- a/c.c ++++ b/c.c +@@ -2528,6 +2528,15 @@ static void processColon (statementInfo *const st) + else if (c == ';') + setToken (st, TOKEN_SEMICOLON); + } ++ else if (isLanguage (Lang_cpp) && st->declaration == DECL_ENUM) ++ { ++ /* skip enum's base type */ ++ c = skipToOneOf ("{;"); ++ if (c == '{') ++ setToken (st, TOKEN_BRACE_OPEN); ++ else if (c == ';') ++ setToken (st, TOKEN_SEMICOLON); ++ } + else + { + const tokenInfo *const prev = prevToken (st, 1); +-- +2.11.0 + diff --git a/0010-Parse-C-11-classed-enums.patch b/0010-Parse-C-11-classed-enums.patch new file mode 100644 index 0000000..c20cc7f --- /dev/null +++ b/0010-Parse-C-11-classed-enums.patch @@ -0,0 +1,48 @@ +From 688ba978ea2394eb7144c964811e2c531e5c9c19 Mon Sep 17 00:00:00 2001 +From: Ivan Grokhotkov +Date: Thu, 4 Feb 2016 19:40:15 +0300 +Subject: [PATCH 10/19] Parse C++11 classed enums + +Manual cherry-pick of https://github.com/geany/geany/commit/6c7f69578d8e142f5994cc9cf0e0abc83a606a1b +--- + c.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/c.c b/c.c +index ff7aa24..40db0e5 100644 +--- a/c.c ++++ b/c.c +@@ -1725,6 +1725,12 @@ static void processInterface (statementInfo *const st) + st->declaration = DECL_INTERFACE; + } + ++static void checkIsClassEnum (statementInfo *const st, const declType decl) ++{ ++ if (! isLanguage (Lang_cpp) || st->declaration != DECL_ENUM) ++ st->declaration = decl; ++} ++ + static void processToken (tokenInfo *const token, statementInfo *const st) + { + switch (token->keyword) /* is it a reserved word? */ +@@ -1740,7 +1746,7 @@ static void processToken (tokenInfo *const token, statementInfo *const st) + case KEYWORD_BIT: st->declaration = DECL_BASE; break; + case KEYWORD_CATCH: skipParens (); skipBraces (); break; + case KEYWORD_CHAR: st->declaration = DECL_BASE; break; +- case KEYWORD_CLASS: st->declaration = DECL_CLASS; break; ++ case KEYWORD_CLASS: checkIsClassEnum (st, DECL_CLASS); break; + case KEYWORD_CONST: st->declaration = DECL_BASE; break; + case KEYWORD_DOUBLE: st->declaration = DECL_BASE; break; + case KEYWORD_ENUM: st->declaration = DECL_ENUM; break; +@@ -1768,7 +1774,7 @@ static void processToken (tokenInfo *const token, statementInfo *const st) + case KEYWORD_SIGNED: st->declaration = DECL_BASE; break; + case KEYWORD_STATIC_ASSERT: skipParens(); break; + case KEYWORD_STRING: st->declaration = DECL_BASE; break; +- case KEYWORD_STRUCT: st->declaration = DECL_STRUCT; break; ++ case KEYWORD_STRUCT: checkIsClassEnum (st, DECL_STRUCT); break; + case KEYWORD_TASK: st->declaration = DECL_TASK; break; + case KEYWORD_THROWS: discardTypeList (token); break; + case KEYWORD_UNION: st->declaration = DECL_UNION; break; +-- +2.11.0 + diff --git a/0011-Handle-template-expressions-that-may-use-the-or-oper.patch b/0011-Handle-template-expressions-that-may-use-the-or-oper.patch new file mode 100644 index 0000000..740c58b --- /dev/null +++ b/0011-Handle-template-expressions-that-may-use-the-or-oper.patch @@ -0,0 +1,62 @@ +From e304e5ffff9718d99ab5767c8399225b79204c1f Mon Sep 17 00:00:00 2001 +From: Daniel Garcia +Date: Tue, 23 Feb 2016 17:16:58 -0800 +Subject: [PATCH 11/19] Handle template expressions that may use the << or >> + operators + +--- + c.c | 34 ++++++++++++++++++++++++---------- + 1 file changed, 24 insertions(+), 10 deletions(-) + +diff --git a/c.c b/c.c +index 40db0e5..b975453 100644 +--- a/c.c ++++ b/c.c +@@ -1392,20 +1392,34 @@ static void skipToMatch (const char *const pair) + + if (c == begin) + { +- ++matchLevel; +- if (braceFormatting && getDirectiveNestLevel () != initialLevel) +- { +- skipToFormattedBraceMatch (); +- break; ++ // watch out for '<<' in template arguments ++ int x = cppGetc (); ++ if(c == '<' && x == '<') { ++ // we've found a << - do nothing ++ } else { ++ cppUngetc (x); ++ ++matchLevel; ++ if (braceFormatting && getDirectiveNestLevel () != initialLevel) ++ { ++ skipToFormattedBraceMatch (); ++ break; ++ } + } + } + else if (c == end) + { +- --matchLevel; +- if (braceFormatting && getDirectiveNestLevel () != initialLevel) +- { +- skipToFormattedBraceMatch (); +- break; ++ // watch out for '>>' in template arguments ++ int x = cppGetc (); ++ if(c == '>' && x == '>') { ++ // we've found a >> in a template - skip it ++ } else { ++ cppUngetc (x); ++ --matchLevel; ++ if (braceFormatting && getDirectiveNestLevel () != initialLevel) ++ { ++ skipToFormattedBraceMatch (); ++ break; ++ } + } + } + } +-- +2.11.0 + diff --git a/0012-Make-sure-we-don-t-throw-things-away-while-collectin.patch b/0012-Make-sure-we-don-t-throw-things-away-while-collectin.patch new file mode 100644 index 0000000..3e5b688 --- /dev/null +++ b/0012-Make-sure-we-don-t-throw-things-away-while-collectin.patch @@ -0,0 +1,39 @@ +From fe0ba956daf1f3940543e3dce8ec0befcab4d386 Mon Sep 17 00:00:00 2001 +From: Daniel Garcia +Date: Wed, 24 Feb 2016 00:59:15 -0800 +Subject: [PATCH 12/19] Make sure we don't throw things away while collecting + the signature, though + +--- + c.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/c.c b/c.c +index b975453..386af29 100644 +--- a/c.c ++++ b/c.c +@@ -1395,7 +1395,9 @@ static void skipToMatch (const char *const pair) + // watch out for '<<' in template arguments + int x = cppGetc (); + if(c == '<' && x == '<') { +- // we've found a << - do nothing ++ // we've found a << - do nothing except record the signature ++ if (CollectingSignature) ++ vStringPut(Signature, x); + } else { + cppUngetc (x); + ++matchLevel; +@@ -1411,7 +1413,9 @@ static void skipToMatch (const char *const pair) + // watch out for '>>' in template arguments + int x = cppGetc (); + if(c == '>' && x == '>') { +- // we've found a >> in a template - skip it ++ // we've found a >> - do nothing except record the signature ++ if (CollectingSignature) ++ vStringPut(Signature, x); + } else { + cppUngetc (x); + --matchLevel; +-- +2.11.0 + diff --git a/0013-C-mitigate-matching-error-on-generics-containing-an-.patch b/0013-C-mitigate-matching-error-on-generics-containing-an-.patch new file mode 100644 index 0000000..44de436 --- /dev/null +++ b/0013-C-mitigate-matching-error-on-generics-containing-an-.patch @@ -0,0 +1,35 @@ +From f928218c753e54968289a73285bf7c4345a8d553 Mon Sep 17 00:00:00 2001 +From: Martino Facchin +Date: Tue, 23 Feb 2016 12:58:40 +0100 +Subject: [PATCH 13/19] C++: mitigate matching error on generics containing an + expression + +backport of https://github.com/geany/geany/commit/d40932ce4d05e57573a6d6c8f89f4aea8c42d4f3 +--- + c.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/c.c b/c.c +index 386af29..1386ddd 100644 +--- a/c.c ++++ b/c.c +@@ -1426,6 +1426,16 @@ static void skipToMatch (const char *const pair) + } + } + } ++ /* early out if matching "<>" and we encounter a ";" or "{" to mitigate ++ * match problems with C++ generics containing a static expression like ++ * foo bar; ++ * normally neither ";" nor "{" could appear inside "<>" anyway. */ ++ else if (isLanguage (Lang_cpp) && begin == '<' && ++ (c == ';' || c == '{')) ++ { ++ cppUngetc (c); ++ break; ++ } + } + if (c == EOF) + { +-- +2.11.0 + diff --git a/0014-fix-wrongly-interpreted-in-template.patch b/0014-fix-wrongly-interpreted-in-template.patch new file mode 100644 index 0000000..e9b3e1e --- /dev/null +++ b/0014-fix-wrongly-interpreted-in-template.patch @@ -0,0 +1,44 @@ +From 5dbd71201f79e976a728802ca8638b14db0728dc Mon Sep 17 00:00:00 2001 +From: Martino Facchin +Date: Wed, 9 Mar 2016 15:03:07 +0100 +Subject: [PATCH 14/19] fix wrongly interpreted >> in template + +--- + c.c | 20 +++++++------------- + 1 file changed, 7 insertions(+), 13 deletions(-) + +diff --git a/c.c b/c.c +index 1386ddd..6add5f3 100644 +--- a/c.c ++++ b/c.c +@@ -1410,20 +1410,14 @@ static void skipToMatch (const char *const pair) + } + else if (c == end) + { +- // watch out for '>>' in template arguments ++ // don't care if you find a '>>' (the important thing is closing the brackets) + int x = cppGetc (); +- if(c == '>' && x == '>') { +- // we've found a >> - do nothing except record the signature +- if (CollectingSignature) +- vStringPut(Signature, x); +- } else { +- cppUngetc (x); +- --matchLevel; +- if (braceFormatting && getDirectiveNestLevel () != initialLevel) +- { +- skipToFormattedBraceMatch (); +- break; +- } ++ cppUngetc (x); ++ --matchLevel; ++ if (braceFormatting && getDirectiveNestLevel () != initialLevel) ++ { ++ skipToFormattedBraceMatch (); ++ break; + } + } + /* early out if matching "<>" and we encounter a ";" or "{" to mitigate +-- +2.11.0 + diff --git a/0015-Added-constexpr-as-keyword.patch b/0015-Added-constexpr-as-keyword.patch new file mode 100644 index 0000000..cc05779 --- /dev/null +++ b/0015-Added-constexpr-as-keyword.patch @@ -0,0 +1,41 @@ +From 83aa36d14a6b82e10b3ac55d54e0641648c56fcf Mon Sep 17 00:00:00 2001 +From: Eric Sorton +Date: Mon, 1 Aug 2016 23:04:35 -0400 +Subject: [PATCH 15/19] Added constexpr as keyword. + +--- + c.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/c.c b/c.c +index 6add5f3..105bfa8 100644 +--- a/c.c ++++ b/c.c +@@ -62,7 +62,7 @@ typedef enum eKeywordId { + KEYWORD_ATTRIBUTE, KEYWORD_ABSTRACT, + KEYWORD_BOOLEAN, KEYWORD_BYTE, KEYWORD_BAD_STATE, KEYWORD_BAD_TRANS, + KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT, +- KEYWORD_CASE, KEYWORD_CATCH, KEYWORD_CHAR, KEYWORD_CLASS, KEYWORD_CONST, ++ KEYWORD_CASE, KEYWORD_CATCH, KEYWORD_CHAR, KEYWORD_CLASS, KEYWORD_CONST, KEYWORD_CONSTEXPR, + KEYWORD_CONSTRAINT, KEYWORD_COVERAGE_BLOCK, KEYWORD_COVERAGE_DEF, + KEYWORD_DEFAULT, KEYWORD_DELEGATE, KEYWORD_DELETE, KEYWORD_DO, + KEYWORD_DOUBLE, +@@ -377,6 +377,7 @@ static const keywordDesc KeywordTable [] = { + { "char", KEYWORD_CHAR, { 1, 1, 1, 1, 0 } }, + { "class", KEYWORD_CLASS, { 0, 1, 1, 1, 1 } }, + { "const", KEYWORD_CONST, { 1, 1, 1, 1, 0 } }, ++ { "constexpr", KEYWORD_CONSTEXPR, { 0, 1, 0, 0, 0 } }, + { "constraint", KEYWORD_CONSTRAINT, { 0, 0, 0, 0, 1 } }, + { "coverage_block", KEYWORD_COVERAGE_BLOCK, { 0, 0, 0, 0, 1 } }, + { "coverage_def", KEYWORD_COVERAGE_DEF, { 0, 0, 0, 0, 1 } }, +@@ -1770,6 +1771,7 @@ static void processToken (tokenInfo *const token, statementInfo *const st) + case KEYWORD_CHAR: st->declaration = DECL_BASE; break; + case KEYWORD_CLASS: checkIsClassEnum (st, DECL_CLASS); break; + case KEYWORD_CONST: st->declaration = DECL_BASE; break; ++ case KEYWORD_CONSTEXPR: st->declaration = DECL_BASE; break; + case KEYWORD_DOUBLE: st->declaration = DECL_BASE; break; + case KEYWORD_ENUM: st->declaration = DECL_ENUM; break; + case KEYWORD_EXTENDS: readParents (st, '.'); +-- +2.11.0 + diff --git a/0016-CVE-2014-7204.patch b/0016-CVE-2014-7204.patch new file mode 100644 index 0000000..145007e --- /dev/null +++ b/0016-CVE-2014-7204.patch @@ -0,0 +1,98 @@ +From 7f6e3f1177f0ed53cf2a66ac207f6834591c568c Mon Sep 17 00:00:00 2001 +From: dfishburn +Date: Wed, 24 Oct 2012 01:13:00 +0000 +Subject: [PATCH 16/19] CVE-2014-7204 + +git-svn-id: svn://svn.code.sf.net/p/ctags/code/trunk@791 c5d04d22-be80-434c-894e-aa346cc9e8e8 +Signed-off-by: Petr Uzel +--- + jscript.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 51 insertions(+), 3 deletions(-) + +diff --git a/jscript.c b/jscript.c +index c4e5b1a..901641a 100644 +--- a/jscript.c ++++ b/jscript.c +@@ -215,6 +215,7 @@ static void deleteToken (tokenInfo *const token) + * Tag generation functions + */ + ++/* + static void makeConstTag (tokenInfo *const token, const jsKind kind) + { + if (JsKinds [kind].enabled && ! token->ignoreTag ) +@@ -238,12 +239,13 @@ static void makeJsTag (tokenInfo *const token, const jsKind kind) + + if (JsKinds [kind].enabled && ! token->ignoreTag ) + { +- /* ++ * + * If a scope has been added to the token, change the token + * string to include the scope when making the tag. +- */ ++ * + if ( vStringLength(token->scope) > 0 ) + { ++ * + fulltag = vStringNew (); + vStringCopy(fulltag, token->scope); + vStringCatS (fulltag, "."); +@@ -251,8 +253,54 @@ static void makeJsTag (tokenInfo *const token, const jsKind kind) + vStringTerminate(fulltag); + vStringCopy(token->string, fulltag); + vStringDelete (fulltag); ++ * ++ jsKind parent_kind = JSTAG_CLASS; ++ ++ * ++ * if we're creating a function (and not a method), ++ * guess we're inside another function ++ * ++ if (kind == JSTAG_FUNCTION) ++ parent_kind = JSTAG_FUNCTION; ++ ++ e.extensionFields.scope[0] = JsKinds [parent_kind].name; ++ e.extensionFields.scope[1] = vStringValue (token->scope); ++ } ++ * makeConstTag (token, kind); * ++ makeTagEntry (&e); ++ } ++} ++*/ ++ ++static void makeJsTag (tokenInfo *const token, const jsKind kind) ++{ ++ if (JsKinds [kind].enabled && ! token->ignoreTag ) ++ { ++ const char *const name = vStringValue (token->string); ++ tagEntryInfo e; ++ initTagEntry (&e, name); ++ ++ e.lineNumber = token->lineNumber; ++ e.filePosition = token->filePosition; ++ e.kindName = JsKinds [kind].name; ++ e.kind = JsKinds [kind].letter; ++ ++ if ( vStringLength(token->scope) > 0 ) ++ { ++ jsKind parent_kind = JSTAG_CLASS; ++ ++ /* ++ * If we're creating a function (and not a method), ++ * guess we're inside another function ++ */ ++ if (kind == JSTAG_FUNCTION) ++ parent_kind = JSTAG_FUNCTION; ++ ++ e.extensionFields.scope[0] = JsKinds [parent_kind].name; ++ e.extensionFields.scope[1] = vStringValue (token->scope); + } +- makeConstTag (token, kind); ++ ++ makeTagEntry (&e); + } + } + +-- +2.11.0 + diff --git a/0017-Go-language-support.patch b/0017-Go-language-support.patch new file mode 100644 index 0000000..3e90ef4 --- /dev/null +++ b/0017-Go-language-support.patch @@ -0,0 +1,731 @@ +From 829234bfb8d481413bf0466562fe87e8c396defd Mon Sep 17 00:00:00 2001 +From: Graham Anderson +Date: Thu, 16 Aug 2012 12:04:00 +0000 +Subject: [PATCH 17/19] Go language support + +--- + go.c | 670 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + parsers.h | 2 + + source.mak | 2 + + 3 files changed, 674 insertions(+) + create mode 100644 go.c + +diff --git a/go.c b/go.c +new file mode 100644 +index 0000000..6bd3a36 +--- /dev/null ++++ b/go.c +@@ -0,0 +1,670 @@ ++/* ++* INCLUDE FILES ++*/ ++#include "general.h" /* must always come first */ ++#include ++ ++#include "debug.h" ++#include "entry.h" ++#include "keyword.h" ++#include "read.h" ++#include "main.h" ++#include "routines.h" ++#include "vstring.h" ++#include "options.h" ++ ++/* ++ * MACROS ++ */ ++#define isType(token,t) (boolean) ((token)->type == (t)) ++#define isKeyword(token,k) (boolean) ((token)->keyword == (k)) ++ ++/* ++ * DATA DECLARATIONS ++ */ ++ ++typedef enum eException { ExceptionNone, ExceptionEOF } exception_t; ++ ++typedef enum eKeywordId { ++ KEYWORD_NONE = -1, ++ KEYWORD_package, ++ KEYWORD_import, ++ KEYWORD_const, ++ KEYWORD_type, ++ KEYWORD_var, ++ KEYWORD_func, ++ KEYWORD_struct, ++ KEYWORD_interface, ++ KEYWORD_map, ++ KEYWORD_chan ++} keywordId; ++ ++/* Used to determine whether keyword is valid for the current language and ++ * what its ID is. ++ */ ++typedef struct sKeywordDesc { ++ const char *name; ++ keywordId id; ++} keywordDesc; ++ ++typedef enum eTokenType { ++ TOKEN_NONE = -1, ++ TOKEN_CHARACTER, ++ // Don't need TOKEN_FORWARD_SLASH ++ TOKEN_FORWARD_SLASH, ++ TOKEN_KEYWORD, ++ TOKEN_IDENTIFIER, ++ TOKEN_STRING, ++ TOKEN_OPEN_PAREN, ++ TOKEN_CLOSE_PAREN, ++ TOKEN_OPEN_CURLY, ++ TOKEN_CLOSE_CURLY, ++ TOKEN_OPEN_SQUARE, ++ TOKEN_CLOSE_SQUARE, ++ TOKEN_SEMICOLON, ++ TOKEN_STAR, ++ TOKEN_LEFT_ARROW, ++ TOKEN_DOT, ++ TOKEN_COMMA ++} tokenType; ++ ++typedef struct sTokenInfo { ++ tokenType type; ++ keywordId keyword; ++ vString *string; /* the name of the token */ ++ unsigned long lineNumber; /* line number of tag */ ++ fpos_t filePosition; /* file position of line containing name */ ++} tokenInfo; ++ ++/* ++* DATA DEFINITIONS ++*/ ++ ++static int Lang_go; ++static jmp_buf Exception; ++static vString *scope; ++ ++typedef enum { ++ GOTAG_UNDEFINED = -1, ++ GOTAG_PACKAGE, ++ GOTAG_FUNCTION, ++ GOTAG_CONST, ++ GOTAG_TYPE, ++ GOTAG_VAR, ++} goKind; ++ ++static kindOption GoKinds[] = { ++ {TRUE, 'p', "package", "packages"}, ++ {TRUE, 'f', "func", "functions"}, ++ {TRUE, 'c', "const", "constants"}, ++ {TRUE, 't', "type", "types"}, ++ {TRUE, 'v', "var", "variables"} ++}; ++ ++static keywordDesc GoKeywordTable[] = { ++ {"package", KEYWORD_package}, ++ {"import", KEYWORD_import}, ++ {"const", KEYWORD_const}, ++ {"type", KEYWORD_type}, ++ {"var", KEYWORD_var}, ++ {"func", KEYWORD_func}, ++ {"struct", KEYWORD_struct}, ++ {"interface", KEYWORD_interface}, ++ {"map", KEYWORD_map}, ++ {"chan", KEYWORD_chan} ++}; ++ ++/* ++* FUNCTION DEFINITIONS ++*/ ++ ++// XXX UTF-8 ++static boolean isIdentChar (const int c) ++{ ++ return (boolean) ++ (isalpha (c) || isdigit (c) || c == '$' || ++ c == '@' || c == '_' || c == '#' || c > 128); ++} ++ ++static void initialize (const langType language) ++{ ++ size_t i; ++ const size_t count = ++ sizeof (GoKeywordTable) / sizeof (GoKeywordTable[0]); ++ Lang_go = language; ++ for (i = 0; i < count; ++i) ++ { ++ const keywordDesc *const p = &GoKeywordTable[i]; ++ addKeyword (p->name, language, (int) p->id); ++ } ++} ++ ++static tokenInfo *newToken (void) ++{ ++ tokenInfo *const token = xMalloc (1, tokenInfo); ++ token->type = TOKEN_NONE; ++ token->keyword = KEYWORD_NONE; ++ token->string = vStringNew (); ++ token->lineNumber = getSourceLineNumber (); ++ token->filePosition = getInputFilePosition (); ++ return token; ++} ++ ++static void deleteToken (tokenInfo * const token) ++{ ++ if (token != NULL) ++ { ++ vStringDelete (token->string); ++ eFree (token); ++ } ++} ++ ++/* ++ * Parsing functions ++ */ ++ ++static void parseString (vString *const string, const int delimiter) ++{ ++ boolean end = FALSE; ++ while (!end) ++ { ++ int c = fileGetc (); ++ if (c == EOF) ++ end = TRUE; ++ else if (c == '\\' && delimiter != '`') ++ { ++ c = fileGetc (); /* This maybe a ' or ". */ ++ vStringPut (string, c); ++ } ++ else if (c == delimiter) ++ end = TRUE; ++ else ++ vStringPut (string, c); ++ } ++ vStringTerminate (string); ++} ++ ++static void parseIdentifier (vString *const string, const int firstChar) ++{ ++ int c = firstChar; ++ //Assert (isIdentChar (c)); ++ do ++ { ++ vStringPut (string, c); ++ c = fileGetc (); ++ } while (isIdentChar (c)); ++ vStringTerminate (string); ++ fileUngetc (c); /* always unget, LF might add a semicolon */ ++} ++ ++static void readToken (tokenInfo *const token) ++{ ++ int c; ++ static tokenType lastTokenType = TOKEN_NONE; ++ ++ token->type = TOKEN_NONE; ++ token->keyword = KEYWORD_NONE; ++ vStringClear (token->string); ++ ++getNextChar: ++ do ++ { ++ c = fileGetc (); ++ token->lineNumber = getSourceLineNumber (); ++ token->filePosition = getInputFilePosition (); ++ if (c == '\n' && (lastTokenType == TOKEN_IDENTIFIER || ++ lastTokenType == TOKEN_STRING || ++ lastTokenType == TOKEN_CLOSE_PAREN || ++ lastTokenType == TOKEN_CLOSE_CURLY || ++ lastTokenType == TOKEN_CLOSE_SQUARE)) ++ { ++ token->type = TOKEN_SEMICOLON; ++ goto done; ++ } ++ } ++ while (c == '\t' || c == ' ' || c == '\r' || c == '\n'); ++ ++ switch (c) ++ { ++ case EOF: ++ longjmp (Exception, (int)ExceptionEOF); ++ break; ++ ++ case '/': ++ { ++ boolean hasNewline = FALSE; ++ int d = fileGetc (); ++ switch (d) ++ { ++ case '/': ++ fileSkipToCharacter ('\n'); ++ /* Line comments start with the ++ * character sequence // and ++ * continue through the next ++ * newline. A line comment acts ++ * like a newline. */ ++ fileUngetc ('\n'); ++ goto getNextChar; ++ case '*': ++ do ++ { ++ int d; ++ do ++ { ++ d = fileGetc (); ++ if (d == '\n') ++ { ++ hasNewline = TRUE; ++ } ++ } while (d != EOF && d != '*'); ++ ++ c = fileGetc (); ++ if (c == '/') ++ break; ++ else ++ fileUngetc (c); ++ } while (c != EOF && c != '\0'); ++ ++ fileUngetc (hasNewline ? '\n' : ' '); ++ goto getNextChar; ++ default: ++ token->type = TOKEN_FORWARD_SLASH; ++ fileUngetc (d); ++ break; ++ } ++ } ++ break; ++ ++ case '"': ++ case '\'': ++ case '`': ++ token->type = TOKEN_STRING; ++ parseString (token->string, c); ++ token->lineNumber = getSourceLineNumber (); ++ token->filePosition = getInputFilePosition (); ++ break; ++ ++ case '<': ++ { ++ int d = fileGetc (); ++ if (d == '-') ++ { ++ token->type = TOKEN_LEFT_ARROW; ++ break; ++ } ++ else ++ goto getNextChar; ++ } ++ ++ case '(': ++ token->type = TOKEN_OPEN_PAREN; ++ break; ++ ++ case ')': ++ token->type = TOKEN_CLOSE_PAREN; ++ break; ++ ++ case '{': ++ token->type = TOKEN_OPEN_CURLY; ++ break; ++ ++ case '}': ++ token->type = TOKEN_CLOSE_CURLY; ++ break; ++ ++ case '[': ++ token->type = TOKEN_OPEN_SQUARE; ++ break; ++ ++ case ']': ++ token->type = TOKEN_CLOSE_SQUARE; ++ break; ++ ++ case '*': ++ token->type = TOKEN_STAR; ++ break; ++ ++ case '.': ++ token->type = TOKEN_DOT; ++ break; ++ ++ case ',': ++ token->type = TOKEN_COMMA; ++ break; ++ ++ default: ++ parseIdentifier (token->string, c); ++ token->lineNumber = getSourceLineNumber (); ++ token->filePosition = getInputFilePosition (); ++ token->keyword = lookupKeyword (vStringValue (token->string), Lang_go); ++ if (isKeyword (token, KEYWORD_NONE)) ++ token->type = TOKEN_IDENTIFIER; ++ else ++ token->type = TOKEN_KEYWORD; ++ break; ++ } ++ ++done: ++ lastTokenType = token->type; ++} ++ ++static void skipToMatched (tokenInfo *const token) ++{ ++ int nest_level = 0; ++ tokenType open_token; ++ tokenType close_token; ++ ++ switch (token->type) ++ { ++ case TOKEN_OPEN_PAREN: ++ open_token = TOKEN_OPEN_PAREN; ++ close_token = TOKEN_CLOSE_PAREN; ++ break; ++ case TOKEN_OPEN_CURLY: ++ open_token = TOKEN_OPEN_CURLY; ++ close_token = TOKEN_CLOSE_CURLY; ++ break; ++ case TOKEN_OPEN_SQUARE: ++ open_token = TOKEN_OPEN_SQUARE; ++ close_token = TOKEN_CLOSE_SQUARE; ++ break; ++ default: ++ return; ++ } ++ ++ /* ++ * This routine will skip to a matching closing token. ++ * It will also handle nested tokens like the (, ) below. ++ * ( name varchar(30), text binary(10) ) ++ */ ++ if (isType (token, open_token)) ++ { ++ nest_level++; ++ while (!(isType (token, close_token) && (nest_level == 0))) ++ { ++ readToken (token); ++ if (isType (token, open_token)) ++ { ++ nest_level++; ++ } ++ if (isType (token, close_token)) ++ { ++ if (nest_level > 0) ++ { ++ nest_level--; ++ } ++ } ++ } ++ readToken (token); ++ } ++} ++ ++static void skipType (tokenInfo *const token) ++{ ++again: ++ // Type = TypeName | TypeLit | "(" Type ")" . ++ if (isType (token, TOKEN_OPEN_PAREN)) ++ { ++ skipToMatched (token); ++ return; ++ } ++ ++ // TypeName = QualifiedIdent. ++ // QualifiedIdent = [ PackageName "." ] identifier . ++ // PackageName = identifier . ++ if (isType (token, TOKEN_IDENTIFIER)) ++ { ++ readToken (token); ++ if (isType (token, TOKEN_DOT)) ++ { ++ readToken (token); ++ Assert (isType (token, TOKEN_IDENTIFIER)); ++ readToken (token); ++ } ++ return; ++ } ++ ++ // StructType = "struct" "{" { FieldDecl ";" } "}" ++ // InterfaceType = "interface" "{" { MethodSpec ";" } "}" . ++ if (isKeyword (token, KEYWORD_struct) || isKeyword (token, KEYWORD_interface)) ++ { ++ readToken (token); ++ Assert (isType (token, TOKEN_OPEN_CURLY)); ++ skipToMatched (token); ++ return; ++ } ++ ++ // ArrayType = "[" ArrayLength "]" ElementType . ++ // SliceType = "[" "]" ElementType . ++ // ElementType = Type . ++ if (isType (token, TOKEN_OPEN_SQUARE)) ++ { ++ skipToMatched (token); ++ goto again; ++ } ++ ++ // PointerType = "*" BaseType . ++ // BaseType = Type . ++ // ChannelType = ( "chan" [ "<-" ] | "<-" "chan" ) ElementType . ++ if (isType (token, TOKEN_STAR) || isKeyword (token, KEYWORD_chan) || isType (token, TOKEN_LEFT_ARROW)) ++ { ++ readToken (token); ++ goto again; ++ } ++ ++ // MapType = "map" "[" KeyType "]" ElementType . ++ // KeyType = Type . ++ if (isKeyword (token, KEYWORD_map)) ++ { ++ readToken (token); ++ Assert (isType (token, TOKEN_OPEN_SQUARE)); ++ skipToMatched (token); ++ goto again; ++ } ++ ++ // FunctionType = "func" Signature . ++ // Signature = Parameters [ Result ] . ++ // Result = Parameters | Type . ++ // Parameters = "(" [ ParameterList [ "," ] ] ")" . ++ if (isKeyword (token, KEYWORD_func)) ++ { ++ readToken (token); ++ Assert (isType (token, TOKEN_OPEN_PAREN)); ++ // Parameters ++ skipToMatched (token); ++ // Result is parameters or type or nothing. skipType treats anything ++ // surrounded by parentheses as a type, and does nothing if what ++ // follows is not a type. ++ goto again; ++ } ++} ++ ++// Skip to the next semicolon, skipping over matching brackets. ++static void skipToTopLevelSemicolon (tokenInfo *const token) ++{ ++ while (!isType (token, TOKEN_SEMICOLON)) ++ { ++ readToken (token); ++ skipToMatched (token); ++ } ++} ++ ++static void makeTag (tokenInfo *const token, const goKind kind) ++{ ++ const char *const name = vStringValue (token->string); ++ ++ tagEntryInfo e; ++ initTagEntry (&e, name); ++ ++ if (!GoKinds [kind].enabled) ++ return; ++ ++ e.lineNumber = token->lineNumber; ++ e.filePosition = token->filePosition; ++ e.kindName = GoKinds [kind].name; ++ e.kind = GoKinds [kind].letter; ++ ++ makeTagEntry (&e); ++ ++ if (scope && Option.include.qualifiedTags) ++ { ++ vString *qualifiedName = vStringNew (); ++ vStringCopy (qualifiedName, scope); ++ vStringCatS (qualifiedName, "."); ++ vStringCat (qualifiedName, token->string); ++ e.name = vStringValue (qualifiedName); ++ makeTagEntry (&e); ++ vStringDelete (qualifiedName); ++ } ++} ++ ++static void parsePackage (tokenInfo *const token) ++{ ++ tokenInfo *const name = newToken (); ++ ++ readToken (name); ++ Assert (isType (name, TOKEN_IDENTIFIER)); ++ makeTag (name, GOTAG_PACKAGE); ++ if (!scope && Option.include.qualifiedTags) ++ { ++ scope = vStringNew (); ++ vStringCopy (scope, name->string); ++ } ++ ++ deleteToken (name); ++} ++ ++static void parseFunctionOrMethod (tokenInfo *const token) ++{ ++ // FunctionDecl = "func" identifier Signature [ Body ] . ++ // Body = Block. ++ // ++ // MethodDecl = "func" Receiver MethodName Signature [ Body ] . ++ // Receiver = "(" [ identifier ] [ "*" ] BaseTypeName ")" . ++ // BaseTypeName = identifier . ++ tokenInfo *const name = newToken (); ++ ++ // Skip over receiver. ++ readToken (name); ++ if (isType (name, TOKEN_OPEN_PAREN)) ++ skipToMatched (name); ++ ++ Assert (isType (name, TOKEN_IDENTIFIER)); ++ ++ // Skip over parameters. ++ readToken (token); ++ skipToMatched (token); ++ ++ // Skip over result. ++ skipType (token); ++ ++ // Skip over function body. ++ if (isType (token, TOKEN_OPEN_CURLY)) ++ skipToMatched (token); ++ ++ makeTag (name, GOTAG_FUNCTION); ++ ++ deleteToken (name); ++} ++ ++static void parseConstTypeVar (tokenInfo *const token, goKind kind) ++{ ++ // ConstDecl = "const" ( ConstSpec | "(" { ConstSpec ";" } ")" ) . ++ // ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] . ++ // IdentifierList = identifier { "," identifier } . ++ // ExpressionList = Expression { "," Expression } . ++ // TypeDecl = "type" ( TypeSpec | "(" { TypeSpec ";" } ")" ) . ++ // TypeSpec = identifier Type . ++ // VarDecl = "var" ( VarSpec | "(" { VarSpec ";" } ")" ) . ++ // VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) . ++ tokenInfo *const name = newToken (); ++ boolean usesParens = FALSE; ++ ++ readToken (name); ++ ++ if (isType (name, TOKEN_OPEN_PAREN)) ++ { ++ usesParens = TRUE; ++ readToken (name); ++ } ++ ++again: ++ while (1) ++ { ++ makeTag (name, kind); ++ readToken (token); ++ if (!isType (token, TOKEN_COMMA) && !isType (token, TOKEN_CLOSE_PAREN)) ++ break; ++ readToken (name); ++ } ++ ++ skipType (token); ++ skipToTopLevelSemicolon (token); ++ ++ if (usesParens) ++ { ++ readToken (name); ++ if (!isType (name, TOKEN_CLOSE_PAREN)) ++ goto again; ++ } ++ ++ deleteToken (name); ++} ++ ++static void parseGoFile (tokenInfo *const token) ++{ ++ do ++ { ++ readToken (token); ++ ++ if (isType (token, TOKEN_KEYWORD)) ++ { ++ switch (token->keyword) ++ { ++ case KEYWORD_package: ++ parsePackage (token); ++ break; ++ case KEYWORD_func: ++ parseFunctionOrMethod (token); ++ break; ++ case KEYWORD_const: ++ parseConstTypeVar (token, GOTAG_CONST); ++ break; ++ case KEYWORD_type: ++ parseConstTypeVar (token, GOTAG_TYPE); ++ break; ++ case KEYWORD_var: ++ parseConstTypeVar (token, GOTAG_VAR); ++ break; ++ default: ++ break; ++ } ++ } ++ } while (TRUE); ++} ++ ++static void findGoTags (void) ++{ ++ tokenInfo *const token = newToken (); ++ exception_t exception; ++ ++ exception = (exception_t) (setjmp (Exception)); ++ while (exception == ExceptionNone) ++ parseGoFile (token); ++ ++ deleteToken (token); ++ vStringDelete (scope); ++ scope = NULL; ++} ++ ++extern parserDefinition *GoParser (void) ++{ ++ static const char *const extensions[] = { "go", NULL }; ++ parserDefinition *def = parserNew ("Go"); ++ def->kinds = GoKinds; ++ def->kindCount = KIND_COUNT (GoKinds); ++ def->extensions = extensions; ++ def->parser = findGoTags; ++ def->initialize = initialize; ++ return def; ++} +diff --git a/parsers.h b/parsers.h +index e4a50e1..b150506 100644 +--- a/parsers.h ++++ b/parsers.h +@@ -32,6 +32,7 @@ + ErlangParser, \ + FlexParser, \ + FortranParser, \ ++ GoParser, \ + HtmlParser, \ + JavaParser, \ + JavaScriptParser, \ +@@ -76,6 +77,7 @@ + FlexParser, \ + FortranParser, \ + GenieParser, \ ++ GoParser, \ + HtmlParser, \ + JavaParser, \ + JavaScriptParser, \ +diff --git a/source.mak b/source.mak +index 3e5f740..d4c4c26 100644 +--- a/source.mak ++++ b/source.mak +@@ -24,6 +24,7 @@ SOURCES = \ + flex.c \ + fortran.c \ + get.c \ ++ go.c \ + html.c \ + jscript.c \ + keyword.c \ +@@ -86,6 +87,7 @@ OBJECTS = \ + flex.$(OBJEXT) \ + fortran.$(OBJEXT) \ + get.$(OBJEXT) \ ++ go.$(OBJEXT) \ + html.$(OBJEXT) \ + jscript.$(OBJEXT) \ + keyword.$(OBJEXT) \ +-- +2.11.0 + diff --git a/0018-SUSE-man-page-changes.patch b/0018-SUSE-man-page-changes.patch new file mode 100644 index 0000000..27ce8d9 --- /dev/null +++ b/0018-SUSE-man-page-changes.patch @@ -0,0 +1,76 @@ +From e63684e0d8924dd6a56bda52ebfc81fb6c35811b Mon Sep 17 00:00:00 2001 +From: Stepan Kasal +Date: Mon, 31 Jan 2000 12:41:54 +0100 +Subject: [PATCH 18/19] SUSE man page changes + +--- + ctags.1 | 35 +++++++++++++++++++++++++++++------ + 1 file changed, 29 insertions(+), 6 deletions(-) + +diff --git a/ctags.1 b/ctags.1 +index 2d89006..138e6ce 100644 +--- a/ctags.1 ++++ b/ctags.1 +@@ -9,12 +9,29 @@ ctags \- Generate tag files for source code + .TP 6 + \fBctags\fP [\fBoptions\fP] [\fIfile(s)\fP] + .TP 6 +-\fBetags\fP [\fBoptions\fP] [\fIfile(s)\fP] +- ++\fBctags\fP \fB-e\fP [\fBoptions\fP] [\fIfile(s)\fP] ++ ++.SH NOTE ++There are three different versions of the ++\fBctags\fP program on SuSE Linux. ++Besides this one you might want to use either ++.BR gnuctags (1), ++supporting wide variety of programming languages ++and originaly distributed with emacs, or ++.BR gctags (1), ++which comes with ++.BR global (1) ++and supports for example Yacc. ++ ++For use with ++.BR emacs (1) ++the best choice is perhaps ++.BR etags (1), ++but it's also possible to use \fBctags\ \-e\fP, ++as described herein, since it supports for example Eiffel. + + .SH "DESCRIPTION" +-The \fBctags\fP and \fBetags\fP programs (hereinafter collectively referred to +-as \fBctags\fP, except where distinguished) generate an index (or "tag") file ++The \fBctags\fP program generates an index (or "tag") file + for a variety of language objects found in \fIfile(s)\fP. + This tag file allows these items to be quickly and easily located by a text + editor or other utility. A "tag" signifies a language object for which an +@@ -1081,7 +1098,7 @@ embedded space. If this is a problem, use a configuration file instead. + .TP 8 + .B ETAGS + Similar to the \fBCTAGS\fP variable above, this variable, if found, will be +-read when \fBetags\fP starts. If this variable is not found, \fBetags\fP will ++read when \fBctags\ \-e\fP starts. If this variable is not found, \fBctags\ \-e\fP will + try to use \fBCTAGS\fP instead. + + .TP 8 +@@ -1136,9 +1153,15 @@ lines to indicate separate command-line arguments. + The default tag file created by \fBctags\fP. + .TP + .I TAGS +-The default tag file created by \fBetags\fP. ++The default tag file created by \fBctags -e\fP. + + .SH "SEE ALSO" ++.BR etags (1), ++.BR gctags (1), ++.BR global (1), ++.BR gnuctags (1). ++ ++.PP + The official Exuberant Ctags web site at: + + .RS +-- +2.11.0 + diff --git a/0019-Do-not-include-build-time-in-binary.patch b/0019-Do-not-include-build-time-in-binary.patch new file mode 100644 index 0000000..0ee7c04 --- /dev/null +++ b/0019-Do-not-include-build-time-in-binary.patch @@ -0,0 +1,47 @@ +From 2814d01a6cdb52a336dc6d6243ecc3cad44e60f1 Mon Sep 17 00:00:00 2001 +From: Unknown Lost in OBS Migration +Date: Sun, 26 Feb 2017 05:34:04 +0100 +Subject: [PATCH 19/19] Do not include build time in binary. + +--- + main.c | 11 ----------- + options.c | 1 - + 2 files changed, 12 deletions(-) + +diff --git a/main.c b/main.c +index 79948fe..8bca242 100644 +--- a/main.c ++++ b/main.c +@@ -93,17 +93,6 @@ + */ + static struct { long files, lines, bytes; } Totals = { 0, 0, 0 }; + +-#ifdef AMIGA +-# include "ctags.h" +- static const char *VERsion = "$VER: "PROGRAM_NAME" "PROGRAM_VERSION" " +-# ifdef __SASC +- __AMIGADATE__ +-# else +- __DATE__ +-# endif +- " "AUTHOR_NAME" $"; +-#endif +- + /* + * FUNCTION PROTOTYPES + */ +diff --git a/options.c b/options.c +index 1bee61d..0fc8e0c 100644 +--- a/options.c ++++ b/options.c +@@ -926,7 +926,6 @@ static void printProgramIdentification (void) + printf ("%s %s, %s %s\n", + PROGRAM_NAME, PROGRAM_VERSION, + PROGRAM_COPYRIGHT, AUTHOR_NAME); +- printf (" Compiled: %s, %s\n", __DATE__, __TIME__); + printf (" Addresses: <%s>, %s\n", AUTHOR_EMAIL, PROGRAM_URL); + printFeatureList (); + } +-- +2.11.0 + diff --git a/CVE-2022-4515.patch b/CVE-2022-4515.patch new file mode 100644 index 0000000..9d84f80 --- /dev/null +++ b/CVE-2022-4515.patch @@ -0,0 +1,209 @@ +Based on +From e00c55d7a0204dc1d0ae316141323959e1e16162 Mon Sep 17 00:00:00 2001 +From: Masatake YAMATO +Date: Mon, 24 Oct 2016 23:52:23 +0900 +Subject: [PATCH] main: quote output file name before passing it to system(3) + function + +Following command line doesn't work: + + $ ctags -o 'a b' ... + +because a shell lauched from system(3) deals a whitespace between 'a' +and 'b' as a separator. The output file name is passed to system(3) +to run external sort command. + +This commit adds code to put double and single quoets around the output +file name before passing it to system(3). + +The issue is reported by Lorenz Hipp in a private mail. + +Signed-off-by: Masatake YAMATO +--- + Tmain/abnormal-output-file-names.d/input.c | 1 + + Tmain/abnormal-output-file-names.d/run.sh | 39 ++++++++++ + .../stderr-expected.txt | 0 + .../stdout-expected.txt | 8 +++ + main/sort.c | 72 ++++++++++++++----- + 5 files changed, 102 insertions(+), 18 deletions(-) + create mode 100644 Tmain/abnormal-output-file-names.d/input.c + create mode 100644 Tmain/abnormal-output-file-names.d/run.sh + create mode 100644 Tmain/abnormal-output-file-names.d/stderr-expected.txt + create mode 100644 Tmain/abnormal-output-file-names.d/stdout-expected.txt + +Index: ctags-5.8/Tmain/abnormal-output-file-names.d/input.c +=================================================================== +--- /dev/null ++++ ctags-5.8/Tmain/abnormal-output-file-names.d/input.c +@@ -0,0 +1 @@ ++int x; +Index: ctags-5.8/Tmain/abnormal-output-file-names.d/run.sh +=================================================================== +--- /dev/null ++++ ctags-5.8/Tmain/abnormal-output-file-names.d/run.sh +@@ -0,0 +1,39 @@ ++# Copyright: 2016 Masatake YAMATO ++# License: GPL-2 ++ ++CTAGS=$1 ++ ++rm -f ./"'" ++rm -f ./'"' ++rm -f ./'$(ls)' ++rm -f ./'a b' ++ ++${CTAGS} --options=NONE -o ./"'" --extra=-pF input.c ++${CTAGS} --options=NONE -o ./'"' --extra=-pF input.c ++${CTAGS} --options=NONE -o ./'$(ls)' --extra=-pF input.c ++${CTAGS} --options=NONE -o ./'a b' --extra=-pF input.c ++ ++echo '#' SINGLE QUOTE ++if [ -e "'" ]; then ++ cat "'" ++fi ++ ++echo '#' DOUBLE QUOTES ++if [ -e '"' ]; then ++ cat '"' ++fi ++ ++echo '#' PROCESS SUBSTITUTION ++if [ -e '$(ls)' ]; then ++ cat '$(ls)' ++fi ++ ++echo '#' SPACE ++if [ -e 'a b' ]; then ++ cat 'a b' ++fi ++ ++rm -f ./"'" ++rm -f ./'"' ++rm -f ./'$(ls)' ++rm -f ./'a b' +Index: ctags-5.8/Tmain/abnormal-output-file-names.d/stdout-expected.txt +=================================================================== +--- /dev/null ++++ ctags-5.8/Tmain/abnormal-output-file-names.d/stdout-expected.txt +@@ -0,0 +1,8 @@ ++# SINGLE QUOTE ++x input.c /^int x;$/;" v typeref:typename:int ++# DOUBLE QUOTES ++x input.c /^int x;$/;" v typeref:typename:int ++# PROCESS SUBSTITUTION ++x input.c /^int x;$/;" v typeref:typename:int ++# SPACE ++x input.c /^int x;$/;" v typeref:typename:int +Index: ctags-5.8/sort.c +=================================================================== +--- ctags-5.8.orig/sort.c ++++ ctags-5.8/sort.c +@@ -19,6 +19,7 @@ + #endif + #include + #include ++#include + + #include "debug.h" + #include "entry.h" +@@ -53,41 +54,83 @@ extern void catFile (const char *const n + # define PE_CONST const + #endif + ++/* ++ Output file name should not be evaluated in system(3) function. ++ The name must be used as is. Quotations are required to block the ++ evaluation. ++ ++ Normal single-quotes are used to quote a cstring: ++ a => 'a' ++ " => '"' ++ ++ If a single-quote is included in the cstring, use double quotes for quoting it. ++ ' => ''"'"'' ++*/ ++static void appendCstringWithQuotes (vString *dest, const char* cstr) ++{ ++ const char* o; ++ ++ vStringPut (dest, '\''); ++ for (o = cstr; *o; o++) ++ { ++ if (*o == '\'') ++ vStringCatS (dest, "'\"'\"'"); ++ else ++ vStringPut (dest, *o); ++ } ++ vStringPut (dest, '\''); ++} ++ + extern void externalSortTags (const boolean toStdout) + { +- const char *const sortNormalCommand = "sort -u -o"; +- const char *const sortFoldedCommand = "sort -u -f -o"; ++ const char *const sortNormalCommand = "/usr/bin/sort -u"; ++ const char *const sortFoldedCommand = "/usr/bin/sort -u -f"; + const char *sortCommand = + Option.sorted == SO_FOLDSORTED ? sortFoldedCommand : sortNormalCommand; ++# ifndef HAVE_SETENV + PE_CONST char *const sortOrder1 = "LC_COLLATE=C"; + PE_CONST char *const sortOrder2 = "LC_ALL=C"; +- const size_t length = 4 + strlen (sortOrder1) + strlen (sortOrder2) + +- strlen (sortCommand) + (2 * strlen (tagFileName ())); +- char *const cmd = (char *) malloc (length + 1); ++# endif ++ vString *cmd = vStringNew (); + int ret = -1; + + if (cmd != NULL) + { + /* Ensure ASCII value sort order. + */ +-#ifdef HAVE_SETENV ++#if defined(HAVE_SETENV) || defined(HAVE_PUTENV) ++# if HAVE_SETENV + setenv ("LC_COLLATE", "C", 1); + setenv ("LC_ALL", "C", 1); +- sprintf (cmd, "%s %s %s", sortCommand, tagFileName (), tagFileName ()); +-#else +-# ifdef HAVE_PUTENV ++# else + putenv (sortOrder1); + putenv (sortOrder2); +- sprintf (cmd, "%s %s %s", sortCommand, tagFileName (), tagFileName ()); +-# else +- sprintf (cmd, "%s %s %s %s %s", sortOrder1, sortOrder2, sortCommand, +- tagFileName (), tagFileName ()); + # endif ++ vStringCatS (cmd, sortCommand); ++// if (! toStdout) ++ { ++ vStringCatS (cmd, " -o "); ++ appendCstringWithQuotes (cmd, tagFileName ()); ++ vStringPut (cmd, ' '); ++ appendCstringWithQuotes (cmd, tagFileName ()); ++ } ++#else ++ vStringCatS (cmd, sortOrder1); ++ vStringPut (cmd, ' '); ++ vStringCatS (cmd, sortOrder2); ++ vStringPut (cmd, ' '); ++ vStringCatS (cmd, sortCommand); ++// if (! toStdout) ++ { ++ vStringCats (cmd, " -o "); ++ appendCstringWithQuotes (cmd, tagFileName ()); ++ vStringPut (cmd, ' '); ++ appendCstringWithQuotes (cmd, tagFileName ()); ++ } + #endif +- verbose ("system (\"%s\")\n", cmd); +- ret = system (cmd); +- free (cmd); +- ++ verbose ("system (\"%s\")\n", vStringValue(cmd)); ++ ret = system (vStringValue(cmd)); ++ vStringDelete (cmd); + } + if (ret != 0) + error (FATAL | PERROR, "cannot sort tag file"); diff --git a/ctags-5.8.tar.gz b/ctags-5.8.tar.gz new file mode 100644 index 0000000..9e92fc6 --- /dev/null +++ b/ctags-5.8.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e44b45dcabe969e0bbbb11e30c246f81abe5d32012db37395eb57d66e9e99c7 +size 479927 diff --git a/ctags-gcc11.patch b/ctags-gcc11.patch new file mode 100644 index 0000000..0b8f643 --- /dev/null +++ b/ctags-gcc11.patch @@ -0,0 +1,268 @@ +diff -u ctags-5.8.orig/c.c ctags-5.8/c.c +--- ctags-5.8.orig/c.c 2021-09-27 10:44:24.772898854 +0200 ++++ ctags-5.8/c.c 2021-09-27 10:58:15.168499970 +0200 +@@ -624,7 +624,7 @@ + return name; + } + +-static void __unused__ pt (tokenInfo *const token) ++static void __maybe_unused__ pt (tokenInfo *const token) + { + if (isType (token, TOKEN_NAME)) + printf ("type: %-12s: %-13s line: %lu\n", +@@ -639,7 +639,7 @@ + tokenString (token->type), token->lineNumber); + } + +-static void __unused__ ps (statementInfo *const st) ++static void __maybe_unused__ ps (statementInfo *const st) + { + unsigned int i; + printf ("scope: %s decl: %s gotName: %s gotParenName: %s isPointer: %s\n", +diff -u ctags-5.8.orig/eiffel.c ctags-5.8/eiffel.c +--- ctags-5.8.orig/eiffel.c 2021-09-27 10:44:24.732898295 +0200 ++++ ctags-5.8/eiffel.c 2021-09-27 10:58:15.168499970 +0200 +@@ -807,7 +807,7 @@ + + static boolean parseType (tokenInfo *const token); + +-static void parseGeneric (tokenInfo *const token, boolean declaration __unused__) ++static void parseGeneric (tokenInfo *const token, boolean declaration __maybe_unused__) + { + unsigned int depth = 0; + #ifdef TYPE_REFERENCE_TOOL +diff -u ctags-5.8.orig/general.h ctags-5.8/general.h +--- ctags-5.8.orig/general.h 2007-05-03 05:21:08.000000000 +0200 ++++ ctags-5.8/general.h 2021-09-27 10:57:03.851490665 +0200 +@@ -57,10 +57,10 @@ + * to prevent warnings about unused variables. + */ + #if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)) && !defined (__GNUG__) +-# define __unused__ __attribute__((unused)) ++# define __maybe_unused__ __attribute__((unused)) + # define __printf__(s,f) __attribute__((format (printf, s, f))) + #else +-# define __unused__ ++# define __maybe_unused__ + # define __printf__(s,f) + #endif + +Common subdirectories: ctags-5.8.orig/gnu_regex and ctags-5.8/gnu_regex +diff -u ctags-5.8.orig/lregex.c ctags-5.8/lregex.c +--- ctags-5.8.orig/lregex.c 2021-09-27 10:44:24.732898295 +0200 ++++ ctags-5.8/lregex.c 2021-09-27 10:58:15.176500083 +0200 +@@ -538,11 +538,11 @@ + #endif /* HAVE_REGEX */ + + extern void addTagRegex ( +- const langType language __unused__, +- const char* const regex __unused__, +- const char* const name __unused__, +- const char* const kinds __unused__, +- const char* const flags __unused__) ++ const langType language __maybe_unused__, ++ const char* const regex __maybe_unused__, ++ const char* const name __maybe_unused__, ++ const char* const kinds __maybe_unused__, ++ const char* const flags __maybe_unused__) + { + #ifdef HAVE_REGEX + Assert (regex != NULL); +@@ -564,10 +564,10 @@ + } + + extern void addCallbackRegex ( +- const langType language __unused__, +- const char* const regex __unused__, +- const char* const flags __unused__, +- const regexCallback callback __unused__) ++ const langType language __maybe_unused__, ++ const char* const regex __maybe_unused__, ++ const char* const flags __maybe_unused__, ++ const regexCallback callback __maybe_unused__) + { + #ifdef HAVE_REGEX + Assert (regex != NULL); +@@ -581,7 +581,7 @@ + } + + extern void addLanguageRegex ( +- const langType language __unused__, const char* const regex __unused__) ++ const langType language __maybe_unused__, const char* const regex __maybe_unused__) + { + #ifdef HAVE_REGEX + if (! regexBroken) +@@ -602,7 +602,7 @@ + */ + + extern boolean processRegexOption (const char *const option, +- const char *const parameter __unused__) ++ const char *const parameter __maybe_unused__) + { + boolean handled = FALSE; + const char* const dash = strchr (option, '-'); +@@ -624,7 +624,7 @@ + return handled; + } + +-extern void disableRegexKinds (const langType language __unused__) ++extern void disableRegexKinds (const langType language __maybe_unused__) + { + #ifdef HAVE_REGEX + if (language <= SetUpper && Sets [language].count > 0) +@@ -639,8 +639,8 @@ + } + + extern boolean enableRegexKind ( +- const langType language __unused__, +- const int kind __unused__, const boolean mode __unused__) ++ const langType language __maybe_unused__, ++ const int kind __maybe_unused__, const boolean mode __maybe_unused__) + { + boolean result = FALSE; + #ifdef HAVE_REGEX +@@ -660,7 +660,7 @@ + return result; + } + +-extern void printRegexKinds (const langType language __unused__, boolean indent __unused__) ++extern void printRegexKinds (const langType language __maybe_unused__, boolean indent __maybe_unused__) + { + #ifdef HAVE_REGEX + if (language <= SetUpper && Sets [language].count > 0) +diff -u ctags-5.8.orig/lua.c ctags-5.8/lua.c +--- ctags-5.8.orig/lua.c 2006-10-12 05:26:40.000000000 +0200 ++++ ctags-5.8/lua.c 2021-09-27 10:58:15.176500083 +0200 +@@ -37,7 +37,7 @@ + */ + + /* for debugging purposes */ +-static void __unused__ print_string (char *p, char *q) ++static void __maybe_unused__ print_string (char *p, char *q) + { + for ( ; p != q; p++) + fprintf (errout, "%c", *p); +diff -u ctags-5.8.orig/main.c ctags-5.8/main.c +--- ctags-5.8.orig/main.c 2021-09-27 10:44:24.784899021 +0200 ++++ ctags-5.8/main.c 2021-09-27 10:58:15.176500083 +0200 +@@ -511,7 +511,7 @@ + * Start up code + */ + +-extern int main (int __unused__ argc, char **argv) ++extern int main (int __maybe_unused__ argc, char **argv) + { + cookedArgs *args; + #ifdef VMS +diff -u ctags-5.8.orig/options.c ctags-5.8/options.c +--- ctags-5.8.orig/options.c 2021-09-27 10:44:24.784899021 +0200 ++++ ctags-5.8/options.c 2021-09-27 10:58:15.180500140 +0200 +@@ -731,7 +731,7 @@ + } + + static void processExcludeOption ( +- const char *const option __unused__, const char *const parameter) ++ const char *const option __maybe_unused__, const char *const parameter) + { + const char *const fileName = parameter + 1; + if (parameter [0] == '\0') +@@ -869,7 +869,7 @@ + } + + static void processFilterTerminatorOption ( +- const char *const option __unused__, const char *const parameter) ++ const char *const option __maybe_unused__, const char *const parameter) + { + freeString (&Option.filterTerminator); + Option.filterTerminator = stringCopy (parameter); +@@ -931,8 +931,8 @@ + } + + static void processHelpOption ( +- const char *const option __unused__, +- const char *const parameter __unused__) ++ const char *const option __maybe_unused__, ++ const char *const parameter __maybe_unused__) + { + printProgramIdentification (); + putchar ('\n'); +@@ -1140,8 +1140,8 @@ + } + + static void processLicenseOption ( +- const char *const option __unused__, +- const char *const parameter __unused__) ++ const char *const option __maybe_unused__, ++ const char *const parameter __maybe_unused__) + { + printProgramIdentification (); + puts (""); +@@ -1167,8 +1167,8 @@ + } + + static void processListMapsOption ( +- const char *const __unused__ option, +- const char *const __unused__ parameter) ++ const char *const __maybe_unused__ option, ++ const char *const __maybe_unused__ parameter) + { + if (parameter [0] == '\0' || strcasecmp (parameter, "all") == 0) + printLanguageMaps (LANG_AUTO); +@@ -1184,8 +1184,8 @@ + } + + static void processListLanguagesOption ( +- const char *const option __unused__, +- const char *const parameter __unused__) ++ const char *const option __maybe_unused__, ++ const char *const parameter __maybe_unused__) + { + printLanguageList (); + exit (0); +@@ -1359,8 +1359,8 @@ + } + + static void processVersionOption ( +- const char *const option __unused__, +- const char *const parameter __unused__) ++ const char *const option __maybe_unused__, ++ const char *const parameter __maybe_unused__) + { + printProgramIdentification (); + exit (0); +diff -u ctags-5.8.orig/parse.c ctags-5.8/parse.c +--- ctags-5.8.orig/parse.c 2007-07-31 07:35:33.000000000 +0200 ++++ ctags-5.8/parse.c 2021-09-27 10:58:15.180500140 +0200 +@@ -376,7 +376,7 @@ + */ + + extern void processLanguageDefineOption ( +- const char *const option, const char *const parameter __unused__) ++ const char *const option, const char *const parameter __maybe_unused__) + { + #ifdef HAVE_REGEX + if (parameter [0] == '\0') +diff -u ctags-5.8.orig/python.c ctags-5.8/python.c +--- ctags-5.8.orig/python.c 2021-09-27 10:44:24.736898351 +0200 ++++ ctags-5.8/python.c 2021-09-27 10:58:15.180500140 +0200 +@@ -135,7 +135,7 @@ + * extract all relevant information and create a tag. + */ + static void makeFunctionTag (vString *const function, +- vString *const parent, int is_class_parent, const char *arglist __unused__) ++ vString *const parent, int is_class_parent, const char *arglist __maybe_unused__) + { + tagEntryInfo tag; + initTagEntry (&tag, vStringValue (function)); +diff -u ctags-5.8.orig/routines.c ctags-5.8/routines.c +--- ctags-5.8.orig/routines.c 2007-06-07 06:35:21.000000000 +0200 ++++ ctags-5.8/routines.c 2021-09-27 10:58:15.184500196 +0200 +@@ -526,7 +526,7 @@ + + #if ! defined (HAVE_STAT_ST_INO) + +-static void canonicalizePath (char *const path __unused__) ++static void canonicalizePath (char *const path __maybe_unused__) + { + #if defined (MSDOS_STYLE_PATH) + char *p; diff --git a/ctags-ycp-parser.diff b/ctags-ycp-parser.diff new file mode 100644 index 0000000..2948749 --- /dev/null +++ b/ctags-ycp-parser.diff @@ -0,0 +1,491 @@ +--- c.c ++++ c.c +@@ -59,35 +59,39 @@ typedef enum eException { + */ + typedef enum eKeywordId { + KEYWORD_NONE = -1, +- KEYWORD_ATTRIBUTE, KEYWORD_ABSTRACT, +- KEYWORD_BOOLEAN, KEYWORD_BYTE, KEYWORD_BAD_STATE, KEYWORD_BAD_TRANS, +- KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT, ++ KEYWORD_ATTRIBUTE, KEYWORD_ABSTRACT, KEYWORD_ANY, ++ KEYWORD_BOOLEAN, KEYWORD_BYTE, KEYWORD_BYTEBLOCK, KEYWORD_BAD_STATE, ++ KEYWORD_BAD_TRANS, ++ KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT, KEYWORD_BLOCK, + KEYWORD_CASE, KEYWORD_CATCH, KEYWORD_CHAR, KEYWORD_CLASS, KEYWORD_CONST, + KEYWORD_CONSTRAINT, KEYWORD_COVERAGE_BLOCK, KEYWORD_COVERAGE_DEF, +- KEYWORD_DEFAULT, KEYWORD_DELEGATE, KEYWORD_DELETE, KEYWORD_DO, ++ KEYWORD_DEFAULT, KEYWORD_DECLARATION, KEYWORD_DELEGATE, KEYWORD_DELETE, ++ KEYWORD_DO, + KEYWORD_DOUBLE, +- KEYWORD_ELSE, KEYWORD_ENUM, KEYWORD_EXPLICIT, KEYWORD_EXTERN, ++ KEYWORD_ELSE, KEYWORD_ENUM, KEYWORD_EXPLICIT, KEYWORD_EXPRESSION, ++ KEYWORD_EXTERN, + KEYWORD_EXTENDS, KEYWORD_EVENT, + KEYWORD_FINAL, KEYWORD_FLOAT, KEYWORD_FOR, KEYWORD_FRIEND, KEYWORD_FUNCTION, + KEYWORD_GOTO, + KEYWORD_IF, KEYWORD_IMPLEMENTS, KEYWORD_IMPORT, KEYWORD_INLINE, KEYWORD_INT, + KEYWORD_INOUT, KEYWORD_INPUT, KEYWORD_INTEGER, KEYWORD_INTERFACE, + KEYWORD_INTERNAL, +- KEYWORD_LOCAL, KEYWORD_LONG, ++ KEYWORD_LIST, KEYWORD_LOCAL, KEYWORD_LOCALE, KEYWORD_LONG, + KEYWORD_M_BAD_STATE, KEYWORD_M_BAD_TRANS, KEYWORD_M_STATE, KEYWORD_M_TRANS, +- KEYWORD_MUTABLE, ++ KEYWORD_MAP, KEYWORD_MUTABLE, + KEYWORD_NAMESPACE, KEYWORD_NEW, KEYWORD_NEWCOV, KEYWORD_NATIVE, + KEYWORD_OPERATOR, KEYWORD_OUTPUT, KEYWORD_OVERLOAD, KEYWORD_OVERRIDE, +- KEYWORD_PACKED, KEYWORD_PORT, KEYWORD_PACKAGE, KEYWORD_PRIVATE, +- KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PUBLIC, ++ KEYWORD_PACKED, KEYWORD_PATH, KEYWORD_PORT, KEYWORD_PACKAGE, ++ KEYWORD_PRIVATE, ++ KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PUBLIC, KEYWORD_REPEAT, + KEYWORD_REGISTER, KEYWORD_RETURN, + KEYWORD_SHADOW, KEYWORD_STATE, + KEYWORD_SHORT, KEYWORD_SIGNED, KEYWORD_STATIC, KEYWORD_STRING, +- KEYWORD_STRUCT, KEYWORD_SWITCH, KEYWORD_SYNCHRONIZED, +- KEYWORD_TASK, KEYWORD_TEMPLATE, KEYWORD_THIS, KEYWORD_THROW, ++ KEYWORD_STRUCT, KEYWORD_SWITCH, KEYWORD_SYNCHRONIZED, KEYWORD_SYMBOL, ++ KEYWORD_TASK, KEYWORD_TEMPLATE, KEYWORD_TERM, KEYWORD_THIS, KEYWORD_THROW, + KEYWORD_THROWS, KEYWORD_TRANSIENT, KEYWORD_TRANS, KEYWORD_TRANSITION, + KEYWORD_TRY, KEYWORD_TYPEDEF, KEYWORD_TYPENAME, +- KEYWORD_UINT, KEYWORD_ULONG, KEYWORD_UNION, KEYWORD_UNSIGNED, KEYWORD_USHORT, ++ KEYWORD_UINT, KEYWORD_ULONG, KEYWORD_UNION, KEYWORD_UNSIGNED, KEYWORD_UNTIL, KEYWORD_USHORT, + KEYWORD_USING, + KEYWORD_VIRTUAL, KEYWORD_VOID, KEYWORD_VOLATILE, + KEYWORD_WCHAR_T, KEYWORD_WHILE +@@ -99,7 +103,7 @@ typedef enum eKeywordId { + typedef struct sKeywordDesc { + const char *name; + keywordId id; +- short isValid [5]; /* indicates languages for which kw is valid */ ++ short isValid [6]; /* indicates languages for which kw is valid */ + } keywordDesc; + + /* Used for reporting the type of object parsed by nextToken (). +@@ -135,6 +139,7 @@ typedef enum eTagScope { + typedef enum eDeclaration { + DECL_NONE, + DECL_BASE, /* base type (default) */ ++ DECL_BLOCK, /* YCP unnamed block */ + DECL_CLASS, + DECL_ENUM, + DECL_EVENT, +@@ -256,6 +261,7 @@ static langType Lang_cpp; + static langType Lang_csharp; + static langType Lang_java; + static langType Lang_vera; ++static langType Lang_ycp; + static vString *Signature; + static boolean CollectingSignature; + +@@ -354,110 +360,138 @@ static kindOption VeraKinds [] = { + { FALSE, 'x', "externvar", "external variable declarations"} + }; + ++/* Used to index into the YCPKinds table. */ ++typedef enum { ++ YK_UNDEFINED = -1, ++ YK_FUNCTION, YK_PROTOTYPE, ++ YK_LOCAL, ++ YK_VARIABLE ++} ycpKind; ++ ++static kindOption YCPKinds [] = { ++ { TRUE, 'f', "function", "function definitions"}, ++ { FALSE, 'p', "prototype", "function prototypes"}, ++ { FALSE, 'l', "local", "local variables"}, ++ { TRUE, 'v', "variable", "variable definitions"}, ++}; ++ + static const keywordDesc KeywordTable [] = { +- /* C++ */ +- /* ANSI C | C# Java */ +- /* | | | | Vera */ +- /* keyword keyword ID | | | | | */ +- { "__attribute__", KEYWORD_ATTRIBUTE, { 1, 1, 1, 0, 0 } }, +- { "abstract", KEYWORD_ABSTRACT, { 0, 0, 1, 1, 0 } }, +- { "bad_state", KEYWORD_BAD_STATE, { 0, 0, 0, 0, 1 } }, +- { "bad_trans", KEYWORD_BAD_TRANS, { 0, 0, 0, 0, 1 } }, +- { "bind", KEYWORD_BIND, { 0, 0, 0, 0, 1 } }, +- { "bind_var", KEYWORD_BIND_VAR, { 0, 0, 0, 0, 1 } }, +- { "bit", KEYWORD_BIT, { 0, 0, 0, 0, 1 } }, +- { "boolean", KEYWORD_BOOLEAN, { 0, 0, 0, 1, 0 } }, +- { "byte", KEYWORD_BYTE, { 0, 0, 0, 1, 0 } }, +- { "case", KEYWORD_CASE, { 1, 1, 1, 1, 0 } }, +- { "catch", KEYWORD_CATCH, { 0, 1, 1, 0, 0 } }, +- { "char", KEYWORD_CHAR, { 1, 1, 1, 1, 0 } }, +- { "class", KEYWORD_CLASS, { 0, 1, 1, 1, 1 } }, +- { "const", KEYWORD_CONST, { 1, 1, 1, 1, 0 } }, +- { "constraint", KEYWORD_CONSTRAINT, { 0, 0, 0, 0, 1 } }, +- { "coverage_block", KEYWORD_COVERAGE_BLOCK, { 0, 0, 0, 0, 1 } }, +- { "coverage_def", KEYWORD_COVERAGE_DEF, { 0, 0, 0, 0, 1 } }, +- { "do", KEYWORD_DO, { 1, 1, 1, 1, 0 } }, +- { "default", KEYWORD_DEFAULT, { 1, 1, 1, 1, 0 } }, +- { "delegate", KEYWORD_DELEGATE, { 0, 0, 1, 0, 0 } }, +- { "delete", KEYWORD_DELETE, { 0, 1, 0, 0, 0 } }, +- { "double", KEYWORD_DOUBLE, { 1, 1, 1, 1, 0 } }, +- { "else", KEYWORD_ELSE, { 1, 1, 0, 1, 0 } }, +- { "enum", KEYWORD_ENUM, { 1, 1, 1, 1, 1 } }, +- { "event", KEYWORD_EVENT, { 0, 0, 1, 0, 1 } }, +- { "explicit", KEYWORD_EXPLICIT, { 0, 1, 1, 0, 0 } }, +- { "extends", KEYWORD_EXTENDS, { 0, 0, 0, 1, 1 } }, +- { "extern", KEYWORD_EXTERN, { 1, 1, 1, 0, 1 } }, +- { "final", KEYWORD_FINAL, { 0, 0, 0, 1, 0 } }, +- { "float", KEYWORD_FLOAT, { 1, 1, 1, 1, 0 } }, +- { "for", KEYWORD_FOR, { 1, 1, 1, 1, 0 } }, +- { "friend", KEYWORD_FRIEND, { 0, 1, 0, 0, 0 } }, +- { "function", KEYWORD_FUNCTION, { 0, 0, 0, 0, 1 } }, +- { "goto", KEYWORD_GOTO, { 1, 1, 1, 1, 0 } }, +- { "if", KEYWORD_IF, { 1, 1, 1, 1, 0 } }, +- { "implements", KEYWORD_IMPLEMENTS, { 0, 0, 0, 1, 0 } }, +- { "import", KEYWORD_IMPORT, { 0, 0, 0, 1, 0 } }, +- { "inline", KEYWORD_INLINE, { 0, 1, 0, 0, 0 } }, +- { "inout", KEYWORD_INOUT, { 0, 0, 0, 0, 1 } }, +- { "input", KEYWORD_INPUT, { 0, 0, 0, 0, 1 } }, +- { "int", KEYWORD_INT, { 1, 1, 1, 1, 0 } }, +- { "integer", KEYWORD_INTEGER, { 0, 0, 0, 0, 1 } }, +- { "interface", KEYWORD_INTERFACE, { 0, 0, 1, 1, 1 } }, +- { "internal", KEYWORD_INTERNAL, { 0, 0, 1, 0, 0 } }, +- { "local", KEYWORD_LOCAL, { 0, 0, 0, 0, 1 } }, +- { "long", KEYWORD_LONG, { 1, 1, 1, 1, 0 } }, +- { "m_bad_state", KEYWORD_M_BAD_STATE, { 0, 0, 0, 0, 1 } }, +- { "m_bad_trans", KEYWORD_M_BAD_TRANS, { 0, 0, 0, 0, 1 } }, +- { "m_state", KEYWORD_M_STATE, { 0, 0, 0, 0, 1 } }, +- { "m_trans", KEYWORD_M_TRANS, { 0, 0, 0, 0, 1 } }, +- { "mutable", KEYWORD_MUTABLE, { 0, 1, 0, 0, 0 } }, +- { "namespace", KEYWORD_NAMESPACE, { 0, 1, 1, 0, 0 } }, +- { "native", KEYWORD_NATIVE, { 0, 0, 0, 1, 0 } }, +- { "new", KEYWORD_NEW, { 0, 1, 1, 1, 0 } }, +- { "newcov", KEYWORD_NEWCOV, { 0, 0, 0, 0, 1 } }, +- { "operator", KEYWORD_OPERATOR, { 0, 1, 1, 0, 0 } }, +- { "output", KEYWORD_OUTPUT, { 0, 0, 0, 0, 1 } }, +- { "overload", KEYWORD_OVERLOAD, { 0, 1, 0, 0, 0 } }, +- { "override", KEYWORD_OVERRIDE, { 0, 0, 1, 0, 0 } }, +- { "package", KEYWORD_PACKAGE, { 0, 0, 0, 1, 0 } }, +- { "packed", KEYWORD_PACKED, { 0, 0, 0, 0, 1 } }, +- { "port", KEYWORD_PORT, { 0, 0, 0, 0, 1 } }, +- { "private", KEYWORD_PRIVATE, { 0, 1, 1, 1, 0 } }, +- { "program", KEYWORD_PROGRAM, { 0, 0, 0, 0, 1 } }, +- { "protected", KEYWORD_PROTECTED, { 0, 1, 1, 1, 1 } }, +- { "public", KEYWORD_PUBLIC, { 0, 1, 1, 1, 1 } }, +- { "register", KEYWORD_REGISTER, { 1, 1, 0, 0, 0 } }, +- { "return", KEYWORD_RETURN, { 1, 1, 1, 1, 0 } }, +- { "shadow", KEYWORD_SHADOW, { 0, 0, 0, 0, 1 } }, +- { "short", KEYWORD_SHORT, { 1, 1, 1, 1, 0 } }, +- { "signed", KEYWORD_SIGNED, { 1, 1, 0, 0, 0 } }, +- { "state", KEYWORD_STATE, { 0, 0, 0, 0, 1 } }, +- { "static", KEYWORD_STATIC, { 1, 1, 1, 1, 1 } }, +- { "string", KEYWORD_STRING, { 0, 0, 1, 0, 1 } }, +- { "struct", KEYWORD_STRUCT, { 1, 1, 1, 0, 0 } }, +- { "switch", KEYWORD_SWITCH, { 1, 1, 1, 1, 0 } }, +- { "synchronized", KEYWORD_SYNCHRONIZED, { 0, 0, 0, 1, 0 } }, +- { "task", KEYWORD_TASK, { 0, 0, 0, 0, 1 } }, +- { "template", KEYWORD_TEMPLATE, { 0, 1, 0, 0, 0 } }, +- { "this", KEYWORD_THIS, { 0, 1, 1, 1, 0 } }, +- { "throw", KEYWORD_THROW, { 0, 1, 1, 1, 0 } }, +- { "throws", KEYWORD_THROWS, { 0, 0, 0, 1, 0 } }, +- { "trans", KEYWORD_TRANS, { 0, 0, 0, 0, 1 } }, +- { "transition", KEYWORD_TRANSITION, { 0, 0, 0, 0, 1 } }, +- { "transient", KEYWORD_TRANSIENT, { 0, 0, 0, 1, 0 } }, +- { "try", KEYWORD_TRY, { 0, 1, 1, 0, 0 } }, +- { "typedef", KEYWORD_TYPEDEF, { 1, 1, 1, 0, 1 } }, +- { "typename", KEYWORD_TYPENAME, { 0, 1, 0, 0, 0 } }, +- { "uint", KEYWORD_UINT, { 0, 0, 1, 0, 0 } }, +- { "ulong", KEYWORD_ULONG, { 0, 0, 1, 0, 0 } }, +- { "union", KEYWORD_UNION, { 1, 1, 0, 0, 0 } }, +- { "unsigned", KEYWORD_UNSIGNED, { 1, 1, 1, 0, 0 } }, +- { "ushort", KEYWORD_USHORT, { 0, 0, 1, 0, 0 } }, +- { "using", KEYWORD_USING, { 0, 1, 1, 0, 0 } }, +- { "virtual", KEYWORD_VIRTUAL, { 0, 1, 1, 0, 1 } }, +- { "void", KEYWORD_VOID, { 1, 1, 1, 1, 1 } }, +- { "volatile", KEYWORD_VOLATILE, { 1, 1, 1, 1, 0 } }, +- { "wchar_t", KEYWORD_WCHAR_T, { 1, 1, 1, 0, 0 } }, +- { "while", KEYWORD_WHILE, { 1, 1, 1, 1, 0 } } ++ /* C++ YCP */ ++ /* ANSI C | C# Java | */ ++ /* | | | | Vera */ ++ /* keyword keyword ID | | | | | | */ ++ { "__attribute__", KEYWORD_ATTRIBUTE, { 1, 1, 1, 0, 0, 0 } }, ++ { "abstract", KEYWORD_ABSTRACT, { 0, 0, 1, 1, 0, 0 } }, ++ { "any", KEYWORD_ANY, { 0, 0, 0, 0, 0, 1 } }, ++ { "bad_state", KEYWORD_BAD_STATE, { 0, 0, 0, 0, 1, 0 } }, ++ { "bad_trans", KEYWORD_BAD_TRANS, { 0, 0, 0, 0, 1, 0 } }, ++ { "bind", KEYWORD_BIND, { 0, 0, 0, 0, 1, 0 } }, ++ { "bind_var", KEYWORD_BIND_VAR, { 0, 0, 0, 0, 1, 0 } }, ++ { "bit", KEYWORD_BIT, { 0, 0, 0, 0, 1, 0 } }, ++ { "block", KEYWORD_BLOCK, { 0, 0, 0, 0, 0, 1 } }, ++ { "boolean", KEYWORD_BOOLEAN, { 0, 0, 0, 1, 0, 1 } }, ++ { "byte", KEYWORD_BYTE, { 0, 0, 0, 1, 0, 0 } }, ++ { "byteblock", KEYWORD_BYTEBLOCK, { 0, 0, 0, 0, 0, 1 } }, ++ { "case", KEYWORD_CASE, { 1, 1, 1, 1, 0, 0 } }, ++ { "catch", KEYWORD_CATCH, { 0, 1, 1, 0, 0, 0 } }, ++ { "char", KEYWORD_CHAR, { 1, 1, 1, 1, 0, 0 } }, ++ { "class", KEYWORD_CLASS, { 0, 1, 1, 1, 1, 0 } }, ++ { "const", KEYWORD_CONST, { 1, 1, 1, 1, 0, 0 } }, ++ { "constraint", KEYWORD_CONSTRAINT, { 0, 0, 0, 0, 1, 0 } }, ++ { "coverage_block", KEYWORD_COVERAGE_BLOCK, { 0, 0, 0, 0, 1, 0 } }, ++ { "coverage_def", KEYWORD_COVERAGE_DEF, { 0, 0, 0, 0, 1, 0 } }, ++ { "declaration", KEYWORD_DECLARATION, { 0, 0, 0, 0, 0, 1 } }, ++ { "do", KEYWORD_DO, { 1, 1, 1, 1, 0, 1 } }, ++ { "default", KEYWORD_DEFAULT, { 1, 1, 1, 1, 0, 0 } }, ++ { "delegate", KEYWORD_DELEGATE, { 0, 0, 1, 0, 0, 0 } }, ++ { "delete", KEYWORD_DELETE, { 0, 1, 0, 0, 0, 0 } }, ++ { "double", KEYWORD_DOUBLE, { 1, 1, 1, 1, 0, 0 } }, ++ { "else", KEYWORD_ELSE, { 1, 1, 0, 1, 0, 1 } }, ++ { "enum", KEYWORD_ENUM, { 1, 1, 1, 1, 1, 1 } }, ++ { "event", KEYWORD_EVENT, { 0, 0, 1, 0, 1, 0 } }, ++ { "explicit", KEYWORD_EXPLICIT, { 0, 1, 1, 0, 0, 0 } }, ++ { "expression", KEYWORD_EXPRESSION, { 0, 0, 0, 0, 0, 1 } }, ++ { "extends", KEYWORD_EXTENDS, { 0, 0, 0, 1, 1, 0 } }, ++ { "extern", KEYWORD_EXTERN, { 1, 1, 1, 0, 1, 0 } }, ++ { "final", KEYWORD_FINAL, { 0, 0, 0, 1, 0, 1 } }, ++ { "float", KEYWORD_FLOAT, { 1, 1, 1, 1, 0, 1 } }, ++ { "for", KEYWORD_FOR, { 1, 1, 1, 1, 0, 0 } }, ++ { "friend", KEYWORD_FRIEND, { 0, 1, 0, 0, 0, 0 } }, ++ { "function", KEYWORD_FUNCTION, { 0, 0, 0, 0, 1, 0 } }, ++ { "goto", KEYWORD_GOTO, { 1, 1, 1, 1, 0, 0 } }, ++ { "if", KEYWORD_IF, { 1, 1, 1, 1, 0, 1 } }, ++ { "implements", KEYWORD_IMPLEMENTS, { 0, 0, 0, 1, 0, 0 } }, ++ { "import", KEYWORD_IMPORT, { 0, 0, 0, 1, 0, 1 } }, ++ { "inline", KEYWORD_INLINE, { 0, 1, 0, 0, 0, 0 } }, ++ { "inout", KEYWORD_INOUT, { 0, 0, 0, 0, 1, 0 } }, ++ { "input", KEYWORD_INPUT, { 0, 0, 0, 0, 1, 0 } }, ++ { "int", KEYWORD_INT, { 1, 1, 1, 1, 0, 0 } }, ++ { "integer", KEYWORD_INTEGER, { 0, 0, 0, 0, 1, 1 } }, ++ { "interface", KEYWORD_INTERFACE, { 0, 0, 1, 1, 1, 0 } }, ++ { "internal", KEYWORD_INTERNAL, { 0, 0, 1, 0, 0, 0 } }, ++ { "list", KEYWORD_LIST, { 0, 0, 0, 0, 0, 1 } }, ++ { "local", KEYWORD_LOCAL, { 0, 0, 0, 0, 1, 0 } }, ++ { "locale", KEYWORD_LOCALE, { 0, 0, 0, 0, 0, 1 } }, ++ { "long", KEYWORD_LONG, { 1, 1, 1, 1, 0, 0 } }, ++ { "m_bad_state", KEYWORD_M_BAD_STATE, { 0, 0, 0, 0, 1, 0 } }, ++ { "m_bad_trans", KEYWORD_M_BAD_TRANS, { 0, 0, 0, 0, 1, 0 } }, ++ { "m_state", KEYWORD_M_STATE, { 0, 0, 0, 0, 1, 0 } }, ++ { "m_trans", KEYWORD_M_TRANS, { 0, 0, 0, 0, 1, 0 } }, ++ { "map", KEYWORD_MAP, { 0, 0, 0, 0, 0, 1 } }, ++ { "mutable", KEYWORD_MUTABLE, { 0, 1, 0, 0, 0, 0 } }, ++ { "namespace", KEYWORD_NAMESPACE, { 0, 1, 1, 0, 0, 0 } }, ++ { "native", KEYWORD_NATIVE, { 0, 0, 0, 1, 0, 0 } }, ++ { "new", KEYWORD_NEW, { 0, 1, 1, 1, 0, 0 } }, ++ { "newcov", KEYWORD_NEWCOV, { 0, 0, 0, 0, 1, 0 } }, ++ { "operator", KEYWORD_OPERATOR, { 0, 1, 1, 0, 0, 0 } }, ++ { "output", KEYWORD_OUTPUT, { 0, 0, 0, 0, 1, 0 } }, ++ { "overload", KEYWORD_OVERLOAD, { 0, 1, 0, 0, 0, 0 } }, ++ { "override", KEYWORD_OVERRIDE, { 0, 0, 1, 0, 0, 0 } }, ++ { "package", KEYWORD_PACKAGE, { 0, 0, 0, 1, 0, 0 } }, ++ { "packed", KEYWORD_PACKED, { 0, 0, 0, 0, 1, 0 } }, ++ { "path", KEYWORD_PATH, { 0, 0, 0, 0, 0, 1 } }, ++ { "port", KEYWORD_PORT, { 0, 0, 0, 0, 1, 0 } }, ++ { "private", KEYWORD_PRIVATE, { 0, 1, 1, 1, 0, 0 } }, ++ { "program", KEYWORD_PROGRAM, { 0, 0, 0, 0, 1, 0 } }, ++ { "protected", KEYWORD_PROTECTED, { 0, 1, 1, 1, 1, 0 } }, ++ { "public", KEYWORD_PUBLIC, { 0, 1, 1, 1, 1, 0 } }, ++ { "repeat", KEYWORD_REPEAT, { 0, 0, 0, 0, 0, 1 } }, ++ { "register", KEYWORD_REGISTER, { 1, 1, 0, 0, 0, 0 } }, ++ { "return", KEYWORD_RETURN, { 1, 1, 1, 1, 0, 1 } }, ++ { "shadow", KEYWORD_SHADOW, { 0, 0, 0, 0, 1, 0 } }, ++ { "short", KEYWORD_SHORT, { 1, 1, 1, 1, 0, 0 } }, ++ { "signed", KEYWORD_SIGNED, { 1, 1, 0, 0, 0, 0 } }, ++ { "state", KEYWORD_STATE, { 0, 0, 0, 0, 1, 0 } }, ++ { "static", KEYWORD_STATIC, { 1, 1, 1, 1, 1, 0 } }, ++ { "string", KEYWORD_STRING, { 0, 0, 1, 0, 1, 1 } }, ++ { "struct", KEYWORD_STRUCT, { 1, 1, 1, 0, 0, 0 } }, ++ { "switch", KEYWORD_SWITCH, { 1, 1, 1, 1, 0, 0 } }, ++ { "synchronized", KEYWORD_SYNCHRONIZED, { 0, 0, 0, 1, 0, 0 } }, ++ { "symbol", KEYWORD_SYMBOL, { 0, 0, 0, 0, 0, 1 } }, ++ { "task", KEYWORD_TASK, { 0, 0, 0, 0, 1, 0 } }, ++ { "template", KEYWORD_TEMPLATE, { 0, 1, 0, 0, 0, 0 } }, ++ { "term", KEYWORD_TERM, { 0, 0, 0, 0, 0, 1 } }, ++ { "this", KEYWORD_THIS, { 0, 1, 1, 1, 0, 0 } }, ++ { "throw", KEYWORD_THROW, { 0, 1, 1, 1, 0, 0 } }, ++ { "throws", KEYWORD_THROWS, { 0, 0, 0, 1, 0, 0 } }, ++ { "trans", KEYWORD_TRANS, { 0, 0, 0, 0, 1, 0 } }, ++ { "transition", KEYWORD_TRANSITION, { 0, 0, 0, 0, 1, 0 } }, ++ { "transient", KEYWORD_TRANSIENT, { 0, 0, 0, 1, 0, 0 } }, ++ { "try", KEYWORD_TRY, { 0, 1, 1, 0, 0, 0 } }, ++ { "typedef", KEYWORD_TYPEDEF, { 1, 1, 1, 0, 1, 0 } }, ++ { "typename", KEYWORD_TYPENAME, { 0, 1, 0, 0, 0, 0 } }, ++ { "uint", KEYWORD_UINT, { 0, 0, 1, 0, 0, 0 } }, ++ { "ulong", KEYWORD_ULONG, { 0, 0, 1, 0, 0, 0 } }, ++ { "union", KEYWORD_UNION, { 1, 1, 0, 0, 0, 0 } }, ++ { "unsigned", KEYWORD_UNSIGNED, { 1, 1, 1, 0, 0, 0 } }, ++ { "until", KEYWORD_UNTIL, { 0, 0, 0, 0, 0, 1 } }, ++ { "ushort", KEYWORD_USHORT, { 0, 0, 1, 0, 0, 0 } }, ++ { "using", KEYWORD_USING, { 0, 1, 1, 0, 0, 0 } }, ++ { "virtual", KEYWORD_VIRTUAL, { 0, 1, 1, 0, 1, 0 } }, ++ { "void", KEYWORD_VOID, { 1, 1, 1, 1, 1, 1 } }, ++ { "volatile", KEYWORD_VOLATILE, { 1, 1, 1, 1, 0, 0 } }, ++ { "wchar_t", KEYWORD_WCHAR_T, { 1, 1, 1, 0, 0, 0 } }, ++ { "while", KEYWORD_WHILE, { 1, 1, 1, 1, 0, 1 } } + }; + + /* +@@ -881,6 +915,21 @@ static veraKind veraTagKind (const tagTy + return result; + } + ++static ycpKind ycpTagKind (const tagType type) ++{ ++ ycpKind result = YK_UNDEFINED; ++ switch (type) ++ { ++ case TAG_FUNCTION: result = YK_FUNCTION; break; ++ case TAG_PROTOTYPE: result = YK_PROTOTYPE; break; ++ case TAG_LOCAL: result = YK_LOCAL; break; ++ case TAG_VARIABLE: result = YK_VARIABLE; break; ++ ++ default: Assert ("Bad YCP tag type" == NULL); break; ++ } ++ return result; ++} ++ + static const char *tagName (const tagType type) + { + const char* result; +@@ -890,6 +939,8 @@ static const char *tagName (const tagTyp + result = JavaKinds [javaTagKind (type)].name; + else if (isLanguage (Lang_vera)) + result = VeraKinds [veraTagKind (type)].name; ++ else if (isLanguage (Lang_ycp)) ++ result = YCPKinds [ycpTagKind (type)].name; + else + result = CKinds [cTagKind (type)].name; + return result; +@@ -904,6 +955,8 @@ static int tagLetter (const tagType type + result = JavaKinds [javaTagKind (type)].letter; + else if (isLanguage (Lang_vera)) + result = VeraKinds [veraTagKind (type)].letter; ++ else if (isLanguage (Lang_ycp)) ++ result = YCPKinds [ycpTagKind (type)].letter; + else + result = CKinds [cTagKind (type)].letter; + return result; +@@ -959,7 +1012,8 @@ static const char* accessField (const st + + static void addContextSeparator (vString *const scope) + { +- if (isLanguage (Lang_c) || isLanguage (Lang_cpp)) ++ if (isLanguage (Lang_c) || isLanguage (Lang_cpp) || ++ isLanguage (Lang_ycp)) + vStringCatS (scope, "::"); + else if (isLanguage (Lang_java) || isLanguage (Lang_csharp)) + vStringCatS (scope, "."); +@@ -1717,9 +1771,11 @@ static void processToken (tokenInfo *con + + case KEYWORD_NONE: processName (st); break; + case KEYWORD_ABSTRACT: st->implementation = IMP_ABSTRACT; break; ++ case KEYWORD_ANY: st->declaration = DECL_BASE; break; + case KEYWORD_ATTRIBUTE: skipParens (); initToken (token); break; + case KEYWORD_BIND: st->declaration = DECL_BASE; break; + case KEYWORD_BIT: st->declaration = DECL_BASE; break; ++ case KEYWORD_BYTEBLOCK: st->declaration = DECL_BASE; break; + case KEYWORD_CATCH: skipParens (); skipBraces (); break; + case KEYWORD_CHAR: st->declaration = DECL_BASE; break; + case KEYWORD_CLASS: st->declaration = DECL_CLASS; break; +@@ -1738,9 +1794,13 @@ static void processToken (tokenInfo *con + case KEYWORD_INT: st->declaration = DECL_BASE; break; + case KEYWORD_INTEGER: st->declaration = DECL_BASE; break; + case KEYWORD_INTERFACE: processInterface (st); break; ++ case KEYWORD_LIST: st->declaration = DECL_BASE; break; + case KEYWORD_LOCAL: setAccess (st, ACCESS_LOCAL); break; ++ case KEYWORD_LOCALE: st->declaration = DECL_BASE; break; + case KEYWORD_LONG: st->declaration = DECL_BASE; break; ++ case KEYWORD_MAP: st->declaration = DECL_BASE; break; + case KEYWORD_OPERATOR: readOperator (st); break; ++ case KEYWORD_PATH: st->declaration = DECL_BASE; break; + case KEYWORD_PRIVATE: setAccess (st, ACCESS_PRIVATE); break; + case KEYWORD_PROGRAM: st->declaration = DECL_PROGRAM; break; + case KEYWORD_PROTECTED: setAccess (st, ACCESS_PROTECTED); break; +@@ -1750,7 +1810,9 @@ static void processToken (tokenInfo *con + case KEYWORD_SIGNED: st->declaration = DECL_BASE; break; + case KEYWORD_STRING: st->declaration = DECL_BASE; break; + case KEYWORD_STRUCT: st->declaration = DECL_STRUCT; break; ++ case KEYWORD_SYMBOL: st->declaration = DECL_BASE; break; + case KEYWORD_TASK: st->declaration = DECL_TASK; break; ++ case KEYWORD_TERM: st->declaration = DECL_BASE; break; + case KEYWORD_THROWS: discardTypeList (token); break; + case KEYWORD_UNION: st->declaration = DECL_UNION; break; + case KEYWORD_UNSIGNED: st->declaration = DECL_BASE; break; +@@ -1793,7 +1855,9 @@ static void processToken (tokenInfo *con + + case KEYWORD_FOR: + case KEYWORD_IF: ++ case KEYWORD_REPEAT: + case KEYWORD_SWITCH: ++ case KEYWORD_UNTIL: + case KEYWORD_WHILE: + { + int c = skipToNonWhite (); +@@ -2302,7 +2366,8 @@ static void addContext (statementInfo *c + { + if (vStringLength (st->context->name) > 0) + { +- if (isLanguage (Lang_c) || isLanguage (Lang_cpp)) ++ if (isLanguage (Lang_c) || isLanguage (Lang_cpp) || ++ isLanguage (Lang_ycp)) + vStringCatS (st->context->name, "::"); + else if (isLanguage (Lang_java) || isLanguage (Lang_csharp)) + vStringCatS (st->context->name, "."); +@@ -2637,7 +2702,12 @@ static void nest (statementInfo *const s + st->inFunction = TRUE; + /* fall through */ + default: +- if (includeTag (TAG_LOCAL, FALSE)) ++ if (isLanguage (Lang_ycp) && ! st->haveQualifyingName) ++ { ++ st->declaration = DECL_BLOCK; ++ createTags (nestLevel, st); ++ } ++ else if (includeTag (TAG_LOCAL, FALSE)) + createTags (nestLevel, st); + else + skipToMatch ("{}"); +@@ -2678,6 +2748,7 @@ static void tagCheck (statementInfo *con + } + } + else if (isContextualStatement (st) || ++ st->declaration == DECL_BLOCK || + st->declaration == DECL_NAMESPACE || + st->declaration == DECL_PROGRAM) + { +@@ -2844,6 +2915,12 @@ static void initializeVeraParser (const + buildKeywordHash (language, 4); + } + ++static void initializeYcpParser (const langType language) ++{ ++ Lang_ycp = language; ++ buildKeywordHash (language, 5); ++} ++ + extern parserDefinition* CParser (void) + { + static const char *const extensions [] = { "c", NULL }; +@@ -2910,4 +2987,16 @@ extern parserDefinition* VeraParser (voi + return def; + } + ++extern parserDefinition* YcpParser (void) ++{ ++ static const char *const extensions [] = { "ycp", NULL }; ++ parserDefinition* def = parserNew ("YCP"); ++ def->kinds = YCPKinds; ++ def->kindCount = KIND_COUNT (YCPKinds); ++ def->extensions = extensions; ++ def->parser2 = findCTags; ++ def->initialize = initializeYcpParser; ++ return def; ++} ++ + /* vi:set tabstop=4 shiftwidth=4 noexpandtab: */ +--- parsers.h ++++ parsers.h +@@ -49,7 +49,8 @@ + VeraParser, \ + VerilogParser, \ + VimParser, \ +- YaccParser ++ YaccParser, \ ++ YcpParser + + #endif /* _PARSERS_H */ + diff --git a/ctags.changes b/ctags.changes new file mode 100644 index 0000000..d0aeecd --- /dev/null +++ b/ctags.changes @@ -0,0 +1,438 @@ +------------------------------------------------------------------- +Thu Feb 2 10:40:02 UTC 2023 - Dirk Müller + +- mark u-a generics as non-%ghost + +------------------------------------------------------------------- +Wed Jan 18 13:06:30 UTC 2023 - Adam Majer + +- CVE-2022-4515.patch: fixes arbitrary command execution via + a tag file with a crafted filename (bsc#1206543, CVE-2022-4515) +- Stop resetting ctags update-alternative priority back to auto. + These are admin settings. +- Remove u-a links in the correct scriptlet + +------------------------------------------------------------------- +Mon Sep 27 08:59:35 UTC 2021 - Michal Suchanek + +- Fix build with gcc 11 + + ctags-gcc11.patch + +------------------------------------------------------------------- +Tue May 4 11:15:01 UTC 2021 - Stefan Brüns + +- Revert ghosting changes, fix real cause for build failure + instead (symlinks pointing to itself). +- Clean spec file: remove historic cruft, use %license for COPYING, + use %make_build/%make_install macros + +------------------------------------------------------------------- +Thu Jan 28 09:54:49 UTC 2021 - Adam Majer + +- Ship symlinks that are not to be ghosted in the first place + +------------------------------------------------------------------- +Mon Jan 11 12:09:50 UTC 2021 - Michal Suchanek + +- Fix build on Tumbleweed - do not ship ghost symlinks. + +------------------------------------------------------------------- +Sun Feb 26 04:37:26 UTC 2017 - msuchanek@suse.com + +- merge with arduino-ctags https://github.com/arduino/ctags + * provide arduino-ctags + * redo patch queue http://repo.or.cz/git-browser/by-commit.html?r=arduino-ctags/SUSE.git + + new patches + 0001-Mixing-with-anjuta-tags-https-git.gnome.org-browse-a.patch + - add vala support + - update many existing tags with new features + 0002-Making-inline-behave-like-an-attribute.-Fixes-1.patch + 0003-Treat-typename-as-an-attribute.patch + 0004-parseReturnType-should-start-from-the-first-non-brac.patch + 0005-Ensuring-a-space-is-printed-in-return-type-AFTER-the.patch + 0006-Prevent-C-static_assert-from-stopping-parsing.patch + 0007-c-Handle-C-11-noexcept.patch + 0008-c-Properly-parse-C-11-override-and-final-members.patch + 0009-Parse-C-11-enums-with-type-specifier.patch + 0010-Parse-C-11-classed-enums.patch + 0011-Handle-template-expressions-that-may-use-the-or-oper.patch + 0012-Make-sure-we-don-t-throw-things-away-while-collectin.patch + 0013-C-mitigate-matching-error-on-generics-containing-an-.patch + 0014-fix-wrongly-interpreted-in-template.patch + 0015-Added-constexpr-as-keyword.patch + + refreshed existing patches + 0016-CVE-2014-7204.patch + 0017-Go-language-support.patch (go-tags.patch) + 0018-SUSE-man-page-changes.patch (ctags-5.7.diff) + 0019-Do-not-include-build-time-in-binary.patch (ctags-date-time.patch) + +------------------------------------------------------------------- +Thu Aug 18 08:25:26 UTC 2016 - adam.majer@suse.de + +- Own our update-alternatives symlink (bnc#994261) +- Use conflict-free symlinks instead of touch files for + placeholders. + +------------------------------------------------------------------- +Tue May 24 15:26:39 UTC 2016 - mpluskal@suse.com + +- Cleanup spec file with spec-cleaner + +------------------------------------------------------------------- +Tue May 24 10:10:43 UTC 2016 - adam.majer@suse.com + +- Add missing Requires(post) on coreutils as it is using `rm`. + (boo #976920) + +------------------------------------------------------------------- +Tue Oct 7 05:45:51 UTC 2014 - puzel@suse.com + +- Fix endless loop in javascript parser + (bnc#899486, CVE-2014-7204) +- Added CVE-2014-7204.patch + +------------------------------------------------------------------- +Sat Apr 27 10:12:43 UTC 2013 - schwab@linux-m68k.org + +- Remove etags and gnuctags, provided by etags package now +- Install ctags as ctags-exuberant and provide ctags via + update-alternatives + +------------------------------------------------------------------- +Fri Mar 22 08:46:26 UTC 2013 - mmeister@suse.com + +- Added url as source. + Please see http://en.opensuse.org/SourceUrls + +------------------------------------------------------------------- +Thu Aug 16 12:04:00 UTC 2012 - graham@andtech.eu + +- go-tags.patch: Add patch supporting Go language + +------------------------------------------------------------------- +Sun Sep 18 00:06:54 UTC 2011 - jengelh@medozas.de + +- Remove redundant tags/sections from specfile + +------------------------------------------------------------------- +Tue Aug 2 15:33:11 UTC 2011 - puzel@novell.com + +- add etags-strcpy-overlap.patch (bnc#705308) + +------------------------------------------------------------------- +Fri Jul 29 16:49:36 UTC 2011 - puzel@novell.com + +- update to ctags-5.8 + - Removed ".ml" as a Lisp extension (now OCaml) [Lisp]. + - Added support for Ant language, contributed by David Fishburn. + - Added support for DOS Batch language, contributed by David + Fishburn. + - Added support for Flex (Adobe) language, contributed by David + Fishburn. + - Added support for MATLAB language, contributed by David Fishburn. + - Added support for Objective Camel (OCaml), provided by Vincent + Berthoux + - Added support for TeX language, contributed by David Fishburn. + - Added support for VHDL language, contributed by Nicolas Vincent + - Added support for Pyrex/Cython declarations [Python]. + - Added support for "v" kind, for variables [Python]. + - Added support for class and member variables + - Added support for recent enhancements to Eiffel language + [Eiffel]. + - Added support for ASP classes, contributed by Zendhi Nagao; + changes meaning of 'c' kind flag [ASP]. + - Added regex support when compiling with MinGW. Gnu regex module + now included in all distributions. + - Fixed detection of triple strings inside other strings + - Fixed an endless loop with comments in triple strings + - Fixed bug where functions were sometimes seen as methods + - Fixed parsing of method parameter annotations, fix contributed by + Paolo "blaisorblade" Giarrusso + - Fixed parsing of global scope qualifiers in base class lists + - Fixed bug where namespace members were given kinds corresponding + to globals + - Fixed parsing of "else" + - Fixed parsing of derived enums + - Fixed parsing of "foreach" + - Fixed parsing of simple generic classes + - Fixed bug with detecting identifiers inside variables + - Fixed bug with detecting identifiers at the start of variables + - Fixed parsing of triple single-quoted multi-line strings +- disabled YCP parser for now (does not apply) +- add ctags-date-time.patch +- use spec-cleaner + +------------------------------------------------------------------- +Fri Dec 18 16:44:25 CET 2009 - jengelh@medozas.de + +- enable parallel building + +------------------------------------------------------------------- +Wed Aug 26 12:53:54 CEST 2009 - mls@suse.de + +- make patch0 usage consistent + +------------------------------------------------------------------- +Fri Sep 5 13:56:30 CEST 2008 - schwab@suse.de + +- Update to etags 17.38.1.4. + +------------------------------------------------------------------- +Wed Jan 9 13:59:22 CET 2008 - schwab@suse.de + +- Update to etags 17.38. + +------------------------------------------------------------------- +Tue Nov 13 14:22:21 CET 2007 - schwab@suse.de + +- Update etags from Emacs trunk. + +------------------------------------------------------------------- +Mon Nov 12 21:43:02 CET 2007 - bwalle@suse.de + +- update to ctags 5.7 + * Added support for DIM AS [Freebasic] + * Added support for arbitrary nesting depth [Python] + * Added support for verbatim string literals [C#] + * Added support for .ctags as well as ctags.cnf on Windows + * Added support for non-extern, non-static functions returning + wchar_t, contributed by Aaron Peromsik [C++] + * Added support for numerous revision control systems including + Bazaar and Mercurial + * Added support for enums [Java] + * Added support for multiple-level namespace declarations [C#] + * Added .svn to list of directories ignored during recursion + (--recurse). + * Added support for BlitzBasic, PureBasic and FreeBasic + * Added support for interfaces and static/public/protected/ + private functions [PHP]. + * Added support for 'package' keyword [Perl]. + * Added support for multi-line subroutine, package, and constant + definitions [Perl]. + * Added support for optional subroutine declarations [Perl]. + * Added support for formats [Perl]. + * Added support for new convert keyword [Eiffel]. + * Added optional tags for forward variable declarations [C, C++]. + * Changed parsing of option input file (-L) to strip trailing + white space. + * Ignore comments mixed into definitions and declarations [Perl]. + * Fixed detecting labels with whitespace after label name [Perl] + * Fixed parsing of generic classes/interfaces [Java] + * Fixed misidentification of fully qualified function calls as + labels [Perl]. + * Fixed parsing of inner classes [Python] + * Fixed line continuation [Python] + * Fixed parsing of annotations [Java] + * Fixed block-comment parsing [Verilog] + * Fixed typo in man page + * Fixed missing chunk of text in man page and over-use of hyphens + in UTF-8 locales + * Fixed parsing of ` as a method name [Ruby]. + * Fixed parsing of keywords in string literals [Ruby] + * Fixed potential segmentation violation + * Fixed parsing of destructors with whitespace after the '~' [C++] + * Fixed default access of unions to be public [C++] + * Fixed various memory leaks, mostly contributed by Dmitry Antipov. + * Fixed parsing of `define [Verilog] + * Fixed crashes involving '/' [Verilog] + * Fixed compilation problem on MinGW + * Fixed generation of HTML-formatted man page + * Fixed recognition of Python scripts having '#!/usr/bin/python' + as first line + * Fixed parsing of Fortran comment-to-end-of-line with no newline + before EOF [Debian] + * Fixed parsing of << [C/C++] + * Fixed parsing of fully-qualified type names [Java] + * Fixed handling of lone carriage-return characters in file + +------------------------------------------------------------------- +Tue Feb 6 13:27:01 CET 2007 - schwab@suse.de + +- Update etags from CVS. + +------------------------------------------------------------------- +Tue Jan 9 13:48:55 CET 2007 - schwab@suse.de + +- More etags fixes from CVS. + +------------------------------------------------------------------- +Sat Dec 30 10:36:34 CET 2006 - schwab@suse.de + +- Fix handling of relative names in #line. + +------------------------------------------------------------------- +Wed Dec 20 12:49:51 CET 2006 - schwab@suse.de + +- Update etags from CVS. + +------------------------------------------------------------------- +Tue May 30 15:10:42 CEST 2006 - schwab@suse.de + +- Update to ctags 5.6 + * Reformatted code for independence of tab stop setting. + * Changed default configuration to disable installation of etags links. + * Changed --langmap to first unmap each supplied extension from other + languages. + * Added support for ASP constants [ASP, Patch #961842]. + * Added support for GNU make extensions [Make]. + * Added .mk as extension recognized as a make language file [Make]. + * Added missing help for list-maps options [Bug #1201826]. + * Added new extension field "typeref" [thanks to Bram Moolenaar]. + * Extended functionality of Ruby parser with patch from Elliot Hughes + [Ruby]. + * Fixed creation of TAGS file with etags-include but no files [Bug + #941233]. + * Fixed problem reading last line of list file (-L) without final + newline. + * Fixed infinite loop that could occur on files without final newline + [C, Java]. + * Fixed incorrect tag for first field of table [SQL]. + * Fixed missing tags for functions beginning with underscore [Sh]. + * Fixed missing tags for functions with variable arg list [C, Bug + #1201689]. + * Fixed parsing problem with parentheses in argument list [C, Bug + #1085585]. + * Fixed problem in preprocessor directive handling [C, Bug #1086609]. +- Update etags to 17.17. + +------------------------------------------------------------------- +Tue Mar 7 23:18:46 CET 2006 - od@suse.de + +- wrote and added a YCP parser based on the C code parser + (ctags-5.5.4-ycp-parser.diff) + +------------------------------------------------------------------- +Wed Jan 25 21:35:15 CET 2006 - mls@suse.de + +- converted neededforbuild to BuildRequires + +------------------------------------------------------------------- +Wed Dec 7 20:46:09 CET 2005 - od@suse.de + +- Added option -A/--allow-duplicates to gnuctags + +------------------------------------------------------------------- +Wed Dec 7 02:28:07 CET 2005 - od@suse.de + +- Don't strip etags/gnuctags + +------------------------------------------------------------------- +Tue Oct 18 12:44:46 CEST 2005 - schwab@suse.de + +- Update to etags 17.14. + +------------------------------------------------------------------- +Mon Nov 15 17:06:34 CET 2004 - schwab@suse.de + +- Update to etags 17.5. + +------------------------------------------------------------------- +Tue May 4 22:17:18 CEST 2004 - schwab@suse.de + +- Update to ctags 5.5.4. + +------------------------------------------------------------------- +Sat Jan 10 20:57:54 CET 2004 - adrian@suse.de + +- add %defattr + +------------------------------------------------------------------- +Fri Sep 26 09:32:30 CEST 2003 - schwab@suse.de + +- Update to ctags 5.5.2. + +------------------------------------------------------------------- +Tue Aug 5 20:47:31 CEST 2003 - schwab@suse.de + +- Update to ctags 5.5.1. + +------------------------------------------------------------------- +Wed Apr 2 13:29:55 CEST 2003 - schwab@suse.de + +- Update to ctags 5.5. +- Update to etags 16.56. + +------------------------------------------------------------------- +Tue Sep 17 17:34:28 CEST 2002 - ro@suse.de + +- removed bogus self-provides + +------------------------------------------------------------------- +Tue Sep 17 17:11:00 CEST 2002 - schwab@suse.de + +- Update to ctags 5.3.1. + +------------------------------------------------------------------- +Thu Jul 18 10:53:15 CEST 2002 - schwab@suse.de + +- Update to ctags 5.3. + +------------------------------------------------------------------- +Fri Dec 14 15:59:05 CET 2001 - schwab@suse.de + +- Update ctags to 5.1. +- Update etags to 14.21. + +------------------------------------------------------------------- +Thu May 18 13:26:59 CEST 2000 - schwab@suse.de + +- Use BuildRoot. +- Remove etags.c changes again. + +------------------------------------------------------------------- +Wed May 17 19:33:55 CEST 2000 - kasal@suse.cz + +- strip etags/gnuctags +- Fixed etags.c changes + +------------------------------------------------------------------- +Mon May 15 16:49:20 CEST 2000 - schwab@suse.de + +- Discard etags.c changes (#2772). + +------------------------------------------------------------------- +Mon Jan 31 18:15:00 CET 2000 - werner@suse.de + +- Really rename gctags to gnuctags + +------------------------------------------------------------------- +Mon Jan 31 12:41:54 CET 2000 - kasal@suse.cz + +- fixed spec file to really use the *dif files +- gctags renamed to gnuctags +- rewrote the NOTEs in the manpages and added + "see also (gnu)ctags(1), gctags(1) and global(1)" +- etags.c now uses #ifdef's + +------------------------------------------------------------------- +Wed Jan 26 19:15:48 CET 2000 - werner@suse.de + +- New ctags version 3.3.1 + * Disable etags (is usable with `ctags -e') +- Add etags/ctags from Emacs sources + * rename this ctags with gctags +- Make some NOTEs within the manual pages of both packages +- Add a README.SuSE to explain why we have two versions + +------------------------------------------------------------------- +Mon Sep 13 17:23:57 CEST 1999 - bs@suse.de + +- ran old prepare_spec on spec file to switch to new prepare_spec. + +------------------------------------------------------------------- +Wed Sep 8 11:59:42 CEST 1999 - schwab@suse.de + +- specfile cleanup + +------------------------------------------------------------------- +Tue Jun 15 16:55:26 MEST 1999 - uli@suse.de + +- update -> 3.2.2 + +---------------------------------------------------------------------------- +Sun Apr 13 23:04:29 MEST 1997 - florian@suse.de + + +- new package with ctags 1.5 (used to be together with vim.tgz) + + diff --git a/ctags.spec b/ctags.spec new file mode 100644 index 0000000..a0d42b4 --- /dev/null +++ b/ctags.spec @@ -0,0 +1,104 @@ +# +# spec file for package ctags +# +# Copyright (c) 2023 SUSE LLC +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via https://bugs.opensuse.org/ +# + + +Name: ctags +Version: 5.8 +Release: 0 +Summary: A Program to Generate Tag Files for Use with vi and Other Editors +License: GPL-2.0-or-later +Group: Development/Tools/Navigators +URL: http://ctags.sourceforge.net/ +Source0: http://downloads.sourceforge.net/project/%{name}/%{name}/%{version}/%{name}-%{version}.tar.gz +# No resources to make this patch work with ctags-5.8 (applied to ctags-5.7) +# Anyone is welcome to make it work again. +Source2: ctags-ycp-parser.diff +Patch1: 0001-Mixing-with-anjuta-tags-https-git.gnome.org-browse-a.patch +Patch2: 0002-Making-inline-behave-like-an-attribute.-Fixes-1.patch +Patch3: 0003-Treat-typename-as-an-attribute.patch +Patch4: 0004-parseReturnType-should-start-from-the-first-non-brac.patch +Patch5: 0005-Ensuring-a-space-is-printed-in-return-type-AFTER-the.patch +Patch6: 0006-Prevent-C-static_assert-from-stopping-parsing.patch +Patch7: 0007-c-Handle-C-11-noexcept.patch +Patch8: 0008-c-Properly-parse-C-11-override-and-final-members.patch +Patch9: 0009-Parse-C-11-enums-with-type-specifier.patch +Patch10: 0010-Parse-C-11-classed-enums.patch +Patch11: 0011-Handle-template-expressions-that-may-use-the-or-oper.patch +Patch12: 0012-Make-sure-we-don-t-throw-things-away-while-collectin.patch +Patch13: 0013-C-mitigate-matching-error-on-generics-containing-an-.patch +Patch14: 0014-fix-wrongly-interpreted-in-template.patch +Patch15: 0015-Added-constexpr-as-keyword.patch +Patch16: 0016-CVE-2014-7204.patch +Patch17: 0017-Go-language-support.patch +Patch18: 0018-SUSE-man-page-changes.patch +Patch19: 0019-Do-not-include-build-time-in-binary.patch +Patch20: ctags-gcc11.patch +Patch21: CVE-2022-4515.patch +BuildRequires: update-alternatives +Requires(pre): update-alternatives +Requires(post): update-alternatives +Requires(post): coreutils +Provides: arduino-ctags + +%description +CTags (from Darren Hiebert) generates tag files from source code in C, +C++, Eiffel, Fortran, and Java to be used with vi and its derivatives, +Emacs, and several other editors. + +%prep +%setup -q +%autopatch -p1 + +%build +%configure +%make_build + +%install +# Makefile ignores DESTDIR ... +%make_install \ + prefix=%{buildroot}%{_prefix} \ + bindir=%{buildroot}%{_bindir} \ + mandir=%{buildroot}%{_mandir} + +mv %{buildroot}%{_bindir}/ctags{,-exuberant} +mv %{buildroot}%{_mandir}/man1/ctags{,-exuberant}.1 + +mkdir -p %{buildroot}%{_sysconfdir}/alternatives/ +ln -s %{_sysconfdir}/alternatives/ctags %{buildroot}%{_bindir}/ctags +ln -s %{_sysconfdir}/alternatives/ctags.1%{ext_man} %{buildroot}%{_mandir}/man1/ctags.1%{ext_man} + +%post +test -L %{_bindir}/ctags || rm -f %{_bindir}/ctags +update-alternatives --install %{_bindir}/ctags ctags %{_bindir}/ctags-exuberant 20 \ + --slave %{_mandir}/man1/ctags.1.gz ctags.1 %{_mandir}/man1/ctags-exuberant.1.gz + +%postun +if [ ! -f %{_bindir}/ctags-exuberant ]; then + update-alternatives --remove ctags %{_bindir}/ctags-exuberant +fi + +%files +%license COPYING +%doc EXTENDING.html FAQ README +%{_bindir}/ctags +%{_bindir}/ctags-exuberant +%{_mandir}/man1/ctags-exuberant.1%{ext_man} +%{_mandir}/man1/ctags.1%{ext_man} +%ghost %{_sysconfdir}/alternatives/ctags +%ghost %{_sysconfdir}/alternatives/ctags.1%{ext_man} + +%changelog