manual: added documentation about replacement of 'untitled.ext' with filename (#1804)
[geany-mirror.git] / ctags / parsers / txt2tags.c
blob05d883629594d9cf83be3cc99746e5b5d13c8605
1 /*
2 * Copyright (c) 2009, Eric Forgeot
3 * Copyright (c) 2014, Colomban Wendling <colomban@geany.org>
5 * Based on work by Jon Strait
7 * This source code is released for free distribution under the terms of the
8 * GNU General Public License.
10 * This module contains functions for generating tags for Txt2tags files.
14 * INCLUDE FILES
16 #include "general.h" /* must always come first */
18 #include <ctype.h>
19 #include <string.h>
21 #include "parse.h"
22 #include "read.h"
23 #include "nestlevel.h"
24 #include "vstring.h"
25 #include "routines.h"
28 /* as any character may happen in an input, use something highly unlikely */
29 #define SCOPE_SEPARATOR '\x3' /* ASCII ETX */
32 * DATA DEFINITIONS
35 typedef enum {
36 K_SECTION = 0
37 } Txt2tagsKind;
39 static kindOption Txt2tagsKinds[] = {
40 { true, 'm', "member", "sections" }
44 * FUNCTION DEFINITIONS
47 static void makeTxt2tagsTag (const vString* const name,
48 const NestingLevels *const nls,
49 Txt2tagsKind type)
51 tagEntryInfo e;
52 vString *scope = NULL;
53 kindOption *kind = &Txt2tagsKinds[type];
54 initTagEntry (&e, vStringValue(name), kind);
56 if (nls->n > 0) {
57 int i;
58 kindOption *parentKind;
60 scope = vStringNew();
61 for (i = 0; i < nls->n; i++) {
62 if (vStringLength(scope) > 0)
63 vStringPut(scope, SCOPE_SEPARATOR);
64 vStringCat(scope, nls->levels[i].name);
66 parentKind = &Txt2tagsKinds[nls->levels[nls->n - 1].type];
68 e.extensionFields.scopeKind = parentKind;
69 e.extensionFields.scopeName = vStringValue(scope);
72 makeTagEntry(&e);
74 vStringDelete(scope);
77 /* matches: ^ *[=_-]{20,} *$ */
78 static bool isTxt2tagsLine (const unsigned char *line)
80 unsigned int len;
82 while (isspace(*line)) line++;
83 for (len = 0; *line == '=' || *line == '-' || *line == '_'; len++)
84 line++;
85 while (isspace(*line)) line++;
87 return len >= 20 && *line == 0;
90 static bool parseTxt2tagsTitle (const unsigned char *line,
91 vString *const title,
92 int *const depth_)
94 const int MAX_TITLE_DEPTH = 5; /* maximum length of a title delimiter */
95 unsigned char delim;
96 int delim_delta = 0;
97 const unsigned char *end;
99 /* skip leading spaces, but no tabs (probably because they create quotes) */
100 while (*line == ' ') line++;
102 /* normal/numbered titles */
103 if (*line != '=' && *line != '+')
104 return false;
106 delim = *line;
108 /* find the start delimiter length */
109 while (*line == delim && delim_delta < MAX_TITLE_DEPTH+1)
111 line++;
112 delim_delta++;
114 while (isspace(*line))
115 line++;
117 if (delim_delta > MAX_TITLE_DEPTH) /* invalid */
118 return false;
120 *depth_ = delim_delta;
122 /* find the end delimiter */
123 end = line + strlen((const char *) line) - 1;
124 while (end > line && isspace(*end)) end--;
125 /* skip a possible label: \[[A-Za-z0-9_-]+\] */
126 if (*end == ']')
128 end--;
129 while (end > line && (isalnum(*end) || *end == '_' || *end == '-'))
130 end--;
131 if (*end != '[') /* invalid */
132 return false;
133 end--;
135 while (end > line && *end == delim && delim_delta >= 0)
137 delim_delta--;
138 end--;
140 while (end > line && isspace(*end)) end--;
141 end++;
143 /* if start and end delimiters are not identical, or the the name is empty */
144 if (delim_delta != 0 || (end - line) <= 0)
145 return false;
147 vStringNCopyS(title, (const char *) line, end - line);
148 return true;
151 static void findTxt2tagsTags (void)
153 NestingLevels *nls = nestingLevelsNew();
154 vString *name = vStringNew();
155 const unsigned char *line;
157 while ((line = readLineFromInputFile()) != NULL)
159 int depth;
161 if (isTxt2tagsLine(line))
162 ; /* skip not to improperly match titles */
163 else if (parseTxt2tagsTitle(line, name, &depth))
165 NestingLevel *nl = nestingLevelsGetCurrent(nls);
166 while (nl && nl->indentation >= depth)
168 nestingLevelsPop(nls);
169 nl = nestingLevelsGetCurrent(nls);
172 makeTxt2tagsTag(name, nls, K_SECTION);
173 nestingLevelsPush(nls, name, K_SECTION);
174 nestingLevelsGetCurrent(nls)->indentation = depth;
177 vStringDelete (name);
178 nestingLevelsFree(nls);
181 extern parserDefinition* Txt2tagsParser (void)
183 static const char *const patterns [] = { "*.t2t", NULL };
184 static const char *const extensions [] = { "t2t", NULL };
185 parserDefinition* const def = parserNew ("Txt2tags");
187 def->kinds = Txt2tagsKinds;
188 def->kindCount = ARRAY_SIZE (Txt2tagsKinds);
189 def->patterns = patterns;
190 def->extensions = extensions;
191 def->parser = findTxt2tagsTags;
192 return def;