Merge pull request #482 from philippwiesemann/fix-typos-po-de
[geany-mirror.git] / tagmanager / ctags / asciidoc.c
blobe873476337d87b281ba991f953e5b9319d8a6420
1 /*
3 * Copyright (c) 2012, Lex Trotman
4 * Based on Rest code by Nick Treleaven, see rest.c
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License.
9 * This module contains functions for generating tags for asciidoc files.
13 * INCLUDE FILES
15 #include "general.h" /* must always come first */
17 #include <ctype.h>
18 #include <string.h>
20 #include "parse.h"
21 #include "read.h"
22 #include "vstring.h"
23 #include "nestlevel.h"
26 * DATA DEFINITIONS
28 typedef enum {
29 K_CHAPTER = 0,
30 K_SECTION,
31 K_SUBSECTION,
32 K_SUBSUBSECTION,
33 K_LEVEL5SECTION,
34 SECTION_COUNT
35 } asciidocKind;
37 static kindOption AsciidocKinds[] = {
38 { TRUE, 'n', "namespace", "chapters"},
39 { TRUE, 'm', "member", "sections" },
40 { TRUE, 'd', "macro", "level2sections" },
41 { TRUE, 'v', "variable", "level3sections" },
42 { TRUE, 's', "struct", "level4sections" }
45 static char kindchars[SECTION_COUNT]={ '=', '-', '~', '^', '+' };
47 static NestingLevels *nestingLevels = NULL;
50 * FUNCTION DEFINITIONS
53 static NestingLevel *getNestingLevel(const int kind)
55 NestingLevel *nl;
57 while (1)
59 nl = nestingLevelsGetCurrent(nestingLevels);
60 if (nl && nl->type >= kind)
61 nestingLevelsPop(nestingLevels);
62 else
63 break;
65 return nl;
68 static void makeAsciidocTag (const vString* const name, const int kind)
70 const NestingLevel *const nl = getNestingLevel(kind);
72 if (vStringLength (name) > 0)
74 tagEntryInfo e;
75 initTagEntry (&e, vStringValue (name));
77 e.lineNumber--; /* we want the line before the '---' underline chars */
78 e.kindName = AsciidocKinds [kind].name;
79 e.kind = AsciidocKinds [kind].letter;
81 if (nl && nl->type < kind)
83 e.extensionFields.scope [0] = AsciidocKinds [nl->type].name;
84 e.extensionFields.scope [1] = vStringValue (nl->name);
86 makeTagEntry (&e);
88 nestingLevelsPush(nestingLevels, name, kind);
92 static int get_kind(char c)
94 int i;
96 for (i = 0; i < SECTION_COUNT; i++)
98 if (kindchars[i] == c)
99 return i;
101 return -1;
105 /* computes the length of an UTF-8 string
106 * if the string doesn't look like UTF-8, return -1
107 * FIXME consider East_Asian_Width Unicode property */
108 static int utf8_strlen(const char *buf, int buf_len)
110 int len = 0;
111 const char *end = buf + buf_len;
113 for (len = 0; buf < end; len ++)
115 /* perform quick and naive validation (no sub-byte checking) */
116 if (! (*buf & 0x80))
117 buf ++;
118 else if ((*buf & 0xe0) == 0xc0)
119 buf += 2;
120 else if ((*buf & 0xf0) == 0xe0)
121 buf += 3;
122 else if ((*buf & 0xf8) == 0xf0)
123 buf += 4;
124 else /* not a valid leading UTF-8 byte, abort */
125 return -1;
127 if (buf > end) /* incomplete last byte */
128 return -1;
131 return len;
135 static void findAsciidocTags(void)
137 vString *name = vStringNew();
138 const unsigned char *line;
139 unsigned char in_block = '\0'; /* holds the block marking char or \0 if not in block */
141 nestingLevels = nestingLevelsNew();
143 while ((line = fileReadLine()) != NULL)
145 int line_len = strlen((const char*) line);
146 int name_len_bytes = vStringLength(name);
147 int name_len = utf8_strlen(vStringValue(name), name_len_bytes);
149 /* if the name doesn't look like UTF-8, assume one-byte charset */
150 if (name_len < 0) name_len = name_len_bytes;
152 /* if its a title underline, or a delimited block marking character */
153 if (line[0] == '=' || line[0] == '-' || line[0] == '~' ||
154 line[0] == '^' || line[0] == '+' || line[0] == '.' ||
155 line[0] == '*' || line[0] == '_' || line[0] == '/')
157 int n_same;
158 for (n_same = 1; line[n_same] == line[0]; ++n_same);
160 /* is it a two line title or a delimited block */
161 if (n_same == line_len)
163 /* if in a block, can't be block start or title, look for block end */
164 if (in_block)
166 if (line[0] == in_block) in_block = '\0';
169 /* if its a =_~^+ and the same length +-2 as the line before then its a title */
170 /* (except in the special case its a -- open block start line) */
171 else if ((line[0] == '=' || line[0] == '-' || line[0] == '~' ||
172 line[0] == '^' || line[0] == '+') &&
173 line_len <= name_len + 2 && line_len >= name_len - 2 &&
174 !(line_len == 2 && line[0] == '-'))
176 int kind = get_kind((char)(line[0]));
177 if (kind >= 0)
179 makeAsciidocTag(name, kind);
180 continue;
184 /* else if its 4 or more /+-.*_= (plus the -- special case) its a block start */
185 else if (((line[0] == '/' || line[0] == '+' || line[0] == '-' ||
186 line[0] == '.' || line[0] == '*' || line[0] == '_' ||
187 line[0] == '=') && line_len >= 4 )
188 || (line[0] == '-' && line_len == 2))
190 in_block = line[0];
194 /* otherwise is it a one line title */
195 else if (line[0] == '=' && n_same <= 5 && isspace(line[n_same]) &&
196 !in_block)
198 int kind = n_same - 1;
199 int start = n_same;
200 int end = line_len - 1;
201 while (line[end] == line[0])--end;
202 while (isspace(line[start]))++start;
203 while (isspace(line[end]))--end;
204 vStringClear(name);
205 vStringNCatS(name, (const char*)(&(line[start])), end - start + 1);
206 vStringTerminate(name);
207 makeAsciidocTag(name, kind);
208 continue;
211 vStringClear(name);
212 if (! isspace(*line))
213 vStringCatS(name, (const char*) line);
214 vStringTerminate(name);
216 vStringDelete(name);
217 nestingLevelsFree(nestingLevels);
220 extern parserDefinition* AsciidocParser (void)
222 static const char *const patterns [] = { "*.asciidoc", NULL };
223 static const char *const extensions [] = { "asciidoc", NULL };
224 parserDefinition* const def = parserNew ("Asciidoc");
226 def->kinds = AsciidocKinds;
227 def->kindCount = KIND_COUNT (AsciidocKinds);
228 def->patterns = patterns;
229 def->extensions = extensions;
230 def->parser = findAsciidocTags;
231 return def;
234 /* vi:set tabstop=8 shiftwidth=4: */