From 895543b272b1bb41e209f580159ec2b4c48d77d5b24b03cd9e949c22b38f7156 Mon Sep 17 00:00:00 2001 From: Adam Majer Date: Tue, 7 Mar 2017 11:05:05 +0000 Subject: [PATCH 1/2] Accepting request 477341 from home:michals:arduino OBS-URL: https://build.opensuse.org/request/show/477341 OBS-URL: https://build.opensuse.org/package/show/devel:tools/ctags?expand=0&rev=29 --- ...ta-tags-https-git.gnome.org-browse-a.patch | 2868 +++++++++++++++++ ...ne-behave-like-an-attribute.-Fixes-1.patch | 26 + 0003-Treat-typename-as-an-attribute.patch | 28 + ...should-start-from-the-first-non-brac.patch | 57 + ...-is-printed-in-return-type-AFTER-the.patch | 32 + ...-static_assert-from-stopping-parsing.patch | 42 + 0007-c-Handle-C-11-noexcept.patch | 42 + ...arse-C-11-override-and-final-members.patch | 56 + ...Parse-C-11-enums-with-type-specifier.patch | 33 + 0010-Parse-C-11-classed-enums.patch | 48 + ...expressions-that-may-use-the-or-oper.patch | 62 + ...-t-throw-things-away-while-collectin.patch | 39 + ...ing-error-on-generics-containing-an-.patch | 35 + ...-fix-wrongly-interpreted-in-template.patch | 44 + 0015-Added-constexpr-as-keyword.patch | 41 + ...014-7204.patch => 0016-CVE-2014-7204.patch | 38 +- ...gs.patch => 0017-Go-language-support.patch | 31 +- ...7.diff => 0018-SUSE-man-page-changes.patch | 27 +- ...-Do-not-include-build-time-in-binary.patch | 45 +- ctags.changes | 30 + ctags.spec | 46 +- 21 files changed, 3616 insertions(+), 54 deletions(-) create mode 100644 0001-Mixing-with-anjuta-tags-https-git.gnome.org-browse-a.patch create mode 100644 0002-Making-inline-behave-like-an-attribute.-Fixes-1.patch create mode 100644 0003-Treat-typename-as-an-attribute.patch create mode 100644 0004-parseReturnType-should-start-from-the-first-non-brac.patch create mode 100644 0005-Ensuring-a-space-is-printed-in-return-type-AFTER-the.patch create mode 100644 0006-Prevent-C-static_assert-from-stopping-parsing.patch create mode 100644 0007-c-Handle-C-11-noexcept.patch create mode 100644 0008-c-Properly-parse-C-11-override-and-final-members.patch create mode 100644 0009-Parse-C-11-enums-with-type-specifier.patch create mode 100644 0010-Parse-C-11-classed-enums.patch create mode 100644 0011-Handle-template-expressions-that-may-use-the-or-oper.patch create mode 100644 0012-Make-sure-we-don-t-throw-things-away-while-collectin.patch create mode 100644 0013-C-mitigate-matching-error-on-generics-containing-an-.patch create mode 100644 0014-fix-wrongly-interpreted-in-template.patch create mode 100644 0015-Added-constexpr-as-keyword.patch rename CVE-2014-7204.patch => 0016-CVE-2014-7204.patch (74%) rename go-tags.patch => 0017-Go-language-support.patch (96%) rename ctags-5.7.diff => 0018-SUSE-man-page-changes.patch (73%) rename ctags-date-time.patch => 0019-Do-not-include-build-time-in-binary.patch (50%) 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..4d9cf09 --- /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..0a0e52a --- /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..a3f57c5 --- /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..4dfc968 --- /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..4206026 --- /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..d82ef66 --- /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..f1ddaec --- /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..9c0e555 --- /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..5289fbb --- /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..2e08506 --- /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..3980720 --- /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..6772f89 --- /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..70e008d --- /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..92ef623 --- /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..c4ebae9 --- /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/CVE-2014-7204.patch b/0016-CVE-2014-7204.patch similarity index 74% rename from CVE-2014-7204.patch rename to 0016-CVE-2014-7204.patch index 2e7e212..da8171d 100644 --- a/CVE-2014-7204.patch +++ b/0016-CVE-2014-7204.patch @@ -1,24 +1,19 @@ -From e23093345c6f63358d979f2c87c57ef4050ba864 Mon Sep 17 00:00:00 2001 -From: dfishburn -Date: Wed, 24 Oct 2012 01:13:13 +0000 -Subject: [PATCH] Changed the javascript parser to set the tag's scope rather - than including it in the tag name. - -Patch from Colomban. - - +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 +++++++++++++++++++++++++++++++++++++++++++++++++++--- + jscript.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) -Index: ctags-5.8/jscript.c -=================================================================== ---- ctags-5.8.orig/jscript.c -+++ ctags-5.8/jscript.c -@@ -215,6 +215,7 @@ static void deleteToken (tokenInfo *cons +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 */ @@ -26,7 +21,7 @@ Index: ctags-5.8/jscript.c static void makeConstTag (tokenInfo *const token, const jsKind kind) { if (JsKinds [kind].enabled && ! token->ignoreTag ) -@@ -238,12 +239,13 @@ static void makeJsTag (tokenInfo *const +@@ -238,12 +239,13 @@ static void makeJsTag (tokenInfo *const token, const jsKind kind) if (JsKinds [kind].enabled && ! token->ignoreTag ) { @@ -42,7 +37,7 @@ Index: ctags-5.8/jscript.c fulltag = vStringNew (); vStringCopy(fulltag, token->scope); vStringCatS (fulltag, "."); -@@ -251,8 +253,54 @@ static void makeJsTag (tokenInfo *const +@@ -251,8 +253,54 @@ static void makeJsTag (tokenInfo *const token, const jsKind kind) vStringTerminate(fulltag); vStringCopy(token->string, fulltag); vStringDelete (fulltag); @@ -58,8 +53,7 @@ Index: ctags-5.8/jscript.c + + e.extensionFields.scope[0] = JsKinds [parent_kind].name; + e.extensionFields.scope[1] = vStringValue (token->scope); - } -- makeConstTag (token, kind); ++ } + * makeConstTag (token, kind); * + makeTagEntry (&e); + } @@ -92,9 +86,13 @@ Index: ctags-5.8/jscript.c + + 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/go-tags.patch b/0017-Go-language-support.patch similarity index 96% rename from go-tags.patch rename to 0017-Go-language-support.patch index 273c72b..d7f3717 100644 --- a/go-tags.patch +++ b/0017-Go-language-support.patch @@ -1,3 +1,15 @@ +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 @@ -675,10 +687,10 @@ index 0000000..6bd3a36 + return def; +} diff --git a/parsers.h b/parsers.h -index c0cab90..8f7b615 100644 +index e4a50e1..b150506 100644 --- a/parsers.h +++ b/parsers.h -@@ -31,6 +31,7 @@ +@@ -32,6 +32,7 @@ ErlangParser, \ FlexParser, \ FortranParser, \ @@ -686,8 +698,16 @@ index c0cab90..8f7b615 100644 HtmlParser, \ JavaParser, \ JavaScriptParser, \ +@@ -76,6 +77,7 @@ + FlexParser, \ + FortranParser, \ + GenieParser, \ ++ GoParser, \ + HtmlParser, \ + JavaParser, \ + JavaScriptParser, \ diff --git a/source.mak b/source.mak -index 559246f..df7067d 100644 +index 3e5f740..d4c4c26 100644 --- a/source.mak +++ b/source.mak @@ -24,6 +24,7 @@ SOURCES = \ @@ -698,7 +718,7 @@ index 559246f..df7067d 100644 html.c \ jscript.c \ keyword.c \ -@@ -87,6 +88,7 @@ OBJECTS = \ +@@ -86,6 +87,7 @@ OBJECTS = \ flex.$(OBJEXT) \ fortran.$(OBJEXT) \ get.$(OBJEXT) \ @@ -706,3 +726,6 @@ index 559246f..df7067d 100644 html.$(OBJEXT) \ jscript.$(OBJEXT) \ keyword.$(OBJEXT) \ +-- +2.11.0 + diff --git a/ctags-5.7.diff b/0018-SUSE-man-page-changes.patch similarity index 73% rename from ctags-5.7.diff rename to 0018-SUSE-man-page-changes.patch index 6d72668..701b628 100644 --- a/ctags-5.7.diff +++ b/0018-SUSE-man-page-changes.patch @@ -1,12 +1,24 @@ ---- ctags.1 -+++ ctags.1 2001/12/14 14:41:12 -@@ -9,12 +9,29 @@ +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. @@ -33,7 +45,7 @@ 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 -@@ -1484,7 +1501,7 @@ +@@ -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 @@ -42,7 +54,7 @@ try to use \fBCTAGS\fP instead. .TP 8 -@@ -1535,9 +1552,15 @@ +@@ -1136,9 +1153,15 @@ lines to indicate separate command-line arguments. The default tag file created by \fBctags\fP. .TP .I TAGS @@ -59,3 +71,6 @@ The official Exuberant Ctags web site at: .RS +-- +2.11.0 + diff --git a/ctags-date-time.patch b/0019-Do-not-include-build-time-in-binary.patch similarity index 50% rename from ctags-date-time.patch rename to 0019-Do-not-include-build-time-in-binary.patch index e57447b..0dd1eec 100644 --- a/ctags-date-time.patch +++ b/0019-Do-not-include-build-time-in-binary.patch @@ -1,19 +1,17 @@ -Index: ctags-5.8/options.c -=================================================================== ---- ctags-5.8.orig/options.c -+++ ctags-5.8/options.c -@@ -924,7 +924,6 @@ static void printProgramIdentification ( - 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 (); - } -Index: ctags-5.8/main.c -=================================================================== ---- ctags-5.8.orig/main.c -+++ ctags-5.8/main.c +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 }; @@ -32,3 +30,18 @@ Index: ctags-5.8/main.c /* * 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/ctags.changes b/ctags.changes index 6d3328b..7b98a40 100644 --- a/ctags.changes +++ b/ctags.changes @@ -1,3 +1,33 @@ +------------------------------------------------------------------- +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 + 0018-SUSE-man-page-changes.patch + 0019-Do-not-include-build-time-in-binary.patch + ------------------------------------------------------------------- Thu Aug 18 08:25:26 UTC 2016 - adam.majer@suse.de diff --git a/ctags.spec b/ctags.spec index da99800..2598fc7 100644 --- a/ctags.spec +++ b/ctags.spec @@ -1,7 +1,7 @@ # # spec file for package ctags # -# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -27,14 +27,30 @@ Source0: http://downloads.sourceforge.net/project/%{name}/%{name}/%{versi # 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: ctags-5.7.diff -Patch3: ctags-date-time.patch -Patch4: go-tags.patch -Patch5: CVE-2014-7204.patch +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 BuildRequires: update-alternatives Requires(pre): update-alternatives -Requires(post): update-alternatives +Requires(post): update-alternatives Requires(post): coreutils +Provides: arduino-ctags BuildRoot: %{_tmppath}/%{name}-%{version}-build %description @@ -44,11 +60,25 @@ Emacs, and several other editors. %prep %setup -q -%patch1 -#%#patch2 +%patch1 -p1 +%patch2 -p1 %patch3 -p1 %patch4 -p1 %patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 +%patch13 -p1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 %build %configure From c010264be8d6212216b729b3d64f6b80ce9a4362c048426773de44a6a6d1096b Mon Sep 17 00:00:00 2001 From: Adam Majer Date: Wed, 8 Mar 2017 16:05:45 +0000 Subject: [PATCH 2/2] Accepting request 477500 from home:michals:arduino Mention old patch names in changelog OBS-URL: https://build.opensuse.org/request/show/477500 OBS-URL: https://build.opensuse.org/package/show/devel:tools/ctags?expand=0&rev=30 --- ctags.changes | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ctags.changes b/ctags.changes index 7b98a40..329d878 100644 --- a/ctags.changes +++ b/ctags.changes @@ -24,9 +24,9 @@ Sun Feb 26 04:37:26 UTC 2017 - msuchanek@suse.com 0015-Added-constexpr-as-keyword.patch + refreshed existing patches 0016-CVE-2014-7204.patch - 0017-Go-language-support.patch - 0018-SUSE-man-page-changes.patch - 0019-Do-not-include-build-time-in-binary.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