From 38c3656d1c25c9ab79ead94160641c3e95075804 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Techet?= Date: Tue, 12 Apr 2022 14:28:20 +0200 Subject: [PATCH] Update to the upstream latex parser The new parser reports scope so update the corresponding functions. In addition this patch adds new root "Part" for reporting parts and adds a separate "Bibitem" root (bibitem and label items used to be reported together which I think is a bit confusing). --- ctags/Makefile.am | 3 +- ctags/parsers/geany_tex.c | 242 ------ ctags/parsers/tex.c | 1253 +++++++++++++++++++++++++++++++ ctags/parsers/tex.h | 114 +++ meson.build | 3 +- src/tagmanager/tm_parser.c | 29 +- tests/ctags/3526726.tex.tags | 266 ++++--- tests/ctags/bug2886870.tex.tags | 19 +- tests/ctags/intro.tex.tags | 18 +- tests/ctags/intro_orig.tex | 15 + tests/ctags/intro_orig.tex.tags | 20 +- 11 files changed, 1570 insertions(+), 412 deletions(-) delete mode 100644 ctags/parsers/geany_tex.c create mode 100644 ctags/parsers/tex.c create mode 100644 ctags/parsers/tex.h diff --git a/ctags/Makefile.am b/ctags/Makefile.am index b7a5c40fe5..e0a6a0d6c8 100644 --- a/ctags/Makefile.am +++ b/ctags/Makefile.am @@ -93,7 +93,8 @@ parsers = \ parsers/tcl.c \ parsers/tcl.h \ parsers/tcloo.c \ - parsers/geany_tex.c \ + parsers/tex.c \ + parsers/tex.h \ parsers/txt2tags.c \ parsers/verilog.c \ parsers/vhdl.c diff --git a/ctags/parsers/geany_tex.c b/ctags/parsers/geany_tex.c deleted file mode 100644 index 8bc1364ede..0000000000 --- a/ctags/parsers/geany_tex.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (c) 2000-2001, Jérôme Plût - * Copyright (c) 2006, Enrico Tröger - * - * 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 source files - * for the TeX formatting system. - */ - -/* -* INCLUDE FILES -*/ -#include "general.h" /* must always come first */ - -#include -#include - -#include "parse.h" -#include "read.h" -#include "vstring.h" -#include "routines.h" - -/* -* DATA DEFINITIONS -*/ -typedef enum { - K_COMMAND, - K_ENVIRONMENT, - K_SECTION, - K_SUBSECTION, - K_SUBSUBSECTION, - K_CHAPTER, - K_LABEL -} TeXKind; - -static kindDefinition TeXKinds[] = { - { true, 'f', "function", "command definitions" }, - { true, 'c', "class", "environment definitions" }, - { true, 'm', "member", "labels, sections and bibliography" }, - { true, 'd', "macro", "subsections" }, - { true, 'v', "variable", "subsubsections" }, - { true, 'n', "namespace", "chapters"}, - { true, 's', "struct", "labels and bibliography" } -}; - -#define TEX_BRACES (1<<0) -#define TEX_BSLASH (1<<1) -#define TEX_LABEL (1<<2) - -/* -* FUNCTION DEFINITIONS -*/ - -static int getWord(const char * ref, const char **ptr) -{ - const char *p = *ptr; - - while ((*ref != '\0') && (*p != '\0') && (*ref == *p)) - ref++, p++; - - - if (*ref) - return false; - - if (*p == '*') /* to allow something like \section*{foobar} */ - p++; - - *ptr = p; - return true; -} - -static void createTag(int flags, TeXKind kind, const char * l) -{ - vString *name = vStringNew (); - - while ((*l == ' ')) - l++; - if (flags & (TEX_BRACES | TEX_LABEL)) - { - if (*l == '[') - { - while (*l != ']') - { - if (*l == '\0') - goto no_tag; - l++; - } - l++; /* skip the closing square bracket */ - } - if (*l != '{') - goto no_tag; - l++; - } - if (flags & TEX_BSLASH) - { - if ((*(l++)) != '\\') - goto no_tag; - } - if (flags & TEX_LABEL) - { - do - { - vStringPut(name, (int) *l); - ++l; - } while ((*l != '\0') && (*l != '}')); - if (name->buffer[0] != '}') - makeSimpleTag(name, kind); - } - else if (isalpha((int) *l) || *l == '@') - { - do - { - vStringPut (name, (int) *l); - ++l; - } while (isalpha((int) *l) || *l == '@'); - makeSimpleTag(name, kind); - } - else - { - vStringPut(name, (int) *l); - makeSimpleTag(name, kind); - } - -no_tag: - vStringDelete(name); -} - -static void findTeXTags(void) -{ - const char *line; - - while ((line = (const char*)readLineFromInputFile()) != NULL) - { - const char *cp = line; - /*int escaped = 0;*/ - - for (; *cp != '\0'; cp++) - { - if (*cp == '%') - break; - if (*cp == '\\') - { - cp++; - - /* \newcommand{\command} */ - if (getWord("newcommand", &cp) - || getWord("providecommand", &cp) - || getWord("renewcommand", &cp) - ) - { - createTag (TEX_BRACES|TEX_BSLASH, K_COMMAND, cp); - continue; - } - - /* \DeclareMathOperator{\command} */ - else if (getWord("DeclareMathOperator", &cp)) - { - if (*cp == '*') - cp++; - createTag(TEX_BRACES|TEX_BSLASH, K_COMMAND, cp); - continue; - } - - /* \def\command */ - else if (getWord("def", &cp)) - { - createTag(TEX_BSLASH, K_COMMAND, cp); - continue; - } - - /* \newenvironment{name} */ - else if ( getWord("newenvironment", &cp) - || getWord("newtheorem", &cp) - || getWord("begin", &cp) - ) - { - createTag(TEX_BRACES, K_ENVIRONMENT, cp); - continue; - } - - /* \bibitem[label]{key} */ - else if (getWord("bibitem", &cp)) - { - while (*cp == ' ') - cp++; - if (*(cp++) != '[') - break; - while ((*cp != '\0') && (*cp != ']')) - cp++; - if (*(cp++) != ']') - break; - createTag(TEX_LABEL, K_LABEL, cp); - continue; - } - - /* \label{key} */ - else if (getWord("label", &cp)) - { - createTag(TEX_LABEL, K_LABEL, cp); - continue; - } - /* \section{key} */ - else if (getWord("section", &cp)) - { - createTag(TEX_LABEL, K_SECTION, cp); - continue; - } - /* \subsection{key} */ - else if (getWord("subsection", &cp)) - { - createTag(TEX_LABEL, K_SUBSECTION, cp); - continue; - } - /* \subsubsection{key} */ - else if (getWord("subsubsection", &cp)) - { - createTag(TEX_LABEL, K_SUBSUBSECTION, cp); - continue; - } - /* \chapter{key} */ - else if (getWord("chapter", &cp)) - { - createTag(TEX_LABEL, K_CHAPTER, cp); - continue; - } - } - } - } -} - -extern parserDefinition* TexParser (void) -{ - static const char *const extensions [] = { "tex", "sty", "idx", NULL }; - parserDefinition * def = parserNew ("LaTeX"); - def->kindTable = TeXKinds; - def->kindCount = ARRAY_SIZE (TeXKinds); - def->extensions = extensions; - def->parser = findTeXTags; - return def; -} diff --git a/ctags/parsers/tex.c b/ctags/parsers/tex.c new file mode 100644 index 0000000000..ac58cf9df8 --- /dev/null +++ b/ctags/parsers/tex.c @@ -0,0 +1,1253 @@ +/* + * Copyright (c) 2008, David Fishburn + * Copyright (c) 2012, Jan Larres + * + * This source code is released for free distribution under the terms of the + * GNU General Public License version 2 or (at your option) any later version. + * + * This module contains functions for generating tags for TeX language files. + * + * Tex language reference: + * http://en.wikibooks.org/wiki/TeX#The_Structure_of_TeX + */ + +/* + * INCLUDE FILES + */ +#include "general.h" /* must always come first */ +#include /* to define isalpha () */ +#ifdef DEBUG +#include +#endif +#include + +#include "debug.h" +#include "entry.h" +#include "keyword.h" +#include "parse.h" +#include "read.h" +#include "routines.h" +#include "vstring.h" + +#include "tex.h" + +/* + * MACROS + */ +#define isType(token,t) (bool) ((token)->type == (t)) +#define isKeyword(token,k) (bool) ((token)->keyword == (k)) +#define isIdentChar(c) \ + (isalpha (c) || isdigit (c) || (c) >= 0x80 || (c) == '$' || \ + (c) == '_' || (c) == '#' || (c) == '-' || (c) == '.' || (c) == ':') + +/* + * DATA DECLARATIONS + */ + +/* + * Used to specify type of keyword. + */ +enum eKeywordId { + KEYWORD_part, + KEYWORD_chapter, + KEYWORD_section, + KEYWORD_subsection, + KEYWORD_subsubsection, + KEYWORD_paragraph, + KEYWORD_subparagraph, + KEYWORD_label, + KEYWORD_include, + KEYWORD_input, + KEYWORD_begin, + KEYWORD_end, + KEYWORD_bibitem, + KEYWORD_bibliography, + KEYWORD_newcommand, + KEYWORD_renewcommand, + KEYWORD_providecommand, + KEYWORD_def, + KEYWORD_declaremathoperator, + KEYWORD_newenvironment, + KEYWORD_renewenvironment, + KEYWORD_newtheorem, + KEYWORD_newcounter, +}; +typedef int keywordId; /* to allow KEYWORD_NONE */ + +enum eTokenType { + /* 0..255 are the byte's value. Some are named for convenience */ + TOKEN_OPEN_PAREN = '(', + TOKEN_CLOSE_PAREN = ')', + TOKEN_OPEN_CURLY = '{', + TOKEN_CLOSE_CURLY = '}', + TOKEN_OPEN_SQUARE = '[', + TOKEN_CLOSE_SQUARE = ']', + TOKEN_STAR = '*', + /* above is special types */ + TOKEN_UNDEFINED = 256, + TOKEN_KEYWORD, + TOKEN_IDENTIFIER, + TOKEN_STRING, +}; +typedef int tokenType; + +typedef struct sTokenInfo { + tokenType type; + keywordId keyword; + vString * string; + vString * scope; + unsigned long lineNumber; + MIOPos filePosition; +} tokenInfo; + +/* + * DATA DEFINITIONS + */ + +static langType Lang_tex; + +static vString *lastPart; +static vString *lastChapter; +static vString *lastSection; +static vString *lastSubS; +static vString *lastSubSubS; + +typedef enum { + TEXTAG_PART, + TEXTAG_CHAPTER, + TEXTAG_SECTION, + TEXTAG_SUBSECTION, + TEXTAG_SUBSUBSECTION, + TEXTAG_PARAGRAPH, + TEXTAG_SUBPARAGRAPH, + TEXTAG_LABEL, + TEXTAG_XINPUT, + TEXTAG_BIBITEM, + TEXTAG_COMMAND, + TEXTAG_OPERATOR, + TEXTAG_ENVIRONMENT, + TEXTAG_THEOREM, + TEXTAG_COUNTER, + TEXTAG_COUNT +} texKind; + +typedef enum { + TEX_XINPUT_INCLUDED, + TEX_XINPUT_INPUT, + TEX_XINPUT_BIBLIOGRAPHY, +} texInputRole; + +typedef enum { + TEX_ENVIRONMENT_USED, +} texEnvironmentRole; + +static roleDefinition TexInputRoles [] = { + { true, "included", + "external input file specified with \\include" }, + { true, "input", + "external input file specified with \\input" }, + { true, "bibliography", + "bibliography (.bib) file" }, +}; + +static roleDefinition TexEnvironmentRoles [] = { + { false, "used", "environment usage introduced by \\begin{MyEnv}" }, +}; + +static kindDefinition TexKinds [] = { + { true, 'p', "part", "parts" }, + { true, 'c', "chapter", "chapters" }, + { true, 's', "section", "sections" }, + { true, 'u', "subsection", "subsections" }, + { true, 'b', "subsubsection", "subsubsections" }, + { true, 'P', "paragraph", "paragraphs" }, + { true, 'G', "subparagraph", "subparagraphs" }, + { true, 'l', "label", "labels" }, + { true, 'i', "xinput", "external input files", + .referenceOnly = true, ATTACH_ROLES(TexInputRoles) }, + { true, 'B', "bibitem", "bibliography items" }, + { true, 'C', "command", "command created with \\newcommand" }, + { true, 'o', "operator", "math operator created with \\DeclareMathOperator" }, + { true, 'e', "environment", "environment created with \\newenvironment", + .referenceOnly = false, ATTACH_ROLES(TexEnvironmentRoles) }, + { true, 't', "theorem", "theorem created with \\newtheorem" }, + { true, 'N', "counter", "counter created with \\newcounter" }, +}; + +static const keywordTable TexKeywordTable [] = { + /* keyword keyword ID */ + { "part", KEYWORD_part }, + { "chapter", KEYWORD_chapter }, + { "section", KEYWORD_section }, + { "subsection", KEYWORD_subsection }, + { "subsubsection", KEYWORD_subsubsection }, + { "paragraph", KEYWORD_paragraph }, + { "subparagraph", KEYWORD_subparagraph }, + { "label", KEYWORD_label }, + { "include", KEYWORD_include }, + { "input", KEYWORD_input }, + { "begin", KEYWORD_begin }, + { "end", KEYWORD_end }, + { "bibitem", KEYWORD_bibitem }, + { "bibliography", KEYWORD_bibliography }, + { "newcommand", KEYWORD_newcommand }, + { "renewcommand", KEYWORD_renewcommand }, + { "providecommand", KEYWORD_providecommand }, + { "def", KEYWORD_def }, + { "DeclareMathOperator", KEYWORD_declaremathoperator }, + { "newenvironment", KEYWORD_newenvironment }, + { "renewenvironment", KEYWORD_renewenvironment}, + { "newtheorem", KEYWORD_newtheorem }, + { "newcounter", KEYWORD_newcounter }, +}; + +/* + * FUNCTION DECLARATIONS + */ + +static bool notifyReadingIdentifier (tokenInfo *id_token, bool *tokenUnprocessed); +static bool notifyReadingBeginEnvironment (tokenInfo *token, vString *envName, bool *tokenUnprocessed); +static bool notifyReadingEndEnvironment (vString *envName); + + +/* + * FUNCTION DEFINITIONS + */ + +static tokenInfo *newToken (void) +{ + tokenInfo *const token = xMalloc (1, tokenInfo); + + token->type = TOKEN_UNDEFINED; + token->keyword = KEYWORD_NONE; + token->string = vStringNew (); + token->scope = vStringNew (); + token->lineNumber = getInputLineNumber (); + token->filePosition = getInputFilePosition (); + + return token; +} + +static void deleteToken (tokenInfo *const token) +{ + vStringDelete (token->string); + vStringDelete (token->scope); + eFree (token); +} + +static int getScopeInfo(texKind kind, vString *const parentName) +{ + int parentKind = KIND_GHOST_INDEX; + int i; + + /* + * Put labels separately instead of under their scope. + * Is this The Right Thing To Do? + */ + if (kind >= TEXTAG_LABEL) { + goto out; + } + + /* + * This abuses the enum internals somewhat, but it should be ok in this + * case. + */ + /* TODO: This loop and conditions can be squashed. */ + for (i = kind - 1; i >= TEXTAG_PART; --i) { + if (i == TEXTAG_SUBSECTION && vStringLength(lastSubS) > 0) { + parentKind = i; + break; + } else if (i == TEXTAG_SECTION && vStringLength(lastSection) > 0) { + parentKind = i; + break; + } else if (i == TEXTAG_CHAPTER && vStringLength(lastChapter) > 0) { + parentKind = i; + break; + } else if (i == TEXTAG_PART && vStringLength(lastPart) > 0) { + parentKind = i; + break; + } + } + + /* + * Is '""' the best way to separate scopes? It has to be something that + * should ideally never occur in normal LaTeX text. + */ + for (i = TEXTAG_PART; i < (int)kind; ++i) { + if (i == TEXTAG_PART && vStringLength(lastPart) > 0) { + vStringCat(parentName, lastPart); + } else if (i == TEXTAG_CHAPTER && vStringLength(lastChapter) > 0) { + if (vStringLength(parentName) > 0) { + vStringCatS(parentName, "\"\""); + } + vStringCat(parentName, lastChapter); + } else if (i == TEXTAG_SECTION && vStringLength(lastSection) > 0) { + if (vStringLength(parentName) > 0) { + vStringCatS(parentName, "\"\""); + } + vStringCat(parentName, lastSection); + } else if (i == TEXTAG_SUBSECTION && vStringLength(lastSubS) > 0) { + if (vStringLength(parentName) > 0) { + vStringCatS(parentName, "\"\""); + } + vStringCat(parentName, lastSubS); + } + } + out: + return parentKind; +} + +/* + * Tag generation functions + */ + +struct symbolData { + langType lang; + int kind; + int *corkQueue; +}; + +static bool findTheName (int corkIndex, tagEntryInfo *entry, void *data) +{ + struct symbolData *symbolData = data; + + if (entry->langType == symbolData->lang && entry->kindIndex == symbolData->kind) + { + /* TODO: The case operation should be removed */ + *symbolData->corkQueue = corkIndex; + return false; + } + return true; +} + +static int makeTexTag (tokenInfo *const token, int kind, + int roleIndex, bool unique, int scopeIndex) +{ + int corkQueue = CORK_NIL; + const char *const name = vStringValue (token->string); + + if (unique) + { + struct symbolData data = { + .lang = getInputLanguage(), + .kind = kind, + .corkQueue = &corkQueue, + }; + /* TODO: The case operation should be removed */ + if (foreachEntriesInScope (scopeIndex, name, findTheName, (void *)&data) == false) + return *data.corkQueue; + } + + tagEntryInfo e; + initTagEntry (&e, name, kind); + + e.lineNumber = token->lineNumber; + e.filePosition = token->filePosition; + + vString *parentName = NULL; + + + if (unique) + e.extensionFields.scopeIndex = scopeIndex; + + /* Filling e.extensionFields.scopeKindIndex and + * e.extensionFields.scopeName can be filled from "kind" parameter + * of this function only when Tex parser calls this function. The + * fields cannot be filled with a kind defined in a subparser. + * Subparsers may fill the scope after running strategy. So in the + * context of a subparser, filling the scope fields here is not + * needed. + */ + if (Lang_tex == getInputLanguage ()) + { + int parentKind = KIND_GHOST_INDEX; + parentName = vStringNew(); + parentKind = getScopeInfo(kind, parentName); + if (parentKind != KIND_GHOST_INDEX) { + e.extensionFields.scopeKindIndex = parentKind; + e.extensionFields.scopeName = vStringValue(parentName); + } + } + + assignRole (&e, roleIndex); + + corkQueue = makeTagEntry (&e); + vStringDelete (parentName); /* NULL is o.k. */ + + if (unique && corkQueue != CORK_NIL) + registerEntry (corkQueue); + + return corkQueue; +} + +/* + * Parsing functions + */ + +/* + * Read a C identifier beginning with "firstChar" and places it into + * "name". + */ +static void parseIdentifier (vString *const string, const int firstChar) +{ + int c = firstChar; + Assert (isIdentChar (c)); + do + { + vStringPut (string, c); + c = getcFromInputFile (); + } while (c != EOF && isIdentChar (c)); + + if (c != EOF) + ungetcToInputFile (c); /* unget non-identifier character */ +} + +static bool readTokenFull (tokenInfo *const token, const bool includeWhitespaces) +{ + int c; + int whitespaces = -1; + + token->type = TOKEN_UNDEFINED; + token->keyword = KEYWORD_NONE; + vStringClear (token->string); + +getNextChar: + + do + { + c = getcFromInputFile (); + whitespaces++; + } + while (c == '\t' || c == ' ' || c == '\n'); + + token->lineNumber = getInputLineNumber (); + token->filePosition = getInputFilePosition (); + + if (includeWhitespaces && whitespaces > 0 && c != '%' && c != EOF) + { + ungetcToInputFile (c); + c = ' '; + } + + token->type = (unsigned char) c; + switch (c) + { + case EOF: return false; + + case '\\': + /* + * All Tex tags start with a backslash. + * Check if the next character is an alpha character + * else it is not a potential tex tag. + */ + c = getcFromInputFile (); + if (! isalpha (c)) + ungetcToInputFile (c); + else + { + vStringPut (token->string, '\\'); + parseIdentifier (token->string, c); + token->keyword = lookupKeyword (vStringValue (token->string) + 1, Lang_tex); + if (isKeyword (token, KEYWORD_NONE)) + token->type = TOKEN_IDENTIFIER; + else + token->type = TOKEN_KEYWORD; + } + break; + + case '%': + skipToCharacterInInputFile ('\n'); /* % are single line comments */ + goto getNextChar; + break; + + default: + if (isIdentChar (c)) + { + parseIdentifier (token->string, c); + token->type = TOKEN_IDENTIFIER; + } + break; + } + return true; +} + +static bool readToken (tokenInfo *const token) +{ + return readTokenFull (token, false); +} + +static void copyToken (tokenInfo *const dest, tokenInfo *const src) +{ + dest->lineNumber = src->lineNumber; + dest->filePosition = src->filePosition; + dest->type = src->type; + dest->keyword = src->keyword; + vStringCopy (dest->string, src->string); + vStringCopy (dest->scope, src->scope); +} + +static void updateScopeInfo (texKind kind, vString *fullname) +{ + switch (kind) + { + case TEXTAG_PART: + vStringCopy(lastPart, fullname); + vStringClear(lastChapter); + vStringClear(lastSection); + vStringClear(lastSubS); + vStringClear(lastSubSubS); + break; + case TEXTAG_CHAPTER: + vStringCopy(lastChapter, fullname); + vStringClear(lastSection); + vStringClear(lastSubS); + vStringClear(lastSubSubS); + break; + case TEXTAG_SECTION: + vStringCopy(lastSection, fullname); + vStringClear(lastSubS); + vStringClear(lastSubSubS); + break; + case TEXTAG_SUBSECTION: + vStringCopy(lastSubS, fullname); + vStringClear(lastSubSubS); + break; + case TEXTAG_SUBSUBSECTION: + vStringCopy(lastSubSubS, fullname); + break; + default: + break; + } +} + +/* + * Scanning functions + */ + +/* STRATEGY array represents the sequence of * expected tokens. If an + * input token matches the current * expectation (the current strategy), + * parseWithStrategy() runs * the actions attached to the strategy. + * + * The actions are making a tag with the kind specified with kindIndex + * field of the current strategy and/or storing a name to NAME field + * of the current strategy. + * + * If the input token doesn't much the current strategy, above actions + * are not run. If TEX_NAME_FLAG_OPTIONAL is specified in FLAGS field + * of the current specified, parseWithStrategy() tries the next + * strategy of STRATEGY array without reading a new token. If + * TEX_NAME_FLAG_OPTIONAL is not in FLAGS field, parseWithStrategy() + * returns the control to its caller immediately. + * + * TOKENUNPROCESSED is used for both input and output. As input, + * TOKENUNPROCESSED tells whether parseWithStrategy() should read a + * new token before matching the STRATEGY array or not. If + * TOKENUNPROCESSED is true, parseWithStrategy function reads a new + * token before matching. As output, TOKENUNPROCESSED tells the + * caller of parseWithStrategy() that a new token is already stored to + * TOKEN but parseWithStrategy() has not processed yet. + */ +static bool parseWithStrategy (tokenInfo *token, + struct TexParseStrategy *strategy, + bool *tokenUnprocessed) +{ + bool next_token = !*tokenUnprocessed; + tokenInfo * name = NULL; + bool eof = false; + bool exclusive = false; + + for (struct TexParseStrategy *s = strategy; s->type != 0; ++s) + s->corkIndex = CORK_NIL; + + for (struct TexParseStrategy *s = strategy; !eof && s->type != 0; ++s) + { + if (s->kindIndex != KIND_GHOST_INDEX || s->name) + { + name = newToken (); + break; + } + } + + for (struct TexParseStrategy *s = strategy; !eof && s->type != 0; ++s) + { + bool capture_name = s->kindIndex != KIND_GHOST_INDEX || s->name; + + if (next_token) + { + if (!readToken (token)) + { + eof = true; + break; + } + } + + if ((s->type == '<' && isType (token, '<')) + || (s->type == '[' && isType (token, '['))) + { + tokenType terminator = (s->type == '<') ? '>' : ']'; + + next_token = true; + + + if (!readToken (token)) + { + eof = true; + break; + } + if (capture_name) + { + copyToken (name, token); + vStringClear (name->string); + } + + while (! isType (token, terminator)) + { + if (capture_name && isType (token, TOKEN_IDENTIFIER)) + { + if (vStringLength (name->string) > 0) + vStringPut (name->string, ' '); + vStringCat (name->string, token->string); + } + + if (!readTokenFull (token, + s->flags & TEX_NAME_FLAG_INCLUDING_WHITESPACE)) + { + eof = true; + break; + } + } + if (!exclusive && capture_name && vStringLength (name->string) > 0) + { + if (s->kindIndex != KIND_GHOST_INDEX) + s->corkIndex = makeTexTag (name, s->kindIndex, s->roleIndex, + s->unique, s->scopeIndex); + + if (s->name) + vStringCopy(s->name, name->string); + + if (s->flags & TEX_NAME_FLAG_EXCLUSIVE) + exclusive = true; + } + } + else if (s->type == '*' && isType (token, '*')) + next_token = true; + else if (((s->type == '{' || s->type == '\\') && isType (token, '{')) || + (s->type == '\\' && isType (token, TOKEN_IDENTIFIER))) + { + int depth = 1; + bool missing_parens = isType (token, TOKEN_IDENTIFIER); + + next_token = true; + + if (!missing_parens && !readToken (token)) + { + eof = true; + break; + } + if (capture_name) + { + copyToken (name, token); + vStringClear (name->string); + } + if (missing_parens) + { + vStringCat (name->string, token->string); + depth = 0; + } + + /* Handle the case the code like \section{} */ + if (isType (token, '}')) + break; + while (depth > 0) + { + if (capture_name) + { + if (isType (token, TOKEN_IDENTIFIER) || isType (token, TOKEN_KEYWORD)) + vStringCat (name->string, token->string); + else + vStringPut (name->string, token->type); + } + if (!readTokenFull (token, + s->flags & TEX_NAME_FLAG_INCLUDING_WHITESPACE)) + { + eof = true; + break; + } + else if (isType (token, TOKEN_OPEN_CURLY)) + depth++; + else if (isType (token, TOKEN_CLOSE_CURLY)) + depth--; + } + if (!exclusive && depth == 0 && capture_name && vStringLength (name->string) > 0) + { + vStringStripTrailing (name->string); + + if (s->kindIndex != KIND_GHOST_INDEX) + s->corkIndex = makeTexTag (name, s->kindIndex, s->roleIndex, + s->unique, s->scopeIndex); + + if (s->name) + vStringCopy(s->name, name->string); + + if (s->flags & TEX_NAME_FLAG_EXCLUSIVE) + exclusive = true; + + } + } + else if (s->flags & TEX_NAME_FLAG_OPTIONAL) + /* Apply next strategy to the same token */ + next_token = false; + else + { + *tokenUnprocessed = true; + break; + } + } + + /* The last token is optional and not present - let the caller know */ + if (!next_token) + *tokenUnprocessed = true; + + if (name) + deleteToken (name); + + return eof; +} + +static bool parseTagFull (tokenInfo *const token, texKind kind, int roleIndex, bool enterSquare, bool *tokenUnprocessed) +{ + bool eof = false; + vString *taggedName = vStringNew(); + + /* + * Tex tags are of these formats: + * \keyword{any number of words} + * \keyword[short desc]{any number of words} + * \keyword*[short desc]{any number of words} + * + * When a keyword is found, loop through all words within + * the curly braces for the tag name. + * + * If the keyword is label like \label, words in the square + * brackets should be skipped. This can be controlled + * with `enterSquare' parameter; true is for tagging, and + * false is for skipping. + */ + + struct TexParseStrategy strategy [] = { + { + .type = '[', + .flags = TEX_NAME_FLAG_OPTIONAL, + /* .kindIndex is initialized dynamically. */ + }, + { + .type = '*', + .flags = TEX_NAME_FLAG_OPTIONAL, + .kindIndex = KIND_GHOST_INDEX, + .name = NULL, + }, + { + .type = '{', + .flags = TEX_NAME_FLAG_INCLUDING_WHITESPACE, + .kindIndex = kind, + .roleIndex = roleIndex, + .name = taggedName, + .unique = false, + }, + { + .type = 0 + } + }; + + + if (enterSquare) + { + strategy [0].kindIndex = kind; + strategy [0].roleIndex = roleIndex; + strategy [0].flags |= TEX_NAME_FLAG_EXCLUSIVE; + strategy [0].name = taggedName; + strategy [0].unique = false; + } + else + { + strategy [0].kindIndex = KIND_GHOST_INDEX; + strategy [0].name = NULL; + } + + if (parseWithStrategy (token, strategy, tokenUnprocessed)) + { + eof = true; + goto out; + } + + /* + * save the name of the last section definitions for scope-resolution + * later + */ + if (vStringLength (taggedName) > 0) + updateScopeInfo (kind, taggedName); + + out: + vStringDelete (taggedName); + + return eof; +} + +static bool parseTag (tokenInfo *const token, texKind kind, + bool enterSquare, bool *tokenUnprocessed) +{ + return parseTagFull (token, kind, ROLE_DEFINITION_INDEX, + enterSquare, tokenUnprocessed); +} + +static bool parseEnv (tokenInfo *const token, bool begin, bool *tokenUnprocessed) +{ + bool eof = false; + vString *envName = vStringNew (); + struct TexParseStrategy strategy [] = { + { + .type = '{', + .flags = TEX_NAME_FLAG_INCLUDING_WHITESPACE, + .kindIndex = begin ? TEXTAG_ENVIRONMENT : KIND_GHOST_INDEX, + .roleIndex = TEX_ENVIRONMENT_USED, + .name = envName, + }, + { + .type = 0 + } + }; + + if (parseWithStrategy (token, strategy, tokenUnprocessed)) + { + eof = true; + goto out; + } + + + if (vStringLength (envName) > 0) + { + if (begin) + eof = notifyReadingBeginEnvironment (token, envName, tokenUnprocessed); + else + eof = notifyReadingEndEnvironment (envName); + } + + out: + vStringDelete (envName); + + return eof; + +} + +static bool parseNewcommandFull (tokenInfo *const token, bool *tokenUnprocessed, texKind kind) +{ + bool eof = false; + + /* \newcommand{cmd}[args][opt]{def} */ + /* \newcommand\cmd[args][opt]{def} */ + /* \def\cmd{replacement} */ + struct TexParseStrategy strategy [] = { + { + .type = '\\', + .flags = 0, + .kindIndex = kind, + .roleIndex = ROLE_DEFINITION_INDEX, + .name = NULL, + .unique = false, + }, + { + .type = '[', + .flags = TEX_NAME_FLAG_OPTIONAL, + .kindIndex = KIND_GHOST_INDEX, + .name = NULL, + }, + { + .type = '[', + .flags = TEX_NAME_FLAG_OPTIONAL, + .kindIndex = KIND_GHOST_INDEX, + .name = NULL, + }, + { + .type = '{', + .flags = 0, + .kindIndex = KIND_GHOST_INDEX, + .name = NULL, + }, + { + .type = 0 + } + }; + + if (parseWithStrategy (token, strategy, tokenUnprocessed)) + eof = true; + + return eof; +} + +static bool parseNewcommand (tokenInfo *const token, bool *tokenUnprocessed) +{ + return parseNewcommandFull (token, tokenUnprocessed, TEXTAG_COMMAND); +} + +static bool parseNewEnvironment (tokenInfo *const token, bool *tokenUnprocessed) +{ + bool eof = false; + /* \newenvironment{nam}[args]{begdef}{enddef} */ + struct TexParseStrategy strategy [] = { + { + .type = '{', + .flags = 0, + .kindIndex = TEXTAG_ENVIRONMENT, + .roleIndex = ROLE_DEFINITION_INDEX, + .name = NULL, + .unique = false, + }, + { + .type = '[', + .flags = TEX_NAME_FLAG_OPTIONAL, + .kindIndex = KIND_GHOST_INDEX, + .name = NULL, + }, + { + .type = '{', + .flags = 0, + .kindIndex = KIND_GHOST_INDEX, + .name = NULL, + }, + { + .type = '{', + .flags = 0, + .kindIndex = KIND_GHOST_INDEX, + .name = NULL, + }, + { + .type = 0 + } + }; + + if (parseWithStrategy (token, strategy, tokenUnprocessed)) + eof = true; + + return eof; +} + +static bool parseNewTheorem (tokenInfo *const token, bool *tokenUnprocessed) +{ + bool eof = false; + /* \newtheorem{name}{title} + \newtheorem{name}{title}[numbered_within] + \newtheorem{name}[numbered_like]{title} */ + struct TexParseStrategy strategy [] = { + { + .type = '{', + .flags = 0, + .kindIndex = TEXTAG_THEOREM, + .roleIndex = ROLE_DEFINITION_INDEX, + .name = NULL, + .unique = false, + }, + { + .type = '[', + .flags = TEX_NAME_FLAG_OPTIONAL, + .kindIndex = KIND_GHOST_INDEX, + .name = NULL, + }, + { + .type = '{', + .flags = 0, + .kindIndex = KIND_GHOST_INDEX, + .name = NULL, + }, + { + .type = '[', + .flags = TEX_NAME_FLAG_OPTIONAL, + .kindIndex = KIND_GHOST_INDEX, + .name = NULL, + }, + { + .type = 0 + } + }; + + if (parseWithStrategy (token, strategy, tokenUnprocessed)) + eof = true; + + return eof; +} + +static bool parseNewcounter (tokenInfo *const token, bool *tokenUnprocessed) +{ + bool eof = false; + /* \newcounter {counter}[parentCounter] */ + struct TexParseStrategy strategy [] = { + { + .type = '{', + .flags = 0, + .kindIndex = TEXTAG_COUNTER, + .roleIndex = ROLE_DEFINITION_INDEX, + .name = NULL, + .unique = false, + }, + { + .type = '[', + .flags = TEX_NAME_FLAG_OPTIONAL, + .kindIndex = KIND_GHOST_INDEX, + .name = NULL, + }, + { + .type = 0 + } + }; + + if (parseWithStrategy (token, strategy, tokenUnprocessed)) + eof = true; + + return eof; +} + +static void parseTexFile (tokenInfo *const token) +{ + bool eof = false; + bool tokenUnprocessed = false; + + do + { + if (!tokenUnprocessed) + { + if (!readToken (token)) + break; + } + tokenUnprocessed = false; + + if (isType (token, TOKEN_KEYWORD)) + { + switch (token->keyword) + { + case KEYWORD_part: + eof = parseTag (token, TEXTAG_PART, true, &tokenUnprocessed); + break; + case KEYWORD_chapter: + eof = parseTag (token, TEXTAG_CHAPTER, true, &tokenUnprocessed); + break; + case KEYWORD_section: + eof = parseTag (token, TEXTAG_SECTION, true, &tokenUnprocessed); + break; + case KEYWORD_subsection: + eof = parseTag (token, TEXTAG_SUBSECTION, true, &tokenUnprocessed); + break; + case KEYWORD_subsubsection: + eof = parseTag (token, TEXTAG_SUBSUBSECTION, true, &tokenUnprocessed); + break; + case KEYWORD_paragraph: + eof = parseTag (token, TEXTAG_PARAGRAPH, true, &tokenUnprocessed); + break; + case KEYWORD_subparagraph: + eof = parseTag (token, TEXTAG_SUBPARAGRAPH, true, &tokenUnprocessed); + break; + case KEYWORD_label: + eof = parseTag (token, TEXTAG_LABEL, false, &tokenUnprocessed); + break; + case KEYWORD_include: + eof = parseTagFull (token, TEXTAG_XINPUT, TEX_XINPUT_INCLUDED, + false, &tokenUnprocessed); + break; + case KEYWORD_input: + eof = parseTagFull (token, TEXTAG_XINPUT, TEX_XINPUT_INPUT, + false, &tokenUnprocessed); + break; + case KEYWORD_begin: + eof = parseEnv (token, true, &tokenUnprocessed); + break; + case KEYWORD_end: + eof = parseEnv (token, false, &tokenUnprocessed); + break; + case KEYWORD_bibitem: + eof = parseTag (token, TEXTAG_BIBITEM, false, &tokenUnprocessed); + break; + case KEYWORD_bibliography: + eof = parseTagFull (token, TEXTAG_XINPUT, TEX_XINPUT_BIBLIOGRAPHY, + false, &tokenUnprocessed); + break; + case KEYWORD_newcommand: + case KEYWORD_renewcommand: + case KEYWORD_providecommand: + case KEYWORD_def: + eof = parseNewcommand (token, &tokenUnprocessed); + break; + case KEYWORD_declaremathoperator: + eof = parseNewcommandFull (token, &tokenUnprocessed, TEXTAG_OPERATOR); + break; + case KEYWORD_newenvironment: + case KEYWORD_renewenvironment: + eof = parseNewEnvironment (token, &tokenUnprocessed); + break; + case KEYWORD_newtheorem: + eof = parseNewTheorem (token, &tokenUnprocessed); + break; + case KEYWORD_newcounter: + eof = parseNewcounter (token, &tokenUnprocessed); + break; + default: + break; + } + } + else if (isType (token, TOKEN_IDENTIFIER)) + eof = notifyReadingIdentifier (token, &tokenUnprocessed); + if (eof) + break; + } while (true); +} + +static void initialize (const langType language) +{ + Assert (ARRAY_SIZE (TexKinds) == TEXTAG_COUNT); + Lang_tex = language; + + lastPart = vStringNew(); + lastChapter = vStringNew(); + lastSection = vStringNew(); + lastSubS = vStringNew(); + lastSubSubS = vStringNew(); +} + +static void finalize (const langType language CTAGS_ATTR_UNUSED, + bool initialized) +{ + if (initialized) + { + vStringDelete(lastPart); + lastPart = NULL; + vStringDelete(lastChapter); + lastChapter = NULL; + vStringDelete(lastSection); + lastSection = NULL; + vStringDelete(lastSubS); + lastSubS = NULL; + vStringDelete(lastSubSubS); + lastSubSubS = NULL; + } +} + +static void findTexTags (void) +{ + tokenInfo *const token = newToken (); + + vStringClear(lastPart); + vStringClear(lastChapter); + vStringClear(lastSection); + vStringClear(lastSubS); + vStringClear(lastSubSubS); + + parseTexFile (token); + + deleteToken (token); +} + +static bool notifyReadingIdentifier (tokenInfo *id_token, bool *tokenUnprocessed) +{ + subparser *sub; + bool eof = false; + + foreachSubparser (sub, false) + { + texSubparser *texsub = (texSubparser *)sub; + + if (texsub->readIdentifierNotify) + { + struct TexParseStrategy *strategy; + + enterSubparser(sub); + + strategy = texsub->readIdentifierNotify (texsub, id_token->string); + + if (strategy) + { + eof = parseWithStrategy (id_token, strategy, tokenUnprocessed); + if (texsub->reportStrategicParsing) + texsub->reportStrategicParsing (texsub, strategy); + } + + leaveSubparser(); + + if (strategy) + break; + } + } + + return eof; +} + +static bool notifyReadingBeginEnvironment (tokenInfo *token, + vString *envName, + bool *tokenUnprocessed) +{ + subparser *sub; + bool eof = false; + + foreachSubparser (sub, false) + { + texSubparser *texsub = (texSubparser *)sub; + + if (texsub->readEnviromentBeginNotify) + { + struct TexParseStrategy *strategy; + + enterSubparser (sub); + strategy = texsub->readEnviromentBeginNotify (texsub, envName); + if (strategy) + { + eof = parseWithStrategy (token, strategy, tokenUnprocessed); + if (texsub->reportStrategicParsing) + texsub->reportStrategicParsing (texsub, strategy); + } + leaveSubparser (); + if (strategy) + break; + } + } + + return eof; +} + +static bool notifyReadingEndEnvironment (vString *envName) +{ + subparser *sub; + + foreachSubparser (sub, false) + { + texSubparser *texsub = (texSubparser *)sub; + + if (texsub->readEnviromentEndNotify) + { + bool consuming; + + enterSubparser (sub); + consuming = texsub->readEnviromentEndNotify (texsub, envName); + leaveSubparser (); + if (consuming) + break; + } + } + + return false; +} + +/* Create parser definition structure */ +extern parserDefinition* TexParser (void) +{ + static const char *const extensions [] = { "tex", NULL }; + parserDefinition *const def = parserNew ("Tex"); + def->extensions = extensions; + /* + * New definitions for parsing instead of regex + */ + def->kindTable = TexKinds; + def->kindCount = ARRAY_SIZE (TexKinds); + def->parser = findTexTags; + def->initialize = initialize; + def->finalize = finalize; + def->keywordTable = TexKeywordTable; + def->keywordCount = ARRAY_SIZE (TexKeywordTable); + def->useCork = CORK_QUEUE | CORK_SYMTAB; + return def; +} diff --git a/ctags/parsers/tex.h b/ctags/parsers/tex.h new file mode 100644 index 0000000000..b5a9d8b9b2 --- /dev/null +++ b/ctags/parsers/tex.h @@ -0,0 +1,114 @@ +/* +* Copyright (c) 2020, Masatake YAMATO +* +* This source code is released for free distribution under the terms of the +* GNU General Public License version 2 or (at your option) any later version. +* +* Tex base parser interface exported to subparsers +*/ + +#ifndef CTAGS_PARSER_TEX_H +#define CTAGS_PARSER_TEX_H + +/* +* INCLUDE FILES +*/ + +#include "general.h" /* must always come first */ + +#include "subparser.h" +#include "vstring.h" + + +/* +* DATA DEFINITIONS +*/ + +/* Parsing strategy */ + +enum TexNameFlag { + /* Allow that the type of input token doesn't match + * the type of strategy. In stread of aborting, + * apply the next strategy to the same token. */ + TEX_NAME_FLAG_OPTIONAL = (1 << 0), + + /* When reading tokens inside pair, + * whitespaces are considered as parts of a token or not. */ + TEX_NAME_FLAG_INCLUDING_WHITESPACE = (1 << 1), + + /* If a tag is created with this strategy, don't + * create a tag in its successor strategies. */ + TEX_NAME_FLAG_EXCLUSIVE = (1 << 2), +}; + +struct TexParseStrategy { + /* Expected token type '<', '[', '*', '{', and '\\' are supported. + * 0 means the end of strategies. '\\' means {} pair may be omitted. + * + * A string between <>, [], or {} (pairs) can be tagged or store to + * a vString. See kindIndex and name field of this structure. + */ + int type; + + /* Bits combination of enum TexNameFlag */ + unsigned int flags; + + /* Kind and role for making a tag for the string surrounded by one of pairs. + * If you don't need to make a tag for the string, + * specify KIND_GHOST_INDEX. */ + int kindIndex; + int roleIndex; + + /* If a tag is made, Tex parser stores its cork index here. */ + int corkIndex; + + /* Store the string surrounded by one of paris. + * If you don't need to store the string, set NULL here. */ + vString *name; + + /* If true, make at most one tag for the name in the scope specified + * with scopeIndex. When making a tag, scopeIndex is set to + * extensionFields.scopeIndex only if unique is true. + * scopeIndex is never referred if unique if false. */ + bool unique; + int scopeIndex; +}; + +typedef struct sTexSubparser texSubparser; +struct sTexSubparser { + subparser subparser; + + /* When Tex parser reads an \begin{foo}, it calls + * this method. + * + * A subparser having interests in successor tokens may return strategies. + * If it doesn't, just return NULL; Tex base parser may call the next subparser. + */ + struct TexParseStrategy * (* readEnviromentBeginNotify) (texSubparser *s, + vString *env); + /* When Tex parser reads an \end{foo}, it calls + * this method. + * + * If this method returns true, Tex base parser may call the next subparser. + * If it returns false, Tex base parser stops calling the rest of subparsers. + */ + bool (* readEnviromentEndNotify) (texSubparser *s, vString *env); + + /* When Tex parser reads an \identifier, it calls + * this method. + * + * A subparser having interests in successor tokens may return strategies. + * If it has no interest, just return NULL; Tex base parser may call next subparser. + */ + struct TexParseStrategy *(* readIdentifierNotify) (texSubparser *s, + vString *identifier); + + /* After Tex parser runs the strategies returned from readIdentifierNotify + * method, Tex parser calls this method to notify the subparser the result + * of running the strategies; corkIndex and/or name fields of strategies + * may be filled. */ + void (* reportStrategicParsing) (texSubparser *s, + const struct TexParseStrategy *strategy); +}; + +#endif /* CTAGS_PARSER_TEX_H */ diff --git a/meson.build b/meson.build index 0f9ea49697..6bf8511669 100644 --- a/meson.build +++ b/meson.build @@ -637,7 +637,6 @@ ctags = static_library('ctags', 'ctags/parsers/geany_lcpp.c', 'ctags/parsers/geany_lcpp.h', 'ctags/parsers/geany_matlab.c', - 'ctags/parsers/geany_tex.c', 'ctags/parsers/go.c', 'ctags/parsers/haskell.c', 'ctags/parsers/haxe.c', @@ -670,6 +669,8 @@ ctags = static_library('ctags', 'ctags/parsers/tcl.c', 'ctags/parsers/tcl.h', 'ctags/parsers/tcloo.c', + 'ctags/parsers/tex.c', + 'ctags/parsers/tex.h', 'ctags/parsers/txt2tags.c', 'ctags/parsers/verilog.c', 'ctags/parsers/vhdl.c', diff --git a/src/tagmanager/tm_parser.c b/src/tagmanager/tm_parser.c index 293383c4e0..aa6e6a7582 100644 --- a/src/tagmanager/tm_parser.c +++ b/src/tagmanager/tm_parser.c @@ -204,22 +204,32 @@ static TMParserMapGroup group_PYTHON[] = { }; static TMParserMapEntry map_LATEX[] = { - {'f', tm_tag_function_t}, - {'c', tm_tag_class_t}, - {'m', tm_tag_member_t}, - {'d', tm_tag_macro_t}, - {'v', tm_tag_variable_t}, - {'n', tm_tag_namespace_t}, - {'s', tm_tag_struct_t}, + {'p', tm_tag_enum_t}, // part + {'c', tm_tag_namespace_t}, // chapter + {'s', tm_tag_member_t}, // section + {'u', tm_tag_macro_t}, // subsection + {'b', tm_tag_variable_t}, // subsubsection + {'P', tm_tag_undef_t}, // paragraph + {'G', tm_tag_undef_t}, // subparagraph + {'l', tm_tag_struct_t}, // label + {'i', tm_tag_undef_t}, // xinput + {'B', tm_tag_field_t}, // bibitem + {'C', tm_tag_function_t}, // command + {'o', tm_tag_function_t}, // operator + {'e', tm_tag_class_t}, // environment + {'t', tm_tag_class_t}, // theorem + {'N', tm_tag_undef_t}, // counter }; static TMParserMapGroup group_LATEX[] = { {_("Command"), TM_ICON_NONE, tm_tag_function_t}, {_("Environment"), TM_ICON_NONE, tm_tag_class_t}, + {_("Part"), TM_ICON_NONE, tm_tag_enum_t}, + {_("Chapter"), TM_ICON_NONE, tm_tag_namespace_t}, {_("Section"), TM_ICON_NONE, tm_tag_member_t}, {_("Subsection"), TM_ICON_NONE, tm_tag_macro_t}, {_("Subsubsection"), TM_ICON_NONE, tm_tag_variable_t}, + {_("Bibitem"), TM_ICON_NONE, tm_tag_field_t}, {_("Label"), TM_ICON_NONE, tm_tag_struct_t}, - {_("Chapter"), TM_ICON_NONE, tm_tag_namespace_t}, }; // no scope information @@ -1472,6 +1482,7 @@ const gchar *tm_parser_scope_separator(TMParserType lang) case TM_PARSER_ZEPHIR: return "::"; + case TM_PARSER_LATEX: case TM_PARSER_MARKDOWN: case TM_PARSER_TXT2TAGS: return "\"\""; @@ -1495,6 +1506,7 @@ const gchar *tm_parser_scope_separator_printable(TMParserType lang) { case TM_PARSER_ASCIIDOC: case TM_PARSER_CONF: + case TM_PARSER_LATEX: case TM_PARSER_MARKDOWN: case TM_PARSER_REST: case TM_PARSER_TXT2TAGS: @@ -1523,6 +1535,7 @@ gboolean tm_parser_has_full_scope(TMParserType lang) case TM_PARSER_JAVA: case TM_PARSER_JAVASCRIPT: case TM_PARSER_JSON: + case TM_PARSER_LATEX: case TM_PARSER_LUA: case TM_PARSER_MARKDOWN: case TM_PARSER_PHP: diff --git a/tests/ctags/3526726.tex.tags b/tests/ctags/3526726.tex.tags index 6a236ebd97..d95ee6aa70 100644 --- a/tests/ctags/3526726.tex.tags +++ b/tests/ctags/3526726.tex.tags @@ -1,155 +1,149 @@ # format=tagmanager - I think I found a bug in Snort. Now what?Ì65536Ö0 - I've got RedHat and ....Ì65536Ö0 -A Rule with PCRE causes a failure to load snort.conf. Why?Ì65536Ö0 -After I add new rules or comment out rules how do I make Snort reload?Ì65536Ö0 -Are rule keywords ORed or ANDed together?Ì65536Ö0 -Are there other output systems for Snort besides ``Barnyard''?\label{spoolersÌ65536Ö0 -BASE appears to be broken in Lynx Ì65536Ö0 +A Rule with PCRE causes a failure to load snort.conf. Why?Ì65536ÎProblemsÖ0 +After I add new rules or comment out rules how do I make Snort reload?Ì65536ÎRules and AlertsÖ0 +Are rule keywords ORed or ANDed together?Ì65536ÎRules and AlertsÖ0 +Are there other output systems for Snort besides ``Barnyard''?\label{spoolers}Ì65536ÎGetting FancyÖ0 +BASE appears to be broken in LynxÌ65536ÎProblemsÖ0 BackgroundÌ64Ö0 -Can Snort be evaded by the use of polymorphic mutators on shellcode?Ì65536Ö0 -Can Snort trigger a rule by MAC addresses?Ì65536Ö0 -Can priorities be assigned to alerts using BASE? Ì65536Ö0 +Can Snort be evaded by the use of polymorphic mutators on shellcode?Ì65536ÎBackgroundÖ0 +Can Snort trigger a rule by MAC addresses?Ì65536ÎRules and AlertsÖ0 +Can priorities be assigned to alerts using BASE?Ì65536ÎRules and AlertsÖ0 Configuring SnortÌ64Ö0 DevelopmentÌ64Ö0 -Does Snort handle IP defragmentation?Ì65536Ö0 -Does Snort log the full packets when it generates alerts? Ì65536Ö0 -Does Snort perform TCP stream reassembly?Ì65536Ö0 -Does Snort perform stateful protocol analysis?Ì65536Ö0 -Does snort see packets filtered by IPTables/IPChains/IPF/PF?Ì65536Ö0 -Errors loading rules filesÌ65536Ö0 +Does Snort handle IP defragmentation?Ì65536ÎBackgroundÖ0 +Does Snort log the full packets when it generates alerts?Ì65536ÎBackgroundÖ0 +Does Snort perform TCP stream reassembly?Ì65536ÎBackgroundÖ0 +Does Snort perform stateful protocol analysis?Ì65536ÎBackgroundÖ0 +Does snort see packets filtered by IPTables/IPChains/IPF/PF?Ì65536ÎRules and AlertsÖ0 +Errors loading rules filesÌ65536ÎRules and AlertsÖ0 Getting FancyÌ64Ö0 Getting StartedÌ64Ö0 -How can I deactivate a rule?Ì65536Ö0 -How can I define an address to be anything except some hosts?Ì65536Ö0 -How can I examine logged packets in more detail?Ì65536Ö0 -How can I protect web servers running on ports other than 80?Ì65536Ö0 -How can I run Snort on multiple interfaces simultaneously?Ì65536Ö0 -How can I specify a list of ports in a rule?Ì65536Ö0 -How can I test Snort without having an Ethernet card or a connection to other computers? Ì65536Ö0 -How can I use Snort to log HTTP URLs or SMTP traffic?Ì65536Ö0 -How do I build this BASE thing?Ì65536Ö0 -How do I configure stream4?Ì65536Ö0 -How do I get Snort and ACID working?Ì65536Ö0 -How do I get Snort to e-mail me alerts?Ì65536Ö0 -How do I get Snort to log the packet payload as well as the header?Ì65536Ö0 -How do I ignore traffic coming from a particular host or hosts?Ì65536Ö0 -How do I log a specific type of traffic and send alerts to syslog?Ì65536Ö0 -How do I log to multiple databases or output plugins?Ì65536Ö0 -How do I process those Snort logs into reports?Ì65536Ö0 -How do I run Snort?Ì65536Ö0 -How do I set EXTERNAL\_NET?Ì65536Ö0 -How do I setup a receive-only ethernet cable?Ì65536Ö0 -How do I setup snort on a `stealth' interface? Ì65536Ö0 -How do I test Snort alerts and logging?Ì65536Ö0 -How do I turn off ``spp:possible EVASIVE RST detection'' alerts?Ì65536Ö0 -How do I understand this traffic and do IDS alert analysis?Ì65536Ö0 -How do I use a remote syslog machine?Ì65536Ö0 -How do you get Snort to ignore some traffic?Ì65536Ö0 -How do you pronounce the names of some of these guys who work on Snort?Ì65536Ö0 -How do you put Snort in debug mode? Ì65536Ö0 -How does rule ordering work?Ì65536Ö0 -How long can address lists, variables, or rules be?Ì65536Ö0 -How to start Snort as a win32 service? Ì65536Ö0 -I am getting `snort [pid] uses obsolete (PF\_INET, SOCK\_PACKET)' warnings. What's wrong?Ì65536Ö0 -I am getting too many ``IIS Unicode attack detected'' and/or ``CGI Null Byte attack detected'' false positives. How can I turn this detection off? Ì65536Ö0 -I am still getting bombarded with spp\_portscan messages even though the IP that I am getting the portscan from is in my \$DNS\_SERVERs var Ì65536Ö0 -I am using Snort on Windows and receive an ``OpenPcap() error upon startup: ERROR: OpenPcap() device open: Error opening adapter'' message. What's wrong? Ì65536Ö0 -I have one network card and two aliases, how can I force Snort to ``listen'' on both addresses?Ì65536Ö0 -I hear people talking about ``Barnyard''. What's that?\label{barnyardÌ65536Ö0 -I just downloaded a new ruleset and now Snort fails, complaining about theÌ65536Ö0 -I try to start Snort and it gives an error like ``ERROR: Unable to openÌ65536Ö0 -I want to build a Snort box. Will this $<$Insert list of hardware$>$ handle $<$this much$>$ traffic? Ì65536Ö0 -I'm getting large amounts of $<$some alerts type$>$. What should I do? Where can I go to find out more about it? Ì65536Ö0 -I'm getting lots of *ICMP Ping Speedera*, is this bad?Ì65536Ö0 -I'm not seeing any interfaces listed under Win32.Ì65536Ö0 -I'm on a switched network, can I still use Snort?Ì65536Ö0 +How can I deactivate a rule?Ì65536ÎRules and AlertsÖ0 +How can I define an address to be anything except some hosts?Ì65536ÎRules and AlertsÖ0 +How can I examine logged packets in more detail?Ì65536ÎGetting FancyÖ0 +How can I protect web servers running on ports other than 80?Ì65536ÎRules and AlertsÖ0 +How can I run Snort on multiple interfaces simultaneously?Ì65536ÎConfiguring SnortÖ0 +How can I specify a list of ports in a rule?Ì65536ÎRules and AlertsÖ0 +How can I test Snort without having an Ethernet card or a connection to other computers?Ì65536ÎGetting FancyÖ0 +How can I use Snort to log HTTP URLs or SMTP traffic?Ì65536ÎGetting FancyÖ0 +How do I build this BASE thing?Ì65536ÎConfiguring SnortÖ0 +How do I configure stream4?Ì65536ÎConfiguring SnortÖ0 +How do I get Snort and ACID working?Ì65536ÎConfiguring SnortÖ0 +How do I get Snort to e-mail me alerts?Ì65536ÎGetting FancyÖ0 +How do I get Snort to log the packet payload as well as the header?Ì65536ÎConfiguring SnortÖ0 +How do I ignore traffic coming from a particular host or hosts?Ì65536ÎConfiguring SnortÖ0 +How do I log a specific type of traffic and send alerts to syslog?Ì65536ÎGetting FancyÖ0 +How do I log to multiple databases or output plugins?Ì65536ÎGetting FancyÖ0 +How do I process those Snort logs into reports?Ì65536ÎGetting FancyÖ0 +How do I run Snort?Ì65536ÎGetting StartedÖ0 +How do I set EXTERNAL\_NET?Ì65536ÎConfiguring SnortÖ0 +How do I setup a receive-only ethernet cable?Ì65536ÎConfiguring SnortÖ0 +How do I setup snort on a `stealth' interface?Ì65536ÎConfiguring SnortÖ0 +How do I test Snort alerts and logging?Ì65536ÎRules and AlertsÖ0 +How do I turn off ``spp:possible EVASIVE RST detection'' alerts?Ì65536ÎRules and AlertsÖ0 +How do I understand this traffic and do IDS alert analysis?Ì65536ÎGetting FancyÖ0 +How do I use a remote syslog machine?Ì65536ÎConfiguring SnortÖ0 +How do you get Snort to ignore some traffic?Ì65536ÎConfiguring SnortÖ0 +How do you pronounce the names of some of these guys who work on Snort?Ì65536ÎBackgroundÖ0 +How do you put Snort in debug mode?Ì65536ÎDevelopmentÖ0 +How does rule ordering work?Ì65536ÎConfiguring SnortÖ0 +How long can address lists, variables, or rules be?Ì65536ÎRules and AlertsÖ0 +How to start Snort as a win32 service?Ì65536ÎGetting FancyÖ0 +I am getting `snort [pid] uses obsolete (PF\_INET, SOCK\_PACKET)' warnings. What's wrong?Ì65536ÎProblemsÖ0 +I am getting too many ``IIS Unicode attack detected'' and/or ``CGI Null Byte attack detected'' false positives. How can I turn this detection off?Ì65536ÎRules and AlertsÖ0 +I am still getting bombarded with spp\_portscan messages even though the IP that I am getting the portscan from is in my \$DNS\_SERVERs varÌ65536ÎProblemsÖ0 +I am using Snort on Windows and receive an ``OpenPcap() error upon startup: ERROR: OpenPcap() device open: Error opening adapter'' message. What's wrong?Ì65536ÎProblemsÖ0 +I have one network card and two aliases, how can I force Snort to ``listen'' on both addresses?Ì65536ÎConfiguring SnortÖ0 +I hear people talking about ``Barnyard''. What's that?\label{barnyard}Ì65536ÎGetting FancyÖ0 +I just downloaded a new ruleset and now Snort fails, complaining about the rules.Ì65536ÎProblemsÖ0 +I think I found a bug in Snort. Now what?Ì65536ÎProblemsÖ0 +I try to start Snort and it gives an error like ``ERROR: Unable to open rules file: /root/.snortrc or /root//root/.snortrc.'' What can I do to fix this?Ì65536ÎProblemsÖ0 +I want to build a Snort box. Will this $<$Insert list of hardware$>$ handle $<$this much$>$ traffic?Ì65536ÎGetting StartedÖ0 +I'm getting large amounts of $<$some alerts type$>$. What should I do? Where can I go to find out more about it?Ì65536ÎRules and AlertsÖ0 +I'm getting lots of *ICMP Ping Speedera*, is this bad?Ì65536ÎProblemsÖ0 +I'm not seeing any interfaces listed under Win32.Ì65536ÎProblemsÖ0 +I'm on a switched network, can I still use Snort?Ì65536ÎBackgroundÖ0 +I've got RedHat and ....Ì65536ÎGetting StartedÖ0 IDSCenterÌ2048Ö0 -Is Fyodor Yarochkin the same Fyodor who wrote nmap?Ì65536Ö0 -Is Snort vulnerable to IDS noise generators like ``Stick'' and ``Snot''?Ì65536Ö0 -Is it possible to have Snort call an external program when an alert is raised?Ì65536Ö0 -Is it possible with snort to add a ipfilter/ipfw rule to a firewall? Ì65536Ö0 -Is there a private SID number range so my rules don't conflict?Ì65536Ö0 -It's not working on Win32, how can I tell if my problem is Snort orÌ65536Ö0 -Libpcap complains about permissions problems, what's going on?Ì65536Ö0 +Is Fyodor Yarochkin the same Fyodor who wrote nmap?Ì65536ÎBackgroundÖ0 +Is Snort vulnerable to IDS noise generators like ``Stick'' and ``Snot''?Ì65536ÎBackgroundÖ0 +Is it possible to have Snort call an external program when an alert is raised?Ì65536ÎGetting FancyÖ0 +Is it possible with snort to add a ipfilter/ipfw rule to a firewall?Ì65536ÎGetting FancyÖ0 +Is there a private SID number range so my rules don't conflict?Ì65536ÎRules and AlertsÖ0 +It's not working on Win32, how can I tell if my problem is Snort or WinPcap?Ì65536ÎProblemsÖ0 +Libpcap complains about permissions problems, what's going on?Ì65536ÎGetting StartedÖ0 MiscellaneousÌ64Ö0 -My /var/log/snort directory gets very large...Ì65536Ö0 -My BASE db connection times-out when performing long operations (e.g.Ì65536Ö0 -My IP address is assigned dynamically to my interface, can I use Snort with it?Ì65536Ö0 -My network spans multiple subnets. How do I define HOME\_NET?Ì65536Ö0 -My snort crashes, how do I restart it?Ì65536Ö0 -On HPUX I get device lan0 open: recv\_ack: promisc\_phys: Invalid argumentÌ65536Ö0 -Portscans are not being logged to my database Ì65536Ö0 +My /var/log/snort directory gets very large...Ì65536ÎProblemsÖ0 +My BASE db connection times-out when performing long operations (e.g. deleting a large number of alerts).Ì65536ÎProblemsÖ0 +My IP address is assigned dynamically to my interface, can I use Snort with it?Ì65536ÎConfiguring SnortÖ0 +My network spans multiple subnets. How do I define HOME\_NET?Ì65536ÎConfiguring SnortÖ0 +My snort crashes, how do I restart it?Ì65536ÎProblemsÖ0 +On HPUX I get device lan0 open: recv\_ack: promisc\_phys: Invalid argumentÌ65536ÎProblemsÖ0 +Portscans are not being logged to my databaseÌ65536ÎProblemsÖ0 ProblemsÌ64Ö0 Rules and AlertsÌ64Ö0 -SMB alerts aren't working, what's wrong? Ì65536Ö0 -Snort complains about the ``react'' keyword...Ì65536Ö0 -Snort fails to respond to a kill signal on Linux. Why?Ì65536Ö0 -Snort is behind a firewall (ipf/pf/ipchains/ipfilter) and awfully quiet...Ì65536Ö0 -Snort is dying with a `can not create file' error and I have plenty of diskspace. What's wrong?Ì65536Ö0 -Snort is not logging to my databaseÌ65536Ö0 -Snort is not logging to syslogÌ65536Ö0 -Snort says BACKDOOR SIGNATURE... does my machine have a Trojan? Ì65536Ö0 -Snort says ``Garbage Packet with Null Pointer discarded!'' Huh?Ì65536Ö0 -Snort says ``Ran Out Of Space.'' Huh?Ì65536Ö0 -Snort says ``Rule IP addr (``1.1.1.1'') didn't x-late, WTF?''Ì65536Ö0 -Trying to install snort it says: ``bad interpreter: No such file orÌ65536Ö0 -What about `SMB Name Wildcard' alerts? Ì65536Ö0 -What about ``CGI Null Byte attacks?'' Ì65536Ö0 -What about all these false alarms? Ì65536Ö0 -What are CIDR netmasks? Ì65536Ö0 -What are HOME\_NET and EXTERNAL\_NET?Ì65536Ö0 -What are all these ICMP files in subdirectories under /var/log/snort? Ì65536Ö0 -What are all these ``ICMP destination unreachable'' alerts? Ì65536Ö0 -What are some resources that I can use to understand more about sourceÌ65536Ö0 -What are these IDS codes in the alert names? Ì65536Ö0 -What do the numbers (ie: [116:56:1]) in front of a Snort alert mean?Ì65536Ö0 -What is the best way to use Snort to block attack traffic?Ì65536Ö0 -What is the difference between ``Alerting'' and ``Logging''?Ì65536Ö0 -What is the use of the ``-r'' switch to read tcpdump files? Ì65536Ö0 -What the heck is a SYNFIN scan?Ì65536Ö0 -What the heck is a SYNFIN scan? Ì65536Ö0 -What the heck is a ``Stealth scan''?Ì65536Ö0 -What version of Winpcap do I need?\label{winpcapÌ65536Ö0 -What's this about a Snort drinking game?Ì65536Ö0 -Where are my log files located? What are they named?Ì65536Ö0 -Where can I get more reading and courses about IDS?\label{coursesÌ65536Ö0 -Where do I find binary packages for BlueHat BSD-Linux-RT?Ì65536Ö0 -Where do I get more help on Snort?Ì65536Ö0 -Where do I get the latest version of Winpcap?Ì65536Ö0 -Where do I get the latest version of libpcap? Ì65536Ö0 -Where do the distance and within keywords work from to modify contentÌ65536Ö0 -Where does one obtain new/modifed rules? How do you merge them in?Ì65536Ö0 -Where's a good place to physically put a Snort sensor?Ì65536Ö0 -Which takes precedence, commandline or rule file ?Ì65536Ö0 -Why am I seeing so many ``SMTP RCPT TO overflow'' alerts ?Ì65536Ö0 -Why are my unified alert times off by +/- N hours?Ì65536Ö0 -Why are there no subdirectories under /var/log/snort for IP addresses?Ì65536Ö0 -Why can't snort see one of the 10Mbps or 100Mbps traffic on my autoswitch hub?Ì65536Ö0 -Why do certain alerts seem to have `unknown' IPs in BASE? Ì65536Ö0 -Why do many Snort rules have the flags P (TCP PuSH) and A (TCP ACK) set? Ì65536Ö0 -Why does Snort complain about /var/log/snort?Ì65536Ö0 -Why does building Snort complain about missing references? Ì65536Ö0 -Why does building snort fail with errors about yylex and lex\_init? Ì65536Ö0 -Why does chrooted Snort die when I send it a SIGHUP? \label{chrootÌ65536Ö0 -Why does snort report ``Packet loss statistics are unavailable under Linux?''Ì65536Ö0 -Why does the `error deleting alert' message occur when attempting to delete an alert with BASE? Ì65536Ö0 -Why does the portscan plugin log ``stealth'' packets even though the host is in the portscan-ignorehosts list? Ì65536Ö0 -Why does the program generate alerts on packets that have pass rules? Ì65536Ö0 -barnyardÌ2048Ö0 +SMB alerts aren't working, what's wrong?Ì65536ÎProblemsÖ0 +Snort complains about the ``react'' keyword...Ì65536ÎGetting FancyÖ0 +Snort fails to respond to a kill signal on Linux. Why?Ì65536ÎProblemsÖ0 +Snort is behind a firewall (ipf/pf/ipchains/ipfilter) and awfully quiet...Ì65536ÎRules and AlertsÖ0 +Snort is dying with a `can not create file' error and I have plenty of diskspace. What's wrong?Ì65536ÎProblemsÖ0 +Snort is not logging to my databaseÌ65536ÎProblemsÖ0 +Snort is not logging to syslogÌ65536ÎProblemsÖ0 +Snort says BACKDOOR SIGNATURE... does my machine have a Trojan?Ì65536ÎRules and AlertsÖ0 +Snort says ``Garbage Packet with Null Pointer discarded!'' Huh?Ì65536ÎProblemsÖ0 +Snort says ``Ran Out Of Space.'' Huh?Ì65536ÎProblemsÖ0 +Snort says ``Rule IP addr (``1.1.1.1'') didn't x-late, WTF?''Ì65536ÎRules and AlertsÖ0 +Trying to install snort it says: ``bad interpreter: No such file or directory''Ì65536ÎProblemsÖ0 +What about `SMB Name Wildcard' alerts?Ì65536ÎRules and AlertsÖ0 +What about ``CGI Null Byte attacks?''Ì65536ÎRules and AlertsÖ0 +What about all these false alarms?Ì65536ÎRules and AlertsÖ0 +What are CIDR netmasks?Ì65536ÎGetting StartedÖ0 +What are HOME\_NET and EXTERNAL\_NET?Ì65536ÎConfiguring SnortÖ0 +What are all these ICMP files in subdirectories under /var/log/snort?Ì65536ÎRules and AlertsÖ0 +What are all these ``ICMP destination unreachable'' alerts?Ì65536ÎRules and AlertsÖ0 +What are some resources that I can use to understand more about source addresses logged and where they are coming from?Ì65536ÎGetting FancyÖ0 +What are these IDS codes in the alert names?Ì65536ÎRules and AlertsÖ0 +What do the numbers (ie: [116:56:1]) in front of a Snort alert mean?Ì65536ÎRules and AlertsÖ0 +What is the best way to use Snort to block attack traffic?Ì65536ÎGetting FancyÖ0 +What is the difference between ``Alerting'' and ``Logging''?Ì65536ÎRules and AlertsÖ0 +What is the use of the ``-r'' switch to read tcpdump files?Ì65536ÎGetting StartedÖ0 +What the heck is a SYNFIN scan?Ì65536ÎConfiguring SnortÖ0 +What the heck is a SYNFIN scan?Ì65536ÎRules and AlertsÖ0 +What the heck is a ``Stealth scan''?Ì65536ÎConfiguring SnortÖ0 +What version of Winpcap do I need?\label{winpcap}Ì65536ÎGetting StartedÖ0 +What's this about a Snort drinking game?Ì65536ÎMiscellaneousÖ0 +Where are my log files located? What are they named?Ì65536ÎGetting StartedÖ0 +Where can I get more reading and courses about IDS?\label{courses}Ì65536ÎBackgroundÖ0 +Where do I find binary packages for BlueHat BSD-Linux-RT?Ì65536ÎGetting StartedÖ0 +Where do I get more help on Snort?Ì65536ÎBackgroundÖ0 +Where do I get the latest version of Winpcap?Ì65536ÎGetting StartedÖ0 +Where do I get the latest version of libpcap?Ì65536ÎGetting StartedÖ0 +Where do the distance and within keywords work from to modify content searches in rules?Ì65536ÎRules and AlertsÖ0 +Where does one obtain new/modifed rules? How do you merge them in?Ì65536ÎConfiguring SnortÖ0 +Where's a good place to physically put a Snort sensor?Ì65536ÎGetting StartedÖ0 +Which takes precedence, commandline or rule file ?Ì65536ÎConfiguring SnortÖ0 +Why am I seeing so many ``SMTP RCPT TO overflow'' alerts ?Ì65536ÎProblemsÖ0 +Why are my unified alert times off by +/- N hours?Ì65536ÎProblemsÖ0 +Why are there no subdirectories under /var/log/snort for IP addresses?Ì65536ÎConfiguring SnortÖ0 +Why can't snort see one of the 10Mbps or 100Mbps traffic on my autoswitch hub?Ì65536ÎProblemsÖ0 +Why do certain alerts seem to have `unknown' IPs in BASE?Ì65536ÎRules and AlertsÖ0 +Why do many Snort rules have the flags P (TCP PuSH) and A (TCP ACK) set?Ì65536ÎRules and AlertsÖ0 +Why does Snort complain about /var/log/snort?Ì65536ÎGetting StartedÖ0 +Why does building Snort complain about missing references?Ì65536ÎGetting StartedÖ0 +Why does building snort fail with errors about yylex and lex\_init?Ì65536ÎGetting StartedÖ0 +Why does chrooted Snort die when I send it a SIGHUP? \label{chroot}Ì65536ÎProblemsÖ0 +Why does snort report ``Packet loss statistics are unavailable under Linux?''Ì65536ÎProblemsÖ0 +Why does the `error deleting alert' message occur when attempting to delete an alert with BASE?Ì65536ÎProblemsÖ0 +Why does the portscan plugin log ``stealth'' packets even though the host is in the portscan-ignorehosts list?Ì65536ÎConfiguring SnortÖ0 +Why does the program generate alerts on packets that have pass rules?Ì65536ÎRules and AlertsÖ0 +\myquoteÌ16Ö0 +\myrefÌ16Ö0 centerÌ1Ö0 -chrootÌ2048Ö0 -coursesÌ2048Ö0 documentÌ1Ö0 enumerateÌ1Ö0 itemizeÌ1Ö0 latexonlyÌ1Ö0 -myquoteÌ16Ö0 -myrefÌ16Ö0 -quoteÌ1Ö0 -spoolersÌ2048Ö0 stealthÌ2048Ö0 stream4Ì2048Ö0 tabularÌ1Ö0 verbatimÌ1Ö0 -winpcapÌ2048Ö0 diff --git a/tests/ctags/bug2886870.tex.tags b/tests/ctags/bug2886870.tex.tags index 23a3819301..7ae7111f75 100644 --- a/tests/ctags/bug2886870.tex.tags +++ b/tests/ctags/bug2886870.tex.tags @@ -1,16 +1,19 @@ # format=tagmanager -Common Greek lettersÌ65536Ö0 +Common Greek lettersÌ65536ÎSpecial SymbolsÖ0 EquationsÌ64Ö0 FiguresÌ64Ö0 IntroductionÌ64Ö0 ListsÌ64Ö0 Literal textÌ64Ö0 Special SymbolsÌ64Ö0 -Special symbolsÌ65536Ö0 +Special symbolsÌ65536ÎSpecial SymbolsÖ0 TablesÌ64Ö0 -Test for ctagsÌ16384Ö0 -\color{redÌ64Ö0 -\label{morefigÌ64Ö0 +Test for ctagsÌ16384ÎSpecial Symbols""Common Greek lettersÖ0 +\color{red}Use of ColorÌ64Ö0 +\label{morefig}SubfiguresÌ64Ö0 +\lbÌ16Ö0 +\rbÌ16Ö0 +\rvÌ16Ö0 alignÌ1Ö0 casesÌ1Ö0 centerÌ1Ö0 @@ -26,14 +29,12 @@ fig:qm/complexfunctions fig:typicalÌ2048Ö0 figureÌ1Ö0 itemizeÌ1Ö0 -lbÌ16Ö0 -morefigÌ2048Ö0 +latexÌ8Ö0 pmatrixÌ1Ö0 -rbÌ16Ö0 -rvÌ16Ö0 subequationsÌ1Ö0 tab:5/tcÌ2048Ö0 tableÌ1Ö0 tabularÌ1Ö0 thebibliographyÌ1Ö0 verbatimÌ1Ö0 +websiteÌ8Ö0 diff --git a/tests/ctags/intro.tex.tags b/tests/ctags/intro.tex.tags index a77efad217..f847255e34 100644 --- a/tests/ctags/intro.tex.tags +++ b/tests/ctags/intro.tex.tags @@ -1,10 +1,14 @@ # format=tagmanager -IntroductionÌ64Ö0 +IntroductionÌ64Îchapter textÖ0 +Part1Ì2Ö0 +Part2Ì2Ö0 chapter textÌ256Ö0 -chapter2Ì256Ö0 -section1 textÌ64Ö0 -section4 textÌ64Ö0 -subsection2Ì65536Ö0 -subsubsection3 with extra textÌ16384Ö0 -subsubsection6 with extra textÌ16384Ö0 +chapter2Ì256ÎPart2Ö0 +section1 textÌ64Îchapter textÖ0 +short section4Ì64ÎPart1Ö0 +shorter intro2Ì64ÎPart2Ö0 +subsec5 textÌ65536ÎPart2""shorter intro2Ö0 +subsection2Ì65536ÎPart1Ö0 +subsubsection3 with extra textÌ16384ÎPart1""subsection2Ö0 +subsubsection6 with extra textÌ16384ÎPart2""shorter intro2""subsec5 textÖ0 verbatimÌ1Ö0 diff --git a/tests/ctags/intro_orig.tex b/tests/ctags/intro_orig.tex index 6a03d140a8..0fbb6ccd21 100644 --- a/tests/ctags/intro_orig.tex +++ b/tests/ctags/intro_orig.tex @@ -20,6 +20,21 @@ \setlength{\marginparpush}{1.0cm} \setlength{\textwidth}{150mm} +\newenvironment{boxed} + {\begin{center} + \begin{tabular}{|p{0.9\textwidth}|} + \hline\\ + } + { + \\\\\hline + \end{tabular} + \end{center} + } + +\DeclareMathOperator{\End}{End} + +\newtheorem{theorem1}{Theorem} + \begin{comment} \pagestyle{empty} % use if page numbers not wanted \end{comment} diff --git a/tests/ctags/intro_orig.tex.tags b/tests/ctags/intro_orig.tex.tags index 700fc4e9ee..5bf95983dd 100644 --- a/tests/ctags/intro_orig.tex.tags +++ b/tests/ctags/intro_orig.tex.tags @@ -1,16 +1,21 @@ # format=tagmanager -Common Greek lettersÌ65536Ö0 +Common Greek lettersÌ65536ÎSpecial SymbolsÖ0 EquationsÌ64Ö0 FiguresÌ64Ö0 IntroductionÌ64Ö0 ListsÌ64Ö0 Literal textÌ64Ö0 Special SymbolsÌ64Ö0 -Special symbolsÌ65536Ö0 +Special symbolsÌ65536ÎSpecial SymbolsÖ0 TablesÌ64Ö0 -\color{redÌ64Ö0 -\label{morefigÌ64Ö0 +\EndÌ16Ö0 +\color{red}Use of ColorÌ64Ö0 +\label{morefig}SubfiguresÌ64Ö0 +\lbÌ16Ö0 +\rbÌ16Ö0 +\rvÌ16Ö0 alignÌ1Ö0 +boxedÌ1Ö0 casesÌ1Ö0 centerÌ1Ö0 commentÌ1Ö0 @@ -25,14 +30,13 @@ fig:qm/complexfunctions fig:typicalÌ2048Ö0 figureÌ1Ö0 itemizeÌ1Ö0 -lbÌ16Ö0 -morefigÌ2048Ö0 +latexÌ8Ö0 pmatrixÌ1Ö0 -rbÌ16Ö0 -rvÌ16Ö0 subequationsÌ1Ö0 tab:5/tcÌ2048Ö0 tableÌ1Ö0 tabularÌ1Ö0 thebibliographyÌ1Ö0 +theorem1Ì1Ö0 verbatimÌ1Ö0 +websiteÌ8Ö0