Branch: refs/heads/master Author: Jiří Techet techet@gmail.com Committer: Jiří Techet techet@gmail.com Date: Thu, 12 May 2022 23:04:38 UTC Commit: 38c3656d1c25c9ab79ead94160641c3e95075804 https://github.com/geany/geany/commit/38c3656d1c25c9ab79ead94160641c3e950758...
Log Message: ----------- 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).
Modified Paths: -------------- ctags/Makefile.am ctags/parsers/geany_tex.c ctags/parsers/tex.c ctags/parsers/tex.h meson.build src/tagmanager/tm_parser.c tests/ctags/3526726.tex.tags tests/ctags/bug2886870.tex.tags tests/ctags/intro.tex.tags tests/ctags/intro_orig.tex tests/ctags/intro_orig.tex.tags
Modified: ctags/Makefile.am 3 lines changed, 2 insertions(+), 1 deletions(-) =================================================================== @@ -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
Modified: ctags/parsers/geany_tex.c 242 lines changed, 0 insertions(+), 242 deletions(-) =================================================================== @@ -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 <ctype.h> -#include <string.h> - -#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; -}
Modified: ctags/parsers/tex.c 1253 lines changed, 1253 insertions(+), 0 deletions(-) =================================================================== @@ -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 <ctype.h> /* to define isalpha () */ +#ifdef DEBUG +#include <stdio.h> +#endif +#include <string.h> + +#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; +}
Modified: ctags/parsers/tex.h 114 lines changed, 114 insertions(+), 0 deletions(-) =================================================================== @@ -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 */
Modified: meson.build 3 lines changed, 2 insertions(+), 1 deletions(-) =================================================================== @@ -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',
Modified: src/tagmanager/tm_parser.c 29 lines changed, 21 insertions(+), 8 deletions(-) =================================================================== @@ -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:
Modified: tests/ctags/3526726.tex.tags 266 lines changed, 130 insertions(+), 136 deletions(-) =================================================================== @@ -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
Modified: tests/ctags/bug2886870.tex.tags 19 lines changed, 10 insertions(+), 9 deletions(-) =================================================================== @@ -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
Modified: tests/ctags/intro.tex.tags 18 lines changed, 11 insertions(+), 7 deletions(-) =================================================================== @@ -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
Modified: tests/ctags/intro_orig.tex 15 lines changed, 15 insertions(+), 0 deletions(-) =================================================================== @@ -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}
Modified: tests/ctags/intro_orig.tex.tags 20 lines changed, 12 insertions(+), 8 deletions(-) =================================================================== @@ -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
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).