11eb07f9cSHadriel Kaplan /*
21eb07f9cSHadriel Kaplan *
3734f4111SHadriel Kaplan * Copyright (c) 2007-2011, Nick Treleaven
41eb07f9cSHadriel Kaplan * Copyright (c) 2012, Lex Trotman
51eb07f9cSHadriel Kaplan *
61eb07f9cSHadriel Kaplan * This source code is released for free distribution under the terms of the
7734f4111SHadriel Kaplan * GNU General Public License version 2 or (at your option) any later version.
81eb07f9cSHadriel Kaplan *
91eb07f9cSHadriel Kaplan * This module contains functions for generating tags for asciidoc files.
101eb07f9cSHadriel Kaplan *
11734f4111SHadriel Kaplan * Based on Rest code by Nick Treleaven, see rest.c
12734f4111SHadriel Kaplan *
131eb07f9cSHadriel Kaplan * This code was ported from geany git commit 40396a3 at:
141eb07f9cSHadriel Kaplan * https://github.com/geany/geany/blob/master/ctags/parsers/asciidoc.c
151eb07f9cSHadriel Kaplan * with the changes in geany's PR #1263, with some changes to work in uctags.
161eb07f9cSHadriel Kaplan */
171eb07f9cSHadriel Kaplan
181eb07f9cSHadriel Kaplan /*
191eb07f9cSHadriel Kaplan * INCLUDE FILES
201eb07f9cSHadriel Kaplan */
211eb07f9cSHadriel Kaplan #include "general.h" /* must always come first */
221eb07f9cSHadriel Kaplan
231eb07f9cSHadriel Kaplan #include <ctype.h>
241eb07f9cSHadriel Kaplan #include <string.h>
251eb07f9cSHadriel Kaplan
2638c27701SHadriel Kaplan #include "debug.h"
271eb07f9cSHadriel Kaplan #include "entry.h"
281eb07f9cSHadriel Kaplan #include "parse.h"
291eb07f9cSHadriel Kaplan #include "read.h"
301eb07f9cSHadriel Kaplan #include "vstring.h"
311eb07f9cSHadriel Kaplan #include "nestlevel.h"
321eb07f9cSHadriel Kaplan #include "routines.h"
331eb07f9cSHadriel Kaplan
341eb07f9cSHadriel Kaplan /*
351eb07f9cSHadriel Kaplan * DATA DEFINITIONS
361eb07f9cSHadriel Kaplan */
371eb07f9cSHadriel Kaplan typedef enum {
381eb07f9cSHadriel Kaplan K_CHAPTER = 0,
391eb07f9cSHadriel Kaplan K_SECTION,
401eb07f9cSHadriel Kaplan K_SUBSECTION,
411eb07f9cSHadriel Kaplan K_SUBSUBSECTION,
421eb07f9cSHadriel Kaplan K_LEVEL4SECTION,
43ab92488cSHadriel Kaplan /* level-5 section not in here because it only works for one-line */
44d776d040SHadriel Kaplan SECTION_COUNT, /* this is the same as level-5 kind number */
45d776d040SHadriel Kaplan K_ANCHOR
461eb07f9cSHadriel Kaplan } asciidocKind;
471eb07f9cSHadriel Kaplan
481eb07f9cSHadriel Kaplan /*
491eb07f9cSHadriel Kaplan * The following kind letters are based on the markdown parser kinds,
501eb07f9cSHadriel Kaplan * and thus different than geany's.
511eb07f9cSHadriel Kaplan */
521eb07f9cSHadriel Kaplan static kindDefinition AsciidocKinds[] = {
531eb07f9cSHadriel Kaplan { true, 'c', "chapter", "chapters"},
541eb07f9cSHadriel Kaplan { true, 's', "section", "sections" },
551eb07f9cSHadriel Kaplan { true, 'S', "subsection", "level 2 sections" },
561eb07f9cSHadriel Kaplan { true, 't', "subsubsection", "level 3 sections" },
57ab92488cSHadriel Kaplan { true, 'T', "l4subsection", "level 4 sections" },
58d776d040SHadriel Kaplan { true, 'u', "l5subsection", "level 5 sections" },
59d776d040SHadriel Kaplan { true, 'a', "anchor", "anchors" }
601eb07f9cSHadriel Kaplan };
611eb07f9cSHadriel Kaplan
621eb07f9cSHadriel Kaplan static char kindchars[SECTION_COUNT]={ '=', '-', '~', '^', '+' };
631eb07f9cSHadriel Kaplan
641eb07f9cSHadriel Kaplan static NestingLevels *nestingLevels = NULL;
651eb07f9cSHadriel Kaplan
661eb07f9cSHadriel Kaplan /*
671eb07f9cSHadriel Kaplan * FUNCTION DEFINITIONS
681eb07f9cSHadriel Kaplan */
691eb07f9cSHadriel Kaplan
getNestingLevel(const int kind)701eb07f9cSHadriel Kaplan static NestingLevel *getNestingLevel(const int kind)
711eb07f9cSHadriel Kaplan {
721eb07f9cSHadriel Kaplan NestingLevel *nl;
731eb07f9cSHadriel Kaplan tagEntryInfo *e;
741eb07f9cSHadriel Kaplan
751eb07f9cSHadriel Kaplan while (1)
761eb07f9cSHadriel Kaplan {
771eb07f9cSHadriel Kaplan nl = nestingLevelsGetCurrent(nestingLevels);
781eb07f9cSHadriel Kaplan e = getEntryOfNestingLevel (nl);
791eb07f9cSHadriel Kaplan if ((nl && (e == NULL)) || (e && (e->kindIndex >= kind)))
801eb07f9cSHadriel Kaplan nestingLevelsPop(nestingLevels);
811eb07f9cSHadriel Kaplan else
821eb07f9cSHadriel Kaplan break;
831eb07f9cSHadriel Kaplan }
841eb07f9cSHadriel Kaplan return nl;
851eb07f9cSHadriel Kaplan }
861eb07f9cSHadriel Kaplan
makeAsciidocTag(const vString * const name,const int kind,const bool two_line)8738c27701SHadriel Kaplan static int makeAsciidocTag (const vString* const name, const int kind, const bool two_line)
881eb07f9cSHadriel Kaplan {
891eb07f9cSHadriel Kaplan const NestingLevel *const nl = getNestingLevel(kind);
901eb07f9cSHadriel Kaplan int r = CORK_NIL;
911eb07f9cSHadriel Kaplan
921eb07f9cSHadriel Kaplan if (vStringLength (name) > 0)
931eb07f9cSHadriel Kaplan {
941eb07f9cSHadriel Kaplan tagEntryInfo *parent = getEntryOfNestingLevel (nl);
951eb07f9cSHadriel Kaplan tagEntryInfo e;
961eb07f9cSHadriel Kaplan
971eb07f9cSHadriel Kaplan initTagEntry (&e, vStringValue (name), kind);
981eb07f9cSHadriel Kaplan
9938c27701SHadriel Kaplan if (two_line)
10038c27701SHadriel Kaplan {
10138c27701SHadriel Kaplan /* we want the line before the '---' underline chars */
10238c27701SHadriel Kaplan const unsigned long line = getInputLineNumber();
10338c27701SHadriel Kaplan Assert (line > 0);
10438c27701SHadriel Kaplan if (line > 0)
10538c27701SHadriel Kaplan {
10638c27701SHadriel Kaplan e.lineNumber--;
10738c27701SHadriel Kaplan e.filePosition = getInputFilePositionForLine(line - 1);
10838c27701SHadriel Kaplan }
10938c27701SHadriel Kaplan }
1101eb07f9cSHadriel Kaplan
1111eb07f9cSHadriel Kaplan if (parent && (parent->kindIndex < kind))
1121eb07f9cSHadriel Kaplan {
1131eb07f9cSHadriel Kaplan /*
1141eb07f9cSHadriel Kaplan * This doesn't use Cork, but in this case I think this is better,
1151eb07f9cSHadriel Kaplan * because Cork would record the scopes of all parents in the chain
1161eb07f9cSHadriel Kaplan * which is weird for text section identifiers, and also this is
1171eb07f9cSHadriel Kaplan * what the rst.c reStructuredText parser does.
1181eb07f9cSHadriel Kaplan */
1191eb07f9cSHadriel Kaplan e.extensionFields.scopeKindIndex = parent->kindIndex;
1201eb07f9cSHadriel Kaplan e.extensionFields.scopeName = parent->name;
1211eb07f9cSHadriel Kaplan }
1221eb07f9cSHadriel Kaplan
1231eb07f9cSHadriel Kaplan r = makeTagEntry (&e);
1241eb07f9cSHadriel Kaplan }
125d776d040SHadriel Kaplan return r;
126d776d040SHadriel Kaplan }
127d776d040SHadriel Kaplan
makeSectionAsciidocTag(const vString * const name,const int kind,const bool two_line)128d776d040SHadriel Kaplan static int makeSectionAsciidocTag (const vString* const name, const int kind, const bool two_line)
129d776d040SHadriel Kaplan {
130d776d040SHadriel Kaplan int r = makeAsciidocTag(name, kind, two_line);
1311eb07f9cSHadriel Kaplan nestingLevelsPush(nestingLevels, r);
1321eb07f9cSHadriel Kaplan return r;
1331eb07f9cSHadriel Kaplan }
1341eb07f9cSHadriel Kaplan
1351eb07f9cSHadriel Kaplan
get_kind(char c)1361eb07f9cSHadriel Kaplan static int get_kind(char c)
1371eb07f9cSHadriel Kaplan {
1381eb07f9cSHadriel Kaplan int i;
1391eb07f9cSHadriel Kaplan
1401eb07f9cSHadriel Kaplan for (i = 0; i < SECTION_COUNT; i++)
1411eb07f9cSHadriel Kaplan {
1421eb07f9cSHadriel Kaplan if (kindchars[i] == c)
1431eb07f9cSHadriel Kaplan return i;
1441eb07f9cSHadriel Kaplan }
1451eb07f9cSHadriel Kaplan return -1;
1461eb07f9cSHadriel Kaplan }
1471eb07f9cSHadriel Kaplan
1481eb07f9cSHadriel Kaplan
is_anchor(const unsigned char * line)149d776d040SHadriel Kaplan static bool is_anchor(const unsigned char *line)
150d776d040SHadriel Kaplan {
151d776d040SHadriel Kaplan /* must be at least "[#a]" */
152d776d040SHadriel Kaplan return line[0] == '[' && (line[1] == '#' || line[1] == '[');
153d776d040SHadriel Kaplan }
154d776d040SHadriel Kaplan
capture_anchor(const unsigned char * const orig,int * captured_len)155d54a1312SHadriel Kaplan static int capture_anchor(const unsigned char *const orig, int* captured_len)
156d776d040SHadriel Kaplan {
157d776d040SHadriel Kaplan vString *name = vStringNew ();
158d776d040SHadriel Kaplan int r = CORK_NIL;
159d54a1312SHadriel Kaplan const bool shorthand = orig[1] == '#' ? true : false;
1604ab8d171SHadriel Kaplan bool is_valid = false;
16152550b1eSHadriel Kaplan bool seen_comma = false;
162d54a1312SHadriel Kaplan const unsigned char *line = orig;
163d776d040SHadriel Kaplan
164d776d040SHadriel Kaplan Assert (line[0] == '[');
165d776d040SHadriel Kaplan Assert (line[1] == '#' || line[1] == '[');
166d776d040SHadriel Kaplan
167d54a1312SHadriel Kaplan if (captured_len) *captured_len = 0;
168d54a1312SHadriel Kaplan
169d776d040SHadriel Kaplan line += 2;
170d776d040SHadriel Kaplan
171d776d040SHadriel Kaplan while (*line != '\0')
172d776d040SHadriel Kaplan {
173d776d040SHadriel Kaplan if (*line == ']')
174d776d040SHadriel Kaplan {
1754ab8d171SHadriel Kaplan if (shorthand || line[1] == ']')
1764ab8d171SHadriel Kaplan {
1774ab8d171SHadriel Kaplan is_valid = true;
178d54a1312SHadriel Kaplan if (shorthand) line++;
179d54a1312SHadriel Kaplan else line += 2;
180d776d040SHadriel Kaplan break;
1814ab8d171SHadriel Kaplan }
182d776d040SHadriel Kaplan /* otherwise it's not the end, keep going */
183d776d040SHadriel Kaplan }
18452550b1eSHadriel Kaplan
18552550b1eSHadriel Kaplan if (*line == ',')
18652550b1eSHadriel Kaplan seen_comma = true;
18752550b1eSHadriel Kaplan
18852550b1eSHadriel Kaplan if (!seen_comma)
189d776d040SHadriel Kaplan vStringPut (name, *line);
19052550b1eSHadriel Kaplan
191d776d040SHadriel Kaplan line++;
192d776d040SHadriel Kaplan }
193d776d040SHadriel Kaplan
1944ab8d171SHadriel Kaplan if (is_valid && vStringLength (name) != 0)
195d776d040SHadriel Kaplan {
196d776d040SHadriel Kaplan r = makeAsciidocTag (name, K_ANCHOR, false);
197d54a1312SHadriel Kaplan
198d54a1312SHadriel Kaplan if (captured_len)
199d54a1312SHadriel Kaplan {
200d54a1312SHadriel Kaplan *captured_len = line - orig;
201d54a1312SHadriel Kaplan }
202d776d040SHadriel Kaplan }
203d776d040SHadriel Kaplan
204d776d040SHadriel Kaplan vStringDelete (name);
205d776d040SHadriel Kaplan return r;
206d776d040SHadriel Kaplan }
207d776d040SHadriel Kaplan
208d776d040SHadriel Kaplan
209d54a1312SHadriel Kaplan /* skips any leading anchor(s) in a one-line title, generating tags for them */
process_leading_anchors(const unsigned char * const begin)210d54a1312SHadriel Kaplan static int process_leading_anchors(const unsigned char *const begin)
211d54a1312SHadriel Kaplan {
212d54a1312SHadriel Kaplan int captured_len = 0;
213d54a1312SHadriel Kaplan const unsigned char *current = begin;
214d54a1312SHadriel Kaplan
215d54a1312SHadriel Kaplan while (is_anchor(current) && capture_anchor(current, &captured_len) != CORK_NIL)
216d54a1312SHadriel Kaplan {
217d54a1312SHadriel Kaplan /* minimum is "[#a]" */
218d54a1312SHadriel Kaplan Assert (captured_len >= 4);
219d54a1312SHadriel Kaplan current += captured_len;
220d54a1312SHadriel Kaplan while (isspace(*current)) ++current;
221d54a1312SHadriel Kaplan }
222d54a1312SHadriel Kaplan
223d54a1312SHadriel Kaplan return current - begin;
224d54a1312SHadriel Kaplan }
225d54a1312SHadriel Kaplan
process_trailing_anchor(const unsigned char * const begin,const unsigned char * const end)2268f0a66adSHadriel Kaplan static int process_trailing_anchor(const unsigned char *const begin,
2278f0a66adSHadriel Kaplan const unsigned char *const end)
2288f0a66adSHadriel Kaplan {
2298f0a66adSHadriel Kaplan int captured_len = 0;
2308f0a66adSHadriel Kaplan const unsigned char *found = NULL;
2318f0a66adSHadriel Kaplan
2328f0a66adSHadriel Kaplan /* minimum is "[#a]" */
2338f0a66adSHadriel Kaplan if (*end == ']' && (end - begin) >= 4)
2348f0a66adSHadriel Kaplan {
2358f0a66adSHadriel Kaplan found = (const unsigned char*) strrchr((const char*) begin , '[');
2368f0a66adSHadriel Kaplan if (found && ((end - found) >= 4))
2378f0a66adSHadriel Kaplan {
2388f0a66adSHadriel Kaplan /* see if it's not shorthand [#a] but instead [[a]] */
2398f0a66adSHadriel Kaplan if (end[-1] == ']' && found > begin && found[-1] == '[')
2408f0a66adSHadriel Kaplan --found;
2418f0a66adSHadriel Kaplan
2423030d1e8SHadriel Kaplan if (is_anchor (found))
2438f0a66adSHadriel Kaplan capture_anchor(found, &captured_len);
2448f0a66adSHadriel Kaplan }
2458f0a66adSHadriel Kaplan }
2468f0a66adSHadriel Kaplan
2478f0a66adSHadriel Kaplan return captured_len;
2488f0a66adSHadriel Kaplan }
2498f0a66adSHadriel Kaplan
process_name(vString * const name,const int kind,const unsigned char * line,const int line_len)2507344a35cSHadriel Kaplan static void process_name(vString *const name, const int kind,
2517344a35cSHadriel Kaplan const unsigned char *line, const int line_len)
2527344a35cSHadriel Kaplan {
2537344a35cSHadriel Kaplan int start = kind + 1;
2547344a35cSHadriel Kaplan int end = line_len - 1;
2557344a35cSHadriel Kaplan
2567344a35cSHadriel Kaplan Assert (kind >= 0 && kind < K_ANCHOR);
2577344a35cSHadriel Kaplan Assert (line_len > start);
2587344a35cSHadriel Kaplan
259d54a1312SHadriel Kaplan vStringClear(name);
260d54a1312SHadriel Kaplan
2617344a35cSHadriel Kaplan while (line[end] == line[0]) --end;
2627344a35cSHadriel Kaplan while (isspace(line[start])) ++start;
2637344a35cSHadriel Kaplan while (isspace(line[end])) --end;
2647344a35cSHadriel Kaplan
265d54a1312SHadriel Kaplan if (start < end)
266d54a1312SHadriel Kaplan {
267cadfac37SHadriel Kaplan /* pop nesting levels, so that anchors get the parent's scope */
268cadfac37SHadriel Kaplan getNestingLevel(kind);
2698f0a66adSHadriel Kaplan end -= process_trailing_anchor(line + start, line + end);
270d54a1312SHadriel Kaplan start += process_leading_anchors(line + start);
271d54a1312SHadriel Kaplan }
272d54a1312SHadriel Kaplan
2738f0a66adSHadriel Kaplan while (isspace(line[end])) --end;
2748f0a66adSHadriel Kaplan
275b4474ed0SMasatake YAMATO if (start <= end)
2767344a35cSHadriel Kaplan vStringNCatS(name, (const char*)(&(line[start])), end - start + 1);
2777344a35cSHadriel Kaplan }
2787344a35cSHadriel Kaplan
2797344a35cSHadriel Kaplan
2801eb07f9cSHadriel Kaplan /* computes the length of an UTF-8 string
2811eb07f9cSHadriel Kaplan * if the string doesn't look like UTF-8, return -1
2821eb07f9cSHadriel Kaplan * FIXME consider East_Asian_Width Unicode property */
utf8_strlen(const char * buf,int buf_len)2831eb07f9cSHadriel Kaplan static int utf8_strlen(const char *buf, int buf_len)
2841eb07f9cSHadriel Kaplan {
2851eb07f9cSHadriel Kaplan int len = 0;
2861eb07f9cSHadriel Kaplan const char *end = buf + buf_len;
2871eb07f9cSHadriel Kaplan
2881eb07f9cSHadriel Kaplan for (len = 0; buf < end; len ++)
2891eb07f9cSHadriel Kaplan {
2901eb07f9cSHadriel Kaplan /* perform quick and naive validation (no sub-byte checking) */
2911eb07f9cSHadriel Kaplan if (! (*buf & 0x80))
2921eb07f9cSHadriel Kaplan buf ++;
2931eb07f9cSHadriel Kaplan else if ((*buf & 0xe0) == 0xc0)
2941eb07f9cSHadriel Kaplan buf += 2;
2951eb07f9cSHadriel Kaplan else if ((*buf & 0xf0) == 0xe0)
2961eb07f9cSHadriel Kaplan buf += 3;
2971eb07f9cSHadriel Kaplan else if ((*buf & 0xf8) == 0xf0)
2981eb07f9cSHadriel Kaplan buf += 4;
2991eb07f9cSHadriel Kaplan else /* not a valid leading UTF-8 byte, abort */
3001eb07f9cSHadriel Kaplan return -1;
3011eb07f9cSHadriel Kaplan
3021eb07f9cSHadriel Kaplan if (buf > end) /* incomplete last byte */
3031eb07f9cSHadriel Kaplan return -1;
3041eb07f9cSHadriel Kaplan }
3051eb07f9cSHadriel Kaplan
3061eb07f9cSHadriel Kaplan return len;
3071eb07f9cSHadriel Kaplan }
3081eb07f9cSHadriel Kaplan
3091eb07f9cSHadriel Kaplan
findAsciidocTags(void)3101eb07f9cSHadriel Kaplan static void findAsciidocTags(void)
3111eb07f9cSHadriel Kaplan {
3121eb07f9cSHadriel Kaplan vString *name = vStringNew();
3131eb07f9cSHadriel Kaplan const unsigned char *line;
3141eb07f9cSHadriel Kaplan unsigned char in_block = '\0'; /* holds the block marking char or \0 if not in block */
3151eb07f9cSHadriel Kaplan
3161eb07f9cSHadriel Kaplan nestingLevels = nestingLevelsNew(0);
3171eb07f9cSHadriel Kaplan
3181eb07f9cSHadriel Kaplan while ((line = readLineFromInputFile()) != NULL)
3191eb07f9cSHadriel Kaplan {
320d776d040SHadriel Kaplan if (is_anchor (line))
321d776d040SHadriel Kaplan {
322d54a1312SHadriel Kaplan if (capture_anchor (line, NULL) != CORK_NIL)
323d776d040SHadriel Kaplan {
324d776d040SHadriel Kaplan vStringClear (name);
325d776d040SHadriel Kaplan continue;
326d776d040SHadriel Kaplan }
327d776d040SHadriel Kaplan }
328d776d040SHadriel Kaplan
3291eb07f9cSHadriel Kaplan int line_len = strlen((const char*) line);
3301eb07f9cSHadriel Kaplan int name_len_bytes = vStringLength(name);
3311eb07f9cSHadriel Kaplan int name_len = utf8_strlen(vStringValue(name), name_len_bytes);
3321eb07f9cSHadriel Kaplan
3331eb07f9cSHadriel Kaplan /* if the name doesn't look like UTF-8, assume one-byte charset */
3341eb07f9cSHadriel Kaplan if (name_len < 0) name_len = name_len_bytes;
3351eb07f9cSHadriel Kaplan
3361eb07f9cSHadriel Kaplan /* if its a title underline, or a delimited block marking character */
3371eb07f9cSHadriel Kaplan if (line[0] == '=' || line[0] == '-' || line[0] == '~' ||
3381eb07f9cSHadriel Kaplan line[0] == '^' || line[0] == '+' || line[0] == '.' ||
3391eb07f9cSHadriel Kaplan line[0] == '*' || line[0] == '_' || line[0] == '/')
3401eb07f9cSHadriel Kaplan {
3411eb07f9cSHadriel Kaplan int n_same;
3421eb07f9cSHadriel Kaplan for (n_same = 1; line[n_same] == line[0]; ++n_same);
3431eb07f9cSHadriel Kaplan
3441eb07f9cSHadriel Kaplan /* is it a two line title or a delimited block */
3451eb07f9cSHadriel Kaplan if (n_same == line_len)
3461eb07f9cSHadriel Kaplan {
3471eb07f9cSHadriel Kaplan /* if in a block, can't be block start or title, look for block end */
3481eb07f9cSHadriel Kaplan if (in_block)
3491eb07f9cSHadriel Kaplan {
3501eb07f9cSHadriel Kaplan if (line[0] == in_block) in_block = '\0';
3511eb07f9cSHadriel Kaplan }
3521eb07f9cSHadriel Kaplan
3531eb07f9cSHadriel Kaplan /* if its a =_~^+ and the same length +-2 as the line before then its a title */
3541eb07f9cSHadriel Kaplan /* (except in the special case its a -- open block start line) */
3551eb07f9cSHadriel Kaplan else if ((line[0] == '=' || line[0] == '-' || line[0] == '~' ||
3561eb07f9cSHadriel Kaplan line[0] == '^' || line[0] == '+') &&
3571eb07f9cSHadriel Kaplan line_len <= name_len + 2 && line_len >= name_len - 2 &&
3581eb07f9cSHadriel Kaplan !(line_len == 2 && line[0] == '-'))
3591eb07f9cSHadriel Kaplan {
3601eb07f9cSHadriel Kaplan int kind = get_kind((char)(line[0]));
3611eb07f9cSHadriel Kaplan if (kind >= 0)
3621eb07f9cSHadriel Kaplan {
363d776d040SHadriel Kaplan makeSectionAsciidocTag(name, kind, true);
3641eb07f9cSHadriel Kaplan continue;
3651eb07f9cSHadriel Kaplan }
3661eb07f9cSHadriel Kaplan }
3671eb07f9cSHadriel Kaplan
3681eb07f9cSHadriel Kaplan /* else if its 4 or more /+-.*_= (plus the -- special case) its a block start */
3691eb07f9cSHadriel Kaplan else if (((line[0] == '/' || line[0] == '+' || line[0] == '-' ||
3701eb07f9cSHadriel Kaplan line[0] == '.' || line[0] == '*' || line[0] == '_' ||
3711eb07f9cSHadriel Kaplan line[0] == '=') && line_len >= 4 )
3721eb07f9cSHadriel Kaplan || (line[0] == '-' && line_len == 2))
3731eb07f9cSHadriel Kaplan {
3741eb07f9cSHadriel Kaplan in_block = line[0];
3751eb07f9cSHadriel Kaplan }
3761eb07f9cSHadriel Kaplan }
3771eb07f9cSHadriel Kaplan
3781eb07f9cSHadriel Kaplan /* otherwise is it a one line title */
379ab92488cSHadriel Kaplan else if (line[0] == '=' && n_same <= 6 && isspace(line[n_same]) &&
3801eb07f9cSHadriel Kaplan !in_block)
3811eb07f9cSHadriel Kaplan {
3821eb07f9cSHadriel Kaplan int kind = n_same - 1;
3837344a35cSHadriel Kaplan process_name(name, kind, line, line_len);
384d776d040SHadriel Kaplan makeSectionAsciidocTag(name, kind, false);
3851eb07f9cSHadriel Kaplan continue;
3861eb07f9cSHadriel Kaplan }
3871eb07f9cSHadriel Kaplan }
3881eb07f9cSHadriel Kaplan vStringClear(name);
3891eb07f9cSHadriel Kaplan if (! isspace(*line))
3901eb07f9cSHadriel Kaplan vStringCatS(name, (const char*) line);
3911eb07f9cSHadriel Kaplan }
3921eb07f9cSHadriel Kaplan vStringDelete(name);
3931eb07f9cSHadriel Kaplan nestingLevelsFree(nestingLevels);
3941eb07f9cSHadriel Kaplan }
3951eb07f9cSHadriel Kaplan
AsciidocParser(void)3961eb07f9cSHadriel Kaplan extern parserDefinition* AsciidocParser (void)
3971eb07f9cSHadriel Kaplan {
3981eb07f9cSHadriel Kaplan static const char *const patterns [] = { "*.asc", "*.adoc", "*.asciidoc", NULL };
3991eb07f9cSHadriel Kaplan static const char *const extensions [] = { "asc", "adoc", "asciidoc", NULL };
4001eb07f9cSHadriel Kaplan
4011eb07f9cSHadriel Kaplan parserDefinition* const def = parserNew ("Asciidoc");
4021eb07f9cSHadriel Kaplan
4031eb07f9cSHadriel Kaplan def->kindTable = AsciidocKinds;
4041eb07f9cSHadriel Kaplan def->kindCount = ARRAY_SIZE (AsciidocKinds);
4051eb07f9cSHadriel Kaplan def->patterns = patterns;
4061eb07f9cSHadriel Kaplan def->extensions = extensions;
4071eb07f9cSHadriel Kaplan def->parser = findAsciidocTags;
4081eb07f9cSHadriel Kaplan /* do we even need to use Cork? */
409*6b1a862eSMasatake YAMATO def->useCork = CORK_QUEUE;
4101eb07f9cSHadriel Kaplan
4111eb07f9cSHadriel Kaplan return def;
4121eb07f9cSHadriel Kaplan }
413