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.
16 #include "general.h" /* must always come first */
23 #include "nestlevel.h"
28 /* as any character may happen in an input, use something highly unlikely */
29 #define SCOPE_SEPARATOR '\x3' /* ASCII ETX */
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
,
52 vString
*scope
= NULL
;
53 kindOption
*kind
= &Txt2tagsKinds
[type
];
54 initTagEntry (&e
, vStringValue(name
), kind
);
58 kindOption
*parentKind
;
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
);
77 /* matches: ^ *[=_-]{20,} *$ */
78 static bool isTxt2tagsLine (const unsigned char *line
)
82 while (isspace(*line
)) line
++;
83 for (len
= 0; *line
== '=' || *line
== '-' || *line
== '_'; len
++)
85 while (isspace(*line
)) line
++;
87 return len
>= 20 && *line
== 0;
90 static bool parseTxt2tagsTitle (const unsigned char *line
,
94 const int MAX_TITLE_DEPTH
= 5; /* maximum length of a title delimiter */
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
!= '+')
108 /* find the start delimiter length */
109 while (*line
== delim
&& delim_delta
< MAX_TITLE_DEPTH
+1)
114 while (isspace(*line
))
117 if (delim_delta
> MAX_TITLE_DEPTH
) /* invalid */
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_-]+\] */
129 while (end
> line
&& (isalnum(*end
) || *end
== '_' || *end
== '-'))
131 if (*end
!= '[') /* invalid */
135 while (end
> line
&& *end
== delim
&& delim_delta
>= 0)
140 while (end
> line
&& isspace(*end
)) end
--;
143 /* if start and end delimiters are not identical, or the the name is empty */
144 if (delim_delta
!= 0 || (end
- line
) <= 0)
147 vStringNCopyS(title
, (const char *) line
, end
- line
);
151 static void findTxt2tagsTags (void)
153 NestingLevels
*nls
= nestingLevelsNew();
154 vString
*name
= vStringNew();
155 const unsigned char *line
;
157 while ((line
= readLineFromInputFile()) != NULL
)
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
;