Index: Makefile
===================================================================
--- Makefile (nonexistent)
+++ Makefile (revision 5)
@@ -0,0 +1,56 @@
+
+COMPONENT_TARGETS = $(HARDWARE_NOARCH)
+
+
+include ../../../../build-system/constants.mk
+
+
+url = $(DOWNLOAD_SERVER)/sources/packages/a/ctags
+
+versions = 5.8
+pkgname = ctags
+suffix = tar.gz
+
+tarballs = $(addsuffix .$(suffix), $(addprefix $(pkgname)-, $(versions)))
+sha1s = $(addsuffix .sha1sum, $(tarballs))
+
+patches = $(CURDIR)/patches/ctags-5.8-unused-attribute.patch
+
+.NOTPARALLEL: $(patches)
+
+
+BUILD_TARGETS = $(tarballs) $(sha1s) $(patches)
+
+
+include ../../../../build-system/core.mk
+
+
+.PHONY: download_clean
+
+
+$(tarballs):
+ @echo -e "\n======= Downloading source tarballs =======" ; \
+ for tarball in $(tarballs) ; do \
+ echo "$(url)/$$tarball" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & \
+ done ; wait
+
+$(sha1s): $(tarballs)
+ @for sha in $@ ; do \
+ echo -e "\n======= Downloading '$$sha' signature =======\n" ; \
+ echo "$(url)/$$sha" | xargs -n 1 -P 100 wget $(WGET_OPTIONS) - & wait %1 ; \
+ touch $$sha ; \
+ echo -e "\n======= Check the '$$sha' sha1sum =======\n" ; \
+ sha1sum --check $$sha ; ret="$$?" ; \
+ if [ "$$ret" == "1" ]; then \
+ echo -e "\n======= ERROR: Bad '$$sha' sha1sum =======\n" ; \
+ exit 1 ; \
+ fi ; \
+ done
+
+$(patches): $(sha1s)
+ @echo -e "\n======= Create Patches =======\n" ; \
+ ( cd create-5.8-unused-attribute-patch ; ./create.patch.sh ) ; \
+ echo -e "\n"
+
+download_clean:
+ @rm -f $(tarballs) $(sha1s) $(patches)
Index: create-5.8-unused-attribute-patch/create.patch.sh
===================================================================
--- create-5.8-unused-attribute-patch/create.patch.sh (nonexistent)
+++ create-5.8-unused-attribute-patch/create.patch.sh (revision 5)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=5.8
+
+tar --files-from=file.list -xzvf ../ctags-$VERSION.tar.gz
+mv ctags-$VERSION ctags-$VERSION-orig
+
+cp -rf ./ctags-$VERSION-new ./ctags-$VERSION
+
+diff --unified -Nr ctags-$VERSION-orig ctags-$VERSION > ctags-$VERSION-unused-attribute.patch
+
+mv ctags-$VERSION-unused-attribute.patch ../patches
+
+rm -rf ./ctags-$VERSION
+rm -rf ./ctags-$VERSION-orig
Property changes on: create-5.8-unused-attribute-patch/create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: create-5.8-unused-attribute-patch/ctags-5.8-new/c.c
===================================================================
--- create-5.8-unused-attribute-patch/ctags-5.8-new/c.c (nonexistent)
+++ create-5.8-unused-attribute-patch/ctags-5.8-new/c.c (revision 5)
@@ -0,0 +1,2932 @@
+/*
+* $Id: c.c 689 2008-12-13 21:17:36Z elliotth $
+*
+* Copyright (c) 1996-2003, Darren Hiebert
+*
+* This source code is released for free distribution under the terms of the
+* GNU General Public License.
+*
+* This module contains functions for parsing and scanning C, C++ and Java
+* source files.
+*/
+
+/*
+* INCLUDE FILES
+*/
+#include "general.h" /* must always come first */
+
+#include <string.h>
+#include <setjmp.h>
+
+#include "debug.h"
+#include "entry.h"
+#include "get.h"
+#include "keyword.h"
+#include "options.h"
+#include "parse.h"
+#include "read.h"
+#include "routines.h"
+
+/*
+* MACROS
+*/
+
+#define activeToken(st) ((st)->token [(int) (st)->tokenIndex])
+#define parentDecl(st) ((st)->parent == NULL ? \
+ DECL_NONE : (st)->parent->declaration)
+#define isType(token,t) (boolean) ((token)->type == (t))
+#define insideEnumBody(st) ((st)->parent == NULL ? FALSE : \
+ (boolean) ((st)->parent->declaration == DECL_ENUM))
+#define isExternCDecl(st,c) (boolean) ((c) == STRING_SYMBOL && \
+ ! (st)->haveQualifyingName && (st)->scope == SCOPE_EXTERN)
+
+#define isOneOf(c,s) (boolean) (strchr ((s), (c)) != NULL)
+
+#define isHighChar(c) ((c) != EOF && (unsigned char)(c) >= 0xc0)
+
+/*
+* DATA DECLARATIONS
+*/
+
+enum { NumTokens = 3 };
+
+typedef enum eException {
+ ExceptionNone, ExceptionEOF, ExceptionFormattingError,
+ ExceptionBraceFormattingError
+} exception_t;
+
+/* Used to specify type of keyword.
+ */
+typedef enum eKeywordId {
+ KEYWORD_NONE = -1,
+ KEYWORD_ATTRIBUTE, KEYWORD_ABSTRACT,
+ KEYWORD_BOOLEAN, KEYWORD_BYTE, KEYWORD_BAD_STATE, KEYWORD_BAD_TRANS,
+ KEYWORD_BIND, KEYWORD_BIND_VAR, KEYWORD_BIT,
+ KEYWORD_CASE, KEYWORD_CATCH, KEYWORD_CHAR, KEYWORD_CLASS, KEYWORD_CONST,
+ KEYWORD_CONSTRAINT, KEYWORD_COVERAGE_BLOCK, KEYWORD_COVERAGE_DEF,
+ KEYWORD_DEFAULT, KEYWORD_DELEGATE, KEYWORD_DELETE, KEYWORD_DO,
+ KEYWORD_DOUBLE,
+ KEYWORD_ELSE, KEYWORD_ENUM, KEYWORD_EXPLICIT, KEYWORD_EXTERN,
+ KEYWORD_EXTENDS, KEYWORD_EVENT,
+ KEYWORD_FINAL, KEYWORD_FLOAT, KEYWORD_FOR, KEYWORD_FOREACH,
+ KEYWORD_FRIEND, KEYWORD_FUNCTION,
+ KEYWORD_GOTO,
+ KEYWORD_IF, KEYWORD_IMPLEMENTS, KEYWORD_IMPORT, KEYWORD_INLINE, KEYWORD_INT,
+ KEYWORD_INOUT, KEYWORD_INPUT, KEYWORD_INTEGER, KEYWORD_INTERFACE,
+ KEYWORD_INTERNAL,
+ KEYWORD_LOCAL, KEYWORD_LONG,
+ KEYWORD_M_BAD_STATE, KEYWORD_M_BAD_TRANS, KEYWORD_M_STATE, KEYWORD_M_TRANS,
+ KEYWORD_MUTABLE,
+ KEYWORD_NAMESPACE, KEYWORD_NEW, KEYWORD_NEWCOV, KEYWORD_NATIVE,
+ KEYWORD_OPERATOR, KEYWORD_OUTPUT, KEYWORD_OVERLOAD, KEYWORD_OVERRIDE,
+ KEYWORD_PACKED, KEYWORD_PORT, KEYWORD_PACKAGE, KEYWORD_PRIVATE,
+ KEYWORD_PROGRAM, KEYWORD_PROTECTED, KEYWORD_PUBLIC,
+ KEYWORD_REGISTER, KEYWORD_RETURN,
+ KEYWORD_SHADOW, KEYWORD_STATE,
+ KEYWORD_SHORT, KEYWORD_SIGNED, KEYWORD_STATIC, KEYWORD_STRING,
+ KEYWORD_STRUCT, KEYWORD_SWITCH, KEYWORD_SYNCHRONIZED,
+ KEYWORD_TASK, KEYWORD_TEMPLATE, KEYWORD_THIS, KEYWORD_THROW,
+ KEYWORD_THROWS, KEYWORD_TRANSIENT, KEYWORD_TRANS, KEYWORD_TRANSITION,
+ KEYWORD_TRY, KEYWORD_TYPEDEF, KEYWORD_TYPENAME,
+ KEYWORD_UINT, KEYWORD_ULONG, KEYWORD_UNION, KEYWORD_UNSIGNED, KEYWORD_USHORT,
+ KEYWORD_USING,
+ KEYWORD_VIRTUAL, KEYWORD_VOID, KEYWORD_VOLATILE,
+ KEYWORD_WCHAR_T, KEYWORD_WHILE
+} keywordId;
+
+/* Used to determine whether keyword is valid for the current language and
+ * what its ID is.
+ */
+typedef struct sKeywordDesc {
+ const char *name;
+ keywordId id;
+ short isValid [5]; /* indicates languages for which kw is valid */
+} keywordDesc;
+
+/* Used for reporting the type of object parsed by nextToken ().
+ */
+typedef enum eTokenType {
+ TOKEN_NONE, /* none */
+ TOKEN_ARGS, /* a parenthetical pair and its contents */
+ TOKEN_BRACE_CLOSE,
+ TOKEN_BRACE_OPEN,
+ TOKEN_COLON, /* the colon character */
+ TOKEN_COMMA, /* the comma character */
+ TOKEN_DOUBLE_COLON, /* double colon indicates nested-name-specifier */
+ TOKEN_KEYWORD,
+ TOKEN_NAME, /* an unknown name */
+ TOKEN_PACKAGE, /* a Java package name */
+ TOKEN_PAREN_NAME, /* a single name in parentheses */
+ TOKEN_SEMICOLON, /* the semicolon character */
+ TOKEN_SPEC, /* a storage class specifier, qualifier, type, etc. */
+ TOKEN_COUNT
+} tokenType;
+
+/* This describes the scoping of the current statement.
+ */
+typedef enum eTagScope {
+ SCOPE_GLOBAL, /* no storage class specified */
+ SCOPE_STATIC, /* static storage class */
+ SCOPE_EXTERN, /* external storage class */
+ SCOPE_FRIEND, /* declares access only */
+ SCOPE_TYPEDEF, /* scoping depends upon context */
+ SCOPE_COUNT
+} tagScope;
+
+typedef enum eDeclaration {
+ DECL_NONE,
+ DECL_BASE, /* base type (default) */
+ DECL_CLASS,
+ DECL_ENUM,
+ DECL_EVENT,
+ DECL_FUNCTION,
+ DECL_IGNORE, /* non-taggable "declaration" */
+ DECL_INTERFACE,
+ DECL_NAMESPACE,
+ DECL_NOMANGLE, /* C++ name demangling block */
+ DECL_PACKAGE,
+ DECL_PROGRAM, /* Vera program */
+ DECL_STRUCT,
+ DECL_TASK, /* Vera task */
+ DECL_UNION,
+ DECL_COUNT
+} declType;
+
+typedef enum eVisibilityType {
+ ACCESS_UNDEFINED,
+ ACCESS_LOCAL,
+ ACCESS_PRIVATE,
+ ACCESS_PROTECTED,
+ ACCESS_PUBLIC,
+ ACCESS_DEFAULT, /* Java-specific */
+ ACCESS_COUNT
+} accessType;
+
+/* Information about the parent class of a member (if any).
+ */
+typedef struct sMemberInfo {
+ accessType access; /* access of current statement */
+ accessType accessDefault; /* access default for current statement */
+} memberInfo;
+
+typedef struct sTokenInfo {
+ tokenType type;
+ keywordId keyword;
+ vString* name; /* the name of the token */
+ unsigned long lineNumber; /* line number of tag */
+ fpos_t filePosition; /* file position of line containing name */
+} tokenInfo;
+
+typedef enum eImplementation {
+ IMP_DEFAULT,
+ IMP_ABSTRACT,
+ IMP_VIRTUAL,
+ IMP_PURE_VIRTUAL,
+ IMP_COUNT
+} impType;
+
+/* Describes the statement currently undergoing analysis.
+ */
+typedef struct sStatementInfo {
+ tagScope scope;
+ declType declaration; /* specifier associated with TOKEN_SPEC */
+ boolean gotName; /* was a name parsed yet? */
+ boolean haveQualifyingName; /* do we have a name we are considering? */
+ boolean gotParenName; /* was a name inside parentheses parsed yet? */
+ boolean gotArgs; /* was a list of parameters parsed yet? */
+ boolean isPointer; /* is 'name' a pointer? */
+ boolean inFunction; /* are we inside of a function? */
+ boolean assignment; /* have we handled an '='? */
+ boolean notVariable; /* has a variable declaration been disqualified ? */
+ impType implementation; /* abstract or concrete implementation? */
+ unsigned int tokenIndex; /* currently active token */
+ tokenInfo* token [(int) NumTokens];
+ tokenInfo* context; /* accumulated scope of current statement */
+ tokenInfo* blockName; /* name of current block */
+ memberInfo member; /* information regarding parent class/struct */
+ vString* parentClasses; /* parent classes */
+ struct sStatementInfo *parent; /* statement we are nested within */
+} statementInfo;
+
+/* Describes the type of tag being generated.
+ */
+typedef enum eTagType {
+ TAG_UNDEFINED,
+ TAG_CLASS, /* class name */
+ TAG_ENUM, /* enumeration name */
+ TAG_ENUMERATOR, /* enumerator (enumeration value) */
+ TAG_EVENT, /* event */
+ TAG_FIELD, /* field (Java) */
+ TAG_FUNCTION, /* function definition */
+ TAG_INTERFACE, /* interface declaration */
+ TAG_LOCAL, /* local variable definition */
+ TAG_MEMBER, /* structure, class or interface member */
+ TAG_METHOD, /* method declaration */
+ TAG_NAMESPACE, /* namespace name */
+ TAG_PACKAGE, /* package name */
+ TAG_PROGRAM, /* program name */
+ TAG_PROPERTY, /* property name */
+ TAG_PROTOTYPE, /* function prototype or declaration */
+ TAG_STRUCT, /* structure name */
+ TAG_TASK, /* task name */
+ TAG_TYPEDEF, /* typedef name */
+ TAG_UNION, /* union name */
+ TAG_VARIABLE, /* variable definition */
+ TAG_EXTERN_VAR, /* external variable declaration */
+ TAG_COUNT /* must be last */
+} tagType;
+
+typedef struct sParenInfo {
+ boolean isPointer;
+ boolean isParamList;
+ boolean isKnrParamList;
+ boolean isNameCandidate;
+ boolean invalidContents;
+ boolean nestedArgs;
+ unsigned int parameterCount;
+} parenInfo;
+
+/*
+* DATA DEFINITIONS
+*/
+
+static jmp_buf Exception;
+
+static langType Lang_c;
+static langType Lang_cpp;
+static langType Lang_csharp;
+static langType Lang_java;
+static langType Lang_vera;
+static vString *Signature;
+static boolean CollectingSignature;
+
+/* Number used to uniquely identify anonymous structs and unions. */
+static int AnonymousID = 0;
+
+/* Used to index into the CKinds table. */
+typedef enum {
+ CK_UNDEFINED = -1,
+ CK_CLASS, CK_DEFINE, CK_ENUMERATOR, CK_FUNCTION,
+ CK_ENUMERATION, CK_LOCAL, CK_MEMBER, CK_NAMESPACE, CK_PROTOTYPE,
+ CK_STRUCT, CK_TYPEDEF, CK_UNION, CK_VARIABLE,
+ CK_EXTERN_VARIABLE
+} cKind;
+
+static kindOption CKinds [] = {
+ { TRUE, 'c', "class", "classes"},
+ { TRUE, 'd', "macro", "macro definitions"},
+ { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
+ { TRUE, 'f', "function", "function definitions"},
+ { TRUE, 'g', "enum", "enumeration names"},
+ { FALSE, 'l', "local", "local variables"},
+ { TRUE, 'm', "member", "class, struct, and union members"},
+ { TRUE, 'n', "namespace", "namespaces"},
+ { FALSE, 'p', "prototype", "function prototypes"},
+ { TRUE, 's', "struct", "structure names"},
+ { TRUE, 't', "typedef", "typedefs"},
+ { TRUE, 'u', "union", "union names"},
+ { TRUE, 'v', "variable", "variable definitions"},
+ { FALSE, 'x', "externvar", "external and forward variable declarations"},
+};
+
+typedef enum {
+ CSK_UNDEFINED = -1,
+ CSK_CLASS, CSK_DEFINE, CSK_ENUMERATOR, CSK_EVENT, CSK_FIELD,
+ CSK_ENUMERATION, CSK_INTERFACE, CSK_LOCAL, CSK_METHOD,
+ CSK_NAMESPACE, CSK_PROPERTY, CSK_STRUCT, CSK_TYPEDEF
+} csharpKind;
+
+static kindOption CsharpKinds [] = {
+ { TRUE, 'c', "class", "classes"},
+ { TRUE, 'd', "macro", "macro definitions"},
+ { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
+ { TRUE, 'E', "event", "events"},
+ { TRUE, 'f', "field", "fields"},
+ { TRUE, 'g', "enum", "enumeration names"},
+ { TRUE, 'i', "interface", "interfaces"},
+ { FALSE, 'l', "local", "local variables"},
+ { TRUE, 'm', "method", "methods"},
+ { TRUE, 'n', "namespace", "namespaces"},
+ { TRUE, 'p', "property", "properties"},
+ { TRUE, 's', "struct", "structure names"},
+ { TRUE, 't', "typedef", "typedefs"},
+};
+
+/* Used to index into the JavaKinds table. */
+typedef enum {
+ JK_UNDEFINED = -1,
+ JK_CLASS, JK_ENUM_CONSTANT, JK_FIELD, JK_ENUM, JK_INTERFACE,
+ JK_LOCAL, JK_METHOD, JK_PACKAGE, JK_ACCESS, JK_CLASS_PREFIX
+} javaKind;
+
+static kindOption JavaKinds [] = {
+ { TRUE, 'c', "class", "classes"},
+ { TRUE, 'e', "enum constant", "enum constants"},
+ { TRUE, 'f', "field", "fields"},
+ { TRUE, 'g', "enum", "enum types"},
+ { TRUE, 'i', "interface", "interfaces"},
+ { FALSE, 'l', "local", "local variables"},
+ { TRUE, 'm', "method", "methods"},
+ { TRUE, 'p', "package", "packages"},
+};
+
+/* Used to index into the VeraKinds table. */
+typedef enum {
+ VK_UNDEFINED = -1,
+ VK_CLASS, VK_DEFINE, VK_ENUMERATOR, VK_FUNCTION,
+ VK_ENUMERATION, VK_LOCAL, VK_MEMBER, VK_PROGRAM, VK_PROTOTYPE,
+ VK_TASK, VK_TYPEDEF, VK_VARIABLE,
+ VK_EXTERN_VARIABLE
+} veraKind;
+
+static kindOption VeraKinds [] = {
+ { TRUE, 'c', "class", "classes"},
+ { TRUE, 'd', "macro", "macro definitions"},
+ { TRUE, 'e', "enumerator", "enumerators (values inside an enumeration)"},
+ { TRUE, 'f', "function", "function definitions"},
+ { TRUE, 'g', "enum", "enumeration names"},
+ { FALSE, 'l', "local", "local variables"},
+ { TRUE, 'm', "member", "class, struct, and union members"},
+ { TRUE, 'p', "program", "programs"},
+ { FALSE, 'P', "prototype", "function prototypes"},
+ { TRUE, 't', "task", "tasks"},
+ { TRUE, 'T', "typedef", "typedefs"},
+ { TRUE, 'v', "variable", "variable definitions"},
+ { FALSE, 'x', "externvar", "external variable declarations"}
+};
+
+static const keywordDesc KeywordTable [] = {
+ /* C++ */
+ /* ANSI C | C# Java */
+ /* | | | | Vera */
+ /* keyword keyword ID | | | | | */
+ { "__attribute__", KEYWORD_ATTRIBUTE, { 1, 1, 1, 0, 0 } },
+ { "abstract", KEYWORD_ABSTRACT, { 0, 0, 1, 1, 0 } },
+ { "bad_state", KEYWORD_BAD_STATE, { 0, 0, 0, 0, 1 } },
+ { "bad_trans", KEYWORD_BAD_TRANS, { 0, 0, 0, 0, 1 } },
+ { "bind", KEYWORD_BIND, { 0, 0, 0, 0, 1 } },
+ { "bind_var", KEYWORD_BIND_VAR, { 0, 0, 0, 0, 1 } },
+ { "bit", KEYWORD_BIT, { 0, 0, 0, 0, 1 } },
+ { "boolean", KEYWORD_BOOLEAN, { 0, 0, 0, 1, 0 } },
+ { "byte", KEYWORD_BYTE, { 0, 0, 0, 1, 0 } },
+ { "case", KEYWORD_CASE, { 1, 1, 1, 1, 0 } },
+ { "catch", KEYWORD_CATCH, { 0, 1, 1, 0, 0 } },
+ { "char", KEYWORD_CHAR, { 1, 1, 1, 1, 0 } },
+ { "class", KEYWORD_CLASS, { 0, 1, 1, 1, 1 } },
+ { "const", KEYWORD_CONST, { 1, 1, 1, 1, 0 } },
+ { "constraint", KEYWORD_CONSTRAINT, { 0, 0, 0, 0, 1 } },
+ { "coverage_block", KEYWORD_COVERAGE_BLOCK, { 0, 0, 0, 0, 1 } },
+ { "coverage_def", KEYWORD_COVERAGE_DEF, { 0, 0, 0, 0, 1 } },
+ { "do", KEYWORD_DO, { 1, 1, 1, 1, 0 } },
+ { "default", KEYWORD_DEFAULT, { 1, 1, 1, 1, 0 } },
+ { "delegate", KEYWORD_DELEGATE, { 0, 0, 1, 0, 0 } },
+ { "delete", KEYWORD_DELETE, { 0, 1, 0, 0, 0 } },
+ { "double", KEYWORD_DOUBLE, { 1, 1, 1, 1, 0 } },
+ { "else", KEYWORD_ELSE, { 1, 1, 1, 1, 0 } },
+ { "enum", KEYWORD_ENUM, { 1, 1, 1, 1, 1 } },
+ { "event", KEYWORD_EVENT, { 0, 0, 1, 0, 1 } },
+ { "explicit", KEYWORD_EXPLICIT, { 0, 1, 1, 0, 0 } },
+ { "extends", KEYWORD_EXTENDS, { 0, 0, 0, 1, 1 } },
+ { "extern", KEYWORD_EXTERN, { 1, 1, 1, 0, 1 } },
+ { "final", KEYWORD_FINAL, { 0, 0, 0, 1, 0 } },
+ { "float", KEYWORD_FLOAT, { 1, 1, 1, 1, 0 } },
+ { "for", KEYWORD_FOR, { 1, 1, 1, 1, 0 } },
+ { "foreach", KEYWORD_FOREACH, { 0, 0, 1, 0, 0 } },
+ { "friend", KEYWORD_FRIEND, { 0, 1, 0, 0, 0 } },
+ { "function", KEYWORD_FUNCTION, { 0, 0, 0, 0, 1 } },
+ { "goto", KEYWORD_GOTO, { 1, 1, 1, 1, 0 } },
+ { "if", KEYWORD_IF, { 1, 1, 1, 1, 0 } },
+ { "implements", KEYWORD_IMPLEMENTS, { 0, 0, 0, 1, 0 } },
+ { "import", KEYWORD_IMPORT, { 0, 0, 0, 1, 0 } },
+ { "inline", KEYWORD_INLINE, { 0, 1, 0, 0, 0 } },
+ { "inout", KEYWORD_INOUT, { 0, 0, 0, 0, 1 } },
+ { "input", KEYWORD_INPUT, { 0, 0, 0, 0, 1 } },
+ { "int", KEYWORD_INT, { 1, 1, 1, 1, 0 } },
+ { "integer", KEYWORD_INTEGER, { 0, 0, 0, 0, 1 } },
+ { "interface", KEYWORD_INTERFACE, { 0, 0, 1, 1, 1 } },
+ { "internal", KEYWORD_INTERNAL, { 0, 0, 1, 0, 0 } },
+ { "local", KEYWORD_LOCAL, { 0, 0, 0, 0, 1 } },
+ { "long", KEYWORD_LONG, { 1, 1, 1, 1, 0 } },
+ { "m_bad_state", KEYWORD_M_BAD_STATE, { 0, 0, 0, 0, 1 } },
+ { "m_bad_trans", KEYWORD_M_BAD_TRANS, { 0, 0, 0, 0, 1 } },
+ { "m_state", KEYWORD_M_STATE, { 0, 0, 0, 0, 1 } },
+ { "m_trans", KEYWORD_M_TRANS, { 0, 0, 0, 0, 1 } },
+ { "mutable", KEYWORD_MUTABLE, { 0, 1, 0, 0, 0 } },
+ { "namespace", KEYWORD_NAMESPACE, { 0, 1, 1, 0, 0 } },
+ { "native", KEYWORD_NATIVE, { 0, 0, 0, 1, 0 } },
+ { "new", KEYWORD_NEW, { 0, 1, 1, 1, 0 } },
+ { "newcov", KEYWORD_NEWCOV, { 0, 0, 0, 0, 1 } },
+ { "operator", KEYWORD_OPERATOR, { 0, 1, 1, 0, 0 } },
+ { "output", KEYWORD_OUTPUT, { 0, 0, 0, 0, 1 } },
+ { "overload", KEYWORD_OVERLOAD, { 0, 1, 0, 0, 0 } },
+ { "override", KEYWORD_OVERRIDE, { 0, 0, 1, 0, 0 } },
+ { "package", KEYWORD_PACKAGE, { 0, 0, 0, 1, 0 } },
+ { "packed", KEYWORD_PACKED, { 0, 0, 0, 0, 1 } },
+ { "port", KEYWORD_PORT, { 0, 0, 0, 0, 1 } },
+ { "private", KEYWORD_PRIVATE, { 0, 1, 1, 1, 0 } },
+ { "program", KEYWORD_PROGRAM, { 0, 0, 0, 0, 1 } },
+ { "protected", KEYWORD_PROTECTED, { 0, 1, 1, 1, 1 } },
+ { "public", KEYWORD_PUBLIC, { 0, 1, 1, 1, 1 } },
+ { "register", KEYWORD_REGISTER, { 1, 1, 0, 0, 0 } },
+ { "return", KEYWORD_RETURN, { 1, 1, 1, 1, 0 } },
+ { "shadow", KEYWORD_SHADOW, { 0, 0, 0, 0, 1 } },
+ { "short", KEYWORD_SHORT, { 1, 1, 1, 1, 0 } },
+ { "signed", KEYWORD_SIGNED, { 1, 1, 0, 0, 0 } },
+ { "state", KEYWORD_STATE, { 0, 0, 0, 0, 1 } },
+ { "static", KEYWORD_STATIC, { 1, 1, 1, 1, 1 } },
+ { "string", KEYWORD_STRING, { 0, 0, 1, 0, 1 } },
+ { "struct", KEYWORD_STRUCT, { 1, 1, 1, 0, 0 } },
+ { "switch", KEYWORD_SWITCH, { 1, 1, 1, 1, 0 } },
+ { "synchronized", KEYWORD_SYNCHRONIZED, { 0, 0, 0, 1, 0 } },
+ { "task", KEYWORD_TASK, { 0, 0, 0, 0, 1 } },
+ { "template", KEYWORD_TEMPLATE, { 0, 1, 0, 0, 0 } },
+ { "this", KEYWORD_THIS, { 0, 1, 1, 1, 0 } },
+ { "throw", KEYWORD_THROW, { 0, 1, 1, 1, 0 } },
+ { "throws", KEYWORD_THROWS, { 0, 0, 0, 1, 0 } },
+ { "trans", KEYWORD_TRANS, { 0, 0, 0, 0, 1 } },
+ { "transition", KEYWORD_TRANSITION, { 0, 0, 0, 0, 1 } },
+ { "transient", KEYWORD_TRANSIENT, { 0, 0, 0, 1, 0 } },
+ { "try", KEYWORD_TRY, { 0, 1, 1, 0, 0 } },
+ { "typedef", KEYWORD_TYPEDEF, { 1, 1, 1, 0, 1 } },
+ { "typename", KEYWORD_TYPENAME, { 0, 1, 0, 0, 0 } },
+ { "uint", KEYWORD_UINT, { 0, 0, 1, 0, 0 } },
+ { "ulong", KEYWORD_ULONG, { 0, 0, 1, 0, 0 } },
+ { "union", KEYWORD_UNION, { 1, 1, 0, 0, 0 } },
+ { "unsigned", KEYWORD_UNSIGNED, { 1, 1, 1, 0, 0 } },
+ { "ushort", KEYWORD_USHORT, { 0, 0, 1, 0, 0 } },
+ { "using", KEYWORD_USING, { 0, 1, 1, 0, 0 } },
+ { "virtual", KEYWORD_VIRTUAL, { 0, 1, 1, 0, 1 } },
+ { "void", KEYWORD_VOID, { 1, 1, 1, 1, 1 } },
+ { "volatile", KEYWORD_VOLATILE, { 1, 1, 1, 1, 0 } },
+ { "wchar_t", KEYWORD_WCHAR_T, { 1, 1, 1, 0, 0 } },
+ { "while", KEYWORD_WHILE, { 1, 1, 1, 1, 0 } }
+};
+
+/*
+* FUNCTION PROTOTYPES
+*/
+static void createTags (const unsigned int nestLevel, statementInfo *const parent);
+
+/*
+* FUNCTION DEFINITIONS
+*/
+
+extern boolean includingDefineTags (void)
+{
+ return CKinds [CK_DEFINE].enabled;
+}
+
+/*
+* Token management
+*/
+
+static void initToken (tokenInfo* const token)
+{
+ token->type = TOKEN_NONE;
+ token->keyword = KEYWORD_NONE;
+ token->lineNumber = getSourceLineNumber ();
+ token->filePosition = getInputFilePosition ();
+ vStringClear (token->name);
+}
+
+static void advanceToken (statementInfo* const st)
+{
+ if (st->tokenIndex >= (unsigned int) NumTokens - 1)
+ st->tokenIndex = 0;
+ else
+ ++st->tokenIndex;
+ initToken (st->token [st->tokenIndex]);
+}
+
+static tokenInfo *prevToken (const statementInfo *const st, unsigned int n)
+{
+ unsigned int tokenIndex;
+ unsigned int num = (unsigned int) NumTokens;
+ Assert (n < num);
+ tokenIndex = (st->tokenIndex + num - n) % num;
+ return st->token [tokenIndex];
+}
+
+static void setToken (statementInfo *const st, const tokenType type)
+{
+ tokenInfo *token;
+ token = activeToken (st);
+ initToken (token);
+ token->type = type;
+}
+
+static void retardToken (statementInfo *const st)
+{
+ if (st->tokenIndex == 0)
+ st->tokenIndex = (unsigned int) NumTokens - 1;
+ else
+ --st->tokenIndex;
+ setToken (st, TOKEN_NONE);
+}
+
+static tokenInfo *newToken (void)
+{
+ tokenInfo *const token = xMalloc (1, tokenInfo);
+ token->name = vStringNew ();
+ initToken (token);
+ return token;
+}
+
+static void deleteToken (tokenInfo *const token)
+{
+ if (token != NULL)
+ {
+ vStringDelete (token->name);
+ eFree (token);
+ }
+}
+
+static const char *accessString (const accessType access)
+{
+ static const char *const names [] = {
+ "?", "local", "private", "protected", "public", "default"
+ };
+ Assert (sizeof (names) / sizeof (names [0]) == ACCESS_COUNT);
+ Assert ((int) access < ACCESS_COUNT);
+ return names [(int) access];
+}
+
+static const char *implementationString (const impType imp)
+{
+ static const char *const names [] ={
+ "?", "abstract", "virtual", "pure virtual"
+ };
+ Assert (sizeof (names) / sizeof (names [0]) == IMP_COUNT);
+ Assert ((int) imp < IMP_COUNT);
+ return names [(int) imp];
+}
+
+/*
+* Debugging functions
+*/
+
+#ifdef DEBUG
+
+#define boolString(c) ((c) ? "TRUE" : "FALSE")
+
+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"
+ };
+ Assert (sizeof (names) / sizeof (names [0]) == TOKEN_COUNT);
+ Assert ((int) type < TOKEN_COUNT);
+ return names [(int) type];
+}
+
+static const char *scopeString (const tagScope scope)
+{
+ static const char *const names [] = {
+ "global", "static", "extern", "friend", "typedef"
+ };
+ Assert (sizeof (names) / sizeof (names [0]) == SCOPE_COUNT);
+ Assert ((int) scope < SCOPE_COUNT);
+ return names [(int) scope];
+}
+
+static const char *declString (const declType declaration)
+{
+ static const char *const names [] = {
+ "?", "base", "class", "enum", "event", "function", "ignore",
+ "interface", "namespace", "no mangle", "package", "program",
+ "struct", "task", "union",
+ };
+ Assert (sizeof (names) / sizeof (names [0]) == DECL_COUNT);
+ Assert ((int) declaration < DECL_COUNT);
+ return names [(int) declaration];
+}
+
+static const char *keywordString (const keywordId keyword)
+{
+ const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
+ const char *name = "none";
+ size_t i;
+ for (i = 0 ; i < count ; ++i)
+ {
+ const keywordDesc *p = &KeywordTable [i];
+ if (p->id == keyword)
+ {
+ name = p->name;
+ break;
+ }
+ }
+ return name;
+}
+
+static void pt (tokenInfo *const token)
+{
+ if (isType (token, TOKEN_NAME))
+ printf ("type: %-12s: %-13s line: %lu\n",
+ tokenString (token->type), vStringValue (token->name),
+ token->lineNumber);
+ else if (isType (token, TOKEN_KEYWORD))
+ printf ("type: %-12s: %-13s line: %lu\n",
+ tokenString (token->type), keywordString (token->keyword),
+ token->lineNumber);
+ else
+ printf ("type: %-12s line: %lu\n",
+ tokenString (token->type), token->lineNumber);
+}
+
+static void ps (statementInfo *const st)
+{
+ unsigned int i;
+ printf ("scope: %s decl: %s gotName: %s gotParenName: %s\n",
+ scopeString (st->scope), declString (st->declaration),
+ boolString (st->gotName), boolString (st->gotParenName));
+ printf ("haveQualifyingName: %s\n", boolString (st->haveQualifyingName));
+ printf ("access: %s default: %s\n", accessString (st->member.access),
+ accessString (st->member.accessDefault));
+ printf ("token : ");
+ pt (activeToken (st));
+ for (i = 1 ; i < (unsigned int) NumTokens ; ++i)
+ {
+ printf ("prev %u : ", i);
+ pt (prevToken (st, i));
+ }
+ printf ("context: ");
+ pt (st->context);
+}
+
+#endif
+
+/*
+* Statement management
+*/
+
+static boolean isContextualKeyword (const tokenInfo *const token)
+{
+ boolean result;
+ switch (token->keyword)
+ {
+ case KEYWORD_CLASS:
+ case KEYWORD_ENUM:
+ case KEYWORD_INTERFACE:
+ case KEYWORD_NAMESPACE:
+ case KEYWORD_STRUCT:
+ case KEYWORD_UNION:
+ result = TRUE;
+ break;
+
+ default: result = FALSE; break;
+ }
+ return result;
+}
+
+static boolean isContextualStatement (const statementInfo *const st)
+{
+ boolean result = FALSE;
+ if (st != NULL) switch (st->declaration)
+ {
+ case DECL_CLASS:
+ case DECL_ENUM:
+ case DECL_INTERFACE:
+ case DECL_NAMESPACE:
+ case DECL_STRUCT:
+ case DECL_UNION:
+ result = TRUE;
+ break;
+
+ default: result = FALSE; break;
+ }
+ return result;
+}
+
+static boolean isMember (const statementInfo *const st)
+{
+ boolean result;
+ if (isType (st->context, TOKEN_NAME))
+ result = TRUE;
+ else
+ result = (boolean)
+ (st->parent != NULL && isContextualStatement (st->parent));
+ return result;
+}
+
+static void initMemberInfo (statementInfo *const st)
+{
+ accessType accessDefault = ACCESS_UNDEFINED;
+
+ if (st->parent != NULL) switch (st->parent->declaration)
+ {
+ case DECL_ENUM:
+ accessDefault = (isLanguage (Lang_java) ? ACCESS_PUBLIC : ACCESS_UNDEFINED);
+ break;
+ case DECL_NAMESPACE:
+ accessDefault = ACCESS_UNDEFINED;
+ break;
+
+ case DECL_CLASS:
+ if (isLanguage (Lang_java))
+ accessDefault = ACCESS_DEFAULT;
+ else
+ accessDefault = ACCESS_PRIVATE;
+ break;
+
+ case DECL_INTERFACE:
+ case DECL_STRUCT:
+ case DECL_UNION:
+ accessDefault = ACCESS_PUBLIC;
+ break;
+
+ default: break;
+ }
+ st->member.accessDefault = accessDefault;
+ st->member.access = accessDefault;
+}
+
+static void reinitStatement (statementInfo *const st, const boolean partial)
+{
+ unsigned int i;
+
+ if (! partial)
+ {
+ st->scope = SCOPE_GLOBAL;
+ if (isContextualStatement (st->parent))
+ st->declaration = DECL_BASE;
+ else
+ st->declaration = DECL_NONE;
+ }
+ st->gotParenName = FALSE;
+ st->isPointer = FALSE;
+ st->inFunction = FALSE;
+ st->assignment = FALSE;
+ st->notVariable = FALSE;
+ st->implementation = IMP_DEFAULT;
+ st->gotArgs = FALSE;
+ st->gotName = FALSE;
+ st->haveQualifyingName = FALSE;
+ st->tokenIndex = 0;
+
+ if (st->parent != NULL)
+ st->inFunction = st->parent->inFunction;
+
+ for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
+ initToken (st->token [i]);
+
+ initToken (st->context);
+
+ /* Keep the block name, so that a variable following after a comma will
+ * still have the structure name.
+ */
+ if (! partial)
+ initToken (st->blockName);
+
+ vStringClear (st->parentClasses);
+
+ /* Init member info.
+ */
+ if (! partial)
+ st->member.access = st->member.accessDefault;
+}
+
+static void initStatement (statementInfo *const st, statementInfo *const parent)
+{
+ st->parent = parent;
+ initMemberInfo (st);
+ reinitStatement (st, FALSE);
+}
+
+/*
+* Tag generation functions
+*/
+static cKind cTagKind (const tagType type)
+{
+ cKind result = CK_UNDEFINED;
+ switch (type)
+ {
+ case TAG_CLASS: result = CK_CLASS; break;
+ case TAG_ENUM: result = CK_ENUMERATION; break;
+ case TAG_ENUMERATOR: result = CK_ENUMERATOR; break;
+ case TAG_FUNCTION: result = CK_FUNCTION; break;
+ case TAG_LOCAL: result = CK_LOCAL; break;
+ case TAG_MEMBER: result = CK_MEMBER; break;
+ case TAG_NAMESPACE: result = CK_NAMESPACE; break;
+ case TAG_PROTOTYPE: result = CK_PROTOTYPE; break;
+ case TAG_STRUCT: result = CK_STRUCT; break;
+ case TAG_TYPEDEF: result = CK_TYPEDEF; break;
+ case TAG_UNION: result = CK_UNION; break;
+ case TAG_VARIABLE: result = CK_VARIABLE; break;
+ case TAG_EXTERN_VAR: result = CK_EXTERN_VARIABLE; break;
+
+ default: Assert ("Bad C tag type" == NULL); break;
+ }
+ return result;
+}
+
+static csharpKind csharpTagKind (const tagType type)
+{
+ csharpKind result = CSK_UNDEFINED;
+ switch (type)
+ {
+ case TAG_CLASS: result = CSK_CLASS; break;
+ case TAG_ENUM: result = CSK_ENUMERATION; break;
+ case TAG_ENUMERATOR: result = CSK_ENUMERATOR; break;
+ case TAG_EVENT: result = CSK_EVENT; break;
+ case TAG_FIELD: result = CSK_FIELD ; break;
+ case TAG_INTERFACE: result = CSK_INTERFACE; break;
+ case TAG_LOCAL: result = CSK_LOCAL; break;
+ case TAG_METHOD: result = CSK_METHOD; break;
+ case TAG_NAMESPACE: result = CSK_NAMESPACE; break;
+ case TAG_PROPERTY: result = CSK_PROPERTY; break;
+ case TAG_STRUCT: result = CSK_STRUCT; break;
+ case TAG_TYPEDEF: result = CSK_TYPEDEF; break;
+
+ default: Assert ("Bad C# tag type" == NULL); break;
+ }
+ return result;
+}
+
+static javaKind javaTagKind (const tagType type)
+{
+ javaKind result = JK_UNDEFINED;
+ switch (type)
+ {
+ case TAG_CLASS: result = JK_CLASS; break;
+ case TAG_ENUM: result = JK_ENUM; break;
+ case TAG_ENUMERATOR: result = JK_ENUM_CONSTANT; break;
+ case TAG_FIELD: result = JK_FIELD; break;
+ case TAG_INTERFACE: result = JK_INTERFACE; break;
+ case TAG_LOCAL: result = JK_LOCAL; break;
+ case TAG_METHOD: result = JK_METHOD; break;
+ case TAG_PACKAGE: result = JK_PACKAGE; break;
+
+ default: Assert ("Bad Java tag type" == NULL); break;
+ }
+ return result;
+}
+
+static veraKind veraTagKind (const tagType type) {
+ veraKind result = VK_UNDEFINED;
+ switch (type)
+ {
+ case TAG_CLASS: result = VK_CLASS; break;
+ case TAG_ENUM: result = VK_ENUMERATION; break;
+ case TAG_ENUMERATOR: result = VK_ENUMERATOR; break;
+ case TAG_FUNCTION: result = VK_FUNCTION; break;
+ case TAG_LOCAL: result = VK_LOCAL; break;
+ case TAG_MEMBER: result = VK_MEMBER; break;
+ case TAG_PROGRAM: result = VK_PROGRAM; break;
+ case TAG_PROTOTYPE: result = VK_PROTOTYPE; break;
+ case TAG_TASK: result = VK_TASK; break;
+ case TAG_TYPEDEF: result = VK_TYPEDEF; break;
+ case TAG_VARIABLE: result = VK_VARIABLE; break;
+ case TAG_EXTERN_VAR: result = VK_EXTERN_VARIABLE; break;
+
+ default: Assert ("Bad Vera tag type" == NULL); break;
+ }
+ return result;
+}
+
+static const char *tagName (const tagType type)
+{
+ const char* result;
+ if (isLanguage (Lang_csharp))
+ result = CsharpKinds [csharpTagKind (type)].name;
+ else if (isLanguage (Lang_java))
+ result = JavaKinds [javaTagKind (type)].name;
+ else if (isLanguage (Lang_vera))
+ result = VeraKinds [veraTagKind (type)].name;
+ else
+ result = CKinds [cTagKind (type)].name;
+ return result;
+}
+
+static int tagLetter (const tagType type)
+{
+ int result;
+ if (isLanguage (Lang_csharp))
+ result = CsharpKinds [csharpTagKind (type)].letter;
+ else if (isLanguage (Lang_java))
+ result = JavaKinds [javaTagKind (type)].letter;
+ else if (isLanguage (Lang_vera))
+ result = VeraKinds [veraTagKind (type)].letter;
+ else
+ result = CKinds [cTagKind (type)].letter;
+ return result;
+}
+
+static boolean includeTag (const tagType type, const boolean isFileScope)
+{
+ boolean result;
+ if (isFileScope && ! Option.include.fileScope)
+ result = FALSE;
+ else if (isLanguage (Lang_csharp))
+ result = CsharpKinds [csharpTagKind (type)].enabled;
+ else if (isLanguage (Lang_java))
+ result = JavaKinds [javaTagKind (type)].enabled;
+ else if (isLanguage (Lang_vera))
+ result = VeraKinds [veraTagKind (type)].enabled;
+ else
+ result = CKinds [cTagKind (type)].enabled;
+ return result;
+}
+
+static tagType declToTagType (const declType declaration)
+{
+ tagType type = TAG_UNDEFINED;
+
+ switch (declaration)
+ {
+ case DECL_CLASS: type = TAG_CLASS; break;
+ case DECL_ENUM: type = TAG_ENUM; break;
+ case DECL_EVENT: type = TAG_EVENT; break;
+ case DECL_FUNCTION: type = TAG_FUNCTION; break;
+ case DECL_INTERFACE: type = TAG_INTERFACE; break;
+ case DECL_NAMESPACE: type = TAG_NAMESPACE; break;
+ case DECL_PROGRAM: type = TAG_PROGRAM; break;
+ case DECL_TASK: type = TAG_TASK; break;
+ case DECL_STRUCT: type = TAG_STRUCT; break;
+ case DECL_UNION: type = TAG_UNION; break;
+
+ default: Assert ("Unexpected declaration" == NULL); break;
+ }
+ return type;
+}
+
+static const char* accessField (const statementInfo *const st)
+{
+ const char* result = NULL;
+ if (isLanguage (Lang_cpp) && st->scope == SCOPE_FRIEND)
+ result = "friend";
+ else if (st->member.access != ACCESS_UNDEFINED)
+ result = accessString (st->member.access);
+ return result;
+}
+
+static void addContextSeparator (vString *const scope)
+{
+ if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
+ vStringCatS (scope, "::");
+ else if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
+ vStringCatS (scope, ".");
+}
+
+static void addOtherFields (tagEntryInfo* const tag, const tagType type,
+ const statementInfo *const st,
+ vString *const scope, vString *const typeRef)
+{
+ /* For selected tag types, append an extension flag designating the
+ * parent object in which the tag is defined.
+ */
+ switch (type)
+ {
+ default: break;
+
+ case TAG_FUNCTION:
+ case TAG_METHOD:
+ case TAG_PROTOTYPE:
+ if (vStringLength (Signature) > 0)
+ tag->extensionFields.signature = vStringValue (Signature);
+ case TAG_CLASS:
+ case TAG_ENUM:
+ case TAG_ENUMERATOR:
+ case TAG_EVENT:
+ case TAG_FIELD:
+ case TAG_INTERFACE:
+ case TAG_MEMBER:
+ case TAG_NAMESPACE:
+ case TAG_PROPERTY:
+ case TAG_STRUCT:
+ case TAG_TASK:
+ case TAG_TYPEDEF:
+ case TAG_UNION:
+ if (vStringLength (scope) > 0 &&
+ (isMember (st) || st->parent->declaration == DECL_NAMESPACE))
+ {
+ if (isType (st->context, TOKEN_NAME))
+ tag->extensionFields.scope [0] = tagName (TAG_CLASS);
+ else
+ tag->extensionFields.scope [0] =
+ tagName (declToTagType (parentDecl (st)));
+ tag->extensionFields.scope [1] = vStringValue (scope);
+ }
+ if ((type == TAG_CLASS || type == TAG_INTERFACE ||
+ type == TAG_STRUCT) && vStringLength (st->parentClasses) > 0)
+ {
+
+ tag->extensionFields.inheritance =
+ vStringValue (st->parentClasses);
+ }
+ if (st->implementation != IMP_DEFAULT &&
+ (isLanguage (Lang_cpp) || isLanguage (Lang_csharp) ||
+ isLanguage (Lang_java)))
+ {
+ tag->extensionFields.implementation =
+ implementationString (st->implementation);
+ }
+ if (isMember (st))
+ {
+ tag->extensionFields.access = accessField (st);
+ }
+ break;
+ }
+
+ /* Add typename info, type of the tag and name of struct/union/etc. */
+ if ((type == TAG_TYPEDEF || type == TAG_VARIABLE || type == TAG_MEMBER)
+ && isContextualStatement(st))
+ {
+ char *p;
+
+ tag->extensionFields.typeRef [0] =
+ tagName (declToTagType (st->declaration));
+ p = vStringValue (st->blockName->name);
+
+ /* If there was no {} block get the name from the token before the
+ * name (current token is ';' or ',', previous token is the name).
+ */
+ if (p == NULL || *p == '\0')
+ {
+ tokenInfo *const prev2 = prevToken (st, 2);
+ if (isType (prev2, TOKEN_NAME))
+ p = vStringValue (prev2->name);
+ }
+
+ /* Prepend the scope name if there is one. */
+ if (vStringLength (scope) > 0)
+ {
+ vStringCopy(typeRef, scope);
+ addContextSeparator (typeRef);
+ vStringCatS(typeRef, p);
+ p = vStringValue (typeRef);
+ }
+ tag->extensionFields.typeRef [1] = p;
+ }
+}
+
+static void findScopeHierarchy (vString *const string,
+ const statementInfo *const st)
+{
+ vStringClear (string);
+ if (isType (st->context, TOKEN_NAME))
+ vStringCopy (string, st->context->name);
+ if (st->parent != NULL)
+ {
+ vString *temp = vStringNew ();
+ const statementInfo *s;
+ for (s = st->parent ; s != NULL ; s = s->parent)
+ {
+ if (isContextualStatement (s) ||
+ s->declaration == DECL_NAMESPACE ||
+ s->declaration == DECL_PROGRAM)
+ {
+ vStringCopy (temp, string);
+ vStringClear (string);
+ Assert (isType (s->blockName, TOKEN_NAME));
+ if (isType (s->context, TOKEN_NAME) &&
+ vStringLength (s->context->name) > 0)
+ {
+ vStringCat (string, s->context->name);
+ addContextSeparator (string);
+ }
+ vStringCat (string, s->blockName->name);
+ if (vStringLength (temp) > 0)
+ addContextSeparator (string);
+ vStringCat (string, temp);
+ }
+ }
+ vStringDelete (temp);
+ }
+}
+
+static void makeExtraTagEntry (const tagType type, tagEntryInfo *const e,
+ vString *const scope)
+{
+ if (Option.include.qualifiedTags &&
+ scope != NULL && vStringLength (scope) > 0)
+ {
+ vString *const scopedName = vStringNew ();
+
+ if (type != TAG_ENUMERATOR)
+ vStringCopy (scopedName, scope);
+ else
+ {
+ /* remove last component (i.e. enumeration name) from scope */
+ const char* const sc = vStringValue (scope);
+ const char* colon = strrchr (sc, ':');
+ if (colon != NULL)
+ {
+ while (*colon == ':' && colon > sc)
+ --colon;
+ vStringNCopy (scopedName, scope, colon + 1 - sc);
+ }
+ }
+ if (vStringLength (scopedName) > 0)
+ {
+ addContextSeparator (scopedName);
+ vStringCatS (scopedName, e->name);
+ e->name = vStringValue (scopedName);
+ makeTagEntry (e);
+ }
+ vStringDelete (scopedName);
+ }
+}
+
+static void makeTag (const tokenInfo *const token,
+ const statementInfo *const st,
+ boolean isFileScope, const tagType type)
+{
+ /* Nothing is really of file scope when it appears in a header file.
+ */
+ isFileScope = (boolean) (isFileScope && ! isHeaderFile ());
+
+ if (isType (token, TOKEN_NAME) && vStringLength (token->name) > 0 &&
+ includeTag (type, isFileScope))
+ {
+ vString *scope = vStringNew ();
+ /* Use "typeRef" to store the typename from addOtherFields() until
+ * it's used in makeTagEntry().
+ */
+ vString *typeRef = vStringNew ();
+ tagEntryInfo e;
+
+ initTagEntry (&e, vStringValue (token->name));
+
+ e.lineNumber = token->lineNumber;
+ e.filePosition = token->filePosition;
+ e.isFileScope = isFileScope;
+ e.kindName = tagName (type);
+ e.kind = tagLetter (type);
+
+ findScopeHierarchy (scope, st);
+ addOtherFields (&e, type, st, scope, typeRef);
+
+ makeTagEntry (&e);
+ makeExtraTagEntry (type, &e, scope);
+ vStringDelete (scope);
+ vStringDelete (typeRef);
+ }
+}
+
+static boolean isValidTypeSpecifier (const declType declaration)
+{
+ boolean result;
+ switch (declaration)
+ {
+ case DECL_BASE:
+ case DECL_CLASS:
+ case DECL_ENUM:
+ case DECL_EVENT:
+ case DECL_STRUCT:
+ case DECL_UNION:
+ result = TRUE;
+ break;
+
+ default:
+ result = FALSE;
+ break;
+ }
+ return result;
+}
+
+static void qualifyEnumeratorTag (const statementInfo *const st,
+ const tokenInfo *const nameToken)
+{
+ if (isType (nameToken, TOKEN_NAME))
+ makeTag (nameToken, st, TRUE, TAG_ENUMERATOR);
+}
+
+static void qualifyFunctionTag (const statementInfo *const st,
+ const tokenInfo *const nameToken)
+{
+ if (isType (nameToken, TOKEN_NAME))
+ {
+ tagType type;
+ const boolean isFileScope =
+ (boolean) (st->member.access == ACCESS_PRIVATE ||
+ (!isMember (st) && st->scope == SCOPE_STATIC));
+ if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
+ type = TAG_METHOD;
+ else if (isLanguage (Lang_vera) && st->declaration == DECL_TASK)
+ type = TAG_TASK;
+ else
+ type = TAG_FUNCTION;
+ makeTag (nameToken, st, isFileScope, type);
+ }
+}
+
+static void qualifyFunctionDeclTag (const statementInfo *const st,
+ const tokenInfo *const nameToken)
+{
+ if (! isType (nameToken, TOKEN_NAME))
+ ;
+ else if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
+ qualifyFunctionTag (st, nameToken);
+ else if (st->scope == SCOPE_TYPEDEF)
+ makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
+ else if (isValidTypeSpecifier (st->declaration) && ! isLanguage (Lang_csharp))
+ makeTag (nameToken, st, TRUE, TAG_PROTOTYPE);
+}
+
+static void qualifyCompoundTag (const statementInfo *const st,
+ const tokenInfo *const nameToken)
+{
+ if (isType (nameToken, TOKEN_NAME))
+ {
+ const tagType type = declToTagType (st->declaration);
+ const boolean fileScoped = (boolean)
+ (!(isLanguage (Lang_java) ||
+ isLanguage (Lang_csharp) ||
+ isLanguage (Lang_vera)));
+
+ if (type != TAG_UNDEFINED)
+ makeTag (nameToken, st, fileScoped, type);
+ }
+}
+
+static void qualifyBlockTag (statementInfo *const st,
+ const tokenInfo *const nameToken)
+{
+ switch (st->declaration)
+ {
+ case DECL_CLASS:
+ case DECL_ENUM:
+ case DECL_INTERFACE:
+ case DECL_NAMESPACE:
+ case DECL_PROGRAM:
+ case DECL_STRUCT:
+ case DECL_UNION:
+ qualifyCompoundTag (st, nameToken);
+ break;
+ default: break;
+ }
+}
+
+static void qualifyVariableTag (const statementInfo *const st,
+ const tokenInfo *const nameToken)
+{
+ /* We have to watch that we do not interpret a declaration of the
+ * form "struct tag;" as a variable definition. In such a case, the
+ * token preceding the name will be a keyword.
+ */
+ if (! isType (nameToken, TOKEN_NAME))
+ ;
+ else if (st->scope == SCOPE_TYPEDEF)
+ makeTag (nameToken, st, TRUE, TAG_TYPEDEF);
+ else if (st->declaration == DECL_EVENT)
+ makeTag (nameToken, st, (boolean) (st->member.access == ACCESS_PRIVATE),
+ TAG_EVENT);
+ else if (st->declaration == DECL_PACKAGE)
+ makeTag (nameToken, st, FALSE, TAG_PACKAGE);
+ else if (isValidTypeSpecifier (st->declaration))
+ {
+ if (st->notVariable)
+ ;
+ else if (isMember (st))
+ {
+ if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
+ makeTag (nameToken, st,
+ (boolean) (st->member.access == ACCESS_PRIVATE), TAG_FIELD);
+ else if (st->scope == SCOPE_GLOBAL || st->scope == SCOPE_STATIC)
+ makeTag (nameToken, st, TRUE, TAG_MEMBER);
+ }
+ else
+ {
+ if (st->scope == SCOPE_EXTERN || ! st->haveQualifyingName)
+ makeTag (nameToken, st, FALSE, TAG_EXTERN_VAR);
+ else if (st->inFunction)
+ makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC),
+ TAG_LOCAL);
+ else
+ makeTag (nameToken, st, (boolean) (st->scope == SCOPE_STATIC),
+ TAG_VARIABLE);
+ }
+ }
+}
+
+/*
+* Parsing functions
+*/
+
+static int skipToOneOf (const char *const chars)
+{
+ int c;
+ do
+ c = cppGetc ();
+ while (c != EOF && c != '\0' && strchr (chars, c) == NULL);
+ return c;
+}
+
+/* Skip to the next non-white character.
+ */
+static int skipToNonWhite (void)
+{
+ boolean found = FALSE;
+ int c;
+
+#if 0
+ do
+ c = cppGetc ();
+ while (isspace (c));
+#else
+ while (1)
+ {
+ c = cppGetc ();
+ if (isspace (c))
+ found = TRUE;
+ else
+ break;
+ }
+ if (CollectingSignature && found)
+ vStringPut (Signature, ' ');
+#endif
+
+ return c;
+}
+
+/* Skips to the next brace in column 1. This is intended for cases where
+ * preprocessor constructs result in unbalanced braces.
+ */
+static void skipToFormattedBraceMatch (void)
+{
+ int c, next;
+
+ c = cppGetc ();
+ next = cppGetc ();
+ while (c != EOF && (c != '\n' || next != '}'))
+ {
+ c = next;
+ next = cppGetc ();
+ }
+}
+
+/* Skip to the matching character indicated by the pair string. If skipping
+ * to a matching brace and any brace is found within a different level of a
+ * #if conditional statement while brace formatting is in effect, we skip to
+ * the brace matched by its formatting. It is assumed that we have already
+ * read the character which starts the group (i.e. the first character of
+ * "pair").
+ */
+static void skipToMatch (const char *const pair)
+{
+ const boolean braceMatching = (boolean) (strcmp ("{}", pair) == 0);
+ const boolean braceFormatting = (boolean) (isBraceFormat () && braceMatching);
+ const unsigned int initialLevel = getDirectiveNestLevel ();
+ const int begin = pair [0], end = pair [1];
+ const unsigned long inputLineNumber = getInputLineNumber ();
+ int matchLevel = 1;
+ int c = '\0';
+
+ while (matchLevel > 0 && (c = skipToNonWhite ()) != EOF)
+ {
+ if (CollectingSignature)
+ vStringPut (Signature, c);
+ if (c == begin)
+ {
+ ++matchLevel;
+ if (braceFormatting && getDirectiveNestLevel () != initialLevel)
+ {
+ skipToFormattedBraceMatch ();
+ break;
+ }
+ }
+ else if (c == end)
+ {
+ --matchLevel;
+ if (braceFormatting && getDirectiveNestLevel () != initialLevel)
+ {
+ skipToFormattedBraceMatch ();
+ break;
+ }
+ }
+ }
+ if (c == EOF)
+ {
+ verbose ("%s: failed to find match for '%c' at line %lu\n",
+ getInputFileName (), begin, inputLineNumber);
+ if (braceMatching)
+ longjmp (Exception, (int) ExceptionBraceFormattingError);
+ else
+ longjmp (Exception, (int) ExceptionFormattingError);
+ }
+}
+
+static void skipParens (void)
+{
+ const int c = skipToNonWhite ();
+
+ if (c == '(')
+ skipToMatch ("()");
+ else
+ cppUngetc (c);
+}
+
+static void skipBraces (void)
+{
+ const int c = skipToNonWhite ();
+
+ if (c == '{')
+ skipToMatch ("{}");
+ else
+ cppUngetc (c);
+}
+
+static keywordId analyzeKeyword (const char *const name)
+{
+ const keywordId id = (keywordId) lookupKeyword (name, getSourceLanguage ());
+ return id;
+}
+
+static void analyzeIdentifier (tokenInfo *const token)
+{
+ char *const name = vStringValue (token->name);
+ const char *replacement = NULL;
+ boolean parensToo = FALSE;
+
+ if (isLanguage (Lang_java) ||
+ ! isIgnoreToken (name, &parensToo, &replacement))
+ {
+ if (replacement != NULL)
+ token->keyword = analyzeKeyword (replacement);
+ else
+ token->keyword = analyzeKeyword (vStringValue (token->name));
+
+ if (token->keyword == KEYWORD_NONE)
+ token->type = TOKEN_NAME;
+ else
+ token->type = TOKEN_KEYWORD;
+ }
+ else
+ {
+ initToken (token);
+ if (parensToo)
+ {
+ int c = skipToNonWhite ();
+
+ if (c == '(')
+ skipToMatch ("()");
+ }
+ }
+}
+
+static void readIdentifier (tokenInfo *const token, const int firstChar)
+{
+ vString *const name = token->name;
+ int c = firstChar;
+ boolean first = TRUE;
+
+ initToken (token);
+
+ /* Bug #1585745: strangely, C++ destructors allow whitespace between
+ * the ~ and the class name. */
+ if (isLanguage (Lang_cpp) && firstChar == '~')
+ {
+ vStringPut (name, c);
+ c = skipToNonWhite ();
+ }
+
+ do
+ {
+ vStringPut (name, c);
+ if (CollectingSignature)
+ {
+ if (!first)
+ vStringPut (Signature, c);
+ first = FALSE;
+ }
+ c = cppGetc ();
+ } while (isident (c) || ((isLanguage (Lang_java) || isLanguage (Lang_csharp)) && (isHighChar (c) || c == '.')));
+ vStringTerminate (name);
+ cppUngetc (c); /* unget non-identifier character */
+
+ analyzeIdentifier (token);
+}
+
+static void readPackageName (tokenInfo *const token, const int firstChar)
+{
+ vString *const name = token->name;
+ int c = firstChar;
+
+ initToken (token);
+
+ while (isident (c) || c == '.')
+ {
+ vStringPut (name, c);
+ c = cppGetc ();
+ }
+ vStringTerminate (name);
+ cppUngetc (c); /* unget non-package character */
+}
+
+static void readPackageOrNamespace (statementInfo *const st, const declType declaration)
+{
+ st->declaration = declaration;
+
+ if (declaration == DECL_NAMESPACE && !isLanguage (Lang_csharp))
+ {
+ /* In C++ a namespace is specified one level at a time. */
+ return;
+ }
+ else
+ {
+ /* In C#, a namespace can also be specified like a Java package name. */
+ tokenInfo *const token = activeToken (st);
+ Assert (isType (token, TOKEN_KEYWORD));
+ readPackageName (token, skipToNonWhite ());
+ token->type = TOKEN_NAME;
+ st->gotName = TRUE;
+ st->haveQualifyingName = TRUE;
+ }
+}
+
+static void processName (statementInfo *const st)
+{
+ Assert (isType (activeToken (st), TOKEN_NAME));
+ if (st->gotName && st->declaration == DECL_NONE)
+ st->declaration = DECL_BASE;
+ st->gotName = TRUE;
+ st->haveQualifyingName = TRUE;
+}
+
+static void readOperator (statementInfo *const st)
+{
+ const char *const acceptable = "+-*/%^&|~!=<>,[]";
+ const tokenInfo* const prev = prevToken (st,1);
+ tokenInfo *const token = activeToken (st);
+ vString *const name = token->name;
+ int c = skipToNonWhite ();
+
+ /* When we arrive here, we have the keyword "operator" in 'name'.
+ */
+ if (isType (prev, TOKEN_KEYWORD) && (prev->keyword == KEYWORD_ENUM ||
+ prev->keyword == KEYWORD_STRUCT || prev->keyword == KEYWORD_UNION))
+ ; /* ignore "operator" keyword if preceded by these keywords */
+ else if (c == '(')
+ {
+ /* Verify whether this is a valid function call (i.e. "()") operator.
+ */
+ if (cppGetc () == ')')
+ {
+ vStringPut (name, ' '); /* always separate operator from keyword */
+ c = skipToNonWhite ();
+ if (c == '(')
+ vStringCatS (name, "()");
+ }
+ else
+ {
+ skipToMatch ("()");
+ c = cppGetc ();
+ }
+ }
+ else if (isident1 (c))
+ {
+ /* Handle "new" and "delete" operators, and conversion functions
+ * (per 13.3.1.1.2 [2] of the C++ spec).
+ */
+ boolean whiteSpace = TRUE; /* default causes insertion of space */
+ do
+ {
+ if (isspace (c))
+ whiteSpace = TRUE;
+ else
+ {
+ if (whiteSpace)
+ {
+ vStringPut (name, ' ');
+ whiteSpace = FALSE;
+ }
+ vStringPut (name, c);
+ }
+ c = cppGetc ();
+ } while (! isOneOf (c, "(;") && c != EOF);
+ vStringTerminate (name);
+ }
+ else if (isOneOf (c, acceptable))
+ {
+ vStringPut (name, ' '); /* always separate operator from keyword */
+ do
+ {
+ vStringPut (name, c);
+ c = cppGetc ();
+ } while (isOneOf (c, acceptable));
+ vStringTerminate (name);
+ }
+
+ cppUngetc (c);
+
+ token->type = TOKEN_NAME;
+ token->keyword = KEYWORD_NONE;
+ processName (st);
+}
+
+static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
+{
+ dest->type = src->type;
+ dest->keyword = src->keyword;
+ dest->filePosition = src->filePosition;
+ dest->lineNumber = src->lineNumber;
+ vStringCopy (dest->name, src->name);
+}
+
+static void setAccess (statementInfo *const st, const accessType access)
+{
+ if (isMember (st))
+ {
+ if (isLanguage (Lang_cpp))
+ {
+ int c = skipToNonWhite ();
+
+ if (c == ':')
+ reinitStatement (st, FALSE);
+ else
+ cppUngetc (c);
+
+ st->member.accessDefault = access;
+ }
+ st->member.access = access;
+ }
+}
+
+static void discardTypeList (tokenInfo *const token)
+{
+ int c = skipToNonWhite ();
+ while (isident1 (c))
+ {
+ readIdentifier (token, c);
+ c = skipToNonWhite ();
+ if (c == '.' || c == ',')
+ c = skipToNonWhite ();
+ }
+ cppUngetc (c);
+}
+
+static void addParentClass (statementInfo *const st, tokenInfo *const token)
+{
+ if (vStringLength (token->name) > 0 &&
+ vStringLength (st->parentClasses) > 0)
+ {
+ vStringPut (st->parentClasses, ',');
+ }
+ vStringCat (st->parentClasses, token->name);
+}
+
+static void readParents (statementInfo *const st, const int qualifier)
+{
+ tokenInfo *const token = newToken ();
+ tokenInfo *const parent = newToken ();
+ int c;
+
+ do
+ {
+ c = skipToNonWhite ();
+ if (isident1 (c))
+ {
+ readIdentifier (token, c);
+ if (isType (token, TOKEN_NAME))
+ vStringCat (parent->name, token->name);
+ else
+ {
+ addParentClass (st, parent);
+ initToken (parent);
+ }
+ }
+ else if (c == qualifier)
+ vStringPut (parent->name, c);
+ else if (c == '<')
+ skipToMatch ("<>");
+ else if (isType (token, TOKEN_NAME))
+ {
+ addParentClass (st, parent);
+ initToken (parent);
+ }
+ } while (c != '{' && c != EOF);
+ cppUngetc (c);
+ deleteToken (parent);
+ deleteToken (token);
+}
+
+static void skipStatement (statementInfo *const st)
+{
+ st->declaration = DECL_IGNORE;
+ skipToOneOf (";");
+}
+
+static void processInterface (statementInfo *const st)
+{
+ st->declaration = DECL_INTERFACE;
+}
+
+static void processToken (tokenInfo *const token, statementInfo *const st)
+{
+ switch (token->keyword) /* is it a reserved word? */
+ {
+ default: break;
+
+ case KEYWORD_NONE: processName (st); break;
+ case KEYWORD_ABSTRACT: st->implementation = IMP_ABSTRACT; break;
+ case KEYWORD_ATTRIBUTE: skipParens (); initToken (token); break;
+ case KEYWORD_BIND: st->declaration = DECL_BASE; break;
+ case KEYWORD_BIT: st->declaration = DECL_BASE; break;
+ case KEYWORD_CATCH: skipParens (); skipBraces (); break;
+ case KEYWORD_CHAR: st->declaration = DECL_BASE; break;
+ case KEYWORD_CLASS: st->declaration = 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;
+ case KEYWORD_EXTENDS: readParents (st, '.');
+ setToken (st, TOKEN_NONE); break;
+ case KEYWORD_FLOAT: st->declaration = DECL_BASE; break;
+ case KEYWORD_FUNCTION: st->declaration = DECL_BASE; break;
+ case KEYWORD_FRIEND: st->scope = SCOPE_FRIEND; break;
+ case KEYWORD_GOTO: skipStatement (st); break;
+ case KEYWORD_IMPLEMENTS:readParents (st, '.');
+ setToken (st, TOKEN_NONE); break;
+ case KEYWORD_IMPORT: skipStatement (st); break;
+ case KEYWORD_INT: st->declaration = DECL_BASE; break;
+ case KEYWORD_INTEGER: st->declaration = DECL_BASE; break;
+ case KEYWORD_INTERFACE: processInterface (st); break;
+ case KEYWORD_LOCAL: setAccess (st, ACCESS_LOCAL); break;
+ case KEYWORD_LONG: st->declaration = DECL_BASE; break;
+ case KEYWORD_OPERATOR: readOperator (st); break;
+ case KEYWORD_PRIVATE: setAccess (st, ACCESS_PRIVATE); break;
+ case KEYWORD_PROGRAM: st->declaration = DECL_PROGRAM; break;
+ case KEYWORD_PROTECTED: setAccess (st, ACCESS_PROTECTED); break;
+ case KEYWORD_PUBLIC: setAccess (st, ACCESS_PUBLIC); break;
+ case KEYWORD_RETURN: skipStatement (st); break;
+ case KEYWORD_SHORT: st->declaration = DECL_BASE; break;
+ case KEYWORD_SIGNED: st->declaration = DECL_BASE; break;
+ case KEYWORD_STRING: st->declaration = DECL_BASE; break;
+ case KEYWORD_STRUCT: st->declaration = DECL_STRUCT; break;
+ case KEYWORD_TASK: st->declaration = DECL_TASK; break;
+ case KEYWORD_THROWS: discardTypeList (token); break;
+ case KEYWORD_UNION: st->declaration = DECL_UNION; break;
+ case KEYWORD_UNSIGNED: st->declaration = DECL_BASE; break;
+ case KEYWORD_USING: skipStatement (st); break;
+ case KEYWORD_VOID: st->declaration = DECL_BASE; break;
+ case KEYWORD_VOLATILE: st->declaration = DECL_BASE; break;
+ case KEYWORD_VIRTUAL: st->implementation = IMP_VIRTUAL; break;
+ case KEYWORD_WCHAR_T: st->declaration = DECL_BASE; break;
+
+ case KEYWORD_NAMESPACE: readPackageOrNamespace (st, DECL_NAMESPACE); break;
+ case KEYWORD_PACKAGE: readPackageOrNamespace (st, DECL_PACKAGE); break;
+
+ case KEYWORD_EVENT:
+ if (isLanguage (Lang_csharp))
+ st->declaration = DECL_EVENT;
+ break;
+
+ case KEYWORD_TYPEDEF:
+ reinitStatement (st, FALSE);
+ st->scope = SCOPE_TYPEDEF;
+ break;
+
+ case KEYWORD_EXTERN:
+ if (! isLanguage (Lang_csharp) || !st->gotName)
+ {
+ reinitStatement (st, FALSE);
+ st->scope = SCOPE_EXTERN;
+ st->declaration = DECL_BASE;
+ }
+ break;
+
+ case KEYWORD_STATIC:
+ if (! (isLanguage (Lang_java) || isLanguage (Lang_csharp)))
+ {
+ reinitStatement (st, FALSE);
+ st->scope = SCOPE_STATIC;
+ st->declaration = DECL_BASE;
+ }
+ break;
+
+ case KEYWORD_FOR:
+ case KEYWORD_FOREACH:
+ case KEYWORD_IF:
+ case KEYWORD_SWITCH:
+ case KEYWORD_WHILE:
+ {
+ int c = skipToNonWhite ();
+ if (c == '(')
+ skipToMatch ("()");
+ break;
+ }
+ }
+}
+
+/*
+* Parenthesis handling functions
+*/
+
+static void restartStatement (statementInfo *const st)
+{
+ tokenInfo *const save = newToken ();
+ tokenInfo *token = activeToken (st);
+
+ copyToken (save, token);
+ DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>");)
+ reinitStatement (st, FALSE);
+ token = activeToken (st);
+ copyToken (token, save);
+ deleteToken (save);
+ processToken (token, st);
+}
+
+/* Skips over a the mem-initializer-list of a ctor-initializer, defined as:
+ *
+ * mem-initializer-list:
+ * mem-initializer, mem-initializer-list
+ *
+ * mem-initializer:
+ * [::] [nested-name-spec] class-name (...)
+ * identifier
+ */
+static void skipMemIntializerList (tokenInfo *const token)
+{
+ int c;
+
+ do
+ {
+ c = skipToNonWhite ();
+ while (isident1 (c) || c == ':')
+ {
+ if (c != ':')
+ readIdentifier (token, c);
+ c = skipToNonWhite ();
+ }
+ if (c == '<')
+ {
+ skipToMatch ("<>");
+ c = skipToNonWhite ();
+ }
+ if (c == '(')
+ {
+ skipToMatch ("()");
+ c = skipToNonWhite ();
+ }
+ } while (c == ',');
+ cppUngetc (c);
+}
+
+static void skipMacro (statementInfo *const st)
+{
+ tokenInfo *const prev2 = prevToken (st, 2);
+
+ if (isType (prev2, TOKEN_NAME))
+ retardToken (st);
+ skipToMatch ("()");
+}
+
+/* Skips over characters following the parameter list. This will be either
+ * non-ANSI style function declarations or C++ stuff. Our choices:
+ *
+ * C (K&R):
+ * int func ();
+ * int func (one, two) int one; float two; {...}
+ * C (ANSI):
+ * int func (int one, float two);
+ * int func (int one, float two) {...}
+ * C++:
+ * int foo (...) [const|volatile] [throw (...)];
+ * int foo (...) [const|volatile] [throw (...)] [ctor-initializer] {...}
+ * int foo (...) [const|volatile] [throw (...)] try [ctor-initializer] {...}
+ * catch (...) {...}
+ */
+static boolean skipPostArgumentStuff (
+ statementInfo *const st, parenInfo *const info)
+{
+ tokenInfo *const token = activeToken (st);
+ unsigned int parameters = info->parameterCount;
+ unsigned int elementCount = 0;
+ boolean restart = FALSE;
+ boolean end = FALSE;
+ int c = skipToNonWhite ();
+
+ do
+ {
+ switch (c)
+ {
+ case ')': break;
+ case ':': skipMemIntializerList (token);break; /* ctor-initializer */
+ case '[': skipToMatch ("[]"); break;
+ case '=': cppUngetc (c); end = TRUE; break;
+ case '{': cppUngetc (c); end = TRUE; break;
+ case '}': cppUngetc (c); end = TRUE; break;
+
+ case '(':
+ if (elementCount > 0)
+ ++elementCount;
+ skipToMatch ("()");
+ break;
+
+ case ';':
+ if (parameters == 0 || elementCount < 2)
+ {
+ cppUngetc (c);
+ end = TRUE;
+ }
+ else if (--parameters == 0)
+ end = TRUE;
+ break;
+
+ default:
+ if (isident1 (c))
+ {
+ readIdentifier (token, c);
+ switch (token->keyword)
+ {
+ case KEYWORD_ATTRIBUTE: skipParens (); break;
+ case KEYWORD_THROW: skipParens (); break;
+ case KEYWORD_TRY: break;
+
+ case KEYWORD_CONST:
+ case KEYWORD_VOLATILE:
+ if (vStringLength (Signature) > 0)
+ {
+ vStringPut (Signature, ' ');
+ vStringCat (Signature, token->name);
+ }
+ break;
+
+ case KEYWORD_CATCH:
+ case KEYWORD_CLASS:
+ case KEYWORD_EXPLICIT:
+ case KEYWORD_EXTERN:
+ case KEYWORD_FRIEND:
+ case KEYWORD_INLINE:
+ case KEYWORD_MUTABLE:
+ case KEYWORD_NAMESPACE:
+ case KEYWORD_NEW:
+ case KEYWORD_NEWCOV:
+ case KEYWORD_OPERATOR:
+ case KEYWORD_OVERLOAD:
+ case KEYWORD_PRIVATE:
+ case KEYWORD_PROTECTED:
+ case KEYWORD_PUBLIC:
+ case KEYWORD_STATIC:
+ case KEYWORD_TEMPLATE:
+ case KEYWORD_TYPEDEF:
+ case KEYWORD_TYPENAME:
+ case KEYWORD_USING:
+ case KEYWORD_VIRTUAL:
+ /* Never allowed within parameter declarations. */
+ restart = TRUE;
+ end = TRUE;
+ break;
+
+ default:
+ if (isType (token, TOKEN_NONE))
+ ;
+ else if (info->isKnrParamList && info->parameterCount > 0)
+ ++elementCount;
+ else
+ {
+ /* If we encounter any other identifier immediately
+ * following an empty parameter list, this is almost
+ * certainly one of those Microsoft macro "thingies"
+ * that the automatic source code generation sticks
+ * in. Terminate the current statement.
+ */
+ restart = TRUE;
+ end = TRUE;
+ }
+ break;
+ }
+ }
+ }
+ if (! end)
+ {
+ c = skipToNonWhite ();
+ if (c == EOF)
+ end = TRUE;
+ }
+ } while (! end);
+
+ if (restart)
+ restartStatement (st);
+ else
+ setToken (st, TOKEN_NONE);
+
+ return (boolean) (c != EOF);
+}
+
+static void skipJavaThrows (statementInfo *const st)
+{
+ tokenInfo *const token = activeToken (st);
+ int c = skipToNonWhite ();
+
+ if (isident1 (c))
+ {
+ readIdentifier (token, c);
+ if (token->keyword == KEYWORD_THROWS)
+ {
+ do
+ {
+ c = skipToNonWhite ();
+ if (isident1 (c))
+ {
+ readIdentifier (token, c);
+ c = skipToNonWhite ();
+ }
+ } while (c == '.' || c == ',');
+ }
+ }
+ cppUngetc (c);
+ setToken (st, TOKEN_NONE);
+}
+
+static void analyzePostParens (statementInfo *const st, parenInfo *const info)
+{
+ const unsigned long inputLineNumber = getInputLineNumber ();
+ int c = skipToNonWhite ();
+
+ cppUngetc (c);
+ if (isOneOf (c, "{;,="))
+ ;
+ else if (isLanguage (Lang_java))
+ skipJavaThrows (st);
+ else
+ {
+ if (! skipPostArgumentStuff (st, info))
+ {
+ verbose (
+ "%s: confusing argument declarations beginning at line %lu\n",
+ getInputFileName (), inputLineNumber);
+ longjmp (Exception, (int) ExceptionFormattingError);
+ }
+ }
+}
+
+static boolean languageSupportsGenerics (void)
+{
+ return (boolean) (isLanguage (Lang_cpp) || isLanguage (Lang_csharp) ||
+ isLanguage (Lang_java));
+}
+
+static void processAngleBracket (void)
+{
+ int c = cppGetc ();
+ if (c == '>') {
+ /* already found match for template */
+ } else if (languageSupportsGenerics () && c != '<' && c != '=') {
+ /* this is a template */
+ cppUngetc (c);
+ skipToMatch ("<>");
+ } else if (c == '<') {
+ /* skip "<<" or "<<=". */
+ c = cppGetc ();
+ if (c != '=') {
+ cppUngetc (c);
+ }
+ } else {
+ cppUngetc (c);
+ }
+}
+
+static void parseJavaAnnotation (statementInfo *const st)
+{
+ /*
+ * @Override
+ * @Target(ElementType.METHOD)
+ * @SuppressWarnings(value = "unchecked")
+ *
+ * But watch out for "@interface"!
+ */
+ tokenInfo *const token = activeToken (st);
+
+ int c = skipToNonWhite ();
+ readIdentifier (token, c);
+ if (token->keyword == KEYWORD_INTERFACE)
+ {
+ /* Oops. This was actually "@interface" defining a new annotation. */
+ processInterface (st);
+ }
+ else
+ {
+ /* Bug #1691412: skip any annotation arguments. */
+ skipParens ();
+ }
+}
+
+static int parseParens (statementInfo *const st, parenInfo *const info)
+{
+ tokenInfo *const token = activeToken (st);
+ unsigned int identifierCount = 0;
+ unsigned int depth = 1;
+ boolean firstChar = TRUE;
+ int nextChar = '\0';
+
+ CollectingSignature = TRUE;
+ vStringClear (Signature);
+ vStringPut (Signature, '(');
+ info->parameterCount = 1;
+ do
+ {
+ int c = skipToNonWhite ();
+ vStringPut (Signature, c);
+
+ switch (c)
+ {
+ case '&':
+ case '*':
+ info->isPointer = TRUE;
+ info->isKnrParamList = FALSE;
+ if (identifierCount == 0)
+ info->isParamList = FALSE;
+ initToken (token);
+ break;
+
+ case ':':
+ info->isKnrParamList = FALSE;
+ break;
+
+ case '.':
+ info->isNameCandidate = FALSE;
+ c = cppGetc ();
+ if (c != '.')
+ {
+ cppUngetc (c);
+ info->isKnrParamList = FALSE;
+ }
+ else
+ {
+ c = cppGetc ();
+ if (c != '.')
+ {
+ cppUngetc (c);
+ info->isKnrParamList = FALSE;
+ }
+ else
+ vStringCatS (Signature, "..."); /* variable arg list */
+ }
+ break;
+
+ case ',':
+ info->isNameCandidate = FALSE;
+ if (info->isKnrParamList)
+ {
+ ++info->parameterCount;
+ identifierCount = 0;
+ }
+ break;
+
+ case '=':
+ info->isKnrParamList = FALSE;
+ info->isNameCandidate = FALSE;
+ if (firstChar)
+ {
+ info->isParamList = FALSE;
+ skipMacro (st);
+ depth = 0;
+ }
+ break;
+
+ case '[':
+ info->isKnrParamList = FALSE;
+ skipToMatch ("[]");
+ break;
+
+ case '<':
+ info->isKnrParamList = FALSE;
+ processAngleBracket ();
+ break;
+
+ case ')':
+ if (firstChar)
+ info->parameterCount = 0;
+ --depth;
+ break;
+
+ case '(':
+ info->isKnrParamList = FALSE;
+ if (firstChar)
+ {
+ info->isNameCandidate = FALSE;
+ cppUngetc (c);
+ vStringClear (Signature);
+ skipMacro (st);
+ depth = 0;
+ vStringChop (Signature);
+ }
+ else if (isType (token, TOKEN_PAREN_NAME))
+ {
+ c = skipToNonWhite ();
+ if (c == '*') /* check for function pointer */
+ {
+ skipToMatch ("()");
+ c = skipToNonWhite ();
+ if (c == '(')
+ skipToMatch ("()");
+ else
+ cppUngetc (c);
+ }
+ else
+ {
+ cppUngetc (c);
+ cppUngetc ('(');
+ info->nestedArgs = TRUE;
+ }
+ }
+ else
+ ++depth;
+ break;
+
+ default:
+ if (c == '@' && isLanguage (Lang_java))
+ {
+ parseJavaAnnotation(st);
+ }
+ else if (isident1 (c))
+ {
+ if (++identifierCount > 1)
+ info->isKnrParamList = FALSE;
+ readIdentifier (token, c);
+ if (isType (token, TOKEN_NAME) && info->isNameCandidate)
+ token->type = TOKEN_PAREN_NAME;
+ else if (isType (token, TOKEN_KEYWORD))
+ {
+ if (token->keyword != KEYWORD_CONST &&
+ token->keyword != KEYWORD_VOLATILE)
+ {
+ info->isKnrParamList = FALSE;
+ info->isNameCandidate = FALSE;
+ }
+ }
+ }
+ else
+ {
+ info->isParamList = FALSE;
+ info->isKnrParamList = FALSE;
+ info->isNameCandidate = FALSE;
+ info->invalidContents = TRUE;
+ }
+ break;
+ }
+ firstChar = FALSE;
+ } while (! info->nestedArgs && depth > 0 &&
+ (info->isKnrParamList || info->isNameCandidate));
+
+ if (! info->nestedArgs) while (depth > 0)
+ {
+ skipToMatch ("()");
+ --depth;
+ }
+
+ if (! info->isNameCandidate)
+ initToken (token);
+
+ vStringTerminate (Signature);
+ if (info->isKnrParamList)
+ vStringClear (Signature);
+ CollectingSignature = FALSE;
+ return nextChar;
+}
+
+static void initParenInfo (parenInfo *const info)
+{
+ info->isPointer = FALSE;
+ info->isParamList = TRUE;
+ info->isKnrParamList = isLanguage (Lang_c);
+ info->isNameCandidate = TRUE;
+ info->invalidContents = FALSE;
+ info->nestedArgs = FALSE;
+ info->parameterCount = 0;
+}
+
+static void analyzeParens (statementInfo *const st)
+{
+ tokenInfo *const prev = prevToken (st, 1);
+
+ if (st->inFunction && ! st->assignment)
+ st->notVariable = TRUE;
+ if (! isType (prev, TOKEN_NONE)) /* in case of ignored enclosing macros */
+ {
+ tokenInfo *const token = activeToken (st);
+ parenInfo info;
+ int c;
+
+ initParenInfo (&info);
+ parseParens (st, &info);
+ c = skipToNonWhite ();
+ cppUngetc (c);
+ if (info.invalidContents)
+ reinitStatement (st, FALSE);
+ else if (info.isNameCandidate && isType (token, TOKEN_PAREN_NAME) &&
+ ! st->gotParenName &&
+ (! info.isParamList || ! st->haveQualifyingName ||
+ c == '(' ||
+ (c == '=' && st->implementation != IMP_VIRTUAL) ||
+ (st->declaration == DECL_NONE && isOneOf (c, ",;"))))
+ {
+ token->type = TOKEN_NAME;
+ processName (st);
+ st->gotParenName = TRUE;
+ if (! (c == '(' && info.nestedArgs))
+ st->isPointer = info.isPointer;
+ }
+ else if (! st->gotArgs && info.isParamList)
+ {
+ st->gotArgs = TRUE;
+ setToken (st, TOKEN_ARGS);
+ advanceToken (st);
+ if (st->scope != SCOPE_TYPEDEF)
+ analyzePostParens (st, &info);
+ }
+ else
+ setToken (st, TOKEN_NONE);
+ }
+}
+
+/*
+* Token parsing functions
+*/
+
+static void addContext (statementInfo *const st, const tokenInfo* const token)
+{
+ if (isType (token, TOKEN_NAME))
+ {
+ if (vStringLength (st->context->name) > 0)
+ {
+ if (isLanguage (Lang_c) || isLanguage (Lang_cpp))
+ vStringCatS (st->context->name, "::");
+ else if (isLanguage (Lang_java) || isLanguage (Lang_csharp))
+ vStringCatS (st->context->name, ".");
+ }
+ vStringCat (st->context->name, token->name);
+ st->context->type = TOKEN_NAME;
+ }
+}
+
+static boolean inheritingDeclaration (declType decl)
+{
+ /* C# supports inheritance for enums. C++0x will too, but not yet. */
+ if (decl == DECL_ENUM)
+ {
+ return (boolean) (isLanguage (Lang_csharp));
+ }
+ return (boolean) (
+ decl == DECL_CLASS ||
+ decl == DECL_STRUCT ||
+ decl == DECL_INTERFACE);
+}
+
+static void processColon (statementInfo *const st)
+{
+ int c = (isLanguage (Lang_cpp) ? cppGetc () : skipToNonWhite ());
+ const boolean doubleColon = (boolean) (c == ':');
+
+ if (doubleColon)
+ {
+ setToken (st, TOKEN_DOUBLE_COLON);
+ st->haveQualifyingName = FALSE;
+ }
+ else
+ {
+ cppUngetc (c);
+ if ((isLanguage (Lang_cpp) || isLanguage (Lang_csharp)) &&
+ inheritingDeclaration (st->declaration))
+ {
+ readParents (st, ':');
+ }
+ else if (parentDecl (st) == DECL_STRUCT)
+ {
+ c = skipToOneOf (",;");
+ if (c == ',')
+ setToken (st, TOKEN_COMMA);
+ else if (c == ';')
+ setToken (st, TOKEN_SEMICOLON);
+ }
+ else
+ {
+ const tokenInfo *const prev = prevToken (st, 1);
+ const tokenInfo *const prev2 = prevToken (st, 2);
+ if (prev->keyword == KEYWORD_DEFAULT ||
+ prev2->keyword == KEYWORD_CASE ||
+ st->parent != NULL)
+ {
+ reinitStatement (st, FALSE);
+ }
+ }
+ }
+}
+
+/* Skips over any initializing value which may follow an '=' character in a
+ * variable definition.
+ */
+static int skipInitializer (statementInfo *const st)
+{
+ boolean done = FALSE;
+ int c;
+
+ while (! done)
+ {
+ c = skipToNonWhite ();
+
+ if (c == EOF)
+ longjmp (Exception, (int) ExceptionFormattingError);
+ else switch (c)
+ {
+ case ',':
+ case ';': done = TRUE; break;
+
+ case '0':
+ if (st->implementation == IMP_VIRTUAL)
+ st->implementation = IMP_PURE_VIRTUAL;
+ break;
+
+ case '[': skipToMatch ("[]"); break;
+ case '(': skipToMatch ("()"); break;
+ case '{': skipToMatch ("{}"); break;
+ case '<': processAngleBracket(); break;
+
+ case '}':
+ if (insideEnumBody (st))
+ done = TRUE;
+ else if (! isBraceFormat ())
+ {
+ verbose ("%s: unexpected closing brace at line %lu\n",
+ getInputFileName (), getInputLineNumber ());
+ longjmp (Exception, (int) ExceptionBraceFormattingError);
+ }
+ break;
+
+ default: break;
+ }
+ }
+ return c;
+}
+
+static void processInitializer (statementInfo *const st)
+{
+ const boolean inEnumBody = insideEnumBody (st);
+ int c = cppGetc ();
+
+ if (c != '=')
+ {
+ cppUngetc (c);
+ c = skipInitializer (st);
+ st->assignment = TRUE;
+ if (c == ';')
+ setToken (st, TOKEN_SEMICOLON);
+ else if (c == ',')
+ setToken (st, TOKEN_COMMA);
+ else if (c == '}' && inEnumBody)
+ {
+ cppUngetc (c);
+ setToken (st, TOKEN_COMMA);
+ }
+ if (st->scope == SCOPE_EXTERN)
+ st->scope = SCOPE_GLOBAL;
+ }
+}
+
+static void parseIdentifier (statementInfo *const st, const int c)
+{
+ tokenInfo *const token = activeToken (st);
+
+ readIdentifier (token, c);
+ if (! isType (token, TOKEN_NONE))
+ processToken (token, st);
+}
+
+static void parseGeneralToken (statementInfo *const st, const int c)
+{
+ const tokenInfo *const prev = prevToken (st, 1);
+
+ if (isident1 (c) || (isLanguage (Lang_java) && isHighChar (c)))
+ {
+ parseIdentifier (st, c);
+ if (isType (st->context, TOKEN_NAME) &&
+ isType (activeToken (st), TOKEN_NAME) && isType (prev, TOKEN_NAME))
+ {
+ initToken (st->context);
+ }
+ }
+ else if (c == '.' || c == '-')
+ {
+ if (! st->assignment)
+ st->notVariable = TRUE;
+ if (c == '-')
+ {
+ int c2 = cppGetc ();
+ if (c2 != '>')
+ cppUngetc (c2);
+ }
+ }
+ else if (c == '!' || c == '>')
+ {
+ int c2 = cppGetc ();
+ if (c2 != '=')
+ cppUngetc (c2);
+ }
+ else if (c == '@' && isLanguage (Lang_java))
+ {
+ parseJavaAnnotation (st);
+ }
+ else if (isExternCDecl (st, c))
+ {
+ st->declaration = DECL_NOMANGLE;
+ st->scope = SCOPE_GLOBAL;
+ }
+}
+
+/* Reads characters from the pre-processor and assembles tokens, setting
+ * the current statement state.
+ */
+static void nextToken (statementInfo *const st)
+{
+ tokenInfo *token;
+ do
+ {
+ int c = skipToNonWhite ();
+ switch (c)
+ {
+ case EOF: longjmp (Exception, (int) ExceptionEOF); break;
+ case '(': analyzeParens (st); break;
+ case '<': processAngleBracket (); break;
+ case '*': st->haveQualifyingName = FALSE; break;
+ case ',': setToken (st, TOKEN_COMMA); break;
+ case ':': processColon (st); break;
+ case ';': setToken (st, TOKEN_SEMICOLON); break;
+ case '=': processInitializer (st); break;
+ case '[': skipToMatch ("[]"); break;
+ case '{': setToken (st, TOKEN_BRACE_OPEN); break;
+ case '}': setToken (st, TOKEN_BRACE_CLOSE); break;
+ default: parseGeneralToken (st, c); break;
+ }
+ token = activeToken (st);
+ } while (isType (token, TOKEN_NONE));
+}
+
+/*
+* Scanning support functions
+*/
+
+static statementInfo *CurrentStatement = NULL;
+
+static statementInfo *newStatement (statementInfo *const parent)
+{
+ statementInfo *const st = xMalloc (1, statementInfo);
+ unsigned int i;
+
+ for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
+ st->token [i] = newToken ();
+
+ st->context = newToken ();
+ st->blockName = newToken ();
+ st->parentClasses = vStringNew ();
+
+ initStatement (st, parent);
+ CurrentStatement = st;
+
+ return st;
+}
+
+static void deleteStatement (void)
+{
+ statementInfo *const st = CurrentStatement;
+ statementInfo *const parent = st->parent;
+ unsigned int i;
+
+ for (i = 0 ; i < (unsigned int) NumTokens ; ++i)
+ {
+ deleteToken (st->token [i]); st->token [i] = NULL;
+ }
+ deleteToken (st->blockName); st->blockName = NULL;
+ deleteToken (st->context); st->context = NULL;
+ vStringDelete (st->parentClasses); st->parentClasses = NULL;
+ eFree (st);
+ CurrentStatement = parent;
+}
+
+static void deleteAllStatements (void)
+{
+ while (CurrentStatement != NULL)
+ deleteStatement ();
+}
+
+static boolean isStatementEnd (const statementInfo *const st)
+{
+ const tokenInfo *const token = activeToken (st);
+ boolean isEnd;
+
+ if (isType (token, TOKEN_SEMICOLON))
+ isEnd = TRUE;
+ else if (isType (token, TOKEN_BRACE_CLOSE))
+ /* Java and C# do not require semicolons to end a block. Neither do C++
+ * namespaces. All other blocks require a semicolon to terminate them.
+ */
+ isEnd = (boolean) (isLanguage (Lang_java) || isLanguage (Lang_csharp) ||
+ ! isContextualStatement (st));
+ else
+ isEnd = FALSE;
+
+ return isEnd;
+}
+
+static void checkStatementEnd (statementInfo *const st)
+{
+ const tokenInfo *const token = activeToken (st);
+
+ if (isType (token, TOKEN_COMMA))
+ reinitStatement (st, TRUE);
+ else if (isStatementEnd (st))
+ {
+ DebugStatement ( if (debug (DEBUG_PARSE)) printf ("<ES>"); )
+ reinitStatement (st, FALSE);
+ cppEndStatement ();
+ }
+ else
+ {
+ cppBeginStatement ();
+ advanceToken (st);
+ }
+}
+
+static void nest (statementInfo *const st, const unsigned int nestLevel)
+{
+ switch (st->declaration)
+ {
+ case DECL_CLASS:
+ case DECL_ENUM:
+ case DECL_INTERFACE:
+ case DECL_NAMESPACE:
+ case DECL_NOMANGLE:
+ case DECL_STRUCT:
+ case DECL_UNION:
+ createTags (nestLevel, st);
+ break;
+
+ case DECL_FUNCTION:
+ case DECL_TASK:
+ st->inFunction = TRUE;
+ /* fall through */
+ default:
+ if (includeTag (TAG_LOCAL, FALSE))
+ createTags (nestLevel, st);
+ else
+ skipToMatch ("{}");
+ break;
+ }
+ advanceToken (st);
+ setToken (st, TOKEN_BRACE_CLOSE);
+}
+
+static void tagCheck (statementInfo *const st)
+{
+ const tokenInfo *const token = activeToken (st);
+ const tokenInfo *const prev = prevToken (st, 1);
+ const tokenInfo *const prev2 = prevToken (st, 2);
+
+ switch (token->type)
+ {
+ case TOKEN_NAME:
+ if (insideEnumBody (st))
+ qualifyEnumeratorTag (st, token);
+ break;
+#if 0
+ case TOKEN_PACKAGE:
+ if (st->haveQualifyingName)
+ makeTag (token, st, FALSE, TAG_PACKAGE);
+ break;
+#endif
+ case TOKEN_BRACE_OPEN:
+ if (isType (prev, TOKEN_ARGS))
+ {
+ if (st->haveQualifyingName)
+ {
+ if (! isLanguage (Lang_vera))
+ st->declaration = DECL_FUNCTION;
+ if (isType (prev2, TOKEN_NAME))
+ copyToken (st->blockName, prev2);
+ qualifyFunctionTag (st, prev2);
+ }
+ }
+ else if (isContextualStatement (st) ||
+ st->declaration == DECL_NAMESPACE ||
+ st->declaration == DECL_PROGRAM)
+ {
+ if (isType (prev, TOKEN_NAME))
+ copyToken (st->blockName, prev);
+ else
+ {
+ /* For an anonymous struct or union we use a unique ID
+ * a number, so that the members can be found.
+ */
+ char buf [20]; /* length of "_anon" + digits + null */
+ sprintf (buf, "__anon%d", ++AnonymousID);
+ vStringCopyS (st->blockName->name, buf);
+ st->blockName->type = TOKEN_NAME;
+ st->blockName->keyword = KEYWORD_NONE;
+ }
+ qualifyBlockTag (st, prev);
+ }
+ else if (isLanguage (Lang_csharp))
+ makeTag (prev, st, FALSE, TAG_PROPERTY);
+ break;
+
+ case TOKEN_SEMICOLON:
+ case TOKEN_COMMA:
+ if (insideEnumBody (st))
+ ;
+ else if (isType (prev, TOKEN_NAME))
+ {
+ if (isContextualKeyword (prev2))
+ makeTag (prev, st, TRUE, TAG_EXTERN_VAR);
+ else
+ qualifyVariableTag (st, prev);
+ }
+ else if (isType (prev, TOKEN_ARGS) && isType (prev2, TOKEN_NAME))
+ {
+ if (st->isPointer)
+ qualifyVariableTag (st, prev2);
+ else
+ qualifyFunctionDeclTag (st, prev2);
+ }
+ if (isLanguage (Lang_java) && token->type == TOKEN_SEMICOLON && insideEnumBody (st))
+ {
+ /* In Java, after an initial enum-like part,
+ * a semicolon introduces a class-like part.
+ * See Bug #1730485 for the full rationale. */
+ st->parent->declaration = DECL_CLASS;
+ }
+ break;
+
+ default: break;
+ }
+}
+
+/* Parses the current file and decides whether to write out and tags that
+ * are discovered.
+ */
+static void createTags (const unsigned int nestLevel,
+ statementInfo *const parent)
+{
+ statementInfo *const st = newStatement (parent);
+
+ DebugStatement ( if (nestLevel > 0) debugParseNest (TRUE, nestLevel); )
+ while (TRUE)
+ {
+ tokenInfo *token;
+
+ nextToken (st);
+ token = activeToken (st);
+ if (isType (token, TOKEN_BRACE_CLOSE))
+ {
+ if (nestLevel > 0)
+ break;
+ else
+ {
+ verbose ("%s: unexpected closing brace at line %lu\n",
+ getInputFileName (), getInputLineNumber ());
+ longjmp (Exception, (int) ExceptionBraceFormattingError);
+ }
+ }
+ else if (isType (token, TOKEN_DOUBLE_COLON))
+ {
+ addContext (st, prevToken (st, 1));
+ advanceToken (st);
+ }
+ else
+ {
+ tagCheck (st);
+ if (isType (token, TOKEN_BRACE_OPEN))
+ nest (st, nestLevel + 1);
+ checkStatementEnd (st);
+ }
+ }
+ deleteStatement ();
+ DebugStatement ( if (nestLevel > 0) debugParseNest (FALSE, nestLevel - 1); )
+}
+
+static boolean findCTags (const unsigned int passCount)
+{
+ exception_t exception;
+ boolean retry;
+
+ Assert (passCount < 3);
+ cppInit ((boolean) (passCount > 1), isLanguage (Lang_csharp));
+ Signature = vStringNew ();
+
+ exception = (exception_t) setjmp (Exception);
+ retry = FALSE;
+ if (exception == ExceptionNone)
+ createTags (0, NULL);
+ else
+ {
+ deleteAllStatements ();
+ if (exception == ExceptionBraceFormattingError && passCount == 1)
+ {
+ retry = TRUE;
+ verbose ("%s: retrying file with fallback brace matching algorithm\n",
+ getInputFileName ());
+ }
+ }
+ vStringDelete (Signature);
+ cppTerminate ();
+ return retry;
+}
+
+static void buildKeywordHash (const langType language, unsigned int idx)
+{
+ const size_t count = sizeof (KeywordTable) / sizeof (KeywordTable [0]);
+ size_t i;
+ for (i = 0 ; i < count ; ++i)
+ {
+ const keywordDesc* const p = &KeywordTable [i];
+ if (p->isValid [idx])
+ addKeyword (p->name, language, (int) p->id);
+ }
+}
+
+static void initializeCParser (const langType language)
+{
+ Lang_c = language;
+ buildKeywordHash (language, 0);
+}
+
+static void initializeCppParser (const langType language)
+{
+ Lang_cpp = language;
+ buildKeywordHash (language, 1);
+}
+
+static void initializeCsharpParser (const langType language)
+{
+ Lang_csharp = language;
+ buildKeywordHash (language, 2);
+}
+
+static void initializeJavaParser (const langType language)
+{
+ Lang_java = language;
+ buildKeywordHash (language, 3);
+}
+
+static void initializeVeraParser (const langType language)
+{
+ Lang_vera = language;
+ buildKeywordHash (language, 4);
+}
+
+extern parserDefinition* CParser (void)
+{
+ static const char *const extensions [] = { "c", NULL };
+ parserDefinition* def = parserNew ("C");
+ def->kinds = CKinds;
+ def->kindCount = KIND_COUNT (CKinds);
+ def->extensions = extensions;
+ def->parser2 = findCTags;
+ def->initialize = initializeCParser;
+ return def;
+}
+
+extern parserDefinition* CppParser (void)
+{
+ static const char *const extensions [] = {
+ "c++", "cc", "cp", "cpp", "cxx", "h", "h++", "hh", "hp", "hpp", "hxx",
+#ifndef CASE_INSENSITIVE_FILENAMES
+ "C", "H",
+#endif
+ NULL
+ };
+ parserDefinition* def = parserNew ("C++");
+ def->kinds = CKinds;
+ def->kindCount = KIND_COUNT (CKinds);
+ def->extensions = extensions;
+ def->parser2 = findCTags;
+ def->initialize = initializeCppParser;
+ return def;
+}
+
+extern parserDefinition* CsharpParser (void)
+{
+ static const char *const extensions [] = { "cs", NULL };
+ parserDefinition* def = parserNew ("C#");
+ def->kinds = CsharpKinds;
+ def->kindCount = KIND_COUNT (CsharpKinds);
+ def->extensions = extensions;
+ def->parser2 = findCTags;
+ def->initialize = initializeCsharpParser;
+ return def;
+}
+
+extern parserDefinition* JavaParser (void)
+{
+ static const char *const extensions [] = { "java", NULL };
+ parserDefinition* def = parserNew ("Java");
+ def->kinds = JavaKinds;
+ def->kindCount = KIND_COUNT (JavaKinds);
+ def->extensions = extensions;
+ def->parser2 = findCTags;
+ def->initialize = initializeJavaParser;
+ return def;
+}
+
+extern parserDefinition* VeraParser (void)
+{
+ static const char *const extensions [] = { "vr", "vri", "vrh", NULL };
+ parserDefinition* def = parserNew ("Vera");
+ def->kinds = VeraKinds;
+ def->kindCount = KIND_COUNT (VeraKinds);
+ def->extensions = extensions;
+ def->parser2 = findCTags;
+ def->initialize = initializeVeraParser;
+ return def;
+}
+
+/* vi:set tabstop=4 shiftwidth=4 noexpandtab: */
Index: create-5.8-unused-attribute-patch/ctags-5.8-new/eiffel.c
===================================================================
--- create-5.8-unused-attribute-patch/ctags-5.8-new/eiffel.c (nonexistent)
+++ create-5.8-unused-attribute-patch/ctags-5.8-new/eiffel.c (revision 5)
@@ -0,0 +1,1352 @@
+/*
+* $Id: eiffel.c 706 2009-06-28 23:09:30Z dhiebert $
+*
+* Copyright (c) 1998-2002, Darren Hiebert
+*
+* 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 Eiffel language
+* files.
+*/
+
+/*
+* INCLUDE FILES
+*/
+#include "general.h" /* must always come first */
+
+#ifdef TYPE_REFERENCE_TOOL
+#include <stdio.h>
+#endif
+#include <string.h>
+#include <limits.h>
+#include <ctype.h> /* to define tolower () */
+#include <setjmp.h>
+
+#include "debug.h"
+#include "keyword.h"
+#include "routines.h"
+#include "vstring.h"
+#ifndef TYPE_REFERENCE_TOOL
+#include "entry.h"
+#include "options.h"
+#include "parse.h"
+#include "read.h"
+#endif
+
+/*
+* MACROS
+*/
+#define isident(c) (isalnum(c) || (c) == '_')
+#define isFreeOperatorChar(c) ((c) == '@' || (c) == '#' || \
+ (c) == '|' || (c) == '&')
+#define isType(token,t) (boolean) ((token)->type == (t))
+#define isKeyword(token,k) (boolean) ((token)->keyword == (k))
+
+/*
+* DATA DECLARATIONS
+*/
+
+typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;
+
+/* Used to specify type of keyword.
+ */
+typedef enum eKeywordId {
+ KEYWORD_NONE = -1,
+ KEYWORD_alias, KEYWORD_all, KEYWORD_and, KEYWORD_as, KEYWORD_assign,
+ 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_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,
+ KEYWORD_or, KEYWORD_prefix, KEYWORD_redefine, KEYWORD_rename,
+ KEYWORD_require, KEYWORD_rescue, KEYWORD_Result, KEYWORD_retry,
+ KEYWORD_select, KEYWORD_separate, KEYWORD_strip, KEYWORD_then,
+ KEYWORD_true, KEYWORD_undefine, KEYWORD_unique, KEYWORD_until,
+ KEYWORD_variant, KEYWORD_when, KEYWORD_xor
+} keywordId;
+
+/* Used to determine whether keyword is valid for the token language and
+ * what its ID is.
+ */
+typedef struct sKeywordDesc {
+ const char *name;
+ keywordId id;
+} keywordDesc;
+
+typedef enum eTokenType {
+ TOKEN_UNDEFINED,
+ TOKEN_BANG,
+ TOKEN_CHARACTER,
+ TOKEN_CLOSE_BRACE,
+ TOKEN_CLOSE_BRACKET,
+ TOKEN_CLOSE_PAREN,
+ TOKEN_COLON,
+ TOKEN_COMMA,
+ TOKEN_CONSTRAINT,
+ TOKEN_DOT,
+ TOKEN_DOLLAR,
+ TOKEN_IDENTIFIER,
+ TOKEN_KEYWORD,
+ TOKEN_NUMERIC,
+ TOKEN_OPEN_BRACE,
+ TOKEN_OPEN_BRACKET,
+ TOKEN_OPEN_PAREN,
+ TOKEN_OPERATOR,
+ TOKEN_OTHER,
+ TOKEN_QUESTION,
+ TOKEN_SEMICOLON,
+ TOKEN_SEPARATOR,
+ TOKEN_STRING,
+ TOKEN_TILDE
+} tokenType;
+
+typedef struct sTokenInfo {
+ tokenType type;
+ keywordId keyword;
+ boolean isExported;
+ vString* string;
+ vString* className;
+ vString* featureName;
+} tokenInfo;
+
+/*
+* DATA DEFINITIONS
+*/
+
+static langType Lang_eiffel;
+
+#ifdef TYPE_REFERENCE_TOOL
+
+static const char *FileName;
+static FILE *File;
+static int PrintClass;
+static int PrintReferences;
+static int SelfReferences;
+static int Debug;
+static stringList *GenericNames;
+static stringList *ReferencedTypes;
+
+#else
+
+typedef enum {
+ EKIND_CLASS, EKIND_FEATURE, EKIND_LOCAL, EKIND_QUALIFIED_TAGS
+} eiffelKind;
+
+static kindOption EiffelKinds [] = {
+ { TRUE, 'c', "class", "classes"},
+ { TRUE, 'f', "feature", "features"},
+ { FALSE, 'l', "local", "local entities"}
+};
+
+#endif
+
+static jmp_buf Exception;
+
+static const keywordDesc EiffelKeywordTable [] = {
+ /* keyword keyword ID */
+ { "alias", KEYWORD_alias },
+ { "all", KEYWORD_all },
+ { "and", KEYWORD_and },
+ { "as", KEYWORD_as },
+ { "assign", KEYWORD_assign },
+ { "check", KEYWORD_check },
+ { "class", KEYWORD_class },
+ { "convert", KEYWORD_convert },
+ { "create", KEYWORD_create },
+ { "creation", KEYWORD_creation },
+ { "current", KEYWORD_Current },
+ { "debug", KEYWORD_debug },
+ { "deferred", KEYWORD_deferred },
+ { "do", KEYWORD_do },
+ { "else", KEYWORD_else },
+ { "elseif", KEYWORD_elseif },
+ { "end", KEYWORD_end },
+ { "ensure", KEYWORD_ensure },
+ { "expanded", KEYWORD_expanded },
+ { "export", KEYWORD_export },
+ { "external", KEYWORD_external },
+ { "false", KEYWORD_false },
+ { "feature", KEYWORD_feature },
+ { "from", KEYWORD_from },
+ { "frozen", KEYWORD_frozen },
+ { "if", KEYWORD_if },
+ { "implies", KEYWORD_implies },
+ { "indexing", KEYWORD_indexing },
+ { "infix", KEYWORD_infix },
+ { "inherit", KEYWORD_inherit },
+ { "inspect", KEYWORD_inspect },
+ { "invariant", KEYWORD_invariant },
+ { "is", KEYWORD_is },
+ { "like", KEYWORD_like },
+ { "local", KEYWORD_local },
+ { "loop", KEYWORD_loop },
+ { "not", KEYWORD_not },
+ { "obsolete", KEYWORD_obsolete },
+ { "old", KEYWORD_old },
+ { "once", KEYWORD_once },
+ { "or", KEYWORD_or },
+ { "prefix", KEYWORD_prefix },
+ { "redefine", KEYWORD_redefine },
+ { "rename", KEYWORD_rename },
+ { "require", KEYWORD_require },
+ { "rescue", KEYWORD_rescue },
+ { "result", KEYWORD_Result },
+ { "retry", KEYWORD_retry },
+ { "select", KEYWORD_select },
+ { "separate", KEYWORD_separate },
+ { "strip", KEYWORD_strip },
+ { "then", KEYWORD_then },
+ { "true", KEYWORD_true },
+ { "undefine", KEYWORD_undefine },
+ { "unique", KEYWORD_unique },
+ { "until", KEYWORD_until },
+ { "variant", KEYWORD_variant },
+ { "when", KEYWORD_when },
+ { "xor", KEYWORD_xor }
+};
+
+/*
+* FUNCTION DEFINITIONS
+*/
+
+static void buildEiffelKeywordHash (void)
+{
+ const size_t count = sizeof (EiffelKeywordTable) /
+ sizeof (EiffelKeywordTable [0]);
+ size_t i;
+ for (i = 0 ; i < count ; ++i)
+ {
+ const keywordDesc* const p = &EiffelKeywordTable [i];
+ addKeyword (p->name, Lang_eiffel, (int) p->id);
+ }
+}
+
+#ifdef TYPE_REFERENCE_TOOL
+
+static void addGenericName (tokenInfo *const token)
+{
+ vStringUpper (token->string);
+ if (vStringLength (token->string) > 0)
+ stringListAdd (GenericNames, vStringNewCopy (token->string));
+}
+
+static boolean isGeneric (tokenInfo *const token)
+{
+ return (boolean) stringListHas (GenericNames, vStringValue (token->string));
+}
+
+static void reportType (tokenInfo *const token)
+{
+ vStringUpper (token->string);
+ if (vStringLength (token->string) > 0 && ! isGeneric (token) &&
+ (SelfReferences || strcmp (vStringValue (
+ token->string), vStringValue (token->className)) != 0) &&
+ ! stringListHas (ReferencedTypes, vStringValue (token->string)))
+ {
+ printf ("%s\n", vStringValue (token->string));
+ stringListAdd (ReferencedTypes, vStringNewCopy (token->string));
+ }
+}
+
+static int fileGetc (void)
+{
+ int c = getc (File);
+ if (c == '\r')
+ {
+ c = getc (File);
+ if (c != '\n')
+ {
+ ungetc (c, File);
+ c = '\n';
+ }
+ }
+ if (Debug > 0 && c != EOF)
+ putc (c, errout);
+ return c;
+}
+
+static int fileUngetc (c)
+{
+ return ungetc (c, File);
+}
+
+extern char *readLine (vString *const vLine, FILE *const fp)
+{
+ return NULL;
+}
+
+#else
+
+/*
+* Tag generation functions
+*/
+
+static void makeEiffelClassTag (tokenInfo *const token)
+{
+ if (EiffelKinds [EKIND_CLASS].enabled)
+ {
+ const char *const name = vStringValue (token->string);
+ tagEntryInfo e;
+
+ initTagEntry (&e, name);
+
+ e.kindName = EiffelKinds [EKIND_CLASS].name;
+ e.kind = EiffelKinds [EKIND_CLASS].letter;
+
+ makeTagEntry (&e);
+ }
+ vStringCopy (token->className, token->string);
+}
+
+static void makeEiffelFeatureTag (tokenInfo *const token)
+{
+ if (EiffelKinds [EKIND_FEATURE].enabled &&
+ (token->isExported || Option.include.fileScope))
+ {
+ const char *const name = vStringValue (token->string);
+ tagEntryInfo e;
+
+ initTagEntry (&e, name);
+
+ e.isFileScope = (boolean) (! token->isExported);
+ e.kindName = EiffelKinds [EKIND_FEATURE].name;
+ e.kind = EiffelKinds [EKIND_FEATURE].letter;
+ e.extensionFields.scope [0] = EiffelKinds [EKIND_CLASS].name;
+ e.extensionFields.scope [1] = vStringValue (token->className);
+
+ makeTagEntry (&e);
+
+ if (Option.include.qualifiedTags)
+ {
+ vString* qualified = vStringNewInit (vStringValue (token->className));
+ vStringPut (qualified, '.');
+ vStringCat (qualified, token->string);
+ e.name = vStringValue (qualified);
+ makeTagEntry (&e);
+ vStringDelete (qualified);
+ }
+ }
+ vStringCopy (token->featureName, token->string);
+}
+
+static void makeEiffelLocalTag (tokenInfo *const token)
+{
+ if (EiffelKinds [EKIND_LOCAL].enabled && Option.include.fileScope)
+ {
+ const char *const name = vStringValue (token->string);
+ vString* scope = vStringNew ();
+ tagEntryInfo e;
+
+ initTagEntry (&e, name);
+
+ e.isFileScope = TRUE;
+ e.kindName = EiffelKinds [EKIND_LOCAL].name;
+ e.kind = EiffelKinds [EKIND_LOCAL].letter;
+
+ vStringCopy (scope, token->className);
+ vStringPut (scope, '.');
+ vStringCat (scope, token->featureName);
+
+ e.extensionFields.scope [0] = EiffelKinds [EKIND_FEATURE].name;
+ e.extensionFields.scope [1] = vStringValue (scope);
+
+ makeTagEntry (&e);
+ vStringDelete (scope);
+ }
+}
+
+#endif
+
+/*
+* Parsing functions
+*/
+
+static int skipToCharacter (const int c)
+{
+ int d;
+
+ do
+ {
+ d = fileGetc ();
+ } while (d != EOF && d != c);
+
+ return d;
+}
+
+/* If a numeric is passed in 'c', this is used as the first digit of the
+ * numeric being parsed.
+ */
+static vString *parseInteger (int c)
+{
+ vString *string = vStringNew ();
+
+ if (c == '\0')
+ c = fileGetc ();
+ if (c == '-')
+ {
+ vStringPut (string, c);
+ c = fileGetc ();
+ }
+ else if (! isdigit (c))
+ c = fileGetc ();
+ while (c != EOF && (isdigit (c) || c == '_'))
+ {
+ vStringPut (string, c);
+ c = fileGetc ();
+ }
+ vStringTerminate (string);
+ fileUngetc (c);
+
+ return string;
+}
+
+static vString *parseNumeric (int c)
+{
+ vString *string = vStringNew ();
+ vString *integer = parseInteger (c);
+ vStringCopy (string, integer);
+ vStringDelete (integer);
+
+ c = fileGetc ();
+ if (c == '.')
+ {
+ integer = parseInteger ('\0');
+ vStringPut (string, c);
+ vStringCat (string, integer);
+ vStringDelete (integer);
+ c = fileGetc ();
+ }
+ if (tolower (c) == 'e')
+ {
+ integer = parseInteger ('\0');
+ vStringPut (string, c);
+ vStringCat (string, integer);
+ vStringDelete (integer);
+ }
+ else if (!isspace (c))
+ fileUngetc (c);
+
+ vStringTerminate (string);
+
+ return string;
+}
+
+static int parseEscapedCharacter (void)
+{
+ int d = '\0';
+ int c = fileGetc ();
+
+ switch (c)
+ {
+ case 'A': d = '@'; break;
+ case 'B': d = '\b'; break;
+ case 'C': d = '^'; break;
+ case 'D': d = '$'; break;
+ case 'F': d = '\f'; break;
+ case 'H': d = '\\'; break;
+ case 'L': d = '~'; break;
+ case 'N': d = '\n'; break;
+#ifdef QDOS
+ case 'Q': d = 0x9F; break;
+#else
+ case 'Q': d = '`'; break;
+#endif
+ case 'R': d = '\r'; break;
+ case 'S': d = '#'; break;
+ case 'T': d = '\t'; break;
+ case 'U': d = '\0'; break;
+ case 'V': d = '|'; break;
+ case '%': d = '%'; break;
+ case '\'': d = '\''; break;
+ case '"': d = '"'; break;
+ case '(': d = '['; break;
+ case ')': d = ']'; break;
+ case '<': d = '{'; break;
+ case '>': d = '}'; break;
+
+ case '\n': skipToCharacter ('%'); break;
+
+ case '/':
+ {
+ vString *string = parseInteger ('\0');
+ const char *value = vStringValue (string);
+ const unsigned long ascii = atol (value);
+ vStringDelete (string);
+
+ c = fileGetc ();
+ if (c == '/' && ascii < 256)
+ d = ascii;
+ break;
+ }
+
+ default: break;
+ }
+ return d;
+}
+
+static int parseCharacter (void)
+{
+ int c = fileGetc ();
+ int result = c;
+
+ if (c == '%')
+ result = parseEscapedCharacter ();
+
+ c = fileGetc ();
+ if (c != '\'')
+ skipToCharacter ('\n');
+
+ return result;
+}
+
+static void parseString (vString *const string)
+{
+ boolean verbatim = FALSE;
+ boolean align = FALSE;
+ boolean end = FALSE;
+ vString *verbatimCloser = vStringNew ();
+ vString *lastLine = vStringNew ();
+ int prev = '\0';
+ int c;
+
+ while (! end)
+ {
+ c = fileGetc ();
+ if (c == EOF)
+ end = TRUE;
+ else if (c == '"')
+ {
+ if (! verbatim)
+ end = TRUE;
+ else
+ end = (boolean) (strcmp (vStringValue (lastLine),
+ vStringValue (verbatimCloser)) == 0);
+ }
+ else if (c == '\n')
+ {
+ if (verbatim)
+ vStringClear (lastLine);
+ if (prev == '[' /* || prev == '{' */)
+ {
+ verbatim = TRUE;
+ vStringClear (verbatimCloser);
+ vStringClear (lastLine);
+ if (prev == '{')
+ vStringPut (verbatimCloser, '}');
+ else
+ {
+ vStringPut (verbatimCloser, ']');
+ align = TRUE;
+ }
+ vStringNCat (verbatimCloser, string, vStringLength (string) - 1);
+ vStringClear (string);
+ }
+ if (verbatim && align)
+ {
+ do
+ c = fileGetc ();
+ while (isspace (c));
+ }
+ }
+ else if (c == '%')
+ c = parseEscapedCharacter ();
+ if (! end)
+ {
+ vStringPut (string, c);
+ if (verbatim)
+ {
+ vStringPut (lastLine, c);
+ vStringTerminate (lastLine);
+ }
+ prev = c;
+ }
+ }
+ vStringTerminate (string);
+ vStringDelete (lastLine);
+ vStringDelete (verbatimCloser);
+}
+
+/* Read a C identifier beginning with "firstChar" and places it into "name".
+ */
+static void parseIdentifier (vString *const string, const int firstChar)
+{
+ int c = firstChar;
+
+ do
+ {
+ vStringPut (string, c);
+ c = fileGetc ();
+ } while (isident (c));
+
+ vStringTerminate (string);
+ if (!isspace (c))
+ fileUngetc (c); /* unget non-identifier character */
+}
+
+static void parseFreeOperator (vString *const string, const int firstChar)
+{
+ int c = firstChar;
+
+ do
+ {
+ vStringPut (string, c);
+ c = fileGetc ();
+ } while (c > ' ');
+
+ vStringTerminate (string);
+ if (!isspace (c))
+ fileUngetc (c); /* unget non-identifier character */
+}
+
+static void copyToken (tokenInfo* dst, const tokenInfo *src)
+{
+ dst->type = src->type;
+ dst->keyword = src->keyword;
+ dst->isExported = src->isExported;
+
+ vStringCopy (dst->string, src->string);
+ vStringCopy (dst->className, src->className);
+ vStringCopy (dst->featureName, src->featureName);
+}
+
+static tokenInfo *newToken (void)
+{
+ tokenInfo *const token = xMalloc (1, tokenInfo);
+
+ token->type = TOKEN_UNDEFINED;
+ token->keyword = KEYWORD_NONE;
+ token->isExported = TRUE;
+
+ token->string = vStringNew ();
+ token->className = vStringNew ();
+ token->featureName = vStringNew ();
+
+ return token;
+}
+
+static void deleteToken (tokenInfo *const token)
+{
+ vStringDelete (token->string);
+ vStringDelete (token->className);
+ vStringDelete (token->featureName);
+
+ eFree (token);
+}
+
+static void readToken (tokenInfo *const token)
+{
+ int c;
+
+ token->type = TOKEN_UNDEFINED;
+ token->keyword = KEYWORD_NONE;
+ vStringClear (token->string);
+
+getNextChar:
+
+ do
+ c = fileGetc ();
+ while (c == '\t' || c == ' ' || c == '\n');
+
+ switch (c)
+ {
+ case EOF: longjmp (Exception, (int)ExceptionEOF); break;
+ case ';': token->type = TOKEN_SEMICOLON; break;
+ case '!': token->type = TOKEN_BANG; break;
+ case '}': token->type = TOKEN_CLOSE_BRACE; break;
+ case ']': token->type = TOKEN_CLOSE_BRACKET; break;
+ case ')': token->type = TOKEN_CLOSE_PAREN; break;
+ case ',': token->type = TOKEN_COMMA; break;
+ case '$': token->type = TOKEN_DOLLAR; break;
+ case '.': token->type = TOKEN_DOT; break;
+ case '{': token->type = TOKEN_OPEN_BRACE; break;
+ case '[': token->type = TOKEN_OPEN_BRACKET; break;
+ case '(': token->type = TOKEN_OPEN_PAREN; break;
+ case '~': token->type = TOKEN_TILDE; break;
+
+
+ case '+':
+ case '*':
+ case '^':
+ case '=': token->type = TOKEN_OPERATOR; break;
+
+ case '-':
+ c = fileGetc ();
+ if (c == '>')
+ token->type = TOKEN_CONSTRAINT;
+ else if (c == '-') /* is this the start of a comment? */
+ {
+ skipToCharacter ('\n');
+ goto getNextChar;
+ }
+ else
+ {
+ if (!isspace (c))
+ fileUngetc (c);
+ token->type = TOKEN_OPERATOR;
+ }
+ break;
+
+ case '?':
+ case ':':
+ {
+ int c2 = fileGetc ();
+ if (c2 == '=')
+ token->type = TOKEN_OPERATOR;
+ else
+ {
+ if (!isspace (c2))
+ fileUngetc (c2);
+ if (c == ':')
+ token->type = TOKEN_COLON;
+ else
+ token->type = TOKEN_QUESTION;
+ }
+ break;
+ }
+
+ case '<':
+ c = fileGetc ();
+ if (c != '=' && c != '>' && !isspace (c))
+ fileUngetc (c);
+ token->type = TOKEN_OPERATOR;
+ break;
+
+ case '>':
+ c = fileGetc ();
+ if (c != '=' && c != '>' && !isspace (c))
+ fileUngetc (c);
+ token->type = TOKEN_OPERATOR;
+ break;
+
+ case '/':
+ c = fileGetc ();
+ if (c != '/' && c != '=' && !isspace (c))
+ fileUngetc (c);
+ token->type = TOKEN_OPERATOR;
+ break;
+
+ case '\\':
+ c = fileGetc ();
+ if (c != '\\' && !isspace (c))
+ fileUngetc (c);
+ token->type = TOKEN_OPERATOR;
+ break;
+
+ case '"':
+ token->type = TOKEN_STRING;
+ parseString (token->string);
+ break;
+
+ case '\'':
+ token->type = TOKEN_CHARACTER;
+ parseCharacter ();
+ break;
+
+ default:
+ if (isalpha (c))
+ {
+ parseIdentifier (token->string, c);
+ token->keyword = analyzeToken (token->string, Lang_eiffel);
+ if (isKeyword (token, KEYWORD_NONE))
+ token->type = TOKEN_IDENTIFIER;
+ else
+ token->type = TOKEN_KEYWORD;
+ }
+ else if (isdigit (c))
+ {
+ vString* numeric = parseNumeric (c);
+ vStringCat (token->string, numeric);
+ vStringDelete (numeric);
+ token->type = TOKEN_NUMERIC;
+ }
+ else if (isFreeOperatorChar (c))
+ {
+ parseFreeOperator (token->string, c);
+ token->type = TOKEN_OPERATOR;
+ }
+ else
+ {
+ token->type = TOKEN_UNDEFINED;
+ Assert (! isType (token, TOKEN_UNDEFINED));
+ }
+ break;
+ }
+}
+
+/*
+* Scanning functions
+*/
+
+static boolean isIdentifierMatch (
+ const tokenInfo *const token, const char *const name)
+{
+ return (boolean) (isType (token, TOKEN_IDENTIFIER) &&
+ strcasecmp (vStringValue (token->string), name) == 0);
+}
+
+static void findToken (tokenInfo *const token, const tokenType type)
+{
+ while (! isType (token, type))
+ readToken (token);
+}
+
+static void findKeyword (tokenInfo *const token, const keywordId keyword)
+{
+ while (! isKeyword (token, keyword))
+ readToken (token);
+}
+
+static boolean parseType (tokenInfo *const token);
+
+static void parseGeneric (tokenInfo *const token, boolean declaration)
+{
+ unsigned int depth = 0;
+#ifdef TYPE_REFERENCE_TOOL
+ boolean constraint = FALSE;
+#endif
+ Assert (isType (token, TOKEN_OPEN_BRACKET));
+ do
+ {
+ if (isType (token, TOKEN_OPEN_BRACKET))
+ {
+ ++depth;
+ readToken (token);
+ }
+ else if (isType (token, TOKEN_CLOSE_BRACKET))
+ {
+ --depth;
+ readToken (token);
+ }
+#ifdef TYPE_REFERENCE_TOOL
+ else if (declaration)
+ {
+ boolean advanced = FALSE;
+ if (depth == 1)
+ {
+ if (isType (token, TOKEN_CONSTRAINT))
+ constraint = TRUE;
+ else if (isKeyword (token, KEYWORD_create))
+ findKeyword (token, KEYWORD_end);
+ else if (isType (token, TOKEN_IDENTIFIER))
+ {
+ if (constraint)
+ advanced = parseType (token);
+ else
+ addGenericName (token);
+ constraint = FALSE;
+ }
+ }
+ else if (isType (token, TOKEN_IDENTIFIER))
+ advanced = parseType (token);
+ if (! advanced)
+ readToken (token);
+ }
+#endif
+ else
+ parseType (token);
+ } while (depth > 0);
+}
+
+static boolean parseType (tokenInfo *const token)
+{
+ tokenInfo* const id = newToken ();
+ copyToken (id, token);
+ readToken (token);
+ if (isType (token, TOKEN_COLON)) /* check for "{entity: TYPE}" */
+ {
+ readToken (id);
+ readToken (token);
+ }
+ if (isKeyword (id, KEYWORD_like))
+ {
+ if (isType (token, TOKEN_IDENTIFIER) ||
+ isKeyword (token, KEYWORD_Current))
+ readToken (token);
+ }
+ else
+ {
+ if (isKeyword (id, KEYWORD_expanded))
+ {
+ copyToken (id, token);
+ readToken (token);
+ }
+ if (isType (id, TOKEN_IDENTIFIER))
+ {
+#ifdef TYPE_REFERENCE_TOOL
+ reportType (id);
+#endif
+ if (isType (token, TOKEN_OPEN_BRACKET))
+ parseGeneric (token, FALSE);
+ else if ((strcmp ("BIT", vStringValue (id->string)) == 0))
+ readToken (token); /* read token after number of bits */
+ }
+ }
+ deleteToken (id);
+ return TRUE;
+}
+
+static void parseEntityType (tokenInfo *const token)
+{
+ Assert (isType (token, TOKEN_COLON));
+ readToken (token);
+
+ if (isType (token, TOKEN_BANG) || isType (token, TOKEN_QUESTION))
+ readToken (token); /* skip over '!' or '?' */
+ parseType (token);
+}
+
+static void parseLocal (tokenInfo *const token)
+{
+ Assert (isKeyword (token, KEYWORD_local));
+ readToken (token);
+
+ /* Check keyword first in case local clause is empty
+ */
+ while (! isKeyword (token, KEYWORD_do) &&
+ ! isKeyword (token, KEYWORD_once))
+ {
+#ifndef TYPE_REFERENCE_TOOL
+ if (isType (token, TOKEN_IDENTIFIER))
+ makeEiffelLocalTag (token);
+#endif
+ readToken (token);
+ if (isType (token, TOKEN_COLON))
+ parseEntityType (token);
+ }
+}
+
+static void findFeatureEnd (tokenInfo *const token)
+{
+ boolean isFound = isKeyword (token, KEYWORD_is);
+ if (isFound)
+ readToken (token);
+ switch (token->keyword)
+ {
+ case KEYWORD_deferred:
+ case KEYWORD_do:
+ case KEYWORD_external:
+ case KEYWORD_local:
+ case KEYWORD_obsolete:
+ case KEYWORD_once:
+ case KEYWORD_require:
+ {
+ int depth = 1;
+
+ while (depth > 0)
+ {
+#ifdef TYPE_REFERENCE_TOOL
+ if (isType (token, TOKEN_OPEN_BRACE))
+ {
+ readToken (token);
+ if (isType (token, TOKEN_IDENTIFIER))
+ parseType (token);
+ }
+ else if (isType (token, TOKEN_BANG))
+ {
+ readToken (token);
+ if (isType (token, TOKEN_IDENTIFIER))
+ parseType (token);
+ if (isType (token, TOKEN_BANG))
+ readToken (token);
+ }
+ else
+#endif
+ switch (token->keyword)
+ {
+ case KEYWORD_check:
+ case KEYWORD_debug:
+ case KEYWORD_from:
+ case KEYWORD_if:
+ case KEYWORD_inspect:
+ ++depth;
+ break;
+
+ case KEYWORD_local:
+ parseLocal (token);
+ break;
+
+ case KEYWORD_end:
+ --depth;
+ break;
+
+ default:
+ break;
+ }
+ readToken (token);
+ }
+ break;
+ }
+
+ default:
+ /* is this a manifest constant? */
+ if (isFound || isType (token, TOKEN_OPERATOR)) {
+ if (isType (token, TOKEN_OPERATOR))
+ readToken (token);
+ readToken (token);
+ }
+ break;
+ }
+}
+
+static boolean readFeatureName (tokenInfo *const token)
+{
+ boolean isFeatureName = FALSE;
+
+ if (isKeyword (token, KEYWORD_frozen))
+ readToken (token);
+ if (isType (token, TOKEN_IDENTIFIER))
+ isFeatureName = TRUE;
+ else if (isKeyword (token, KEYWORD_assign)) /* legacy code */
+ isFeatureName = TRUE;
+ else if (isKeyword (token, KEYWORD_infix) ||
+ isKeyword (token, KEYWORD_prefix))
+ {
+ readToken (token);
+ if (isType (token, TOKEN_STRING))
+ isFeatureName = TRUE;
+ }
+ return isFeatureName;
+}
+
+static void parseArguments (tokenInfo *const token)
+{
+#ifndef TYPE_REFERENCE_TOOL
+ findToken (token, TOKEN_CLOSE_PAREN);
+ readToken (token);
+#else
+ Assert (isType (token, TOKEN_OPEN_PAREN));
+ readToken (token);
+ do
+ {
+ if (isType (token, TOKEN_COLON))
+ parseEntityType (token);
+ else
+ readToken (token);
+ } while (! isType (token, TOKEN_CLOSE_PAREN));
+ readToken (token);
+#endif
+}
+
+static boolean parseFeature (tokenInfo *const token)
+{
+ boolean found = FALSE;
+ while (readFeatureName (token))
+ {
+ found = TRUE;
+#ifndef TYPE_REFERENCE_TOOL
+ makeEiffelFeatureTag (token);
+#endif
+ readToken (token);
+ if (isType (token, TOKEN_COMMA))
+ readToken (token);
+ }
+ if (found)
+ {
+ if (isKeyword (token, KEYWORD_alias)) {
+ readToken (token);
+#ifndef TYPE_REFERENCE_TOOL
+ if (isType (token, TOKEN_STRING))
+ makeEiffelFeatureTag (token);
+#endif
+ readToken (token);
+ }
+ if (isType (token, TOKEN_OPEN_PAREN)) /* arguments? */
+ parseArguments (token);
+ if (isType (token, TOKEN_COLON)) /* a query? */
+ parseEntityType (token);
+ if (isKeyword (token, KEYWORD_assign))
+ {
+ readToken (token);
+ readToken (token);
+ }
+ if (isKeyword (token, KEYWORD_obsolete))
+ {
+ readToken (token);
+ if (isType (token, TOKEN_STRING))
+ readToken (token);
+ }
+ findFeatureEnd (token);
+ }
+ return found;
+}
+
+static void parseExport (tokenInfo *const token)
+{
+ token->isExported = TRUE;
+ readToken (token);
+ if (isType (token, TOKEN_OPEN_BRACE))
+ {
+ token->isExported = FALSE;
+ while (! isType (token, TOKEN_CLOSE_BRACE))
+ {
+ if (isType (token, TOKEN_IDENTIFIER))
+ token->isExported |= !isIdentifierMatch (token, "NONE");
+ readToken (token);
+ }
+ readToken (token);
+ }
+}
+
+static void parseFeatureClauses (tokenInfo *const token)
+{
+ Assert (isKeyword (token, KEYWORD_feature));
+ do
+ {
+ if (isKeyword (token, KEYWORD_feature))
+ parseExport (token);
+ if (! isKeyword (token, KEYWORD_feature) &&
+ ! isKeyword (token, KEYWORD_invariant) &&
+ ! isKeyword (token, KEYWORD_indexing))
+ {
+ if (! parseFeature (token))
+ readToken (token);
+ }
+ } while (! isKeyword (token, KEYWORD_end) &&
+ ! isKeyword (token, KEYWORD_invariant) &&
+ ! isKeyword (token, KEYWORD_indexing));
+}
+
+static void parseRename (tokenInfo *const token)
+{
+ Assert (isKeyword (token, KEYWORD_rename));
+ do {
+ readToken (token);
+ if (readFeatureName (token))
+ {
+ readToken (token);
+ if (isKeyword (token, KEYWORD_as))
+ {
+ readToken (token);
+ if (readFeatureName (token))
+ {
+#ifndef TYPE_REFERENCE_TOOL
+ makeEiffelFeatureTag (token); /* renamed feature */
+#endif
+ readToken (token);
+ }
+ }
+ }
+ } while (isType (token, TOKEN_COMMA));
+}
+
+static void parseInherit (tokenInfo *const token)
+{
+ Assert (isKeyword (token, KEYWORD_inherit));
+ readToken (token);
+ while (isType (token, TOKEN_IDENTIFIER))
+ {
+ parseType (token);
+ if (isType (token, TOKEN_KEYWORD))
+ {
+ switch (token->keyword) /* check for feature adaptation */
+ {
+ case KEYWORD_rename:
+ parseRename (token);
+ case KEYWORD_export:
+ case KEYWORD_undefine:
+ case KEYWORD_redefine:
+ case KEYWORD_select:
+ findKeyword (token, KEYWORD_end);
+ readToken (token);
+ break;
+
+ case KEYWORD_end:
+ readToken (token);
+ break;
+
+ default: break;
+ }
+ }
+ if (isType (token, TOKEN_SEMICOLON))
+ readToken (token);
+ }
+}
+
+static void parseConvert (tokenInfo *const token)
+{
+ Assert (isKeyword (token, KEYWORD_convert));
+ do
+ {
+ readToken (token);
+ if (! isType (token, TOKEN_IDENTIFIER))
+ break;
+ else if (isType (token, TOKEN_OPEN_PAREN))
+ {
+ while (! isType (token, TOKEN_CLOSE_PAREN))
+ readToken (token);
+ }
+ else if (isType (token, TOKEN_COLON))
+ {
+ readToken (token);
+ if (! isType (token, TOKEN_OPEN_BRACE))
+ break;
+ else while (! isType (token, TOKEN_CLOSE_BRACE))
+ readToken (token);
+ }
+ } while (isType (token, TOKEN_COMMA));
+}
+
+static void parseClass (tokenInfo *const token)
+{
+ Assert (isKeyword (token, KEYWORD_class));
+ readToken (token);
+ if (isType (token, TOKEN_IDENTIFIER))
+ {
+#ifndef TYPE_REFERENCE_TOOL
+ makeEiffelClassTag (token);
+ readToken (token);
+#else
+ vStringCopy (token->className, token->string);
+ vStringUpper (token->className);
+ if (PrintClass)
+ puts (vStringValue (token->className));
+ if (! PrintReferences)
+ exit (0);
+ readToken (token);
+#endif
+ }
+
+ do
+ {
+ if (isType (token, TOKEN_OPEN_BRACKET))
+ parseGeneric (token, TRUE);
+ else if (! isType (token, TOKEN_KEYWORD))
+ readToken (token);
+ else switch (token->keyword)
+ {
+ case KEYWORD_inherit: parseInherit (token); break;
+ case KEYWORD_feature: parseFeatureClauses (token); break;
+ case KEYWORD_convert: parseConvert (token); break;
+ default: readToken (token); break;
+ }
+ } while (! isKeyword (token, KEYWORD_end));
+}
+
+static void initialize (const langType language)
+{
+ Lang_eiffel = language;
+ buildEiffelKeywordHash ();
+}
+
+static void findEiffelTags (void)
+{
+ tokenInfo *const token = newToken ();
+ exception_t exception;
+
+ exception = (exception_t) (setjmp (Exception));
+ while (exception == ExceptionNone)
+ {
+ findKeyword (token, KEYWORD_class);
+ parseClass (token);
+ }
+ deleteToken (token);
+}
+
+#ifndef TYPE_REFERENCE_TOOL
+
+extern parserDefinition* EiffelParser (void)
+{
+ static const char *const extensions [] = { "e", NULL };
+ parserDefinition* def = parserNew ("Eiffel");
+ def->kinds = EiffelKinds;
+ def->kindCount = KIND_COUNT (EiffelKinds);
+ def->extensions = extensions;
+ def->parser = findEiffelTags;
+ def->initialize = initialize;
+ return def;
+}
+
+#else
+
+static void findReferences (void)
+{
+ ReferencedTypes = stringListNew ();
+ GenericNames = stringListNew ();
+ initialize (0);
+
+ findEiffelTags ();
+
+ stringListDelete (GenericNames);
+ GenericNames = NULL;
+ stringListDelete (ReferencedTypes);
+ ReferencedTypes = NULL;
+}
+
+static const char *const Usage =
+ "Prints names of types referenced by an Eiffel language file.\n"
+ "\n"
+ "Usage: %s [-cdrs] [file_name | -]\n"
+ "\n"
+ "Options:\n"
+ " -c Print class name of current file (on first line of output).\n"
+ " -d Enable debug output.\n"
+ " -r Print types referenced by current file (default unless -c).\n"
+ " -s Include self-references.\n"
+ "\n";
+
+extern int main (int argc, char** argv)
+{
+ int i;
+ for (i = 1 ; argv [i] != NULL ; ++i)
+ {
+ const char *const arg = argv [i];
+ if (arg [0] == '-')
+ {
+ int j;
+ if (arg [1] == '\0')
+ {
+ File = stdin;
+ FileName = "stdin";
+ }
+ else for (j = 1 ; arg [j] != '\0' ; ++j) switch (arg [j])
+ {
+ case 'c': PrintClass = 1; break;
+ case 'r': PrintReferences = 1; break;
+ case 's': SelfReferences = 1; break;
+ case 'd': Debug = 1; break;
+ default:
+ fprintf (errout, "%s: unknown option: %c\n", argv [0], arg [1]);
+ fprintf (errout, Usage, argv [0]);
+ exit (1);
+ break;
+ }
+ }
+ else if (File != NULL)
+ {
+ fprintf (errout, Usage, argv [0]);
+ exit (1);
+ }
+ else
+ {
+ FileName = arg;
+ File = fopen (FileName, "r");
+ if (File == NULL)
+ {
+ perror (argv [0]);
+ exit (1);
+ }
+ }
+ }
+ if (! PrintClass)
+ PrintReferences = 1;
+ if (File == NULL)
+ {
+ fprintf (errout, Usage, argv [0]);
+ exit (1);
+ }
+ else
+ {
+ findReferences ();
+ fclose (File);
+ }
+ return 0;
+}
+
+#endif
+
+/* vi:set tabstop=4 shiftwidth=4: */
Index: create-5.8-unused-attribute-patch/ctags-5.8-new/general.h
===================================================================
--- create-5.8-unused-attribute-patch/ctags-5.8-new/general.h (nonexistent)
+++ create-5.8-unused-attribute-patch/ctags-5.8-new/general.h (revision 5)
@@ -0,0 +1,125 @@
+/*
+* $Id: general.h 508 2007-05-03 03:20:59Z dhiebert $
+*
+* Copyright (c) 1998-2003, Darren Hiebert
+*
+* This source code is released for free distribution under the terms of the
+* GNU General Public License.
+*
+* Provides the general (non-ctags-specific) environment assumed by all.
+*/
+#ifndef _GENERAL_H
+#define _GENERAL_H
+
+/*
+* INCLUDE FILES
+*/
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#elif defined (AMIGA)
+# include "e_amiga.h"
+#elif defined (DJGPP)
+# include "e_djgpp.h"
+#elif defined (macintosh)
+# include "e_mac.h"
+#elif defined (MSDOS) || defined (WIN32)
+# include "e_msoft.h"
+#elif defined (OS2)
+# include "e_os2.h"
+#elif defined (QDOS)
+# include "e_qdos.h"
+#elif defined (RISCOS)
+# include "e_riscos.h"
+#elif defined (__vms) || defined (VMS)
+# include "e_vms.h"
+# ifndef VMS
+# define VMS 1
+# endif
+#endif
+
+
+/*
+* MACROS
+*/
+
+/* Define standard error destination
+ */
+#ifndef errout
+# define errout stderr
+#endif
+
+/* Define regex if supported */
+#if (defined (HAVE_REGCOMP) && !defined (REGCOMP_BROKEN))
+# define HAVE_REGEX 1
+#endif
+
+/* This is a helpful internal feature of later versions (> 2.7) of GCC
+ * to prevent warnings about unused variables.
+ */
+#if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)) && !defined (__GNUG__)
+# define __printf__(s,f) __attribute__((format (printf, s, f)))
+#else
+# define __printf__(s,f)
+#endif
+
+/*
+ * Portability macros
+ */
+#if !defined(HAVE_STRCASECMP) && !defined(strcasecmp)
+# ifdef HAVE_STRICMP
+# define strcasecmp(s1,s2) stricmp(s1,s2)
+# else
+# define strcasecmp(s1,s2) struppercmp(s1,s2)
+# endif
+#endif
+
+#if !defined(HAVE_STRNCASECMP) && !defined(strncasecmp)
+# ifdef HAVE_STRNICMP
+# define strncasecmp(s1,s2,n) strnicmp(s1,s2,n)
+# else
+# define strncasecmp(s1,s2,n) strnuppercmp(s1,s2,n)
+# endif
+#endif
+
+/*
+* DATA DECLARATIONS
+*/
+
+#undef FALSE
+#undef TRUE
+#ifdef VAXC
+typedef enum { FALSE, TRUE } booleanType;
+typedef int boolean;
+#else
+# ifdef __cplusplus
+typedef bool boolean;
+#define FALSE false
+#define TRUE true
+# else
+typedef enum { FALSE, TRUE } boolean;
+# endif
+#endif
+
+#if ! defined (HAVE_FGETPOS) && ! defined (fpos_t)
+# define fpos_t long
+#endif
+
+/*
+* FUNCTION PROTOTYPES
+*/
+
+#if defined (NEED_PROTO_REMOVE) && defined (HAVE_REMOVE)
+extern int remove (const char *);
+#endif
+
+#if defined (NEED_PROTO_UNLINK) && ! defined (HAVE_REMOVE)
+extern void *unlink (const char *);
+#endif
+
+#ifdef NEED_PROTO_GETENV
+extern char *getenv (const char *);
+#endif
+
+#endif /* _GENERAL_H */
+
+/* vi:set tabstop=4 shiftwidth=4: */
Index: create-5.8-unused-attribute-patch/ctags-5.8-new/lregex.c
===================================================================
--- create-5.8-unused-attribute-patch/ctags-5.8-new/lregex.c (nonexistent)
+++ create-5.8-unused-attribute-patch/ctags-5.8-new/lregex.c (revision 5)
@@ -0,0 +1,704 @@
+/*
+* $Id: lregex.c 576 2007-06-30 04:16:23Z elliotth $
+*
+* Copyright (c) 2000-2003, Darren Hiebert
+*
+* This source code is released for free distribution under the terms of the
+* GNU General Public License.
+*
+* This module contains functions for applying regular expression matching.
+*
+* The code for utlizing the Gnu regex package with regards to processing the
+* regex option and checking for regex matches was adapted from routines in
+* Gnu etags.
+*/
+
+/*
+* INCLUDE FILES
+*/
+#include "general.h" /* must always come first */
+
+#include <string.h>
+
+#ifdef HAVE_REGCOMP
+# include <ctype.h>
+# include <stddef.h>
+# ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h> /* declare off_t (not known to regex.h on FreeBSD) */
+# endif
+# include <regex.h>
+#endif
+
+#include "debug.h"
+#include "entry.h"
+#include "parse.h"
+#include "read.h"
+#include "routines.h"
+
+#ifdef HAVE_REGEX
+
+/*
+* MACROS
+*/
+
+/* Back-references \0 through \9 */
+#define BACK_REFERENCE_COUNT 10
+
+#if defined (HAVE_REGCOMP) && !defined (REGCOMP_BROKEN)
+# define POSIX_REGEX
+#endif
+
+#define REGEX_NAME "Regex"
+
+/*
+* DATA DECLARATIONS
+*/
+#if defined (POSIX_REGEX)
+
+struct sKind {
+ boolean enabled;
+ char letter;
+ char* name;
+ char* description;
+};
+
+enum pType { PTRN_TAG, PTRN_CALLBACK };
+
+typedef struct {
+ regex_t *pattern;
+ enum pType type;
+ union {
+ struct {
+ char *name_pattern;
+ struct sKind kind;
+ } tag;
+ struct {
+ regexCallback function;
+ } callback;
+ } u;
+} regexPattern;
+
+#endif
+
+typedef struct {
+ regexPattern *patterns;
+ unsigned int count;
+} patternSet;
+
+/*
+* DATA DEFINITIONS
+*/
+
+static boolean regexBroken = FALSE;
+
+/* Array of pattern sets, indexed by language */
+static patternSet* Sets = NULL;
+static int SetUpper = -1; /* upper language index in list */
+
+/*
+* FUNCTION DEFINITIONS
+*/
+
+static void clearPatternSet (const langType language)
+{
+ if (language <= SetUpper)
+ {
+ patternSet* const set = Sets + language;
+ unsigned int i;
+ for (i = 0 ; i < set->count ; ++i)
+ {
+ regexPattern *p = &set->patterns [i];
+#if defined (POSIX_REGEX)
+ regfree (p->pattern);
+#endif
+ eFree (p->pattern);
+ p->pattern = NULL;
+
+ if (p->type == PTRN_TAG)
+ {
+ eFree (p->u.tag.name_pattern);
+ p->u.tag.name_pattern = NULL;
+ eFree (p->u.tag.kind.name);
+ p->u.tag.kind.name = NULL;
+ if (p->u.tag.kind.description != NULL)
+ {
+ eFree (p->u.tag.kind.description);
+ p->u.tag.kind.description = NULL;
+ }
+ }
+ }
+ if (set->patterns != NULL)
+ eFree (set->patterns);
+ set->patterns = NULL;
+ set->count = 0;
+ }
+}
+
+/*
+* Regex psuedo-parser
+*/
+
+static void makeRegexTag (
+ const vString* const name, const struct sKind* const kind)
+{
+ if (kind->enabled)
+ {
+ tagEntryInfo e;
+ Assert (name != NULL && vStringLength (name) > 0);
+ Assert (kind != NULL);
+ initTagEntry (&e, vStringValue (name));
+ e.kind = kind->letter;
+ e.kindName = kind->name;
+ makeTagEntry (&e);
+ }
+}
+
+/*
+* Regex pattern definition
+*/
+
+/* Take a string like "/blah/" and turn it into "blah", making sure
+ * that the first and last characters are the same, and handling
+ * quoted separator characters. Actually, stops on the occurrence of
+ * an unquoted separator. Also turns "\t" into a Tab character.
+ * Returns pointer to terminating separator. Works in place. Null
+ * terminates name string.
+ */
+static char* scanSeparators (char* name)
+{
+ char sep = name [0];
+ char *copyto = name;
+ boolean quoted = FALSE;
+
+ for (++name ; *name != '\0' ; ++name)
+ {
+ if (quoted)
+ {
+ if (*name == sep)
+ *copyto++ = sep;
+ else if (*name == 't')
+ *copyto++ = '\t';
+ else
+ {
+ /* Something else is quoted, so preserve the quote. */
+ *copyto++ = '\\';
+ *copyto++ = *name;
+ }
+ quoted = FALSE;
+ }
+ else if (*name == '\\')
+ quoted = TRUE;
+ else if (*name == sep)
+ {
+ break;
+ }
+ else
+ *copyto++ = *name;
+ }
+ *copyto = '\0';
+ return name;
+}
+
+/* Parse `regexp', in form "/regex/name/[k,Kind/]flags" (where the separator
+ * character is whatever the first character of `regexp' is), by breaking it
+ * up into null terminated strings, removing the separators, and expanding
+ * '\t' into tabs. When complete, `regexp' points to the line matching
+ * pattern, a pointer to the name matching pattern is written to `name', a
+ * pointer to the kinds is written to `kinds' (possibly NULL), and a pointer
+ * to the trailing flags is written to `flags'. If the pattern is not in the
+ * correct format, a false value is returned.
+ */
+static boolean parseTagRegex (
+ char* const regexp, char** const name,
+ char** const kinds, char** const flags)
+{
+ boolean result = FALSE;
+ const int separator = (unsigned char) regexp [0];
+
+ *name = scanSeparators (regexp);
+ if (*regexp == '\0')
+ error (WARNING, "empty regexp");
+ else if (**name != separator)
+ error (WARNING, "%s: incomplete regexp", regexp);
+ else
+ {
+ char* const third = scanSeparators (*name);
+ if (**name == '\0')
+ error (WARNING, "%s: regexp missing name pattern", regexp);
+ if ((*name) [strlen (*name) - 1] == '\\')
+ error (WARNING, "error in name pattern: \"%s\"", *name);
+ if (*third != separator)
+ error (WARNING, "%s: regexp missing final separator", regexp);
+ else
+ {
+ char* const fourth = scanSeparators (third);
+ if (*fourth == separator)
+ {
+ *kinds = third;
+ scanSeparators (fourth);
+ *flags = fourth;
+ }
+ else
+ {
+ *flags = third;
+ *kinds = NULL;
+ }
+ result = TRUE;
+ }
+ }
+ return result;
+}
+
+static void addCompiledTagPattern (
+ const langType language, regex_t* const pattern,
+ char* const name, const char kind, char* const kindName,
+ char *const description)
+{
+ patternSet* set;
+ regexPattern *ptrn;
+ if (language > SetUpper)
+ {
+ int i;
+ Sets = xRealloc (Sets, (language + 1), patternSet);
+ for (i = SetUpper + 1 ; i <= language ; ++i)
+ {
+ Sets [i].patterns = NULL;
+ Sets [i].count = 0;
+ }
+ SetUpper = language;
+ }
+ set = Sets + language;
+ set->patterns = xRealloc (set->patterns, (set->count + 1), regexPattern);
+ ptrn = &set->patterns [set->count];
+ set->count += 1;
+
+ ptrn->pattern = pattern;
+ ptrn->type = PTRN_TAG;
+ ptrn->u.tag.name_pattern = name;
+ ptrn->u.tag.kind.enabled = TRUE;
+ ptrn->u.tag.kind.letter = kind;
+ ptrn->u.tag.kind.name = kindName;
+ ptrn->u.tag.kind.description = description;
+}
+
+static void addCompiledCallbackPattern (
+ const langType language, regex_t* const pattern,
+ const regexCallback callback)
+{
+ patternSet* set;
+ regexPattern *ptrn;
+ if (language > SetUpper)
+ {
+ int i;
+ Sets = xRealloc (Sets, (language + 1), patternSet);
+ for (i = SetUpper + 1 ; i <= language ; ++i)
+ {
+ Sets [i].patterns = NULL;
+ Sets [i].count = 0;
+ }
+ SetUpper = language;
+ }
+ set = Sets + language;
+ set->patterns = xRealloc (set->patterns, (set->count + 1), regexPattern);
+ ptrn = &set->patterns [set->count];
+ set->count += 1;
+
+ ptrn->pattern = pattern;
+ ptrn->type = PTRN_CALLBACK;
+ ptrn->u.callback.function = callback;
+}
+
+#if defined (POSIX_REGEX)
+
+static regex_t* compileRegex (const char* const regexp, const char* const flags)
+{
+ int cflags = REG_EXTENDED | REG_NEWLINE;
+ regex_t *result = NULL;
+ int errcode;
+ int i;
+ for (i = 0 ; flags != NULL && flags [i] != '\0' ; ++i)
+ {
+ switch ((int) flags [i])
+ {
+ case 'b': cflags &= ~REG_EXTENDED; break;
+ case 'e': cflags |= REG_EXTENDED; break;
+ case 'i': cflags |= REG_ICASE; break;
+ default: error (WARNING, "unknown regex flag: '%c'", *flags); break;
+ }
+ }
+ result = xMalloc (1, regex_t);
+ errcode = regcomp (result, regexp, cflags);
+ if (errcode != 0)
+ {
+ char errmsg[256];
+ regerror (errcode, result, errmsg, 256);
+ error (WARNING, "regcomp %s: %s", regexp, errmsg);
+ regfree (result);
+ eFree (result);
+ result = NULL;
+ }
+ return result;
+}
+
+#endif
+
+static void parseKinds (
+ const char* const kinds, char* const kind, char** const kindName,
+ char **description)
+{
+ *kind = '\0';
+ *kindName = NULL;
+ *description = NULL;
+ if (kinds == NULL || kinds [0] == '\0')
+ {
+ *kind = 'r';
+ *kindName = eStrdup ("regex");
+ }
+ else if (kinds [0] != '\0')
+ {
+ const char* k = kinds;
+ if (k [0] != ',' && (k [1] == ',' || k [1] == '\0'))
+ *kind = *k++;
+ else
+ *kind = 'r';
+ if (*k == ',')
+ ++k;
+ if (k [0] == '\0')
+ *kindName = eStrdup ("regex");
+ else
+ {
+ const char *const comma = strchr (k, ',');
+ if (comma == NULL)
+ *kindName = eStrdup (k);
+ else
+ {
+ *kindName = (char*) eMalloc (comma - k + 1);
+ strncpy (*kindName, k, comma - k);
+ (*kindName) [comma - k] = '\0';
+ k = comma + 1;
+ if (k [0] != '\0')
+ *description = eStrdup (k);
+ }
+ }
+ }
+}
+
+static void printRegexKind (const regexPattern *pat, unsigned int i, boolean indent)
+{
+ const struct sKind *const kind = &pat [i].u.tag.kind;
+ const char *const indentation = indent ? " " : "";
+ Assert (pat [i].type == PTRN_TAG);
+ printf ("%s%c %s %s\n", indentation,
+ kind->letter != '\0' ? kind->letter : '?',
+ kind->description != NULL ? kind->description : kind->name,
+ kind->enabled ? "" : " [off]");
+}
+
+static void processLanguageRegex (const langType language,
+ const char* const parameter)
+{
+ if (parameter == NULL || parameter [0] == '\0')
+ clearPatternSet (language);
+ else if (parameter [0] != '@')
+ addLanguageRegex (language, parameter);
+ else if (! doesFileExist (parameter + 1))
+ error (WARNING, "cannot open regex file");
+ else
+ {
+ const char* regexfile = parameter + 1;
+ FILE* const fp = fopen (regexfile, "r");
+ if (fp == NULL)
+ error (WARNING | PERROR, regexfile);
+ else
+ {
+ vString* const regex = vStringNew ();
+ while (readLine (regex, fp))
+ addLanguageRegex (language, vStringValue (regex));
+ fclose (fp);
+ vStringDelete (regex);
+ }
+ }
+}
+
+/*
+* Regex pattern matching
+*/
+
+#if defined (POSIX_REGEX)
+
+static vString* substitute (
+ const char* const in, const char* out,
+ const int nmatch, const regmatch_t* const pmatch)
+{
+ vString* result = vStringNew ();
+ const char* p;
+ for (p = out ; *p != '\0' ; p++)
+ {
+ if (*p == '\\' && isdigit ((int) *++p))
+ {
+ const int dig = *p - '0';
+ if (0 < dig && dig < nmatch && pmatch [dig].rm_so != -1)
+ {
+ const int diglen = pmatch [dig].rm_eo - pmatch [dig].rm_so;
+ vStringNCatS (result, in + pmatch [dig].rm_so, diglen);
+ }
+ }
+ else if (*p != '\n' && *p != '\r')
+ vStringPut (result, *p);
+ }
+ vStringTerminate (result);
+ return result;
+}
+
+static void matchTagPattern (const vString* const line,
+ const regexPattern* const patbuf,
+ const regmatch_t* const pmatch)
+{
+ vString *const name = substitute (vStringValue (line),
+ patbuf->u.tag.name_pattern, BACK_REFERENCE_COUNT, pmatch);
+ vStringStripLeading (name);
+ vStringStripTrailing (name);
+ if (vStringLength (name) > 0)
+ makeRegexTag (name, &patbuf->u.tag.kind);
+ else
+ error (WARNING, "%s:%ld: null expansion of name pattern \"%s\"",
+ getInputFileName (), getInputLineNumber (),
+ patbuf->u.tag.name_pattern);
+ vStringDelete (name);
+}
+
+static void matchCallbackPattern (
+ const vString* const line, const regexPattern* const patbuf,
+ const regmatch_t* const pmatch)
+{
+ regexMatch matches [BACK_REFERENCE_COUNT];
+ unsigned int count = 0;
+ int i;
+ for (i = 0 ; i < BACK_REFERENCE_COUNT && pmatch [i].rm_so != -1 ; ++i)
+ {
+ matches [i].start = pmatch [i].rm_so;
+ matches [i].length = pmatch [i].rm_eo - pmatch [i].rm_so;
+ ++count;
+ }
+ patbuf->u.callback.function (vStringValue (line), matches, count);
+}
+
+static boolean matchRegexPattern (const vString* const line,
+ const regexPattern* const patbuf)
+{
+ boolean result = FALSE;
+ regmatch_t pmatch [BACK_REFERENCE_COUNT];
+ const int match = regexec (patbuf->pattern, vStringValue (line),
+ BACK_REFERENCE_COUNT, pmatch, 0);
+ if (match == 0)
+ {
+ result = TRUE;
+ if (patbuf->type == PTRN_TAG)
+ matchTagPattern (line, patbuf, pmatch);
+ else if (patbuf->type == PTRN_CALLBACK)
+ matchCallbackPattern (line, patbuf, pmatch);
+ else
+ {
+ Assert ("invalid pattern type" == NULL);
+ result = FALSE;
+ }
+ }
+ return result;
+}
+
+#endif
+
+/* PUBLIC INTERFACE */
+
+/* Match against all patterns for specified language. Returns true if at least
+ * on pattern matched.
+ */
+extern boolean matchRegex (const vString* const line, const langType language)
+{
+ boolean result = FALSE;
+ if (language != LANG_IGNORE && language <= SetUpper &&
+ Sets [language].count > 0)
+ {
+ const patternSet* const set = Sets + language;
+ unsigned int i;
+ for (i = 0 ; i < set->count ; ++i)
+ if (matchRegexPattern (line, set->patterns + i))
+ result = TRUE;
+ }
+ return result;
+}
+
+extern void findRegexTags (void)
+{
+ /* merely read all lines of the file */
+ while (fileReadLine () != NULL)
+ ;
+}
+
+#endif /* HAVE_REGEX */
+
+extern void addTagRegex (
+ const langType language,
+ const char* const regex,
+ const char* const name,
+ const char* const kinds,
+ const char* const flags)
+{
+#ifdef HAVE_REGEX
+ Assert (regex != NULL);
+ Assert (name != NULL);
+ if (! regexBroken)
+ {
+ regex_t* const cp = compileRegex (regex, flags);
+ if (cp != NULL)
+ {
+ char kind;
+ char* kindName;
+ char* description;
+ parseKinds (kinds, &kind, &kindName, &description);
+ addCompiledTagPattern (language, cp, eStrdup (name),
+ kind, kindName, description);
+ }
+ }
+#endif
+}
+
+extern void addCallbackRegex (
+ const langType language,
+ const char* const regex,
+ const char* const flags,
+ const regexCallback callback)
+{
+#ifdef HAVE_REGEX
+ Assert (regex != NULL);
+ if (! regexBroken)
+ {
+ regex_t* const cp = compileRegex (regex, flags);
+ if (cp != NULL)
+ addCompiledCallbackPattern (language, cp, callback);
+ }
+#endif
+}
+
+extern void addLanguageRegex (
+ const langType language, const char* const regex)
+{
+#ifdef HAVE_REGEX
+ if (! regexBroken)
+ {
+ char *const regex_pat = eStrdup (regex);
+ char *name, *kinds, *flags;
+ if (parseTagRegex (regex_pat, &name, &kinds, &flags))
+ {
+ addTagRegex (language, regex_pat, name, kinds, flags);
+ eFree (regex_pat);
+ }
+ }
+#endif
+}
+
+/*
+* Regex option parsing
+*/
+
+extern boolean processRegexOption (const char *const option,
+ const char *const parameter)
+{
+ boolean handled = FALSE;
+ const char* const dash = strchr (option, '-');
+ if (dash != NULL && strncmp (option, "regex", dash - option) == 0)
+ {
+#ifdef HAVE_REGEX
+ langType language;
+ language = getNamedLanguage (dash + 1);
+ if (language == LANG_IGNORE)
+ error (WARNING, "unknown language \"%s\" in --%s option", (dash + 1), option);
+ else
+ processLanguageRegex (language, parameter);
+#else
+ error (WARNING, "regex support not available; required for --%s option",
+ option);
+#endif
+ handled = TRUE;
+ }
+ return handled;
+}
+
+extern void disableRegexKinds (const langType language)
+{
+#ifdef HAVE_REGEX
+ if (language <= SetUpper && Sets [language].count > 0)
+ {
+ patternSet* const set = Sets + language;
+ unsigned int i;
+ for (i = 0 ; i < set->count ; ++i)
+ if (set->patterns [i].type == PTRN_TAG)
+ set->patterns [i].u.tag.kind.enabled = FALSE;
+ }
+#endif
+}
+
+extern boolean enableRegexKind (
+ const langType language,
+ const int kind, const boolean mode)
+{
+ boolean result = FALSE;
+#ifdef HAVE_REGEX
+ if (language <= SetUpper && Sets [language].count > 0)
+ {
+ patternSet* const set = Sets + language;
+ unsigned int i;
+ for (i = 0 ; i < set->count ; ++i)
+ if (set->patterns [i].type == PTRN_TAG &&
+ set->patterns [i].u.tag.kind.letter == kind)
+ {
+ set->patterns [i].u.tag.kind.enabled = mode;
+ result = TRUE;
+ }
+ }
+#endif
+ return result;
+}
+
+extern void printRegexKinds (const langType language, boolean indent)
+{
+#ifdef HAVE_REGEX
+ if (language <= SetUpper && Sets [language].count > 0)
+ {
+ patternSet* const set = Sets + language;
+ unsigned int i;
+ for (i = 0 ; i < set->count ; ++i)
+ if (set->patterns [i].type == PTRN_TAG)
+ printRegexKind (set->patterns, i, indent);
+ }
+#endif
+}
+
+extern void freeRegexResources (void)
+{
+#ifdef HAVE_REGEX
+ int i;
+ for (i = 0 ; i <= SetUpper ; ++i)
+ clearPatternSet (i);
+ if (Sets != NULL)
+ eFree (Sets);
+ Sets = NULL;
+ SetUpper = -1;
+#endif
+}
+
+/* Check for broken regcomp() on Cygwin */
+extern void checkRegex (void)
+{
+#if defined (HAVE_REGEX) && defined (CHECK_REGCOMP)
+ regex_t patbuf;
+ int errcode;
+ if (regcomp (&patbuf, "/hello/", 0) != 0)
+ {
+ error (WARNING, "Disabling broken regex");
+ regexBroken = TRUE;
+ }
+#endif
+}
+
+/* vi:set tabstop=4 shiftwidth=4: */
Index: create-5.8-unused-attribute-patch/ctags-5.8-new/lua.c
===================================================================
--- create-5.8-unused-attribute-patch/ctags-5.8-new/lua.c (nonexistent)
+++ create-5.8-unused-attribute-patch/ctags-5.8-new/lua.c (revision 5)
@@ -0,0 +1,133 @@
+/*
+* $Id: lua.c 443 2006-05-30 04:37:13Z darren $
+*
+* Copyright (c) 2000-2001, Max Ischenko <mfi@ukr.net>.
+*
+* 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 Lua language.
+*/
+
+/*
+* INCLUDE FILES
+*/
+#include "general.h" /* must always come first */
+
+#include <string.h>
+
+#include "options.h"
+#include "parse.h"
+#include "read.h"
+#include "vstring.h"
+
+/*
+* DATA DEFINITIONS
+*/
+typedef enum {
+ K_FUNCTION
+} luaKind;
+
+static kindOption LuaKinds [] = {
+ { TRUE, 'f', "function", "functions" }
+};
+
+/*
+* FUNCTION DEFINITIONS
+*/
+
+/* for debugging purposes */
+static void print_string (char *p, char *q)
+{
+ for ( ; p != q; p++)
+ fprintf (errout, "%c", *p);
+ fprintf (errout, "\n");
+}
+
+/*
+ * Helper function.
+ * Returns 1 if line looks like a line of Lua code.
+ *
+ * TODO: Recognize UNIX bang notation.
+ * (Lua treat first line as a comment if it starts with #!)
+ *
+ */
+static boolean is_a_code_line (const unsigned char *line)
+{
+ boolean result;
+ const unsigned char *p = line;
+ while (isspace ((int) *p))
+ p++;
+ if (p [0] == '\0')
+ result = FALSE;
+ else if (p [0] == '-' && p [1] == '-')
+ result = FALSE;
+ else
+ result = TRUE;
+ return result;
+}
+
+static void extract_name (const char *begin, const char *end, vString *name)
+{
+ if (begin != NULL && end != NULL && begin < end)
+ {
+ const char *cp;
+
+ while (isspace ((int) *begin))
+ begin++;
+ while (isspace ((int) *end))
+ end--;
+ if (begin < end)
+ {
+ for (cp = begin ; cp != end; cp++)
+ vStringPut (name, (int) *cp);
+ vStringTerminate (name);
+
+ makeSimpleTag (name, LuaKinds, K_FUNCTION);
+ vStringClear (name);
+ }
+ }
+}
+
+static void findLuaTags (void)
+{
+ vString *name = vStringNew ();
+ const unsigned char *line;
+
+ while ((line = fileReadLine ()) != NULL)
+ {
+ const char *p, *q;
+
+ if (! is_a_code_line (line))
+ continue;
+
+ p = (const char*) strstr ((const char*) line, "function");
+ if (p == NULL)
+ continue;
+
+ q = strchr ((const char*) line, '=');
+
+ if (q == NULL) {
+ p = p + 9; /* skip the `function' word */
+ q = strchr ((const char*) p, '(');
+ extract_name (p, q, name);
+ } else {
+ p = (const char*) &line[0];
+ extract_name (p, q, name);
+ }
+ }
+ vStringDelete (name);
+}
+
+extern parserDefinition* LuaParser (void)
+{
+ static const char* const extensions [] = { "lua", NULL };
+ parserDefinition* def = parserNew ("Lua");
+ def->kinds = LuaKinds;
+ def->kindCount = KIND_COUNT (LuaKinds);
+ def->extensions = extensions;
+ def->parser = findLuaTags;
+ return def;
+}
+
+/* vi:set tabstop=4 shiftwidth=4: */
Index: create-5.8-unused-attribute-patch/ctags-5.8-new/main.c
===================================================================
--- create-5.8-unused-attribute-patch/ctags-5.8-new/main.c (nonexistent)
+++ create-5.8-unused-attribute-patch/ctags-5.8-new/main.c (revision 5)
@@ -0,0 +1,579 @@
+/*
+* $Id: main.c 536 2007-06-02 06:09:00Z elliotth $
+*
+* Copyright (c) 1996-2003, Darren Hiebert
+*
+* Author: Darren Hiebert <dhiebert@users.sourceforge.net>
+* http://ctags.sourceforge.net
+*
+* This source code is released for free distribution under the terms of the
+* GNU General Public License. It is provided on an as-is basis and no
+* responsibility is accepted for its failure to perform as expected.
+*
+* This is a reimplementation of the ctags (1) program. It is an attempt to
+* provide a fully featured ctags program which is free of the limitations
+* which most (all?) others are subject to.
+*
+* This module contains the start-up code and routines to determine the list
+* of files to parsed for tags.
+*/
+
+/*
+* INCLUDE FILES
+*/
+#include "general.h" /* must always come first */
+
+#include <string.h>
+
+/* To provide timings features if available.
+ */
+#ifdef HAVE_CLOCK
+# ifdef HAVE_TIME_H
+# include <time.h>
+# endif
+#else
+# ifdef HAVE_TIMES
+# ifdef HAVE_SYS_TIMES_H
+# include <sys/times.h>
+# endif
+# endif
+#endif
+
+/* To provide directory searching for recursion feature.
+ */
+#ifdef AMIGA
+# include <dos/dosasl.h> /* for struct AnchorPath */
+# include <clib/dos_protos.h> /* function prototypes */
+# define ANCHOR_BUF_SIZE 512
+# define ANCHOR_SIZE (sizeof (struct AnchorPath) + ANCHOR_BUF_SIZE)
+# ifdef __SASC
+ extern struct DosLibrary *DOSBase;
+# include <pragmas/dos_pragmas.h>
+# endif
+#endif
+
+#ifdef HAVE_DIRENT_H
+# ifdef __BORLANDC__
+# define boolean BORLAND_boolean
+# endif
+# ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h> /* required by dirent.h */
+# endif
+# include <dirent.h> /* to declare opendir() */
+# undef boolean
+#endif
+#ifdef HAVE_DIRECT_H
+# include <direct.h> /* to _getcwd() */
+#endif
+#ifdef HAVE_DOS_H
+# include <dos.h> /* to declare FA_DIREC */
+#endif
+#ifdef HAVE_DIR_H
+# include <dir.h> /* to declare findfirst() and findnext */
+#endif
+#ifdef HAVE_IO_H
+# include <io.h> /* to declare _findfirst() */
+#endif
+
+
+#include "debug.h"
+#include "keyword.h"
+#include "main.h"
+#include "options.h"
+#include "read.h"
+#include "routines.h"
+
+/*
+* MACROS
+*/
+#define plural(value) (((unsigned long)(value) == 1L) ? "" : "s")
+
+/*
+* DATA DEFINITIONS
+*/
+static struct { long files, lines, bytes; } Totals = { 0, 0, 0 };
+
+#ifdef AMIGA
+# include "ctags.h"
+ static const char *VERsion = "$VER: "PROGRAM_NAME" "PROGRAM_VERSION" "
+# ifdef __SASC
+ __AMIGADATE__
+# else
+ __DATE__
+# endif
+ " "AUTHOR_NAME" $";
+#endif
+
+/*
+* FUNCTION PROTOTYPES
+*/
+static boolean createTagsForEntry (const char *const entryName);
+
+/*
+* FUNCTION DEFINITIONS
+*/
+
+extern void addTotals (
+ const unsigned int files, const long unsigned int lines,
+ const long unsigned int bytes)
+{
+ Totals.files += files;
+ Totals.lines += lines;
+ Totals.bytes += bytes;
+}
+
+extern boolean isDestinationStdout (void)
+{
+ boolean toStdout = FALSE;
+
+ if (Option.xref || Option.filter ||
+ (Option.tagFileName != NULL && (strcmp (Option.tagFileName, "-") == 0
+#if defined (VMS)
+ || strcmp (Option.tagFileName, "sys$output") == 0
+#else
+ || strcmp (Option.tagFileName, "/dev/stdout") == 0
+#endif
+ )))
+ toStdout = TRUE;
+ return toStdout;
+}
+
+#if defined (HAVE_OPENDIR)
+static boolean recurseUsingOpendir (const char *const dirName)
+{
+ boolean resize = FALSE;
+ DIR *const dir = opendir (dirName);
+ if (dir == NULL)
+ error (WARNING | PERROR, "cannot recurse into directory \"%s\"", dirName);
+ else
+ {
+ struct dirent *entry;
+ while ((entry = readdir (dir)) != NULL)
+ {
+ if (strcmp (entry->d_name, ".") != 0 &&
+ strcmp (entry->d_name, "..") != 0)
+ {
+ vString *filePath;
+ if (strcmp (dirName, ".") == 0)
+ filePath = vStringNewInit (entry->d_name);
+ else
+ filePath = combinePathAndFile (dirName, entry->d_name);
+ resize |= createTagsForEntry (vStringValue (filePath));
+ vStringDelete (filePath);
+ }
+ }
+ closedir (dir);
+ }
+ return resize;
+}
+
+#elif defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST)
+
+static boolean createTagsForWildcardEntry (
+ const char *const pattern, const size_t dirLength,
+ const char *const entryName)
+{
+ boolean resize = FALSE;
+ /* we must not recurse into the directories "." or ".." */
+ if (strcmp (entryName, ".") != 0 && strcmp (entryName, "..") != 0)
+ {
+ vString *const filePath = vStringNew ();
+ vStringNCopyS (filePath, pattern, dirLength);
+ vStringCatS (filePath, entryName);
+ resize = createTagsForEntry (vStringValue (filePath));
+ vStringDelete (filePath);
+ }
+ return resize;
+}
+
+static boolean createTagsForWildcardUsingFindfirst (const char *const pattern)
+{
+ boolean resize = FALSE;
+ const size_t dirLength = baseFilename (pattern) - pattern;
+#if defined (HAVE_FINDFIRST)
+ struct ffblk fileInfo;
+ int result = findfirst (pattern, &fileInfo, FA_DIREC);
+ while (result == 0)
+ {
+ const char *const entry = (const char *) fileInfo.ff_name;
+ resize |= createTagsForWildcardEntry (pattern, dirLength, entry);
+ result = findnext (&fileInfo);
+ }
+#elif defined (HAVE__FINDFIRST)
+ struct _finddata_t fileInfo;
+ findfirst_t hFile = _findfirst (pattern, &fileInfo);
+ if (hFile != -1L)
+ {
+ do
+ {
+ const char *const entry = (const char *) fileInfo.name;
+ resize |= createTagsForWildcardEntry (pattern, dirLength, entry);
+ } while (_findnext (hFile, &fileInfo) == 0);
+ _findclose (hFile);
+ }
+#endif
+ return resize;
+}
+
+#elif defined (AMIGA)
+
+static boolean createTagsForAmigaWildcard (const char *const pattern)
+{
+ boolean resize = FALSE;
+ struct AnchorPath *const anchor =
+ (struct AnchorPath *) eMalloc ((size_t) ANCHOR_SIZE);
+ LONG result;
+
+ memset (anchor, 0, (size_t) ANCHOR_SIZE);
+ anchor->ap_Strlen = ANCHOR_BUF_SIZE;
+ /* Allow '.' for current directory */
+#ifdef APF_DODOT
+ anchor->ap_Flags = APF_DODOT | APF_DOWILD;
+#else
+ anchor->ap_Flags = APF_DoDot | APF_DoWild;
+#endif
+ result = MatchFirst ((UBYTE *) pattern, anchor);
+ while (result == 0)
+ {
+ resize |= createTagsForEntry ((char *) anchor->ap_Buf);
+ result = MatchNext (anchor);
+ }
+ MatchEnd (anchor);
+ eFree (anchor);
+ return resize;
+}
+#endif
+
+static boolean recurseIntoDirectory (const char *const dirName)
+{
+ boolean resize = FALSE;
+ if (isRecursiveLink (dirName))
+ verbose ("ignoring \"%s\" (recursive link)\n", dirName);
+ else if (! Option.recurse)
+ verbose ("ignoring \"%s\" (directory)\n", dirName);
+ else
+ {
+ verbose ("RECURSING into directory \"%s\"\n", dirName);
+#if defined (HAVE_OPENDIR)
+ resize = recurseUsingOpendir (dirName);
+#elif defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST)
+ {
+ vString *const pattern = vStringNew ();
+ vStringCopyS (pattern, dirName);
+ vStringPut (pattern, OUTPUT_PATH_SEPARATOR);
+ vStringCatS (pattern, "*.*");
+ resize = createTagsForWildcardUsingFindfirst (vStringValue (pattern));
+ vStringDelete (pattern);
+ }
+#elif defined (AMIGA)
+ {
+ vString *const pattern = vStringNew ();
+ if (*dirName != '\0' && strcmp (dirName, ".") != 0)
+ {
+ vStringCopyS (pattern, dirName);
+ if (dirName [strlen (dirName) - 1] != '/')
+ vStringPut (pattern, '/');
+ }
+ vStringCatS (pattern, "#?");
+ resize = createTagsForAmigaWildcard (vStringValue (pattern));
+ vStringDelete (pattern);
+ }
+#endif
+ }
+ return resize;
+}
+
+static boolean createTagsForEntry (const char *const entryName)
+{
+ boolean resize = FALSE;
+ fileStatus *status = eStat (entryName);
+
+ Assert (entryName != NULL);
+ if (isExcludedFile (entryName))
+ verbose ("excluding \"%s\"\n", entryName);
+ else if (status->isSymbolicLink && ! Option.followLinks)
+ verbose ("ignoring \"%s\" (symbolic link)\n", entryName);
+ else if (! status->exists)
+ error (WARNING | PERROR, "cannot open source file \"%s\"", entryName);
+ else if (status->isDirectory)
+ resize = recurseIntoDirectory (entryName);
+ else if (! status->isNormalFile)
+ verbose ("ignoring \"%s\" (special file)\n", entryName);
+ else
+ resize = parseFile (entryName);
+
+ eStatFree (status);
+ return resize;
+}
+
+#ifdef MANUAL_GLOBBING
+
+static boolean createTagsForWildcardArg (const char *const arg)
+{
+ boolean resize = FALSE;
+ vString *const pattern = vStringNewInit (arg);
+ char *patternS = vStringValue (pattern);
+
+#if defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST)
+ /* We must transform the "." and ".." forms into something that can
+ * be expanded by the findfirst/_findfirst functions.
+ */
+ if (Option.recurse &&
+ (strcmp (patternS, ".") == 0 || strcmp (patternS, "..") == 0))
+ {
+ vStringPut (pattern, OUTPUT_PATH_SEPARATOR);
+ vStringCatS (pattern, "*.*");
+ }
+ resize |= createTagsForWildcardUsingFindfirst (patternS);
+#endif
+ vStringDelete (pattern);
+ return resize;
+}
+
+#endif
+
+static boolean createTagsForArgs (cookedArgs *const args)
+{
+ boolean resize = FALSE;
+
+ /* Generate tags for each argument on the command line.
+ */
+ while (! cArgOff (args))
+ {
+ const char *const arg = cArgItem (args);
+
+#ifdef MANUAL_GLOBBING
+ resize |= createTagsForWildcardArg (arg);
+#else
+ resize |= createTagsForEntry (arg);
+#endif
+ cArgForth (args);
+ parseOptions (args);
+ }
+ return resize;
+}
+
+/* Read from an opened file a list of file names for which to generate tags.
+ */
+static boolean createTagsFromFileInput (FILE *const fp, const boolean filter)
+{
+ boolean resize = FALSE;
+ if (fp != NULL)
+ {
+ cookedArgs *args = cArgNewFromLineFile (fp);
+ parseOptions (args);
+ while (! cArgOff (args))
+ {
+ resize |= createTagsForEntry (cArgItem (args));
+ if (filter)
+ {
+ if (Option.filterTerminator != NULL)
+ fputs (Option.filterTerminator, stdout);
+ fflush (stdout);
+ }
+ cArgForth (args);
+ parseOptions (args);
+ }
+ cArgDelete (args);
+ }
+ return resize;
+}
+
+/* Read from a named file a list of file names for which to generate tags.
+ */
+static boolean createTagsFromListFile (const char *const fileName)
+{
+ boolean resize;
+ Assert (fileName != NULL);
+ if (strcmp (fileName, "-") == 0)
+ resize = createTagsFromFileInput (stdin, FALSE);
+ else
+ {
+ FILE *const fp = fopen (fileName, "r");
+ if (fp == NULL)
+ error (FATAL | PERROR, "cannot open list file \"%s\"", fileName);
+ resize = createTagsFromFileInput (fp, FALSE);
+ fclose (fp);
+ }
+ return resize;
+}
+
+#if defined (HAVE_CLOCK)
+# define CLOCK_AVAILABLE
+# ifndef CLOCKS_PER_SEC
+# define CLOCKS_PER_SEC 1000000
+# endif
+#elif defined (HAVE_TIMES)
+# define CLOCK_AVAILABLE
+# define CLOCKS_PER_SEC 60
+static clock_t clock (void)
+{
+ struct tms buf;
+
+ times (&buf);
+ return (buf.tms_utime + buf.tms_stime);
+}
+#else
+# define clock() (clock_t)0
+#endif
+
+static void printTotals (const clock_t *const timeStamps)
+{
+ const unsigned long totalTags = TagFile.numTags.added +
+ TagFile.numTags.prev;
+
+ fprintf (errout, "%ld file%s, %ld line%s (%ld kB) scanned",
+ Totals.files, plural (Totals.files),
+ Totals.lines, plural (Totals.lines),
+ Totals.bytes/1024L);
+#ifdef CLOCK_AVAILABLE
+ {
+ const double interval = ((double) (timeStamps [1] - timeStamps [0])) /
+ CLOCKS_PER_SEC;
+
+ fprintf (errout, " in %.01f seconds", interval);
+ if (interval != (double) 0.0)
+ fprintf (errout, " (%lu kB/s)",
+ (unsigned long) (Totals.bytes / interval) / 1024L);
+ }
+#endif
+ fputc ('\n', errout);
+
+ fprintf (errout, "%lu tag%s added to tag file",
+ TagFile.numTags.added, plural (TagFile.numTags.added));
+ if (Option.append)
+ fprintf (errout, " (now %lu tags)", totalTags);
+ fputc ('\n', errout);
+
+ if (totalTags > 0 && Option.sorted != SO_UNSORTED)
+ {
+ fprintf (errout, "%lu tag%s sorted", totalTags, plural (totalTags));
+#ifdef CLOCK_AVAILABLE
+ fprintf (errout, " in %.02f seconds",
+ ((double) (timeStamps [2] - timeStamps [1])) / CLOCKS_PER_SEC);
+#endif
+ fputc ('\n', errout);
+ }
+
+#ifdef DEBUG
+ fprintf (errout, "longest tag line = %lu\n",
+ (unsigned long) TagFile.max.line);
+#endif
+}
+
+static boolean etagsInclude (void)
+{
+ return (boolean)(Option.etags && Option.etagsInclude != NULL);
+}
+
+static void makeTags (cookedArgs *args)
+{
+ clock_t timeStamps [3];
+ boolean resize = FALSE;
+ boolean files = (boolean)(! cArgOff (args) || Option.fileList != NULL
+ || Option.filter);
+
+ if (! files)
+ {
+ if (filesRequired ())
+ error (FATAL, "No files specified. Try \"%s --help\".",
+ getExecutableName ());
+ else if (! Option.recurse && ! etagsInclude ())
+ return;
+ }
+
+#define timeStamp(n) timeStamps[(n)]=(Option.printTotals ? clock():(clock_t)0)
+ if (! Option.filter)
+ openTagFile ();
+
+ timeStamp (0);
+
+ if (! cArgOff (args))
+ {
+ verbose ("Reading command line arguments\n");
+ resize = createTagsForArgs (args);
+ }
+ if (Option.fileList != NULL)
+ {
+ verbose ("Reading list file\n");
+ resize = (boolean) (createTagsFromListFile (Option.fileList) || resize);
+ }
+ if (Option.filter)
+ {
+ verbose ("Reading filter input\n");
+ resize = (boolean) (createTagsFromFileInput (stdin, TRUE) || resize);
+ }
+ if (! files && Option.recurse)
+ resize = recurseIntoDirectory (".");
+
+ timeStamp (1);
+
+ if (! Option.filter)
+ closeTagFile (resize);
+
+ timeStamp (2);
+
+ if (Option.printTotals)
+ printTotals (timeStamps);
+#undef timeStamp
+}
+
+/*
+ * Start up code
+ */
+
+extern int main (int argc, char **argv)
+{
+ cookedArgs *args;
+#ifdef VMS
+ extern int getredirection (int *ac, char ***av);
+
+ /* do wildcard expansion and I/O redirection */
+ getredirection (&argc, &argv);
+#endif
+
+#ifdef AMIGA
+ /* This program doesn't work when started from the Workbench */
+ if (argc == 0)
+ exit (1);
+#endif
+
+#ifdef __EMX__
+ _wildcard (&argc, &argv); /* expand wildcards in argument list */
+#endif
+
+#if defined (macintosh) && BUILD_MPW_TOOL == 0
+ argc = ccommand (&argv);
+#endif
+
+ setCurrentDirectory ();
+ setExecutableName (*argv++);
+ checkRegex ();
+
+ args = cArgNewFromArgv (argv);
+ previewFirstOption (args);
+ testEtagsInvocation ();
+ initializeParsing ();
+ initOptions ();
+ readOptionConfiguration ();
+ verbose ("Reading initial options from command line\n");
+ parseOptions (args);
+ checkOptions ();
+ makeTags (args);
+
+ /* Clean up.
+ */
+ cArgDelete (args);
+ freeKeywordTable ();
+ freeRoutineResources ();
+ freeSourceFileResources ();
+ freeTagFileResources ();
+ freeOptionResources ();
+ freeParserResources ();
+ freeRegexResources ();
+
+ exit (0);
+ return 0;
+}
+
+/* vi:set tabstop=4 shiftwidth=4: */
Index: create-5.8-unused-attribute-patch/ctags-5.8-new/options.c
===================================================================
--- create-5.8-unused-attribute-patch/ctags-5.8-new/options.c (nonexistent)
+++ create-5.8-unused-attribute-patch/ctags-5.8-new/options.c (revision 5)
@@ -0,0 +1,1829 @@
+/*
+* $Id: options.c 576 2007-06-30 04:16:23Z elliotth $
+*
+* Copyright (c) 1996-2003, Darren Hiebert
+*
+* This source code is released for free distribution under the terms of the
+* GNU General Public License.
+*
+* This module contains functions to process command line options.
+*/
+
+/*
+* INCLUDE FILES
+*/
+#include "general.h" /* must always come first */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h> /* to declare isspace () */
+
+#include "ctags.h"
+#include "debug.h"
+#include "main.h"
+#define OPTION_WRITE
+#include "options.h"
+#include "parse.h"
+#include "routines.h"
+
+/*
+* MACROS
+*/
+#define INVOCATION "Usage: %s [options] [file(s)]\n"
+
+#define CTAGS_ENVIRONMENT "CTAGS"
+#define ETAGS_ENVIRONMENT "ETAGS"
+
+#define CTAGS_FILE "tags"
+#define ETAGS_FILE "TAGS"
+
+#ifndef ETAGS
+# define ETAGS "etags" /* name which causes default use of to -e */
+#endif
+
+/* The following separators are permitted for list options.
+ */
+#define EXTENSION_SEPARATOR '.'
+#define PATTERN_START '('
+#define PATTERN_STOP ')'
+#define IGNORE_SEPARATORS ", \t\n"
+
+#ifndef DEFAULT_FILE_FORMAT
+# define DEFAULT_FILE_FORMAT 2
+#endif
+
+#if defined (HAVE_OPENDIR) || defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST) || defined (AMIGA)
+# define RECURSE_SUPPORTED
+#endif
+
+#define isCompoundOption(c) (boolean) (strchr ("fohiILpDb", (c)) != NULL)
+
+/*
+* Data declarations
+*/
+
+enum eOptionLimits {
+ MaxHeaderExtensions = 100, /* maximum number of extensions in -h option */
+ MaxSupportedTagFormat = 2
+};
+
+typedef struct sOptionDescription {
+ int usedByEtags;
+ const char *description;
+} optionDescription;
+
+typedef void (*parametricOptionHandler) (const char *const option, const char *const parameter);
+
+typedef const struct {
+ const char* name; /* name of option as specified by user */
+ parametricOptionHandler handler; /* routine to handle option */
+ boolean initOnly; /* option must be specified before any files */
+} parametricOption;
+
+typedef const struct {
+ const char* name; /* name of option as specified by user */
+ boolean* pValue; /* pointer to option value */
+ boolean initOnly; /* option must be specified before any files */
+} booleanOption;
+
+/*
+* DATA DEFINITIONS
+*/
+
+static boolean NonOptionEncountered;
+static stringList *OptionFiles;
+static stringList* Excluded;
+static boolean FilesRequired = TRUE;
+static boolean SkipConfiguration;
+
+static const char *const HeaderExtensions [] = {
+ "h", "H", "hh", "hpp", "hxx", "h++", "inc", "def", NULL
+};
+
+optionValues Option = {
+ {
+ FALSE, /* --extra=f */
+ FALSE, /* --extra=q */
+ TRUE, /* --file-scope */
+ },
+ {
+ FALSE, /* -fields=a */
+ TRUE, /* -fields=f */
+ FALSE, /* -fields=m */
+ FALSE, /* -fields=i */
+ TRUE, /* -fields=k */
+ FALSE, /* -fields=z */
+ FALSE, /* -fields=K */
+ FALSE, /* -fields=l */
+ FALSE, /* -fields=n */
+ TRUE, /* -fields=s */
+ FALSE, /* -fields=S */
+ TRUE /* -fields=t */
+ },
+ NULL, /* -I */
+ FALSE, /* -a */
+ FALSE, /* -B */
+ FALSE, /* -e */
+#ifdef MACROS_USE_PATTERNS
+ EX_PATTERN, /* -n, --excmd */
+#else
+ EX_MIX, /* -n, --excmd */
+#endif
+ FALSE, /* -R */
+ SO_SORTED, /* -u, --sort */
+ FALSE, /* -V */
+ FALSE, /* -x */
+ NULL, /* -L */
+ NULL, /* -o */
+ NULL, /* -h */
+ NULL, /* --etags-include */
+ DEFAULT_FILE_FORMAT,/* --format */
+ FALSE, /* --if0 */
+ FALSE, /* --kind-long */
+ LANG_AUTO, /* --lang */
+ TRUE, /* --links */
+ FALSE, /* --filter */
+ NULL, /* --filter-terminator */
+ FALSE, /* --tag-relative */
+ FALSE, /* --totals */
+ FALSE, /* --line-directives */
+#ifdef DEBUG
+ 0, 0 /* -D, -b */
+#endif
+};
+
+/*
+- Locally used only
+*/
+
+static optionDescription LongOptionDescription [] = {
+ {1," -a Append the tags to an existing tag file."},
+#ifdef DEBUG
+ {1," -b <line>"},
+ {1," Set break line."},
+#endif
+ {0," -B Use backward searching patterns (?...?)."},
+#ifdef DEBUG
+ {1," -D <level>"},
+ {1," Set debug level."},
+#endif
+ {0," -e Output tag file for use with Emacs."},
+ {1," -f <name>"},
+ {1," Write tags to specified file. Value of \"-\" writes tags to stdout"},
+ {1," [\"tags\"; or \"TAGS\" when -e supplied]."},
+ {0," -F Use forward searching patterns (/.../) (default)."},
+ {1," -h <list>"},
+ {1," Specify list of file extensions to be treated as include files."},
+ {1," [\".h.H.hh.hpp.hxx.h++\"]."},
+ {1," -I <list|@file>"},
+ {1," A list of tokens to be specially handled is read from either the"},
+ {1," command line or the specified file."},
+ {1," -L <file>"},
+ {1," A list of source file names are read from the specified file."},
+ {1," If specified as \"-\", then standard input is read."},
+ {0," -n Equivalent to --excmd=number."},
+ {0," -N Equivalent to --excmd=pattern."},
+ {1," -o Alternative for -f."},
+#ifdef RECURSE_SUPPORTED
+ {1," -R Equivalent to --recurse."},
+#else
+ {1," -R Not supported on this platform."},
+#endif
+ {0," -u Equivalent to --sort=no."},
+ {1," -V Equivalent to --verbose."},
+ {1," -x Print a tabular cross reference file to standard output."},
+ {1," --append=[yes|no]"},
+ {1," Should tags should be appended to existing tag file [no]?"},
+ {1," --etags-include=file"},
+ {1," Include reference to 'file' in Emacs-style tag file (requires -e)."},
+ {1," --exclude=pattern"},
+ {1," Exclude files and directories matching 'pattern'."},
+ {0," --excmd=number|pattern|mix"},
+#ifdef MACROS_USE_PATTERNS
+ {0," Uses the specified type of EX command to locate tags [pattern]."},
+#else
+ {0," Uses the specified type of EX command to locate tags [mix]."},
+#endif
+ {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," --file-scope=[yes|no]"},
+ {1," Should tags scoped only for a single file (e.g. \"static\" tags"},
+ {1," be included in the output [yes]?"},
+ {1," --filter=[yes|no]"},
+ {1," Behave as a filter, reading file names from standard input and"},
+ {1," writing tags to standard output [no]."},
+ {1," --filter-terminator=string"},
+ {1," Specify string to print to stdout following the tags for each file"},
+ {1," parsed when --filter is enabled."},
+ {0," --format=level"},
+#if DEFAULT_FILE_FORMAT == 1
+ {0," Force output of specified tag file format [1]."},
+#else
+ {0," Force output of specified tag file format [2]."},
+#endif
+ {1," --help"},
+ {1," Print this option summary."},
+ {1," --if0=[yes|no]"},
+ {1," Should C code within #if 0 conditional branches be parsed [no]?"},
+ {1," --<LANG>-kinds=[+|-]kinds"},
+ {1," Enable/disable tag kinds for language <LANG>."},
+ {1," --langdef=name"},
+ {1," Define a new language to be parsed with regular expressions."},
+ {1," --langmap=map(s)"},
+ {1," Override default mapping of language to source file extension."},
+ {1," --language-force=language"},
+ {1," Force all files to be interpreted using specified language."},
+ {1," --languages=[+|-]list"},
+ {1," Restrict files scanned for tags to those mapped to langauges"},
+ {1," specified in the comma-separated 'list'. The list can contain any"},
+ {1," built-in or user-defined language [all]."},
+ {1," --license"},
+ {1," Print details of software license."},
+ {0," --line-directives=[yes|no]"},
+ {0," Should #line directives be processed [no]?"},
+ {1," --links=[yes|no]"},
+ {1," Indicate whether symbolic links should be followed [yes]."},
+ {1," --list-kinds=[language|all]"},
+ {1," Output a list of all tag kinds for specified language or all."},
+ {1," --list-languages"},
+ {1," Output list of supported languages."},
+ {1," --list-maps=[language|all]"},
+ {1," Output list of language mappings."},
+ {1," --options=file"},
+ {1," Specify file from which command line options should be read."},
+ {1," --recurse=[yes|no]"},
+#ifdef RECURSE_SUPPORTED
+ {1," Recurse into directories supplied on command line [no]."},
+#else
+ {1," Not supported on this platform."},
+#endif
+#ifdef HAVE_REGEX
+ {1," --regex-<LANG>=/line_pattern/name_pattern/[flags]"},
+ {1," Define regular expression for locating tags in specific language."},
+#endif
+ {0," --sort=[yes|no|foldcase]"},
+ {0," Should tags be sorted (optionally ignoring case) [yes]?."},
+ {0," --tag-relative=[yes|no]"},
+ {0," Should paths be relative to location of tag file [no; yes when -e]?"},
+ {1," --totals=[yes|no]"},
+ {1," Print statistics about source and tag files [no]."},
+ {1," --verbose=[yes|no]"},
+ {1," Enable verbose messages describing actions on each source file."},
+ {1," --version"},
+ {1," Print version identifier to standard output."},
+ {1, NULL}
+};
+
+static const char* const License1 =
+"This program is free software; you can redistribute it and/or\n"
+"modify it under the terms of the GNU General Public License\n"
+"as published by the Free Software Foundation; either version 2\n"
+"of the License, or (at your option) any later version.\n"
+"\n";
+static const char* const License2 =
+"This program is distributed in the hope that it will be useful,\n"
+"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+"GNU General Public License for more details.\n"
+"\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";
+
+/* Contains a set of strings describing the set of "features" compiled into
+ * the code.
+ */
+static const char *const Features [] = {
+#ifdef WIN32
+ "win32",
+#endif
+#ifdef DJGPP
+ "msdos_32",
+#else
+# ifdef MSDOS
+ "msdos_16",
+# endif
+#endif
+#ifdef OS2
+ "os2",
+#endif
+#ifdef AMIGA
+ "amiga",
+#endif
+#ifdef VMS
+ "vms",
+#endif
+#ifdef HAVE_FNMATCH
+ "wildcards",
+#endif
+#ifdef HAVE_REGEX
+ "regex",
+#endif
+#ifndef EXTERNAL_SORT
+ "internal-sort",
+#endif
+#ifdef CUSTOM_CONFIGURATION_FILE
+ "custom-conf",
+#endif
+#if (defined (MSDOS) || defined (WIN32) || defined (OS2)) && defined (UNIX_PATH_SEPARATOR)
+ "unix-path-separator",
+#endif
+#ifdef DEBUG
+ "debug",
+#endif
+ NULL
+};
+
+/*
+* FUNCTION PROTOTYPES
+*/
+static boolean parseFileOptions (const char *const fileName);
+
+/*
+* FUNCTION DEFINITIONS
+*/
+
+extern void verbose (const char *const format, ...)
+{
+ if (Option.verbose)
+ {
+ va_list ap;
+ va_start (ap, format);
+ vprintf (format, ap);
+ va_end (ap);
+ }
+}
+
+static char *stringCopy (const char *const string)
+{
+ char* result = NULL;
+ if (string != NULL)
+ result = eStrdup (string);
+ return result;
+}
+
+static void freeString (char **const pString)
+{
+ if (*pString != NULL)
+ {
+ eFree (*pString);
+ *pString = NULL;
+ }
+}
+
+extern void freeList (stringList** const pList)
+{
+ if (*pList != NULL)
+ {
+ stringListDelete (*pList);
+ *pList = NULL;
+ }
+}
+
+extern void setDefaultTagFileName (void)
+{
+ if (Option.tagFileName != NULL)
+ ; /* accept given name */
+ else if (Option.etags)
+ Option.tagFileName = stringCopy (ETAGS_FILE);
+ else
+ Option.tagFileName = stringCopy (CTAGS_FILE);
+}
+
+extern boolean filesRequired (void)
+{
+ boolean result = FilesRequired;
+ if (Option.recurse)
+ result = FALSE;
+ return result;
+}
+
+extern void checkOptions (void)
+{
+ const char* notice;
+ if (Option.xref)
+ {
+ notice = "xref output";
+ if (Option.include.fileNames)
+ {
+ error (WARNING, "%s disables file name tags", notice);
+ Option.include.fileNames = FALSE;
+ }
+ }
+ if (Option.append)
+ {
+ notice = "append mode is not compatible with";
+ if (isDestinationStdout ())
+ error (FATAL, "%s tags to stdout", notice);
+ }
+ if (Option.filter)
+ {
+ notice = "filter mode";
+ if (Option.printTotals)
+ {
+ error (WARNING, "%s disables totals", notice);
+ Option.printTotals = FALSE;
+ }
+ if (Option.tagFileName != NULL)
+ error (WARNING, "%s ignores output tag file name", notice);
+ }
+}
+
+static void setEtagsMode (void)
+{
+ Option.etags = TRUE;
+ Option.sorted = SO_UNSORTED;
+ Option.lineDirectives = FALSE;
+ Option.tagRelative = TRUE;
+}
+
+extern void testEtagsInvocation (void)
+{
+ char* const execName = eStrdup (getExecutableName ());
+ char* const etags = eStrdup (ETAGS);
+#ifdef CASE_INSENSITIVE_FILENAMES
+ toLowerString (execName);
+ toLowerString (etags);
+#endif
+ if (strstr (execName, etags) != NULL)
+ {
+ verbose ("Running in etags mode\n");
+ setEtagsMode ();
+ }
+ eFree (execName);
+ eFree (etags);
+}
+
+/*
+ * Cooked argument parsing
+ */
+
+static void parseShortOption (cookedArgs *const args)
+{
+ args->simple [0] = *args->shortOptions++;
+ args->simple [1] = '\0';
+ args->item = args->simple;
+ if (! isCompoundOption (*args->simple))
+ args->parameter = "";
+ else if (*args->shortOptions == '\0')
+ {
+ argForth (args->args);
+ if (argOff (args->args))
+ args->parameter = NULL;
+ else
+ args->parameter = argItem (args->args);
+ args->shortOptions = NULL;
+ }
+ else
+ {
+ args->parameter = args->shortOptions;
+ args->shortOptions = NULL;
+ }
+}
+
+static void parseLongOption (cookedArgs *const args, const char *item)
+{
+ const char* const equal = strchr (item, '=');
+ if (equal == NULL)
+ {
+ args->item = eStrdup (item); /* FIXME: memory leak. */
+ args->parameter = "";
+ }
+ else
+ {
+ const size_t length = equal - item;
+ args->item = xMalloc (length + 1, char); /* FIXME: memory leak. */
+ strncpy (args->item, item, length);
+ args->item [length] = '\0';
+ args->parameter = equal + 1;
+ }
+ Assert (args->item != NULL);
+ Assert (args->parameter != NULL);
+}
+
+static void cArgRead (cookedArgs *const current)
+{
+ char* item;
+
+ Assert (current != NULL);
+ if (! argOff (current->args))
+ {
+ item = argItem (current->args);
+ current->shortOptions = NULL;
+ Assert (item != NULL);
+ if (strncmp (item, "--", (size_t) 2) == 0)
+ {
+ current->isOption = TRUE;
+ current->longOption = TRUE;
+ parseLongOption (current, item + 2);
+ Assert (current->item != NULL);
+ Assert (current->parameter != NULL);
+ }
+ else if (*item == '-')
+ {
+ current->isOption = TRUE;
+ current->longOption = FALSE;
+ current->shortOptions = item + 1;
+ parseShortOption (current);
+ }
+ else
+ {
+ current->isOption = FALSE;
+ current->longOption = FALSE;
+ current->item = item;
+ current->parameter = NULL;
+ }
+ }
+}
+
+extern cookedArgs* cArgNewFromString (const char* string)
+{
+ cookedArgs* const result = xMalloc (1, cookedArgs);
+ memset (result, 0, sizeof (cookedArgs));
+ result->args = argNewFromString (string);
+ cArgRead (result);
+ return result;
+}
+
+extern cookedArgs* cArgNewFromArgv (char* const* const argv)
+{
+ cookedArgs* const result = xMalloc (1, cookedArgs);
+ memset (result, 0, sizeof (cookedArgs));
+ result->args = argNewFromArgv (argv);
+ cArgRead (result);
+ return result;
+}
+
+extern cookedArgs* cArgNewFromFile (FILE* const fp)
+{
+ cookedArgs* const result = xMalloc (1, cookedArgs);
+ memset (result, 0, sizeof (cookedArgs));
+ result->args = argNewFromFile (fp);
+ cArgRead (result);
+ return result;
+}
+
+extern cookedArgs* cArgNewFromLineFile (FILE* const fp)
+{
+ cookedArgs* const result = xMalloc (1, cookedArgs);
+ memset (result, 0, sizeof (cookedArgs));
+ result->args = argNewFromLineFile (fp);
+ cArgRead (result);
+ return result;
+}
+
+extern void cArgDelete (cookedArgs* const current)
+{
+ Assert (current != NULL);
+ argDelete (current->args);
+ memset (current, 0, sizeof (cookedArgs));
+ eFree (current);
+}
+
+static boolean cArgOptionPending (cookedArgs* const current)
+{
+ boolean result = FALSE;
+ if (current->shortOptions != NULL)
+ if (*current->shortOptions != '\0')
+ result = TRUE;
+ return result;
+}
+
+extern boolean cArgOff (cookedArgs* const current)
+{
+ Assert (current != NULL);
+ return (boolean) (argOff (current->args) && ! cArgOptionPending (current));
+}
+
+extern boolean cArgIsOption (cookedArgs* const current)
+{
+ Assert (current != NULL);
+ return current->isOption;
+}
+
+extern const char* cArgItem (cookedArgs* const current)
+{
+ Assert (current != NULL);
+ return current->item;
+}
+
+extern void cArgForth (cookedArgs* const current)
+{
+ Assert (current != NULL);
+ Assert (! cArgOff (current));
+ if (cArgOptionPending (current))
+ parseShortOption (current);
+ else
+ {
+ Assert (! argOff (current->args));
+ argForth (current->args);
+ if (! argOff (current->args))
+ cArgRead (current);
+ else
+ {
+ current->isOption = FALSE;
+ current->longOption = FALSE;
+ current->shortOptions = NULL;
+ current->item = NULL;
+ current->parameter = NULL;
+ }
+ }
+}
+
+/*
+ * File extension and language mapping
+ */
+
+static void addExtensionList (
+ stringList *const slist, const char *const elist, const boolean clear)
+{
+ char *const extensionList = eStrdup (elist);
+ const char *extension = NULL;
+ boolean first = TRUE;
+
+ if (clear)
+ {
+ verbose (" clearing\n");
+ stringListClear (slist);
+ }
+ verbose (" adding: ");
+ if (elist != NULL && *elist != '\0')
+ {
+ extension = extensionList;
+ if (elist [0] == EXTENSION_SEPARATOR)
+ ++extension;
+ }
+ while (extension != NULL)
+ {
+ char *separator = strchr (extension, EXTENSION_SEPARATOR);
+ if (separator != NULL)
+ *separator = '\0';
+ verbose ("%s%s", first ? "" : ", ",
+ *extension == '\0' ? "(NONE)" : extension);
+ stringListAdd (slist, vStringNewInit (extension));
+ first = FALSE;
+ if (separator == NULL)
+ extension = NULL;
+ else
+ extension = separator + 1;
+ }
+ if (Option.verbose)
+ {
+ printf ("\n now: ");
+ stringListPrint (slist);
+ putchar ('\n');
+ }
+ eFree (extensionList);
+}
+
+static boolean isFalse (const char *parameter)
+{
+ return (boolean) (
+ strcasecmp (parameter, "0" ) == 0 ||
+ strcasecmp (parameter, "n" ) == 0 ||
+ strcasecmp (parameter, "no" ) == 0 ||
+ strcasecmp (parameter, "off") == 0);
+}
+
+static boolean isTrue (const char *parameter)
+{
+ return (boolean) (
+ strcasecmp (parameter, "1" ) == 0 ||
+ strcasecmp (parameter, "y" ) == 0 ||
+ strcasecmp (parameter, "yes") == 0 ||
+ strcasecmp (parameter, "on" ) == 0);
+}
+
+/* Determines whether the specified file name is considered to be a header
+ * file for the purposes of determining whether enclosed tags are global or
+ * static.
+ */
+extern boolean isIncludeFile (const char *const fileName)
+{
+ boolean result = FALSE;
+ const char *const extension = fileExtension (fileName);
+ if (Option.headerExt != NULL)
+ result = stringListExtensionMatched (Option.headerExt, extension);
+ return result;
+}
+
+/*
+ * Specific option processing
+ */
+
+static void processEtagsInclude (
+ const char *const option, const char *const parameter)
+{
+ if (! Option.etags)
+ error (FATAL, "Etags must be enabled to use \"%s\" option", option);
+ else
+ {
+ vString *const file = vStringNewInit (parameter);
+ if (Option.etagsInclude == NULL)
+ Option.etagsInclude = stringListNew ();
+ stringListAdd (Option.etagsInclude, file);
+ FilesRequired = FALSE;
+ }
+}
+
+static void processExcludeOption (
+ const char *const option, const char *const parameter)
+{
+ const char *const fileName = parameter + 1;
+ if (parameter [0] == '\0')
+ freeList (&Excluded);
+ else if (parameter [0] == '@')
+ {
+ stringList* const sl = stringListNewFromFile (fileName);
+ if (sl == NULL)
+ error (FATAL | PERROR, "cannot open \"%s\"", fileName);
+ if (Excluded == NULL)
+ Excluded = sl;
+ else
+ stringListCombine (Excluded, sl);
+ verbose (" adding exclude patterns from %s\n", fileName);
+ }
+ else
+ {
+ vString *const item = vStringNewInit (parameter);
+ if (Excluded == NULL)
+ Excluded = stringListNew ();
+ stringListAdd (Excluded, item);
+ verbose (" adding exclude pattern: %s\n", parameter);
+ }
+}
+
+extern boolean isExcludedFile (const char* const name)
+{
+ const char* base = baseFilename (name);
+ boolean result = FALSE;
+ if (Excluded != NULL)
+ {
+ result = stringListFileMatched (Excluded, base);
+ if (! result && name != base)
+ result = stringListFileMatched (Excluded, name);
+ }
+#ifdef AMIGA
+ /* not a good solution, but the only one which works often */
+ if (! result)
+ result = (boolean) (strcmp (name, TagFile.name) == 0);
+#endif
+ return result;
+}
+
+static void processExcmdOption (
+ const char *const option, const char *const parameter)
+{
+ switch (*parameter)
+ {
+ case 'm': Option.locate = EX_MIX; break;
+ case 'n': Option.locate = EX_LINENUM; break;
+ case 'p': Option.locate = EX_PATTERN; break;
+ default:
+ error (FATAL, "Invalid value for \"%s\" option", option);
+ break;
+ }
+}
+
+static void processExtraTagsOption (
+ const char *const option, const char *const parameter)
+{
+ struct sInclude *const inc = &Option.include;
+ const char *p = parameter;
+ boolean mode = TRUE;
+ int c;
+
+ if (*p != '+' && *p != '-')
+ {
+ inc->fileNames = FALSE;
+ inc->qualifiedTags = FALSE;
+#if 0
+ inc->fileScope = FALSE;
+#endif
+ }
+ while ((c = *p++) != '\0') switch (c)
+ {
+ case '+': mode = TRUE; break;
+ case '-': mode = FALSE; break;
+
+ case 'f': inc->fileNames = mode; break;
+ case 'q': inc->qualifiedTags = mode; break;
+#if 0
+ case 'F': inc->fileScope = mode; break;
+#endif
+
+ default: error(WARNING, "Unsupported parameter '%c' for \"%s\" option",
+ c, option);
+ break;
+ }
+}
+
+static void processFieldsOption (
+ const char *const option, const char *const parameter)
+{
+ struct sExtFields *field = &Option.extensionFields;
+ const char *p = parameter;
+ boolean mode = TRUE;
+ int c;
+
+ if (*p != '+' && *p != '-')
+ {
+ field->access = FALSE;
+ field->fileScope = FALSE;
+ field->implementation = FALSE;
+ field->inheritance = FALSE;
+ field->kind = FALSE;
+ field->kindKey = FALSE;
+ field->kindLong = FALSE;
+ field->language = FALSE;
+ field->scope = FALSE;
+ field->typeRef = FALSE;
+ }
+ while ((c = *p++) != '\0') switch (c)
+ {
+ case '+': mode = TRUE; break;
+ case '-': mode = FALSE; break;
+
+ case 'a': field->access = mode; break;
+ case 'f': field->fileScope = mode; break;
+ case 'm': field->implementation = mode; break;
+ case 'i': field->inheritance = mode; break;
+ case 'k': field->kind = mode; break;
+ case 'K': field->kindLong = mode; break;
+ case 'l': field->language = mode; break;
+ case 'n': field->lineNumber = mode; break;
+ case 's': field->scope = mode; break;
+ case 'S': field->signature = mode; break;
+ case 'z': field->kindKey = mode; break;
+ case 't': field->typeRef = mode; break;
+
+ default: error(WARNING, "Unsupported parameter '%c' for \"%s\" option",
+ c, option);
+ break;
+ }
+}
+
+static void processFilterTerminatorOption (
+ const char *const option, const char *const parameter)
+{
+ freeString (&Option.filterTerminator);
+ Option.filterTerminator = stringCopy (parameter);
+}
+
+static void processFormatOption (
+ const char *const option, const char *const parameter)
+{
+ unsigned int format;
+
+ if (sscanf (parameter, "%u", &format) < 1)
+ error (FATAL, "Invalid value for \"%s\" option",option);
+ else if (format <= (unsigned int) MaxSupportedTagFormat)
+ Option.tagFileFormat = format;
+ else
+ error (FATAL, "Unsupported value for \"%s\" option", option);
+}
+
+static void printInvocationDescription (void)
+{
+ printf (INVOCATION, getExecutableName ());
+}
+
+static void printOptionDescriptions (const optionDescription *const optDesc)
+{
+ int i;
+ for (i = 0 ; optDesc [i].description != NULL ; ++i)
+ {
+ if (! Option.etags || optDesc [i].usedByEtags)
+ puts (optDesc [i].description);
+ }
+}
+
+static void printFeatureList (void)
+{
+ int i;
+
+ for (i = 0 ; Features [i] != NULL ; ++i)
+ {
+ if (i == 0)
+ printf (" Optional compiled features: ");
+ printf ("%s+%s", (i>0 ? ", " : ""), Features [i]);
+#ifdef CUSTOM_CONFIGURATION_FILE
+ if (strcmp (Features [i], "custom-conf") == 0)
+ printf ("=%s", CUSTOM_CONFIGURATION_FILE);
+#endif
+ }
+ if (i > 0)
+ putchar ('\n');
+}
+
+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 ();
+}
+
+static void processHelpOption (
+ const char *const option,
+ const char *const parameter)
+{
+ printProgramIdentification ();
+ putchar ('\n');
+ printInvocationDescription ();
+ putchar ('\n');
+ printOptionDescriptions (LongOptionDescription);
+ exit (0);
+}
+
+static void processLanguageForceOption (
+ const char *const option, const char *const parameter)
+{
+ langType language;
+ if (strcasecmp (parameter, "auto") == 0)
+ language = LANG_AUTO;
+ else
+ language = getNamedLanguage (parameter);
+
+ if (strcmp (option, "lang") == 0 || strcmp (option, "language") == 0)
+ error (WARNING,
+ "\"--%s\" option is obsolete; use \"--language-force\" instead",
+ option);
+ if (language == LANG_IGNORE)
+ error (FATAL, "Unknown language \"%s\" in \"%s\" option", parameter, option);
+ else
+ Option.language = language;
+}
+static char* skipPastMap (char* p)
+{
+ while (*p != EXTENSION_SEPARATOR &&
+ *p != PATTERN_START && *p != ',' && *p != '\0')
+ ++p;
+ return p;
+}
+
+/* Parses the mapping beginning at `map', adds it to the language map, and
+ * returns first character past the map.
+ */
+static char* addLanguageMap (const langType language, char* map)
+{
+ char* p = NULL;
+ const char first = *map;
+ if (first == EXTENSION_SEPARATOR) /* extension map */
+ {
+ ++map;
+ p = skipPastMap (map);
+ if (*p == '\0')
+ {
+ verbose (" .%s", map);
+ addLanguageExtensionMap (language, map);
+ p = map + strlen (map);
+ }
+ else
+ {
+ const char separator = *p;
+ *p = '\0';
+ verbose (" .%s", map);
+ addLanguageExtensionMap (language, map);
+ *p = separator;
+ }
+ }
+ else if (first == PATTERN_START) /* pattern map */
+ {
+ ++map;
+ for (p = map ; *p != PATTERN_STOP && *p != '\0' ; ++p)
+ {
+ if (*p == '\\' && *(p + 1) == PATTERN_STOP)
+ ++p;
+ }
+ if (*p == '\0')
+ error (FATAL, "Unterminated file name pattern for %s language",
+ getLanguageName (language));
+ else
+ {
+ *p++ = '\0';
+ verbose (" (%s)", map);
+ addLanguagePatternMap (language, map);
+ }
+ }
+ else
+ error (FATAL, "Badly formed language map for %s language",
+ getLanguageName (language));
+ return p;
+}
+
+static char* processLanguageMap (char* map)
+{
+ char* const separator = strchr (map, ':');
+ char* result = NULL;
+ if (separator != NULL)
+ {
+ langType language;
+ char *list = separator + 1;
+ boolean clear = FALSE;
+ *separator = '\0';
+ language = getNamedLanguage (map);
+ if (language != LANG_IGNORE)
+ {
+ const char *const deflt = "default";
+ char* p;
+ if (*list == '+')
+ ++list;
+ else
+ clear = TRUE;
+ for (p = list ; *p != ',' && *p != '\0' ; ++p) /*no-op*/ ;
+ if ((size_t) (p - list) == strlen (deflt) &&
+ strncasecmp (list, deflt, p - list) == 0)
+ {
+ verbose (" Restoring default %s language map: ", getLanguageName (language));
+ installLanguageMapDefault (language);
+ list = p;
+ }
+ else
+ {
+ if (clear)
+ {
+ verbose (" Setting %s language map:", getLanguageName (language));
+ clearLanguageMap (language);
+ }
+ else
+ verbose (" Adding to %s language map:", getLanguageName (language));
+ while (list != NULL && *list != '\0' && *list != ',')
+ list = addLanguageMap (language, list);
+ verbose ("\n");
+ }
+ if (list != NULL && *list == ',')
+ ++list;
+ result = list;
+ }
+ }
+ return result;
+}
+
+static void processLanguageMapOption (
+ const char *const option, const char *const parameter)
+{
+ char *const maps = eStrdup (parameter);
+ char *map = maps;
+
+ if (strcmp (parameter, "default") == 0)
+ {
+ verbose (" Restoring default language maps:\n");
+ installLanguageMapDefaults ();
+ }
+ else while (map != NULL && *map != '\0')
+ {
+ char* const next = processLanguageMap (map);
+ if (next == NULL)
+ error (WARNING, "Unknown language \"%s\" in \"%s\" option", parameter, option);
+ map = next;
+ }
+ eFree (maps);
+}
+
+static void processLanguagesOption (
+ const char *const option, const char *const parameter)
+{
+ char *const langs = eStrdup (parameter);
+ enum { Add, Remove, Replace } mode = Replace;
+ boolean first = TRUE;
+ char *lang = langs;
+ const char* prefix = "";
+ verbose (" Enabled languages: ");
+ while (lang != NULL)
+ {
+ char *const end = strchr (lang, ',');
+ if (lang [0] == '+')
+ {
+ ++lang;
+ mode = Add;
+ prefix = "+ ";
+ }
+ else if (lang [0] == '-')
+ {
+ ++lang;
+ mode = Remove;
+ prefix = "- ";
+ }
+ if (mode == Replace)
+ enableLanguages (FALSE);
+ if (end != NULL)
+ *end = '\0';
+ if (lang [0] != '\0')
+ {
+ if (strcmp (lang, "all") == 0)
+ enableLanguages ((boolean) (mode != Remove));
+ else
+ {
+ const langType language = getNamedLanguage (lang);
+ if (language == LANG_IGNORE)
+ error (WARNING, "Unknown language \"%s\" in \"%s\" option", lang, option);
+ else
+ enableLanguage (language, (boolean) (mode != Remove));
+ }
+ verbose ("%s%s%s", (first ? "" : ", "), prefix, lang);
+ prefix = "";
+ first = FALSE;
+ if (mode == Replace)
+ mode = Add;
+ }
+ lang = (end != NULL ? end + 1 : NULL);
+ }
+ verbose ("\n");
+ eFree (langs);
+}
+
+static void processLicenseOption (
+ const char *const option,
+ const char *const parameter)
+{
+ printProgramIdentification ();
+ puts ("");
+ puts (License1);
+ puts (License2);
+ exit (0);
+}
+
+static void processListKindsOption (
+ const char *const option, const char *const parameter)
+{
+ if (parameter [0] == '\0' || strcasecmp (parameter, "all") == 0)
+ printLanguageKinds (LANG_AUTO);
+ else
+ {
+ langType language = getNamedLanguage (parameter);
+ if (language == LANG_IGNORE)
+ error (FATAL, "Unknown language \"%s\" in \"%s\" option", parameter, option);
+ else
+ printLanguageKinds (language);
+ }
+ exit (0);
+}
+
+static void processListMapsOption (
+ const char *const option,
+ const char *const parameter)
+{
+ if (parameter [0] == '\0' || strcasecmp (parameter, "all") == 0)
+ printLanguageMaps (LANG_AUTO);
+ else
+ {
+ langType language = getNamedLanguage (parameter);
+ if (language == LANG_IGNORE)
+ error (FATAL, "Unknown language \"%s\" in \"%s\" option", parameter, option);
+ else
+ printLanguageMaps (language);
+ }
+ exit (0);
+}
+
+static void processListLanguagesOption (
+ const char *const option,
+ const char *const parameter)
+{
+ printLanguageList ();
+ exit (0);
+}
+
+static void processOptionFile (
+ const char *const option, const char *const parameter)
+{
+ if (parameter [0] == '\0')
+ error (WARNING, "no option file supplied for \"%s\"", option);
+ else if (! parseFileOptions (parameter))
+ error (FATAL | PERROR, "cannot open option file \"%s\"", parameter);
+}
+
+static void processSortOption (
+ const char *const option, const char *const parameter)
+{
+ if (isFalse (parameter))
+ Option.sorted = SO_UNSORTED;
+ else if (isTrue (parameter))
+ Option.sorted = SO_SORTED;
+ else if (strcasecmp (parameter, "f") == 0 ||
+ strcasecmp (parameter, "fold") == 0 ||
+ strcasecmp (parameter, "foldcase") == 0)
+ Option.sorted = SO_FOLDSORTED;
+ else
+ error (FATAL, "Invalid value for \"%s\" option", option);
+}
+
+static void installHeaderListDefaults (void)
+{
+ Option.headerExt = stringListNewFromArgv (HeaderExtensions);
+ if (Option.verbose)
+ {
+ printf (" Setting default header extensions: ");
+ stringListPrint (Option.headerExt);
+ putchar ('\n');
+ }
+}
+
+static void processHeaderListOption (const int option, const char *parameter)
+{
+ /* Check to make sure that the user did not enter "ctags -h *.c"
+ * by testing to see if the list is a filename that exists.
+ */
+ if (doesFileExist (parameter))
+ error (FATAL, "-%c: Invalid list", option);
+ if (strcmp (parameter, "default") == 0)
+ installHeaderListDefaults ();
+ else
+ {
+ boolean clear = TRUE;
+
+ if (parameter [0] == '+')
+ {
+ ++parameter;
+ clear = FALSE;
+ }
+ if (Option.headerExt == NULL)
+ Option.headerExt = stringListNew ();
+ verbose (" Header Extensions:\n");
+ addExtensionList (Option.headerExt, parameter, clear);
+ }
+}
+
+/*
+ * Token ignore processing
+ */
+
+/* Determines whether or not "name" should be ignored, per the ignore list.
+ */
+extern boolean isIgnoreToken (
+ const char *const name, boolean *const pIgnoreParens,
+ const char **const replacement)
+{
+ boolean result = FALSE;
+
+ if (Option.ignore != NULL)
+ {
+ const size_t nameLen = strlen (name);
+ unsigned int i;
+
+ if (pIgnoreParens != NULL)
+ *pIgnoreParens = FALSE;
+
+ for (i = 0 ; i < stringListCount (Option.ignore) ; ++i)
+ {
+ vString *token = stringListItem (Option.ignore, i);
+
+ if (strncmp (vStringValue (token), name, nameLen) == 0)
+ {
+ const size_t tokenLen = vStringLength (token);
+
+ if (nameLen == tokenLen)
+ {
+ result = TRUE;
+ break;
+ }
+ else if (tokenLen == nameLen + 1 &&
+ vStringChar (token, tokenLen - 1) == '+')
+ {
+ result = TRUE;
+ if (pIgnoreParens != NULL)
+ *pIgnoreParens = TRUE;
+ break;
+ }
+ else if (vStringChar (token, nameLen) == '=')
+ {
+ if (replacement != NULL)
+ *replacement = vStringValue (token) + nameLen + 1;
+ break;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+static void saveIgnoreToken (vString *const ignoreToken)
+{
+ if (Option.ignore == NULL)
+ Option.ignore = stringListNew ();
+ stringListAdd (Option.ignore, ignoreToken);
+ verbose (" ignore token: %s\n", vStringValue (ignoreToken));
+}
+
+static void readIgnoreList (const char *const list)
+{
+ char* newList = stringCopy (list);
+ const char *token = strtok (newList, IGNORE_SEPARATORS);
+
+ while (token != NULL)
+ {
+ vString *const entry = vStringNewInit (token);
+
+ saveIgnoreToken (entry);
+ token = strtok (NULL, IGNORE_SEPARATORS);
+ }
+ eFree (newList);
+}
+
+static void addIgnoreListFromFile (const char *const fileName)
+{
+ stringList* tokens = stringListNewFromFile (fileName);
+ if (tokens == NULL)
+ error (FATAL | PERROR, "cannot open \"%s\"", fileName);
+ if (Option.ignore == NULL)
+ Option.ignore = tokens;
+ else
+ stringListCombine (Option.ignore, tokens);
+}
+
+static void processIgnoreOption (const char *const list)
+{
+ if (strchr ("@./\\", list [0]) != NULL)
+ {
+ const char* fileName = (*list == '@') ? list + 1 : list;
+ addIgnoreListFromFile (fileName);
+ }
+#if defined (MSDOS) || defined (WIN32) || defined (OS2)
+ else if (isalpha (list [0]) && list [1] == ':')
+ addIgnoreListFromFile (list);
+#endif
+ else if (strcmp (list, "-") == 0)
+ {
+ freeList (&Option.ignore);
+ verbose (" clearing list\n");
+ }
+ else
+ readIgnoreList (list);
+}
+
+static void processVersionOption (
+ const char *const option,
+ const char *const parameter)
+{
+ printProgramIdentification ();
+ exit (0);
+}
+
+/*
+ * Option tables
+ */
+
+static parametricOption ParametricOptions [] = {
+ { "etags-include", processEtagsInclude, FALSE },
+ { "exclude", processExcludeOption, FALSE },
+ { "excmd", processExcmdOption, FALSE },
+ { "extra", processExtraTagsOption, FALSE },
+ { "fields", processFieldsOption, FALSE },
+ { "filter-terminator", processFilterTerminatorOption, TRUE },
+ { "format", processFormatOption, TRUE },
+ { "help", processHelpOption, TRUE },
+ { "lang", processLanguageForceOption, FALSE },
+ { "language", processLanguageForceOption, FALSE },
+ { "language-force", processLanguageForceOption, FALSE },
+ { "languages", processLanguagesOption, FALSE },
+ { "langdef", processLanguageDefineOption, FALSE },
+ { "langmap", processLanguageMapOption, FALSE },
+ { "license", processLicenseOption, TRUE },
+ { "list-kinds", processListKindsOption, TRUE },
+ { "list-maps", processListMapsOption, TRUE },
+ { "list-languages", processListLanguagesOption, TRUE },
+ { "options", processOptionFile, FALSE },
+ { "sort", processSortOption, TRUE },
+ { "version", processVersionOption, TRUE },
+};
+
+static booleanOption BooleanOptions [] = {
+ { "append", &Option.append, TRUE },
+ { "file-scope", &Option.include.fileScope, FALSE },
+ { "file-tags", &Option.include.fileNames, FALSE },
+ { "filter", &Option.filter, TRUE },
+ { "if0", &Option.if0, FALSE },
+ { "kind-long", &Option.kindLong, TRUE },
+ { "line-directives",&Option.lineDirectives, FALSE },
+ { "links", &Option.followLinks, FALSE },
+#ifdef RECURSE_SUPPORTED
+ { "recurse", &Option.recurse, FALSE },
+#endif
+ { "tag-relative", &Option.tagRelative, TRUE },
+ { "totals", &Option.printTotals, TRUE },
+ { "verbose", &Option.verbose, FALSE },
+};
+
+/*
+ * Generic option parsing
+ */
+
+static void checkOptionOrder (const char* const option)
+{
+ if (NonOptionEncountered)
+ error (FATAL, "-%s option may not follow a file name", option);
+}
+
+static boolean processParametricOption (
+ const char *const option, const char *const parameter)
+{
+ const int count = sizeof (ParametricOptions) / sizeof (parametricOption);
+ boolean found = FALSE;
+ int i;
+
+ for (i = 0 ; i < count && ! found ; ++i)
+ {
+ parametricOption* const entry = &ParametricOptions [i];
+ if (strcmp (option, entry->name) == 0)
+ {
+ found = TRUE;
+ if (entry->initOnly)
+ checkOptionOrder (option);
+ (entry->handler) (option, parameter);
+ }
+ }
+ return found;
+}
+
+static boolean getBooleanOption (
+ const char *const option, const char *const parameter)
+{
+ boolean selection = TRUE;
+
+ if (parameter [0] == '\0')
+ selection = TRUE;
+ else if (isFalse (parameter))
+ selection = FALSE;
+ else if (isTrue (parameter))
+ selection = TRUE;
+ else
+ error (FATAL, "Invalid value for \"%s\" option", option);
+
+ return selection;
+}
+
+static boolean processBooleanOption (
+ const char *const option, const char *const parameter)
+{
+ const int count = sizeof (BooleanOptions) / sizeof (booleanOption);
+ boolean found = FALSE;
+ int i;
+
+ for (i = 0 ; i < count && ! found ; ++i)
+ {
+ booleanOption* const entry = &BooleanOptions [i];
+ if (strcmp (option, entry->name) == 0)
+ {
+ found = TRUE;
+ if (entry->initOnly)
+ checkOptionOrder (option);
+ *entry->pValue = getBooleanOption (option, parameter);
+ }
+ }
+ return found;
+}
+
+static void processLongOption (
+ const char *const option, const char *const parameter)
+{
+ Assert (parameter != NULL);
+ if (parameter == NULL && parameter [0] == '\0')
+ verbose (" Option: --%s\n", option);
+ else
+ verbose (" Option: --%s=%s\n", option, parameter);
+
+ if (processBooleanOption (option, parameter))
+ ;
+ else if (processParametricOption (option, parameter))
+ ;
+ else if (processKindOption (option, parameter))
+ ;
+ else if (processRegexOption (option, parameter))
+ ;
+#ifndef RECURSE_SUPPORTED
+ else if (strcmp (option, "recurse") == 0)
+ error (WARNING, "%s option not supported on this host", option);
+#endif
+ else
+ error (FATAL, "Unknown option: --%s", option);
+}
+
+static void processShortOption (
+ const char *const option, const char *const parameter)
+{
+ if (parameter == NULL || parameter [0] == '\0')
+ verbose (" Option: -%s\n", option);
+ else
+ verbose (" Option: -%s %s\n", option, parameter);
+
+ if (isCompoundOption (*option) && (parameter == NULL || parameter [0] == '\0'))
+ error (FATAL, "Missing parameter for \"%s\" option", option);
+ else switch (*option)
+ {
+ case '?':
+ processHelpOption ("?", NULL);
+ exit (0);
+ break;
+ case 'a':
+ checkOptionOrder (option);
+ Option.append = TRUE;
+ break;
+#ifdef DEBUG
+ case 'b':
+ if (atol (parameter) < 0)
+ error (FATAL, "-%s: Invalid line number", option);
+ Option.breakLine = atol (parameter);
+ break;
+ case 'D':
+ Option.debugLevel = strtol (parameter, NULL, 0);
+ if (debug (DEBUG_STATUS))
+ Option.verbose = TRUE;
+ break;
+#endif
+ case 'B':
+ Option.backward = TRUE;
+ break;
+ case 'e':
+ checkOptionOrder (option);
+ setEtagsMode ();
+ break;
+ case 'f':
+ case 'o':
+ checkOptionOrder (option);
+ if (Option.tagFileName != NULL)
+ {
+ error (WARNING,
+ "-%s option specified more than once, last value used",
+ option);
+ freeString (&Option.tagFileName);
+ }
+ else if (parameter [0] == '-' && parameter [1] != '\0')
+ error (FATAL, "output file name may not begin with a '-'");
+ Option.tagFileName = stringCopy (parameter);
+ break;
+ case 'F':
+ Option.backward = FALSE;
+ break;
+ case 'h':
+ processHeaderListOption (*option, parameter);
+ break;
+ case 'I':
+ processIgnoreOption (parameter);
+ break;
+ case 'L':
+ if (Option.fileList != NULL)
+ {
+ error (WARNING,
+ "-%s option specified more than once, last value used",
+ option);
+ freeString (&Option.fileList);
+ }
+ Option.fileList = stringCopy (parameter);
+ break;
+ case 'n':
+ Option.locate = EX_LINENUM;
+ break;
+ case 'N':
+ Option.locate = EX_PATTERN;
+ break;
+ case 'R':
+#ifdef RECURSE_SUPPORTED
+ Option.recurse = TRUE;
+#else
+ error (WARNING, "-%s option not supported on this host", option);
+#endif
+ break;
+ case 'u':
+ checkOptionOrder (option);
+ Option.sorted = SO_UNSORTED;
+ break;
+ case 'V':
+ Option.verbose = TRUE;
+ break;
+ case 'w':
+ /* silently ignored */
+ break;
+ case 'x':
+ checkOptionOrder (option);
+ Option.xref = TRUE;
+ break;
+ default:
+ error (FATAL, "Unknown option: -%s", option);
+ break;
+ }
+}
+
+extern void parseOption (cookedArgs* const args)
+{
+ Assert (! cArgOff (args));
+ if (args->isOption)
+ {
+ if (args->longOption)
+ processLongOption (args->item, args->parameter);
+ else
+ {
+ const char *parameter = args->parameter;
+ while (*parameter == ' ')
+ ++parameter;
+ processShortOption (args->item, parameter);
+ }
+ cArgForth (args);
+ }
+}
+
+extern void parseOptions (cookedArgs* const args)
+{
+ NonOptionEncountered = FALSE;
+ while (! cArgOff (args) && cArgIsOption (args))
+ parseOption (args);
+ if (! cArgOff (args) && ! cArgIsOption (args))
+ NonOptionEncountered = TRUE;
+}
+
+static const char *CheckFile;
+static boolean checkSameFile (const char *const fileName)
+{
+ return isSameFile (CheckFile, fileName);
+}
+
+static boolean parseFileOptions (const char* const fileName)
+{
+ boolean fileFound = FALSE;
+ const char* const format = "Considering option file %s: %s\n";
+ CheckFile = fileName;
+ if (stringListHasTest (OptionFiles, checkSameFile))
+ verbose (format, fileName, "already considered");
+ else
+ {
+ FILE* const fp = fopen (fileName, "r");
+ if (fp == NULL)
+ verbose (format, fileName, "not found");
+ else
+ {
+ cookedArgs* const args = cArgNewFromLineFile (fp);
+ vString* file = vStringNewInit (fileName);
+ stringListAdd (OptionFiles, file);
+ verbose (format, fileName, "reading...");
+ parseOptions (args);
+ if (NonOptionEncountered)
+ error (WARNING, "Ignoring non-option in %s\n", fileName);
+ cArgDelete (args);
+ fclose (fp);
+ fileFound = TRUE;
+ }
+ }
+ return fileFound;
+}
+
+/* Actions to be taken before reading any other options */
+extern void previewFirstOption (cookedArgs* const args)
+{
+ while (cArgIsOption (args))
+ {
+ if (strcmp (args->item, "V") == 0 || strcmp (args->item, "verbose") == 0)
+ parseOption (args);
+ else if (strcmp (args->item, "options") == 0 &&
+ strcmp (args->parameter, "NONE") == 0)
+ {
+ fprintf (stderr, "No options will be read from files or environment\n");
+ SkipConfiguration = TRUE;
+ cArgForth (args);
+ }
+ else
+ break;
+ }
+}
+
+static void parseConfigurationFileOptionsInDirectoryWithLeafname (const char* directory, const char* leafname)
+{
+ vString* const pathname = combinePathAndFile (directory, leafname);
+ parseFileOptions (vStringValue (pathname));
+ vStringDelete (pathname);
+}
+
+static void parseConfigurationFileOptionsInDirectory (const char* directory)
+{
+ parseConfigurationFileOptionsInDirectoryWithLeafname (directory, ".ctags");
+#ifdef MSDOS_STYLE_PATH
+ parseConfigurationFileOptionsInDirectoryWithLeafname (directory, "ctags.cnf");
+#endif
+}
+
+static void parseConfigurationFileOptions (void)
+{
+ /* We parse .ctags on all systems, and additionally ctags.cnf on DOS. */
+ const char* const home = getenv ("HOME");
+#ifdef CUSTOM_CONFIGURATION_FILE
+ parseFileOptions (CUSTOM_CONFIGURATION_FILE);
+#endif
+#ifdef MSDOS_STYLE_PATH
+ parseFileOptions ("/ctags.cnf");
+#endif
+ parseFileOptions ("/etc/ctags.conf");
+ parseFileOptions ("/usr/local/etc/ctags.conf");
+ if (home != NULL)
+ {
+ parseConfigurationFileOptionsInDirectory (home);
+ }
+ else
+ {
+#ifdef MSDOS_STYLE_PATH
+ /*
+ * Windows users don't usually set HOME.
+ * The OS sets HOMEDRIVE and HOMEPATH for them.
+ */
+ const char* homeDrive = getenv ("HOMEDRIVE");
+ const char* homePath = getenv ("HOMEPATH");
+ if (homeDrive != NULL && homePath != NULL)
+ {
+ vString* const windowsHome = vStringNew ();
+ vStringCatS (windowsHome, homeDrive);
+ vStringCatS (windowsHome, homePath);
+ parseConfigurationFileOptionsInDirectory (vStringValue (windowsHome));
+ vStringDelete (windowsHome);
+ }
+#endif
+ }
+ parseConfigurationFileOptionsInDirectory (".");
+}
+
+static void parseEnvironmentOptions (void)
+{
+ const char *envOptions = NULL;
+ const char* var = NULL;
+
+ if (Option.etags)
+ {
+ var = ETAGS_ENVIRONMENT;
+ envOptions = getenv (var);
+ }
+ if (envOptions == NULL)
+ {
+ var = CTAGS_ENVIRONMENT;
+ envOptions = getenv (var);
+ }
+ if (envOptions != NULL && envOptions [0] != '\0')
+ {
+ cookedArgs* const args = cArgNewFromString (envOptions);
+ verbose ("Reading options from $CTAGS\n");
+ parseOptions (args);
+ cArgDelete (args);
+ if (NonOptionEncountered)
+ error (WARNING, "Ignoring non-option in %s variable", var);
+ }
+}
+
+extern void readOptionConfiguration (void)
+{
+ if (! SkipConfiguration)
+ {
+ parseConfigurationFileOptions ();
+ parseEnvironmentOptions ();
+ }
+}
+
+/*
+* Option initialization
+*/
+
+extern void initOptions (void)
+{
+ OptionFiles = stringListNew ();
+ verbose ("Setting option defaults\n");
+ installHeaderListDefaults ();
+ verbose (" Installing default language mappings:\n");
+ installLanguageMapDefaults ();
+
+ /* always excluded by default */
+ verbose (" Installing default exclude patterns:\n");
+ processExcludeOption (NULL, "{arch}");
+ processExcludeOption (NULL, ".arch-ids");
+ processExcludeOption (NULL, ".arch-inventory");
+ processExcludeOption (NULL, "autom4te.cache");
+ processExcludeOption (NULL, "BitKeeper");
+ processExcludeOption (NULL, ".bzr");
+ processExcludeOption (NULL, ".bzrignore");
+ processExcludeOption (NULL, "CVS");
+ processExcludeOption (NULL, ".cvsignore");
+ processExcludeOption (NULL, "_darcs");
+ processExcludeOption (NULL, ".deps");
+ processExcludeOption (NULL, "EIFGEN");
+ processExcludeOption (NULL, ".git");
+ processExcludeOption (NULL, ".hg");
+ processExcludeOption (NULL, "PENDING");
+ processExcludeOption (NULL, "RCS");
+ processExcludeOption (NULL, "RESYNC");
+ processExcludeOption (NULL, "SCCS");
+ processExcludeOption (NULL, ".svn");
+}
+
+extern void freeOptionResources (void)
+{
+ freeString (&Option.tagFileName);
+ freeString (&Option.fileList);
+ freeString (&Option.filterTerminator);
+
+ freeList (&Excluded);
+ freeList (&Option.ignore);
+ freeList (&Option.headerExt);
+ freeList (&Option.etagsInclude);
+ freeList (&OptionFiles);
+}
+
+/* vi:set tabstop=4 shiftwidth=4: */
Index: create-5.8-unused-attribute-patch/ctags-5.8-new/parse.c
===================================================================
--- create-5.8-unused-attribute-patch/ctags-5.8-new/parse.c (nonexistent)
+++ create-5.8-unused-attribute-patch/ctags-5.8-new/parse.c (revision 5)
@@ -0,0 +1,677 @@
+/*
+* $Id: parse.c 597 2007-07-31 05:35:30Z dhiebert $
+*
+* Copyright (c) 1996-2003, Darren Hiebert
+*
+* This source code is released for free distribution under the terms of the
+* GNU General Public License.
+*
+* This module contains functions for managing source languages and
+* dispatching files to the appropriate language parser.
+*/
+
+/*
+* INCLUDE FILES
+*/
+#include "general.h" /* must always come first */
+
+#include <string.h>
+
+#include "debug.h"
+#include "entry.h"
+#include "main.h"
+#define OPTION_WRITE
+#include "options.h"
+#include "parsers.h"
+#include "read.h"
+#include "routines.h"
+#include "vstring.h"
+
+/*
+* DATA DEFINITIONS
+*/
+static parserDefinitionFunc* BuiltInParsers[] = { PARSER_LIST };
+static parserDefinition** LanguageTable = NULL;
+static unsigned int LanguageCount = 0;
+
+/*
+* FUNCTION DEFINITIONS
+*/
+
+extern void makeSimpleTag (
+ const vString* const name, kindOption* const kinds, const int kind)
+{
+ if (kinds [kind].enabled && name != NULL && vStringLength (name) > 0)
+ {
+ tagEntryInfo e;
+ initTagEntry (&e, vStringValue (name));
+
+ e.kindName = kinds [kind].name;
+ e.kind = kinds [kind].letter;
+
+ makeTagEntry (&e);
+ }
+}
+
+/*
+* parserDescription mapping management
+*/
+
+extern parserDefinition* parserNew (const char* name)
+{
+ parserDefinition* result = xCalloc (1, parserDefinition);
+ result->name = eStrdup (name);
+ return result;
+}
+
+extern const char *getLanguageName (const langType language)
+{
+ const char* result;
+ if (language == LANG_IGNORE)
+ result = "unknown";
+ else
+ {
+ Assert (0 <= language && language < (int) LanguageCount);
+ result = LanguageTable [language]->name;
+ }
+ return result;
+}
+
+extern langType getNamedLanguage (const char *const name)
+{
+ langType result = LANG_IGNORE;
+ unsigned int i;
+ Assert (name != NULL);
+ for (i = 0 ; i < LanguageCount && result == LANG_IGNORE ; ++i)
+ {
+ const parserDefinition* const lang = LanguageTable [i];
+ if (lang->name != NULL)
+ if (strcasecmp (name, lang->name) == 0)
+ result = i;
+ }
+ return result;
+}
+
+static langType getExtensionLanguage (const char *const extension)
+{
+ langType result = LANG_IGNORE;
+ unsigned int i;
+ for (i = 0 ; i < LanguageCount && result == LANG_IGNORE ; ++i)
+ {
+ stringList* const exts = LanguageTable [i]->currentExtensions;
+ if (exts != NULL && stringListExtensionMatched (exts, extension))
+ result = i;
+ }
+ return result;
+}
+
+static langType getPatternLanguage (const char *const fileName)
+{
+ langType result = LANG_IGNORE;
+ const char* base = baseFilename (fileName);
+ unsigned int i;
+ for (i = 0 ; i < LanguageCount && result == LANG_IGNORE ; ++i)
+ {
+ stringList* const ptrns = LanguageTable [i]->currentPatterns;
+ if (ptrns != NULL && stringListFileMatched (ptrns, base))
+ result = i;
+ }
+ return result;
+}
+
+#ifdef SYS_INTERPRETER
+
+/* The name of the language interpreter, either directly or as the argument
+ * to "env".
+ */
+static vString* determineInterpreter (const char* const cmd)
+{
+ vString* const interpreter = vStringNew ();
+ const char* p = cmd;
+ do
+ {
+ vStringClear (interpreter);
+ for ( ; isspace ((int) *p) ; ++p)
+ ; /* no-op */
+ for ( ; *p != '\0' && ! isspace ((int) *p) ; ++p)
+ vStringPut (interpreter, (int) *p);
+ vStringTerminate (interpreter);
+ } while (strcmp (vStringValue (interpreter), "env") == 0);
+ return interpreter;
+}
+
+static langType getInterpreterLanguage (const char *const fileName)
+{
+ langType result = LANG_IGNORE;
+ FILE* const fp = fopen (fileName, "r");
+ if (fp != NULL)
+ {
+ vString* const vLine = vStringNew ();
+ const char* const line = readLine (vLine, fp);
+ if (line != NULL && line [0] == '#' && line [1] == '!')
+ {
+ const char* const lastSlash = strrchr (line, '/');
+ const char *const cmd = lastSlash != NULL ? lastSlash+1 : line+2;
+ vString* const interpreter = determineInterpreter (cmd);
+ result = getExtensionLanguage (vStringValue (interpreter));
+ if (result == LANG_IGNORE)
+ result = getNamedLanguage (vStringValue (interpreter));
+ vStringDelete (interpreter);
+ }
+ vStringDelete (vLine);
+ fclose (fp);
+ }
+ return result;
+}
+
+#endif
+
+extern langType getFileLanguage (const char *const fileName)
+{
+ langType language = Option.language;
+ if (language == LANG_AUTO)
+ {
+ language = getExtensionLanguage (fileExtension (fileName));
+ if (language == LANG_IGNORE)
+ language = getPatternLanguage (fileName);
+#ifdef SYS_INTERPRETER
+ if (language == LANG_IGNORE)
+ {
+ fileStatus *status = eStat (fileName);
+ if (status->isExecutable)
+ language = getInterpreterLanguage (fileName);
+ }
+#endif
+ }
+ return language;
+}
+
+extern void printLanguageMap (const langType language)
+{
+ boolean first = TRUE;
+ unsigned int i;
+ stringList* map = LanguageTable [language]->currentPatterns;
+ Assert (0 <= language && language < (int) LanguageCount);
+ for (i = 0 ; map != NULL && i < stringListCount (map) ; ++i)
+ {
+ printf ("%s(%s)", (first ? "" : " "),
+ vStringValue (stringListItem (map, i)));
+ first = FALSE;
+ }
+ map = LanguageTable [language]->currentExtensions;
+ for (i = 0 ; map != NULL && i < stringListCount (map) ; ++i)
+ {
+ printf ("%s.%s", (first ? "" : " "),
+ vStringValue (stringListItem (map, i)));
+ first = FALSE;
+ }
+}
+
+extern void installLanguageMapDefault (const langType language)
+{
+ parserDefinition* lang;
+ Assert (0 <= language && language < (int) LanguageCount);
+ lang = LanguageTable [language];
+ if (lang->currentPatterns != NULL)
+ stringListDelete (lang->currentPatterns);
+ if (lang->currentExtensions != NULL)
+ stringListDelete (lang->currentExtensions);
+
+ if (lang->patterns == NULL)
+ lang->currentPatterns = stringListNew ();
+ else
+ {
+ lang->currentPatterns =
+ stringListNewFromArgv (lang->patterns);
+ }
+ if (lang->extensions == NULL)
+ lang->currentExtensions = stringListNew ();
+ else
+ {
+ lang->currentExtensions =
+ stringListNewFromArgv (lang->extensions);
+ }
+ if (Option.verbose)
+ printLanguageMap (language);
+ verbose ("\n");
+}
+
+extern void installLanguageMapDefaults (void)
+{
+ unsigned int i;
+ for (i = 0 ; i < LanguageCount ; ++i)
+ {
+ verbose (" %s: ", getLanguageName (i));
+ installLanguageMapDefault (i);
+ }
+}
+
+extern void clearLanguageMap (const langType language)
+{
+ Assert (0 <= language && language < (int) LanguageCount);
+ stringListClear (LanguageTable [language]->currentPatterns);
+ stringListClear (LanguageTable [language]->currentExtensions);
+}
+
+extern void addLanguagePatternMap (const langType language, const char* ptrn)
+{
+ vString* const str = vStringNewInit (ptrn);
+ parserDefinition* lang;
+ Assert (0 <= language && language < (int) LanguageCount);
+ lang = LanguageTable [language];
+ if (lang->currentPatterns == NULL)
+ lang->currentPatterns = stringListNew ();
+ stringListAdd (lang->currentPatterns, str);
+}
+
+extern boolean removeLanguageExtensionMap (const char *const extension)
+{
+ boolean result = FALSE;
+ unsigned int i;
+ for (i = 0 ; i < LanguageCount && ! result ; ++i)
+ {
+ stringList* const exts = LanguageTable [i]->currentExtensions;
+ if (exts != NULL && stringListRemoveExtension (exts, extension))
+ {
+ verbose (" (removed from %s)", getLanguageName (i));
+ result = TRUE;
+ }
+ }
+ return result;
+}
+
+extern void addLanguageExtensionMap (
+ const langType language, const char* extension)
+{
+ vString* const str = vStringNewInit (extension);
+ Assert (0 <= language && language < (int) LanguageCount);
+ removeLanguageExtensionMap (extension);
+ stringListAdd (LanguageTable [language]->currentExtensions, str);
+}
+
+extern void enableLanguage (const langType language, const boolean state)
+{
+ Assert (0 <= language && language < (int) LanguageCount);
+ LanguageTable [language]->enabled = state;
+}
+
+extern void enableLanguages (const boolean state)
+{
+ unsigned int i;
+ for (i = 0 ; i < LanguageCount ; ++i)
+ enableLanguage (i, state);
+}
+
+static void initializeParsers (void)
+{
+ unsigned int i;
+ for (i = 0 ; i < LanguageCount ; ++i)
+ if (LanguageTable [i]->initialize != NULL)
+ (LanguageTable [i]->initialize) ((langType) i);
+}
+
+extern void initializeParsing (void)
+{
+ unsigned int builtInCount;
+ unsigned int i;
+
+ builtInCount = sizeof (BuiltInParsers) / sizeof (BuiltInParsers [0]);
+ LanguageTable = xMalloc (builtInCount, parserDefinition*);
+
+ verbose ("Installing parsers: ");
+ for (i = 0 ; i < builtInCount ; ++i)
+ {
+ parserDefinition* const def = (*BuiltInParsers [i]) ();
+ if (def != NULL)
+ {
+ boolean accepted = FALSE;
+ if (def->name == NULL || def->name[0] == '\0')
+ error (FATAL, "parser definition must contain name\n");
+ else if (def->regex)
+ {
+#ifdef HAVE_REGEX
+ def->parser = findRegexTags;
+ accepted = TRUE;
+#endif
+ }
+ else if ((def->parser == NULL) == (def->parser2 == NULL))
+ error (FATAL,
+ "%s parser definition must define one and only one parsing routine\n",
+ def->name);
+ else
+ accepted = TRUE;
+ if (accepted)
+ {
+ verbose ("%s%s", i > 0 ? ", " : "", def->name);
+ def->id = LanguageCount++;
+ LanguageTable [def->id] = def;
+ }
+ }
+ }
+ verbose ("\n");
+ enableLanguages (TRUE);
+ initializeParsers ();
+}
+
+extern void freeParserResources (void)
+{
+ unsigned int i;
+ for (i = 0 ; i < LanguageCount ; ++i)
+ {
+ parserDefinition* const lang = LanguageTable [i];
+ freeList (&lang->currentPatterns);
+ freeList (&lang->currentExtensions);
+ eFree (lang->name);
+ lang->name = NULL;
+ eFree (lang);
+ }
+ if (LanguageTable != NULL)
+ eFree (LanguageTable);
+ LanguageTable = NULL;
+ LanguageCount = 0;
+}
+
+/*
+* Option parsing
+*/
+
+extern void processLanguageDefineOption (
+ const char *const option, const char *const parameter)
+{
+#ifdef HAVE_REGEX
+ if (parameter [0] == '\0')
+ error (WARNING, "No language specified for \"%s\" option", option);
+ else if (getNamedLanguage (parameter) != LANG_IGNORE)
+ error (WARNING, "Language \"%s\" already defined", parameter);
+ else
+ {
+ unsigned int i = LanguageCount++;
+ parserDefinition* const def = parserNew (parameter);
+ def->parser = findRegexTags;
+ def->currentPatterns = stringListNew ();
+ def->currentExtensions = stringListNew ();
+ def->regex = TRUE;
+ def->enabled = TRUE;
+ def->id = i;
+ LanguageTable = xRealloc (LanguageTable, i + 1, parserDefinition*);
+ LanguageTable [i] = def;
+ }
+#else
+ error (WARNING, "regex support not available; required for --%s option",
+ option);
+#endif
+}
+
+static kindOption *langKindOption (const langType language, const int flag)
+{
+ unsigned int i;
+ kindOption* result = NULL;
+ const parserDefinition* lang;
+ Assert (0 <= language && language < (int) LanguageCount);
+ lang = LanguageTable [language];
+ for (i=0 ; i < lang->kindCount && result == NULL ; ++i)
+ if (lang->kinds [i].letter == flag)
+ result = &lang->kinds [i];
+ return result;
+}
+
+static void disableLanguageKinds (const langType language)
+{
+ const parserDefinition* lang;
+ Assert (0 <= language && language < (int) LanguageCount);
+ lang = LanguageTable [language];
+ if (lang->regex)
+ disableRegexKinds (language);
+ else
+ {
+ unsigned int i;
+ for (i = 0 ; i < lang->kindCount ; ++i)
+ lang->kinds [i].enabled = FALSE;
+ }
+}
+
+static boolean enableLanguageKind (
+ const langType language, const int kind, const boolean mode)
+{
+ boolean result = FALSE;
+ if (LanguageTable [language]->regex)
+ result = enableRegexKind (language, kind, mode);
+ else
+ {
+ kindOption* const opt = langKindOption (language, kind);
+ if (opt != NULL)
+ {
+ opt->enabled = mode;
+ result = TRUE;
+ }
+ }
+ return result;
+}
+
+static void processLangKindOption (
+ const langType language, const char *const option,
+ const char *const parameter)
+{
+ const char *p = parameter;
+ boolean mode = TRUE;
+ int c;
+
+ Assert (0 <= language && language < (int) LanguageCount);
+ if (*p != '+' && *p != '-')
+ disableLanguageKinds (language);
+ while ((c = *p++) != '\0') switch (c)
+ {
+ case '+': mode = TRUE; break;
+ case '-': mode = FALSE; break;
+ default:
+ if (! enableLanguageKind (language, c, mode))
+ error (WARNING, "Unsupported parameter '%c' for --%s option",
+ c, option);
+ break;
+ }
+}
+
+extern boolean processKindOption (
+ const char *const option, const char *const parameter)
+{
+ boolean handled = FALSE;
+ const char* const dash = strchr (option, '-');
+ if (dash != NULL &&
+ (strcmp (dash + 1, "kinds") == 0 || strcmp (dash + 1, "types") == 0))
+ {
+ langType language;
+ vString* langName = vStringNew ();
+ vStringNCopyS (langName, option, dash - option);
+ language = getNamedLanguage (vStringValue (langName));
+ if (language == LANG_IGNORE)
+ error (WARNING, "Unknown language \"%s\" in \"%s\" option", vStringValue (langName), option);
+ else
+ processLangKindOption (language, option, parameter);
+ vStringDelete (langName);
+ handled = TRUE;
+ }
+ return handled;
+}
+
+static void printLanguageKind (const kindOption* const kind, boolean indent)
+{
+ const char *const indentation = indent ? " " : "";
+ printf ("%s%c %s%s\n", indentation, kind->letter,
+ kind->description != NULL ? kind->description :
+ (kind->name != NULL ? kind->name : ""),
+ kind->enabled ? "" : " [off]");
+}
+
+static void printKinds (langType language, boolean indent)
+{
+ const parserDefinition* lang;
+ Assert (0 <= language && language < (int) LanguageCount);
+ lang = LanguageTable [language];
+ if (lang->kinds != NULL || lang->regex)
+ {
+ unsigned int i;
+ for (i = 0 ; i < lang->kindCount ; ++i)
+ printLanguageKind (lang->kinds + i, indent);
+ printRegexKinds (language, indent);
+ }
+}
+
+extern void printLanguageKinds (const langType language)
+{
+ if (language == LANG_AUTO)
+ {
+ unsigned int i;
+ for (i = 0 ; i < LanguageCount ; ++i)
+ {
+ const parserDefinition* const lang = LanguageTable [i];
+ printf ("%s%s\n", lang->name, lang->enabled ? "" : " [disabled]");
+ printKinds (i, TRUE);
+ }
+ }
+ else
+ printKinds (language, FALSE);
+}
+
+static void printMaps (const langType language)
+{
+ const parserDefinition* lang;
+ unsigned int i;
+ Assert (0 <= language && language < (int) LanguageCount);
+ lang = LanguageTable [language];
+ printf ("%-8s", lang->name);
+ if (lang->currentExtensions != NULL)
+ for (i = 0 ; i < stringListCount (lang->currentExtensions) ; ++i)
+ printf (" *.%s", vStringValue (
+ stringListItem (lang->currentExtensions, i)));
+ if (lang->currentPatterns != NULL)
+ for (i = 0 ; i < stringListCount (lang->currentPatterns) ; ++i)
+ printf (" %s", vStringValue (
+ stringListItem (lang->currentPatterns, i)));
+ putchar ('\n');
+}
+
+extern void printLanguageMaps (const langType language)
+{
+ if (language == LANG_AUTO)
+ {
+ unsigned int i;
+ for (i = 0 ; i < LanguageCount ; ++i)
+ printMaps (i);
+ }
+ else
+ printMaps (language);
+}
+
+static void printLanguage (const langType language)
+{
+ const parserDefinition* lang;
+ Assert (0 <= language && language < (int) LanguageCount);
+ lang = LanguageTable [language];
+ if (lang->kinds != NULL || lang->regex)
+ printf ("%s%s\n", lang->name, lang->enabled ? "" : " [disabled]");
+}
+
+extern void printLanguageList (void)
+{
+ unsigned int i;
+ for (i = 0 ; i < LanguageCount ; ++i)
+ printLanguage (i);
+}
+
+/*
+* File parsing
+*/
+
+static void makeFileTag (const char *const fileName)
+{
+ if (Option.include.fileNames)
+ {
+ tagEntryInfo tag;
+ initTagEntry (&tag, baseFilename (fileName));
+
+ tag.isFileEntry = TRUE;
+ tag.lineNumberEntry = TRUE;
+ tag.lineNumber = 1;
+ tag.kindName = "file";
+ tag.kind = 'F';
+
+ makeTagEntry (&tag);
+ }
+}
+
+static boolean createTagsForFile (
+ const char *const fileName, const langType language,
+ const unsigned int passCount)
+{
+ boolean retried = FALSE;
+ Assert (0 <= language && language < (int) LanguageCount);
+ if (fileOpen (fileName, language))
+ {
+ const parserDefinition* const lang = LanguageTable [language];
+ if (Option.etags)
+ beginEtagsFile ();
+
+ makeFileTag (fileName);
+
+ if (lang->parser != NULL)
+ lang->parser ();
+ else if (lang->parser2 != NULL)
+ retried = lang->parser2 (passCount);
+
+ if (Option.etags)
+ endEtagsFile (getSourceFileTagPath ());
+
+ fileClose ();
+ }
+
+ return retried;
+}
+
+static boolean createTagsWithFallback (
+ const char *const fileName, const langType language)
+{
+ const unsigned long numTags = TagFile.numTags.added;
+ fpos_t tagFilePosition;
+ unsigned int passCount = 0;
+ boolean tagFileResized = FALSE;
+
+ fgetpos (TagFile.fp, &tagFilePosition);
+ while (createTagsForFile (fileName, language, ++passCount))
+ {
+ /* Restore prior state of tag file.
+ */
+ fsetpos (TagFile.fp, &tagFilePosition);
+ TagFile.numTags.added = numTags;
+ tagFileResized = TRUE;
+ }
+ return tagFileResized;
+}
+
+extern boolean parseFile (const char *const fileName)
+{
+ boolean tagFileResized = FALSE;
+ langType language = Option.language;
+ if (Option.language == LANG_AUTO)
+ language = getFileLanguage (fileName);
+ Assert (language != LANG_AUTO);
+ if (language == LANG_IGNORE)
+ verbose ("ignoring %s (unknown language)\n", fileName);
+ else if (! LanguageTable [language]->enabled)
+ verbose ("ignoring %s (language disabled)\n", fileName);
+ else
+ {
+ if (Option.filter)
+ openTagFile ();
+
+ tagFileResized = createTagsWithFallback (fileName, language);
+
+ if (Option.filter)
+ closeTagFile (tagFileResized);
+ addTotals (1, 0L, 0L);
+
+ return tagFileResized;
+ }
+ return tagFileResized;
+}
+
+/* vi:set tabstop=4 shiftwidth=4 nowrap: */
Index: create-5.8-unused-attribute-patch/ctags-5.8-new/python.c
===================================================================
--- create-5.8-unused-attribute-patch/ctags-5.8-new/python.c (nonexistent)
+++ create-5.8-unused-attribute-patch/ctags-5.8-new/python.c (revision 5)
@@ -0,0 +1,771 @@
+/*
+* $Id: python.c 720 2009-07-07 03:55:23Z dhiebert $
+*
+* Copyright (c) 2000-2003, Darren Hiebert
+*
+* 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 Python language
+* files.
+*/
+/*
+* INCLUDE FILES
+*/
+#include "general.h" /* must always come first */
+
+#include <string.h>
+
+#include "entry.h"
+#include "options.h"
+#include "read.h"
+#include "main.h"
+#include "vstring.h"
+#include "routines.h"
+#include "debug.h"
+
+/*
+* DATA DECLARATIONS
+*/
+typedef struct NestingLevel NestingLevel;
+typedef struct NestingLevels NestingLevels;
+
+struct NestingLevel
+{
+ int indentation;
+ vString *name;
+ int type;
+};
+
+struct NestingLevels
+{
+ NestingLevel *levels;
+ int n; /* number of levels in use */
+ int allocated;
+};
+
+typedef enum {
+ K_CLASS, K_FUNCTION, K_MEMBER, K_VARIABLE, K_IMPORT
+} pythonKind;
+
+/*
+* DATA DEFINITIONS
+*/
+static kindOption PythonKinds[] = {
+ {TRUE, 'c', "class", "classes"},
+ {TRUE, 'f', "function", "functions"},
+ {TRUE, 'm', "member", "class members"},
+ {TRUE, 'v', "variable", "variables"},
+ {TRUE, 'i', "namespace", "imports"}
+};
+
+static char const * const singletriple = "'''";
+static char const * const doubletriple = "\"\"\"";
+
+/*
+* FUNCTION DEFINITIONS
+*/
+
+static NestingLevels *nestingLevelsNew (void)
+{
+ NestingLevels *nls = xCalloc (1, NestingLevels);
+ return nls;
+}
+
+static void nestingLevelsFree (NestingLevels *nls)
+{
+ int i;
+ for (i = 0; i < nls->allocated; i++)
+ vStringDelete(nls->levels[i].name);
+ if (nls->levels) eFree(nls->levels);
+ eFree(nls);
+}
+
+static void nestingLevelsPush (NestingLevels *nls,
+ const vString *name, int type)
+{
+ NestingLevel *nl = NULL;
+
+ if (nls->n >= nls->allocated)
+ {
+ nls->allocated++;
+ nls->levels = xRealloc(nls->levels,
+ nls->allocated, NestingLevel);
+ nls->levels[nls->n].name = vStringNew();
+ }
+ nl = &nls->levels[nls->n];
+ nls->n++;
+
+ vStringCopy(nl->name, name);
+ nl->type = type;
+}
+
+#if 0
+static NestingLevel *nestingLevelsGetCurrent (NestingLevels *nls)
+{
+ Assert (nls != NULL);
+
+ if (nls->n < 1)
+ return NULL;
+
+ return &nls->levels[nls->n - 1];
+}
+
+static void nestingLevelsPop (NestingLevels *nls)
+{
+ const NestingLevel *nl = nestingLevelsGetCurrent(nls);
+
+ Assert (nl != NULL);
+ vStringClear(nl->name);
+ nls->n--;
+}
+#endif
+
+static boolean isIdentifierFirstCharacter (int c)
+{
+ return (boolean) (isalpha (c) || c == '_');
+}
+
+static boolean isIdentifierCharacter (int c)
+{
+ return (boolean) (isalnum (c) || c == '_');
+}
+
+/* Given a string with the contents of a line directly after the "def" keyword,
+ * extract all relevant information and create a tag.
+ */
+static void makeFunctionTag (vString *const function,
+ vString *const parent, int is_class_parent, const char *arglist)
+{
+ tagEntryInfo tag;
+ initTagEntry (&tag, vStringValue (function));
+
+ tag.kindName = "function";
+ tag.kind = 'f';
+ /* tag.extensionFields.arglist = arglist; */
+
+ if (vStringLength (parent) > 0)
+ {
+ if (is_class_parent)
+ {
+ tag.kindName = "member";
+ tag.kind = 'm';
+ tag.extensionFields.scope [0] = "class";
+ tag.extensionFields.scope [1] = vStringValue (parent);
+ }
+ else
+ {
+ tag.extensionFields.scope [0] = "function";
+ tag.extensionFields.scope [1] = vStringValue (parent);
+ }
+ }
+
+ /* If a function starts with __, we mark it as file scope.
+ * FIXME: What is the proper way to signal such attributes?
+ * TODO: What does functions/classes starting with _ and __ mean in python?
+ */
+ if (strncmp (vStringValue (function), "__", 2) == 0 &&
+ strcmp (vStringValue (function), "__init__") != 0)
+ {
+ tag.extensionFields.access = "private";
+ tag.isFileScope = TRUE;
+ }
+ else
+ {
+ tag.extensionFields.access = "public";
+ }
+ makeTagEntry (&tag);
+}
+
+/* Given a string with the contents of the line directly after the "class"
+ * keyword, extract all necessary information and create a tag.
+ */
+static void makeClassTag (vString *const class, vString *const inheritance,
+ vString *const parent, int is_class_parent)
+{
+ tagEntryInfo tag;
+ initTagEntry (&tag, vStringValue (class));
+ tag.kindName = "class";
+ tag.kind = 'c';
+ if (vStringLength (parent) > 0)
+ {
+ if (is_class_parent)
+ {
+ tag.extensionFields.scope [0] = "class";
+ tag.extensionFields.scope [1] = vStringValue (parent);
+ }
+ else
+ {
+ tag.extensionFields.scope [0] = "function";
+ tag.extensionFields.scope [1] = vStringValue (parent);
+ }
+ }
+ tag.extensionFields.inheritance = vStringValue (inheritance);
+ makeTagEntry (&tag);
+}
+
+static void makeVariableTag (vString *const var, vString *const parent)
+{
+ tagEntryInfo tag;
+ initTagEntry (&tag, vStringValue (var));
+ tag.kindName = "variable";
+ tag.kind = 'v';
+ if (vStringLength (parent) > 0)
+ {
+ tag.extensionFields.scope [0] = "class";
+ tag.extensionFields.scope [1] = vStringValue (parent);
+ }
+ makeTagEntry (&tag);
+}
+
+/* Skip a single or double quoted string. */
+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;
+}
+
+/* Skip everything up to an identifier start. */
+static const char *skipEverything (const char *cp)
+{
+ for (; *cp; cp++)
+ {
+ if (*cp == '"' || *cp == '\'')
+ {
+ cp = skipString(cp);
+ if (!*cp) break;
+ }
+ if (isIdentifierFirstCharacter ((int) *cp))
+ return cp;
+ }
+ return cp;
+}
+
+/* Skip an identifier. */
+static const char *skipIdentifier (const char *cp)
+{
+ while (isIdentifierCharacter ((int) *cp))
+ cp++;
+ return cp;
+}
+
+static const char *findDefinitionOrClass (const char *cp)
+{
+ while (*cp)
+ {
+ cp = skipEverything (cp);
+ if (!strncmp(cp, "def", 3) || !strncmp(cp, "class", 5) ||
+ !strncmp(cp, "cdef", 4) || !strncmp(cp, "cpdef", 5))
+ {
+ return cp;
+ }
+ cp = skipIdentifier (cp);
+ }
+ return NULL;
+}
+
+static const char *skipSpace (const char *cp)
+{
+ while (isspace ((int) *cp))
+ ++cp;
+ return cp;
+}
+
+/* Starting at ''cp'', parse an identifier into ''identifier''. */
+static const char *parseIdentifier (const char *cp, vString *const identifier)
+{
+ vStringClear (identifier);
+ while (isIdentifierCharacter ((int) *cp))
+ {
+ vStringPut (identifier, (int) *cp);
+ ++cp;
+ }
+ vStringTerminate (identifier);
+ return cp;
+}
+
+static void parseClass (const char *cp, vString *const class,
+ vString *const parent, int is_class_parent)
+{
+ vString *const inheritance = vStringNew ();
+ vStringClear (inheritance);
+ cp = parseIdentifier (cp, class);
+ cp = skipSpace (cp);
+ if (*cp == '(')
+ {
+ ++cp;
+ while (*cp != ')')
+ {
+ if (*cp == '\0')
+ {
+ /* Closing parenthesis can be in follow up line. */
+ cp = (const char *) fileReadLine ();
+ if (!cp) break;
+ vStringPut (inheritance, ' ');
+ continue;
+ }
+ vStringPut (inheritance, *cp);
+ ++cp;
+ }
+ vStringTerminate (inheritance);
+ }
+ makeClassTag (class, inheritance, parent, is_class_parent);
+ vStringDelete (inheritance);
+}
+
+static void parseImports (const char *cp)
+{
+ const char *pos;
+ vString *name, *name_next;
+
+ cp = skipEverything (cp);
+
+ if ((pos = strstr (cp, "import")) == NULL)
+ return;
+
+ cp = pos + 6;
+
+ /* continue only if there is some space between the keyword and the identifier */
+ if (! isspace (*cp))
+ return;
+
+ cp++;
+ cp = skipSpace (cp);
+
+ name = vStringNew ();
+ name_next = vStringNew ();
+
+ cp = skipEverything (cp);
+ while (*cp)
+ {
+ cp = parseIdentifier (cp, name);
+
+ cp = skipEverything (cp);
+ /* we parse the next possible import statement as well to be able to ignore 'foo' in
+ * 'import foo as bar' */
+ parseIdentifier (cp, name_next);
+
+ /* take the current tag only if the next one is not "as" */
+ if (strcmp (vStringValue (name_next), "as") != 0 &&
+ strcmp (vStringValue (name), "as") != 0)
+ {
+ makeSimpleTag (name, PythonKinds, K_IMPORT);
+ }
+ }
+ vStringDelete (name);
+ vStringDelete (name_next);
+}
+
+/* modified from get.c getArglistFromStr().
+ * warning: terminates rest of string past arglist!
+ * note: does not ignore brackets inside strings! */
+static char *parseArglist(const char *buf)
+{
+ char *start, *end;
+ int level;
+ if (NULL == buf)
+ return NULL;
+ if (NULL == (start = strchr(buf, '(')))
+ return NULL;
+ for (level = 1, end = start + 1; level > 0; ++end)
+ {
+ if ('\0' == *end)
+ break;
+ else if ('(' == *end)
+ ++ level;
+ else if (')' == *end)
+ -- level;
+ }
+ *end = '\0';
+ return strdup(start);
+}
+
+static void parseFunction (const char *cp, vString *const def,
+ vString *const parent, int is_class_parent)
+{
+ char *arglist;
+
+ cp = parseIdentifier (cp, def);
+ arglist = parseArglist (cp);
+ makeFunctionTag (def, parent, is_class_parent, arglist);
+ eFree (arglist);
+}
+
+/* Get the combined name of a nested symbol. Classes are separated with ".",
+ * functions with "/". For example this code:
+ * class MyClass:
+ * def myFunction:
+ * def SubFunction:
+ * class SubClass:
+ * def Method:
+ * pass
+ * Would produce this string:
+ * MyClass.MyFunction/SubFunction/SubClass.Method
+ */
+static boolean constructParentString(NestingLevels *nls, int indent,
+ vString *result)
+{
+ int i;
+ NestingLevel *prev = NULL;
+ int is_class = FALSE;
+ vStringClear (result);
+ for (i = 0; i < nls->n; i++)
+ {
+ NestingLevel *nl = nls->levels + i;
+ if (indent <= nl->indentation)
+ break;
+ if (prev)
+ {
+ vStringCatS(result, "."); /* make Geany symbol list grouping work properly */
+/*
+ if (prev->type == K_CLASS)
+ vStringCatS(result, ".");
+ else
+ vStringCatS(result, "/");
+*/
+ }
+ vStringCat(result, nl->name);
+ is_class = (nl->type == K_CLASS);
+ prev = nl;
+ }
+ return is_class;
+}
+
+/* Check whether parent's indentation level is higher than the current level and
+ * if so, remove it.
+ */
+static void checkParent(NestingLevels *nls, int indent, vString *parent)
+{
+ int i;
+ NestingLevel *n;
+
+ for (i = 0; i < nls->n; i++)
+ {
+ n = nls->levels + i;
+ /* is there a better way to compare two vStrings? */
+ if (strcmp(vStringValue(parent), vStringValue(n->name)) == 0)
+ {
+ if (n && indent <= n->indentation)
+ {
+ /* remove this level by clearing its name */
+ vStringClear(n->name);
+ }
+ break;
+ }
+ }
+}
+
+static void addNestingLevel(NestingLevels *nls, int indentation,
+ const vString *name, boolean is_class)
+{
+ int i;
+ NestingLevel *nl = NULL;
+
+ for (i = 0; i < nls->n; i++)
+ {
+ nl = nls->levels + i;
+ if (indentation <= nl->indentation) break;
+ }
+ if (i == nls->n)
+ {
+ nestingLevelsPush(nls, name, 0);
+ nl = nls->levels + i;
+ }
+ else
+ { /* reuse existing slot */
+ nls->n = i + 1;
+ vStringCopy(nl->name, name);
+ }
+ nl->indentation = indentation;
+ nl->type = is_class ? K_CLASS : !K_CLASS;
+}
+
+/* Return a pointer to the start of the next triple string, or NULL. Store
+ * the kind of triple string in "which" if the return is not NULL.
+ */
+static char const *find_triple_start(char const *string, char const **which)
+{
+ char const *cp = string;
+
+ for (; *cp; cp++)
+ {
+ if (*cp == '"' || *cp == '\'')
+ {
+ if (strncmp(cp, doubletriple, 3) == 0)
+ {
+ *which = doubletriple;
+ return cp;
+ }
+ if (strncmp(cp, singletriple, 3) == 0)
+ {
+ *which = singletriple;
+ return cp;
+ }
+ cp = skipString(cp);
+ if (!*cp) break;
+ }
+ }
+ return NULL;
+}
+
+/* Find the end of a triple string as pointed to by "which", and update "which"
+ * with any other triple strings following in the given string.
+ */
+static void find_triple_end(char const *string, char const **which)
+{
+ char const *s = string;
+ while (1)
+ {
+ /* Check if the string ends in the same line. */
+ s = strstr (s, *which);
+ if (!s) break;
+ s += 3;
+ *which = NULL;
+ /* If yes, check if another one starts in the same line. */
+ s = find_triple_start(s, which);
+ if (!s) break;
+ s += 3;
+ }
+}
+
+static const char *findVariable(const char *line)
+{
+ /* Parse global and class variable names (C.x) from assignment statements.
+ * Object attributes (obj.x) are ignored.
+ * Assignment to a tuple 'x, y = 2, 3' not supported.
+ * TODO: ignore duplicate tags from reassignment statements. */
+ const char *cp, *sp, *eq, *start;
+
+ cp = strstr(line, "=");
+ if (!cp)
+ return NULL;
+ eq = cp + 1;
+ while (*eq)
+ {
+ if (*eq == '=')
+ return NULL; /* ignore '==' operator and 'x=5,y=6)' function lines */
+ if (*eq == '(' || *eq == '#')
+ break; /* allow 'x = func(b=2,y=2,' lines and comments at the end of line */
+ eq++;
+ }
+
+ /* go backwards to the start of the line, checking we have valid chars */
+ start = cp - 1;
+ while (start >= line && isspace ((int) *start))
+ --start;
+ while (start >= line && isIdentifierCharacter ((int) *start))
+ --start;
+ if (!isIdentifierFirstCharacter(*(start + 1)))
+ return NULL;
+ sp = start;
+ while (sp >= line && isspace ((int) *sp))
+ --sp;
+ if ((sp + 1) != line) /* the line isn't a simple variable assignment */
+ return NULL;
+ /* the line is valid, parse the variable name */
+ ++start;
+ return start;
+}
+
+/* Skip type declaration that optionally follows a cdef/cpdef */
+static const char *skipTypeDecl (const char *cp, boolean *is_class)
+{
+ const char *lastStart = cp, *ptr = cp;
+ int loopCount = 0;
+ ptr = skipSpace(cp);
+ if (!strncmp("extern", ptr, 6)) {
+ ptr += 6;
+ ptr = skipSpace(ptr);
+ if (!strncmp("from", ptr, 4)) { return NULL; }
+ }
+ if (!strncmp("class", ptr, 5)) {
+ ptr += 5 ;
+ *is_class = TRUE;
+ ptr = skipSpace(ptr);
+ return ptr;
+ }
+ /* limit so that we don't pick off "int item=obj()" */
+ while (*ptr && loopCount++ < 2) {
+ while (*ptr && *ptr != '=' && *ptr != '(' && !isspace(*ptr)) ptr++;
+ if (!*ptr || *ptr == '=') return NULL;
+ if (*ptr == '(') {
+ return lastStart; /* if we stopped on a '(' we are done */
+ }
+ ptr = skipSpace(ptr);
+ lastStart = ptr;
+ while (*lastStart == '*') lastStart++; /* cdef int *identifier */
+ }
+ return NULL;
+}
+
+static void findPythonTags (void)
+{
+ vString *const continuation = vStringNew ();
+ vString *const name = vStringNew ();
+ vString *const parent = vStringNew();
+
+ NestingLevels *const nesting_levels = nestingLevelsNew();
+
+ const char *line;
+ int line_skip = 0;
+ char const *longStringLiteral = NULL;
+
+ while ((line = (const char *) fileReadLine ()) != NULL)
+ {
+ const char *cp = line, *candidate;
+ char const *longstring;
+ char const *keyword, *variable;
+ int indent;
+
+ cp = skipSpace (cp);
+
+ if (*cp == '\0') /* skip blank line */
+ continue;
+
+ /* Skip comment if we are not inside a multi-line string. */
+ if (*cp == '#' && !longStringLiteral)
+ continue;
+
+ /* Deal with line continuation. */
+ if (!line_skip) vStringClear(continuation);
+ vStringCatS(continuation, line);
+ vStringStripTrailing(continuation);
+ if (vStringLast(continuation) == '\\')
+ {
+ vStringChop(continuation);
+ vStringCatS(continuation, " ");
+ line_skip = 1;
+ continue;
+ }
+ cp = line = vStringValue(continuation);
+ cp = skipSpace (cp);
+ indent = cp - line;
+ line_skip = 0;
+
+ checkParent(nesting_levels, indent, parent);
+
+ /* Deal with multiline string ending. */
+ if (longStringLiteral)
+ {
+ find_triple_end(cp, &longStringLiteral);
+ continue;
+ }
+
+ /* Deal with multiline string start. */
+ longstring = find_triple_start(cp, &longStringLiteral);
+ if (longstring)
+ {
+ longstring += 3;
+ find_triple_end(longstring, &longStringLiteral);
+ /* We don't parse for any tags in the rest of the line. */
+ continue;
+ }
+
+ /* Deal with def and class keywords. */
+ keyword = findDefinitionOrClass (cp);
+ if (keyword)
+ {
+ boolean found = FALSE;
+ boolean is_class = FALSE;
+ if (!strncmp (keyword, "def ", 4))
+ {
+ cp = skipSpace (keyword + 3);
+ found = TRUE;
+ }
+ else if (!strncmp (keyword, "class ", 6))
+ {
+ cp = skipSpace (keyword + 5);
+ found = TRUE;
+ is_class = TRUE;
+ }
+ else if (!strncmp (keyword, "cdef ", 5))
+ {
+ cp = skipSpace(keyword + 4);
+ candidate = skipTypeDecl (cp, &is_class);
+ if (candidate)
+ {
+ found = TRUE;
+ cp = candidate;
+ }
+
+ }
+ else if (!strncmp (keyword, "cpdef ", 6))
+ {
+ cp = skipSpace(keyword + 5);
+ candidate = skipTypeDecl (cp, &is_class);
+ if (candidate)
+ {
+ found = TRUE;
+ cp = candidate;
+ }
+ }
+
+ if (found)
+ {
+ boolean is_parent_class;
+
+ is_parent_class =
+ constructParentString(nesting_levels, indent, parent);
+
+ if (is_class)
+ parseClass (cp, name, parent, is_parent_class);
+ else
+ parseFunction(cp, name, parent, is_parent_class);
+
+ addNestingLevel(nesting_levels, indent, name, is_class);
+ }
+ }
+ /* Find global and class variables */
+ variable = findVariable(line);
+ if (variable)
+ {
+ const char *start = variable;
+ boolean parent_is_class;
+
+ vStringClear (name);
+ while (isIdentifierCharacter ((int) *start))
+ {
+ vStringPut (name, (int) *start);
+ ++start;
+ }
+ vStringTerminate (name);
+
+ parent_is_class = constructParentString(nesting_levels, indent, parent);
+ /* skip variables in methods */
+ if (! parent_is_class && vStringLength(parent) > 0)
+ continue;
+
+ makeVariableTag (name, parent);
+ }
+ /* Find and parse imports */
+ parseImports(line);
+ }
+ /* Clean up all memory we allocated. */
+ vStringDelete (parent);
+ vStringDelete (name);
+ vStringDelete (continuation);
+ nestingLevelsFree (nesting_levels);
+}
+
+extern parserDefinition *PythonParser (void)
+{
+ static const char *const extensions[] = { "py", "pyx", "pxd", "pxi" ,"scons", NULL };
+ parserDefinition *def = parserNew ("Python");
+ def->kinds = PythonKinds;
+ def->kindCount = KIND_COUNT (PythonKinds);
+ def->extensions = extensions;
+ def->parser = findPythonTags;
+ return def;
+}
+
+/* vi:set tabstop=4 shiftwidth=4: */
Index: create-5.8-unused-attribute-patch/ctags-5.8-new/routines.c
===================================================================
--- create-5.8-unused-attribute-patch/ctags-5.8-new/routines.c (nonexistent)
+++ create-5.8-unused-attribute-patch/ctags-5.8-new/routines.c (revision 5)
@@ -0,0 +1,891 @@
+/*
+* $Id: routines.c 536 2007-06-02 06:09:00Z elliotth $
+*
+* Copyright (c) 2002-2003, Darren Hiebert
+*
+* This source code is released for free distribution under the terms of the
+* GNU General Public License.
+*
+* This module contains a lose assortment of shared functions.
+*/
+
+/*
+* INCLUDE FILES
+*/
+#include "general.h" /* must always come first */
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h> /* to declare malloc (), realloc () */
+#endif
+#include <ctype.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <stdio.h> /* to declare tempnam(), and SEEK_SET (hopefully) */
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h> /* to declar O_RDWR, O_CREAT, O_EXCL */
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> /* to declare mkstemp () */
+#endif
+
+/* To declare "struct stat" and stat ().
+ */
+#if defined (HAVE_SYS_TYPES_H)
+# include <sys/types.h>
+#else
+# if defined (HAVE_TYPES_H)
+# include <types.h>
+# endif
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#else
+# ifdef HAVE_STAT_H
+# include <stat.h>
+# endif
+#endif
+
+#ifdef HAVE_DOS_H
+# include <dos.h> /* to declare MAXPATH */
+#endif
+#ifdef HAVE_DIRECT_H
+# include <direct.h> /* to _getcwd */
+#endif
+#ifdef HAVE_DIR_H
+# include <dir.h> /* to declare findfirst() and findnext() */
+#endif
+#ifdef HAVE_IO_H
+# include <io.h> /* to declare open() */
+#endif
+#include "debug.h"
+#include "routines.h"
+
+/*
+* MACROS
+*/
+#ifndef TMPDIR
+# define TMPDIR "/tmp"
+#endif
+
+/* File type tests.
+ */
+#ifndef S_ISREG
+# if defined (S_IFREG) && ! defined (AMIGA)
+# define S_ISREG(mode) ((mode) & S_IFREG)
+# else
+# define S_ISREG(mode) TRUE /* assume regular file */
+# endif
+#endif
+
+#ifndef S_ISLNK
+# ifdef S_IFLNK
+# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
+# else
+# define S_ISLNK(mode) FALSE /* assume no soft links */
+# endif
+#endif
+
+#ifndef S_ISDIR
+# ifdef S_IFDIR
+# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+# else
+# define S_ISDIR(mode) FALSE /* assume no soft links */
+# endif
+#endif
+
+#ifndef S_IFMT
+# define S_IFMT 0
+#endif
+
+#ifndef S_IXUSR
+# define S_IXUSR 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+
+#ifndef S_IRUSR
+# define S_IRUSR 0400
+#endif
+#ifndef S_IWUSR
+# define S_IWUSR 0200
+#endif
+
+#ifndef S_ISUID
+# define S_ISUID 0
+#endif
+
+/* Hack for rediculous practice of Microsoft Visual C++.
+ */
+#if defined (WIN32)
+# if defined (_MSC_VER)
+# define stat _stat
+# define getcwd _getcwd
+# define currentdrive() (_getdrive() + 'A' - 1)
+# define PATH_MAX _MAX_PATH
+# elif defined (__BORLANDC__)
+# define PATH_MAX MAXPATH
+# define currentdrive() (getdisk() + 'A')
+# elif defined (DJGPP)
+# define currentdrive() (getdisk() + 'A')
+# else
+# define currentdrive() 'C'
+# endif
+#endif
+
+#ifndef PATH_MAX
+# define PATH_MAX 256
+#endif
+
+/*
+ * Miscellaneous macros
+ */
+#define selected(var,feature) (((int)(var) & (int)(feature)) == (int)feature)
+
+/*
+* DATA DEFINITIONS
+*/
+#if defined (MSDOS_STYLE_PATH)
+const char *const PathDelimiters = ":/\\";
+#elif defined (VMS)
+const char *const PathDelimiters = ":]>";
+#endif
+
+char *CurrentDirectory;
+
+static const char *ExecutableProgram;
+static const char *ExecutableName;
+
+/*
+* FUNCTION PROTOTYPES
+*/
+#ifdef NEED_PROTO_STAT
+extern int stat (const char *, struct stat *);
+#endif
+#ifdef NEED_PROTO_LSTAT
+extern int lstat (const char *, struct stat *);
+#endif
+#if defined (MSDOS) || defined (WIN32) || defined (VMS) || defined (__EMX__) || defined (AMIGA)
+# define lstat(fn,buf) stat(fn,buf)
+#endif
+
+/*
+* FUNCTION DEFINITIONS
+*/
+
+extern void freeRoutineResources (void)
+{
+ if (CurrentDirectory != NULL)
+ eFree (CurrentDirectory);
+}
+
+extern void setExecutableName (const char *const path)
+{
+ ExecutableProgram = path;
+ ExecutableName = baseFilename (path);
+#ifdef VAXC
+{
+ /* remove filetype from executable name */
+ char *p = strrchr (ExecutableName, '.');
+ if (p != NULL)
+ *p = '\0';
+}
+#endif
+}
+
+extern const char *getExecutableName (void)
+{
+ return ExecutableName;
+}
+
+extern const char *getExecutablePath (void)
+{
+ return ExecutableProgram;
+}
+
+extern void error (
+ const errorSelection selection, const char *const format, ...)
+{
+ va_list ap;
+
+ va_start (ap, format);
+ fprintf (errout, "%s: %s", getExecutableName (),
+ selected (selection, WARNING) ? "Warning: " : "");
+ vfprintf (errout, format, ap);
+ if (selected (selection, PERROR))
+#ifdef HAVE_STRERROR
+ fprintf (errout, " : %s", strerror (errno));
+#else
+ perror (" ");
+#endif
+ fputs ("\n", errout);
+ va_end (ap);
+ if (selected (selection, FATAL))
+ exit (1);
+}
+
+/*
+ * Memory allocation functions
+ */
+
+extern void *eMalloc (const size_t size)
+{
+ void *buffer = malloc (size);
+
+ if (buffer == NULL)
+ error (FATAL, "out of memory");
+
+ return buffer;
+}
+
+extern void *eCalloc (const size_t count, const size_t size)
+{
+ void *buffer = calloc (count, size);
+
+ if (buffer == NULL)
+ error (FATAL, "out of memory");
+
+ return buffer;
+}
+
+extern void *eRealloc (void *const ptr, const size_t size)
+{
+ void *buffer;
+ if (ptr == NULL)
+ buffer = eMalloc (size);
+ else
+ {
+ buffer = realloc (ptr, size);
+ if (buffer == NULL)
+ error (FATAL, "out of memory");
+ }
+ return buffer;
+}
+
+extern void eFree (void *const ptr)
+{
+ Assert (ptr != NULL);
+ free (ptr);
+}
+
+/*
+ * String manipulation functions
+ */
+
+/*
+ * Compare two strings, ignoring case.
+ * Return 0 for match, < 0 for smaller, > 0 for bigger
+ * Make sure case is folded to uppercase in comparison (like for 'sort -f')
+ * This makes a difference when one of the chars lies between upper and lower
+ * ie. one of the chars [ \ ] ^ _ ` for ascii. (The '_' in particular !)
+ */
+extern int struppercmp (const char *s1, const char *s2)
+{
+ int result;
+ do
+ {
+ result = toupper ((int) *s1) - toupper ((int) *s2);
+ } while (result == 0 && *s1++ != '\0' && *s2++ != '\0');
+ return result;
+}
+
+extern int strnuppercmp (const char *s1, const char *s2, size_t n)
+{
+ int result;
+ do
+ {
+ result = toupper ((int) *s1) - toupper ((int) *s2);
+ } while (result == 0 && --n > 0 && *s1++ != '\0' && *s2++ != '\0');
+ return result;
+}
+
+#ifndef HAVE_STRSTR
+extern char* strstr (const char *str, const char *substr)
+{
+ const size_t length = strlen (substr);
+ const char *match = NULL;
+ const char *p;
+
+ for (p = str ; *p != '\0' && match == NULL ; ++p)
+ if (strncmp (p, substr, length) == 0)
+ match = p;
+ return (char*) match;
+}
+#endif
+
+extern char* eStrdup (const char* str)
+{
+ char* result = xMalloc (strlen (str) + 1, char);
+ strcpy (result, str);
+ return result;
+}
+
+extern void toLowerString (char* str)
+{
+ while (*str != '\0')
+ {
+ *str = tolower ((int) *str);
+ ++str;
+ }
+}
+
+extern void toUpperString (char* str)
+{
+ while (*str != '\0')
+ {
+ *str = toupper ((int) *str);
+ ++str;
+ }
+}
+
+/* Newly allocated string containing lower case conversion of a string.
+ */
+extern char* newLowerString (const char* str)
+{
+ char* const result = xMalloc (strlen (str) + 1, char);
+ int i = 0;
+ do
+ result [i] = tolower ((int) str [i]);
+ while (str [i++] != '\0');
+ return result;
+}
+
+/* Newly allocated string containing upper case conversion of a string.
+ */
+extern char* newUpperString (const char* str)
+{
+ char* const result = xMalloc (strlen (str) + 1, char);
+ int i = 0;
+ do
+ result [i] = toupper ((int) str [i]);
+ while (str [i++] != '\0');
+ return result;
+}
+
+/*
+ * File system functions
+ */
+
+extern void setCurrentDirectory (void)
+{
+#ifndef AMIGA
+ char* buf;
+#endif
+ if (CurrentDirectory == NULL)
+ CurrentDirectory = xMalloc ((size_t) (PATH_MAX + 1), char);
+#ifdef AMIGA
+ strcpy (CurrentDirectory, ".");
+#else
+ buf = getcwd (CurrentDirectory, PATH_MAX);
+ if (buf == NULL)
+ perror ("");
+#endif
+ if (CurrentDirectory [strlen (CurrentDirectory) - (size_t) 1] !=
+ PATH_SEPARATOR)
+ {
+ sprintf (CurrentDirectory + strlen (CurrentDirectory), "%c",
+ OUTPUT_PATH_SEPARATOR);
+ }
+}
+
+#ifdef AMIGA
+static boolean isAmigaDirectory (const char *const name)
+{
+ boolean result = FALSE;
+ struct FileInfoBlock *const fib = xMalloc (1, struct FileInfoBlock);
+ if (fib != NULL)
+ {
+ const BPTR flock = Lock ((UBYTE *) name, (long) ACCESS_READ);
+
+ if (flock != (BPTR) NULL)
+ {
+ if (Examine (flock, fib))
+ result = ((fib->fib_DirEntryType >= 0) ? TRUE : FALSE);
+ UnLock (flock);
+ }
+ eFree (fib);
+ }
+ return result;
+}
+#endif
+
+/* For caching of stat() calls */
+extern fileStatus *eStat (const char *const fileName)
+{
+ struct stat status;
+ static fileStatus file;
+ if (file.name == NULL || strcmp (fileName, file.name) != 0)
+ {
+ eStatFree (&file);
+ file.name = eStrdup (fileName);
+ if (lstat (file.name, &status) != 0)
+ file.exists = FALSE;
+ else
+ {
+ file.isSymbolicLink = (boolean) S_ISLNK (status.st_mode);
+ if (file.isSymbolicLink && stat (file.name, &status) != 0)
+ file.exists = FALSE;
+ else
+ {
+ file.exists = TRUE;
+#ifdef AMIGA
+ file.isDirectory = isAmigaDirectory (file.name);
+#else
+ file.isDirectory = (boolean) S_ISDIR (status.st_mode);
+#endif
+ file.isNormalFile = (boolean) (S_ISREG (status.st_mode));
+ file.isExecutable = (boolean) ((status.st_mode &
+ (S_IXUSR | S_IXGRP | S_IXOTH)) != 0);
+ file.isSetuid = (boolean) ((status.st_mode & S_ISUID) != 0);
+ file.size = status.st_size;
+ }
+ }
+ }
+ return &file;
+}
+
+extern void eStatFree (fileStatus *status)
+{
+ if (status->name != NULL)
+ {
+ eFree (status->name);
+ status->name = NULL;
+ }
+}
+
+extern boolean doesFileExist (const char *const fileName)
+{
+ fileStatus *status = eStat (fileName);
+ return status->exists;
+}
+
+extern boolean isRecursiveLink (const char* const dirName)
+{
+ boolean result = FALSE;
+ fileStatus *status = eStat (dirName);
+ if (status->isSymbolicLink)
+ {
+ char* const path = absoluteFilename (dirName);
+ while (path [strlen (path) - 1] == PATH_SEPARATOR)
+ path [strlen (path) - 1] = '\0';
+ while (! result && strlen (path) > (size_t) 1)
+ {
+ char *const separator = strrchr (path, PATH_SEPARATOR);
+ if (separator == NULL)
+ break;
+ else if (separator == path) /* backed up to root directory */
+ *(separator + 1) = '\0';
+ else
+ *separator = '\0';
+ result = isSameFile (path, dirName);
+ }
+ eFree (path);
+ }
+ return result;
+}
+
+#ifndef HAVE_FGETPOS
+
+extern int fgetpos (FILE *stream, fpos_t *pos)
+{
+ int result = 0;
+
+ *pos = ftell (stream);
+ if (*pos == -1L)
+ result = -1;
+
+ return result;
+}
+
+extern int fsetpos (FILE *stream, fpos_t const *pos)
+{
+ return fseek (stream, *pos, SEEK_SET);
+}
+
+#endif
+
+/*
+ * Pathname manipulation (O/S dependent!!!)
+ */
+
+static boolean isPathSeparator (const int c)
+{
+ boolean result;
+#if defined (MSDOS_STYLE_PATH) || defined (VMS)
+ result = (boolean) (strchr (PathDelimiters, c) != NULL);
+#else
+ result = (boolean) (c == PATH_SEPARATOR);
+#endif
+ return result;
+}
+
+#if ! defined (HAVE_STAT_ST_INO)
+
+static void canonicalizePath (char *const path)
+{
+#if defined (MSDOS_STYLE_PATH)
+ char *p;
+ for (p = path ; *p != '\0' ; ++p)
+ if (isPathSeparator (*p) && *p != ':')
+ *p = PATH_SEPARATOR;
+#endif
+}
+
+#endif
+
+extern boolean isSameFile (const char *const name1, const char *const name2)
+{
+ boolean result = FALSE;
+#if defined (HAVE_STAT_ST_INO)
+ struct stat stat1, stat2;
+
+ if (stat (name1, &stat1) == 0 && stat (name2, &stat2) == 0)
+ result = (boolean) (stat1.st_ino == stat2.st_ino);
+#else
+ {
+ char *const n1 = absoluteFilename (name1);
+ char *const n2 = absoluteFilename (name2);
+ canonicalizePath (n1);
+ canonicalizePath (n2);
+# if defined (CASE_INSENSITIVE_FILENAMES)
+ result = (boolean) (strcasecmp (n1, n2) == 0);
+#else
+ result = (boolean) (strcmp (n1, n2) == 0);
+#endif
+ free (n1);
+ free (n2);
+ }
+#endif
+ return result;
+}
+
+extern const char *baseFilename (const char *const filePath)
+{
+#if defined (MSDOS_STYLE_PATH) || defined (VMS)
+ const char *tail = NULL;
+ unsigned int i;
+
+ /* Find whichever of the path delimiters is last.
+ */
+ for (i = 0 ; i < strlen (PathDelimiters) ; ++i)
+ {
+ const char *sep = strrchr (filePath, PathDelimiters [i]);
+
+ if (sep > tail)
+ tail = sep;
+ }
+#else
+ const char *tail = strrchr (filePath, PATH_SEPARATOR);
+#endif
+ if (tail == NULL)
+ tail = filePath;
+ else
+ ++tail; /* step past last delimiter */
+#ifdef VAXC
+ {
+ /* remove version number from filename */
+ char *p = strrchr ((char *) tail, ';');
+ if (p != NULL)
+ *p = '\0';
+ }
+#endif
+
+ return tail;
+}
+
+extern const char *fileExtension (const char *const fileName)
+{
+ const char *extension;
+ const char *pDelimiter = NULL;
+ const char *const base = baseFilename (fileName);
+#ifdef QDOS
+ pDelimiter = strrchr (base, '_');
+#endif
+ if (pDelimiter == NULL)
+ pDelimiter = strrchr (base, '.');
+
+ if (pDelimiter == NULL)
+ extension = "";
+ else
+ extension = pDelimiter + 1; /* skip to first char of extension */
+
+ return extension;
+}
+
+extern boolean isAbsolutePath (const char *const path)
+{
+ boolean result = FALSE;
+#if defined (MSDOS_STYLE_PATH)
+ if (isPathSeparator (path [0]))
+ result = TRUE;
+ else if (isalpha (path [0]) && path [1] == ':')
+ {
+ if (isPathSeparator (path [2]))
+ result = TRUE;
+ else
+ /* We don't support non-absolute file names with a drive
+ * letter, like `d:NAME' (it's too much hassle).
+ */
+ error (FATAL,
+ "%s: relative file names with drive letters not supported",
+ path);
+ }
+#elif defined (VMS)
+ result = (boolean) (strchr (path, ':') != NULL);
+#else
+ result = isPathSeparator (path [0]);
+#endif
+ return result;
+}
+
+extern vString *combinePathAndFile (
+ const char *const path, const char *const file)
+{
+ vString *const filePath = vStringNew ();
+#ifdef VMS
+ const char *const directoryId = strstr (file, ".DIR;1");
+
+ if (directoryId == NULL)
+ {
+ const char *const versionId = strchr (file, ';');
+
+ vStringCopyS (filePath, path);
+ if (versionId == NULL)
+ vStringCatS (filePath, file);
+ else
+ vStringNCatS (filePath, file, versionId - file);
+ vStringCopyToLower (filePath, filePath);
+ }
+ else
+ {
+ /* File really is a directory; append it to the path.
+ * Gotcha: doesn't work with logical names.
+ */
+ vStringNCopyS (filePath, path, strlen (path) - 1);
+ vStringPut (filePath, '.');
+ vStringNCatS (filePath, file, directoryId - file);
+ if (strchr (path, '[') != NULL)
+ vStringPut (filePath, ']');
+ else
+ vStringPut (filePath, '>');
+ vStringTerminate (filePath);
+ }
+#else
+ const int lastChar = path [strlen (path) - 1];
+ boolean terminated = isPathSeparator (lastChar);
+
+ vStringCopyS (filePath, path);
+ if (! terminated)
+ {
+ vStringPut (filePath, OUTPUT_PATH_SEPARATOR);
+ vStringTerminate (filePath);
+ }
+ vStringCatS (filePath, file);
+#endif
+
+ return filePath;
+}
+
+/* Return a newly-allocated string whose contents concatenate those of
+ * s1, s2, s3.
+ * Routine adapted from Gnu etags.
+ */
+static char* concat (const char *s1, const char *s2, const char *s3)
+{
+ int len1 = strlen (s1), len2 = strlen (s2), len3 = strlen (s3);
+ char *result = xMalloc (len1 + len2 + len3 + 1, char);
+
+ strcpy (result, s1);
+ strcpy (result + len1, s2);
+ strcpy (result + len1 + len2, s3);
+ result [len1 + len2 + len3] = '\0';
+
+ return result;
+}
+
+/* Return a newly allocated string containing the absolute file name of FILE
+ * given CWD (which should end with a slash).
+ * Routine adapted from Gnu etags.
+ */
+extern char* absoluteFilename (const char *file)
+{
+ char *slashp, *cp;
+ char *res = NULL;
+ if (isAbsolutePath (file))
+ {
+#ifdef MSDOS_STYLE_PATH
+ if (file [1] == ':')
+ res = eStrdup (file);
+ else
+ {
+ char drive [3];
+ sprintf (drive, "%c:", currentdrive ());
+ res = concat (drive, file, "");
+ }
+#else
+ res = eStrdup (file);
+#endif
+ }
+ else
+ res = concat (CurrentDirectory, file, "");
+
+ /* Delete the "/dirname/.." and "/." substrings. */
+ slashp = strchr (res, PATH_SEPARATOR);
+ while (slashp != NULL && slashp [0] != '\0')
+ {
+ if (slashp[1] == '.')
+ {
+ if (slashp [2] == '.' &&
+ (slashp [3] == PATH_SEPARATOR || slashp [3] == '\0'))
+ {
+ cp = slashp;
+ do
+ cp--;
+ while (cp >= res && ! isAbsolutePath (cp));
+ if (cp < res)
+ cp = slashp;/* the absolute name begins with "/.." */
+#ifdef MSDOS_STYLE_PATH
+ /* Under MSDOS and NT we get `d:/NAME' as absolute file name,
+ * so the luser could say `d:/../NAME'. We silently treat this
+ * as `d:/NAME'.
+ */
+ else if (cp [0] != PATH_SEPARATOR)
+ cp = slashp;
+#endif
+ strcpy (cp, slashp + 3);
+ slashp = cp;
+ continue;
+ }
+ else if (slashp [2] == PATH_SEPARATOR || slashp [2] == '\0')
+ {
+ strcpy (slashp, slashp + 2);
+ continue;
+ }
+ }
+ slashp = strchr (slashp + 1, PATH_SEPARATOR);
+ }
+
+ if (res [0] == '\0')
+ return eStrdup ("/");
+ else
+ {
+#ifdef MSDOS_STYLE_PATH
+ /* Canonicalize drive letter case. */
+ if (res [1] == ':' && islower (res [0]))
+ res [0] = toupper (res [0]);
+#endif
+
+ return res;
+ }
+}
+
+/* Return a newly allocated string containing the absolute file name of dir
+ * where `file' resides given `CurrentDirectory'.
+ * Routine adapted from Gnu etags.
+ */
+extern char* absoluteDirname (char *file)
+{
+ char *slashp, *res;
+ char save;
+ slashp = strrchr (file, PATH_SEPARATOR);
+ if (slashp == NULL)
+ res = eStrdup (CurrentDirectory);
+ else
+ {
+ save = slashp [1];
+ slashp [1] = '\0';
+ res = absoluteFilename (file);
+ slashp [1] = save;
+ }
+ return res;
+}
+
+/* Return a newly allocated string containing the file name of FILE relative
+ * to the absolute directory DIR (which should end with a slash).
+ * Routine adapted from Gnu etags.
+ */
+extern char* relativeFilename (const char *file, const char *dir)
+{
+ const char *fp, *dp;
+ char *absdir, *res;
+ int i;
+
+ /* Find the common root of file and dir (with a trailing slash). */
+ absdir = absoluteFilename (file);
+ fp = absdir;
+ dp = dir;
+ while (*fp++ == *dp++)
+ continue;
+ fp--;
+ dp--; /* back to the first differing char */
+ do
+ { /* look at the equal chars until path sep */
+ if (fp == absdir)
+ return absdir; /* first char differs, give up */
+ fp--;
+ dp--;
+ } while (*fp != PATH_SEPARATOR);
+
+ /* Build a sequence of "../" strings for the resulting relative file name.
+ */
+ i = 0;
+ while ((dp = strchr (dp + 1, PATH_SEPARATOR)) != NULL)
+ i += 1;
+ res = xMalloc (3 * i + strlen (fp + 1) + 1, char);
+ res [0] = '\0';
+ while (i-- > 0)
+ strcat (res, "../");
+
+ /* Add the file name relative to the common root of file and dir. */
+ strcat (res, fp + 1);
+ free (absdir);
+
+ return res;
+}
+
+extern FILE *tempFile (const char *const mode, char **const pName)
+{
+ char *name;
+ FILE *fp;
+ int fd;
+#if defined(HAVE_MKSTEMP)
+ const char *const pattern = "tags.XXXXXX";
+ const char *tmpdir = NULL;
+ fileStatus *file = eStat (ExecutableProgram);
+ if (! file->isSetuid)
+ tmpdir = getenv ("TMPDIR");
+ if (tmpdir == NULL)
+ tmpdir = TMPDIR;
+ name = xMalloc (strlen (tmpdir) + 1 + strlen (pattern) + 1, char);
+ sprintf (name, "%s%c%s", tmpdir, OUTPUT_PATH_SEPARATOR, pattern);
+ fd = mkstemp (name);
+ eStatFree (file);
+#elif defined(HAVE_TEMPNAM)
+ name = tempnam (TMPDIR, "tags");
+ if (name == NULL)
+ error (FATAL | PERROR, "cannot allocate temporary file name");
+ fd = open (name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+#else
+ name = xMalloc (L_tmpnam, char);
+ if (tmpnam (name) != name)
+ error (FATAL | PERROR, "cannot assign temporary file name");
+ fd = open (name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+#endif
+ if (fd == -1)
+ error (FATAL | PERROR, "cannot open temporary file");
+ fp = fdopen (fd, mode);
+ if (fp == NULL)
+ error (FATAL | PERROR, "cannot open temporary file");
+ DebugStatement (
+ debugPrintf (DEBUG_STATUS, "opened temporary file %s\n", name); )
+ Assert (*pName == NULL);
+ *pName = name;
+ return fp;
+}
+
+/* vi:set tabstop=4 shiftwidth=4: */
Index: create-5.8-unused-attribute-patch/ctags-5.8-new
===================================================================
--- create-5.8-unused-attribute-patch/ctags-5.8-new (nonexistent)
+++ create-5.8-unused-attribute-patch/ctags-5.8-new (revision 5)
Property changes on: create-5.8-unused-attribute-patch/ctags-5.8-new
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create-5.8-unused-attribute-patch/file.list
===================================================================
--- create-5.8-unused-attribute-patch/file.list (nonexistent)
+++ create-5.8-unused-attribute-patch/file.list (revision 5)
@@ -0,0 +1,10 @@
+ctags-5.8/c.c
+ctags-5.8/eiffel.c
+ctags-5.8/general.h
+ctags-5.8/lregex.c
+ctags-5.8/lua.c
+ctags-5.8/main.c
+ctags-5.8/options.c
+ctags-5.8/parse.c
+ctags-5.8/python.c
+ctags-5.8/routines.c
Index: create-5.8-unused-attribute-patch
===================================================================
--- create-5.8-unused-attribute-patch (nonexistent)
+++ create-5.8-unused-attribute-patch (revision 5)
Property changes on: create-5.8-unused-attribute-patch
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: patches/README
===================================================================
--- patches/README (nonexistent)
+++ patches/README (revision 5)
@@ -0,0 +1,6 @@
+
+/* begin *
+
+ TODO: Leave some comment here.
+
+ * end */
Index: patches
===================================================================
--- patches (nonexistent)
+++ patches (revision 5)
Property changes on: patches
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: .
===================================================================
--- . (nonexistent)
+++ . (revision 5)
Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~