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 version 2 or (at your opinion) any later version.
10 * This module contains functions for generating tags for Txt2tags files
11 * (https://en.wikipedia.org/wiki/Txt2tags).
17 #include "general.h" /* must always come first */
24 #include "nestlevel.h"
30 #define SCOPE_SEPARATOR "\"\""
40 static scopeSeparator Txt2TagsSeparators
[] = {
41 { KIND_WILDCARD_INDEX
, SCOPE_SEPARATOR
}
44 static kindDefinition Txt2tagsKinds
[] = {
45 { true, 's', "section", "sections",
46 ATTACH_SEPARATORS(Txt2TagsSeparators
) },
49 struct nestingLevelUserData
{
52 #define NL_INDENTATION(nl) ((struct nestingLevelUserData *)nestingLevelGetUserData(nl))->indentation
55 * FUNCTION DEFINITIONS
58 static int makeTxt2tagsTag (const vString
* const name
,
59 const NestingLevels
*const nls
,
64 initTagEntry (&e
, vStringValue(name
), type
);
66 nl
= nestingLevelsGetCurrent (nls
);
68 e
.extensionFields
.scopeIndex
= nl
->corkIndex
;
70 return makeTagEntry(&e
);
73 /* matches: ^ *[=_-]{20,} *$ */
74 static bool isTxt2tagsLine (const unsigned char *line
)
78 while (isspace(*line
)) line
++;
79 for (len
= 0; *line
== '=' || *line
== '-' || *line
== '_'; len
++)
81 while (isspace(*line
)) line
++;
83 return len
>= 20 && *line
== 0;
86 static bool parseTxt2tagsTitle (const unsigned char *line
,
90 const int MAX_TITLE_DEPTH
= 5; /* maximum length of a title delimiter */
93 const unsigned char *end
;
95 /* skip leading spaces, but no tabs (probably because they create quotes) */
96 while (*line
== ' ') line
++;
98 /* normal/numbered titles */
99 if (*line
!= '=' && *line
!= '+')
104 /* find the start delimiter length */
105 while (*line
== delim
&& delim_delta
< MAX_TITLE_DEPTH
+1)
110 while (isspace(*line
))
113 if (delim_delta
> MAX_TITLE_DEPTH
) /* invalid */
116 *depth_
= delim_delta
;
118 /* find the end delimiter */
119 end
= line
+ strlen((const char *) line
) - 1;
120 while (end
> line
&& isspace(*end
)) end
--;
121 /* skip a possible label: \[[A-Za-z0-9_-]+\] */
125 while (end
> line
&& (isalnum(*end
) || *end
== '_' || *end
== '-'))
127 if (*end
!= '[') /* invalid */
131 while (end
> line
&& *end
== delim
&& delim_delta
>= 0)
136 while (end
> line
&& isspace(*end
)) end
--;
139 /* if start and end delimiters are not identical, or the the name is empty */
140 if (delim_delta
!= 0 || (end
- line
) <= 0)
143 vStringNCopyS(title
, (const char *) line
, end
- line
);
147 static void findTxt2tagsTags (void)
149 NestingLevels
*nls
= nestingLevelsNew(sizeof(struct nestingLevelUserData
));
150 vString
*name
= vStringNew();
151 const unsigned char *line
;
153 while ((line
= readLineFromInputFile()) != NULL
)
157 if (isTxt2tagsLine(line
))
158 ; /* skip not to improperly match titles */
159 else if (parseTxt2tagsTitle(line
, name
, &depth
))
161 NestingLevel
*nl
= nestingLevelsGetCurrent(nls
);
164 while (nl
&& NL_INDENTATION(nl
) >= depth
)
166 nestingLevelsPop(nls
);
167 nl
= nestingLevelsGetCurrent(nls
);
170 r
= makeTxt2tagsTag(name
, nls
, K_SECTION
);
171 nestingLevelsPush(nls
, r
);
172 nl
= nestingLevelsGetCurrent(nls
);
173 NL_INDENTATION(nl
) = depth
;
176 vStringDelete (name
);
177 nestingLevelsFree(nls
);
180 extern parserDefinition
* Txt2tagsParser (void)
182 static const char *const patterns
[] = { "*.t2t", NULL
};
183 static const char *const extensions
[] = { "t2t", NULL
};
184 parserDefinition
* const def
= parserNew ("Txt2tags");
186 def
->kindTable
= Txt2tagsKinds
;
187 def
->kindCount
= ARRAY_SIZE (Txt2tagsKinds
);
188 def
->patterns
= patterns
;
189 def
->extensions
= extensions
;
190 def
->parser
= findTxt2tagsTags
;
191 def
->useCork
= CORK_QUEUE
;