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"
27 /* as any character may happen in an input, use something highly unlikely */
28 #define SCOPE_SEPARATOR '\x3' /* ASCII ETX */
38 static kindOption Txt2tagsKinds
[] = {
39 { TRUE
, 'm', "member", "sections" }
43 * FUNCTION DEFINITIONS
46 static void makeTxt2tagsTag (const vString
* const name
,
47 const NestingLevels
*const nls
,
51 vString
*scope
= NULL
;
52 kindOption
*kind
= &Txt2tagsKinds
[type
];
53 initTagEntry (&e
, vStringValue(name
));
55 e
.kindName
= kind
->name
;
56 e
.kind
= kind
->letter
;
60 kindOption
*parentKind
;
63 for (i
= 0; i
< nls
->n
; i
++) {
64 if (vStringLength(scope
) > 0)
65 vStringPut(scope
, SCOPE_SEPARATOR
);
66 vStringCat(scope
, nls
->levels
[i
].name
);
68 parentKind
= &Txt2tagsKinds
[nls
->levels
[nls
->n
- 1].type
];
70 e
.extensionFields
.scope
[0] = parentKind
->name
;
71 e
.extensionFields
.scope
[1] = vStringValue(scope
);
79 /* matches: ^ *[=_-]{20,} *$ */
80 static boolean
isTxt2tagsLine (const unsigned char *line
)
84 while (isspace(*line
)) line
++;
85 for (len
= 0; *line
== '=' || *line
== '-' || *line
== '_'; len
++)
87 while (isspace(*line
)) line
++;
89 return len
>= 20 && *line
== 0;
92 static boolean
parseTxt2tagsTitle (const unsigned char *line
,
96 const int MAX_TITLE_DEPTH
= 5; /* maximum length of a title delimiter */
99 const unsigned char *end
;
101 /* skip leading spaces, but no tabs (probably because they create quotes) */
102 while (*line
== ' ') line
++;
104 /* normal/numbered titles */
105 if (*line
!= '=' && *line
!= '+')
110 /* find the start delimiter length */
111 while (*line
== delim
&& delim_delta
< MAX_TITLE_DEPTH
+1)
116 while (isspace(*line
))
119 if (delim_delta
> MAX_TITLE_DEPTH
) /* invalid */
122 *depth_
= delim_delta
;
124 /* find the end delimiter */
125 end
= line
+ strlen((const char *) line
) - 1;
126 while (end
> line
&& isspace(*end
)) end
--;
127 /* skip a possible label: \[[A-Za-z0-9_-]+\] */
131 while (end
> line
&& (isalnum(*end
) || *end
== '_' || *end
== '-'))
133 if (*end
!= '[') /* invalid */
137 while (end
> line
&& *end
== delim
&& delim_delta
>= 0)
142 while (end
> line
&& isspace(*end
)) end
--;
145 /* if start and end delimiters are not identical, or the the name is empty */
146 if (delim_delta
!= 0 || (end
- line
) <= 0)
149 vStringNCopyS(title
, (const char *) line
, end
- line
);
153 static void findTxt2tagsTags (void)
155 NestingLevels
*nls
= nestingLevelsNew();
156 vString
*name
= vStringNew();
157 const unsigned char *line
;
159 while ((line
= fileReadLine()) != NULL
)
163 if (isTxt2tagsLine(line
))
164 ; /* skip not to improperly match titles */
165 else if (parseTxt2tagsTitle(line
, name
, &depth
))
167 NestingLevel
*nl
= nestingLevelsGetCurrent(nls
);
168 while (nl
&& nl
->indentation
>= depth
)
170 nestingLevelsPop(nls
);
171 nl
= nestingLevelsGetCurrent(nls
);
174 vStringTerminate(name
);
175 makeTxt2tagsTag(name
, nls
, K_SECTION
);
176 nestingLevelsPush(nls
, name
, K_SECTION
);
177 nestingLevelsGetCurrent(nls
)->indentation
= depth
;
180 vStringDelete (name
);
181 nestingLevelsFree(nls
);
184 extern parserDefinition
* Txt2tagsParser (void)
186 static const char *const patterns
[] = { "*.t2t", NULL
};
187 static const char *const extensions
[] = { "t2t", NULL
};
188 parserDefinition
* const def
= parserNew ("Txt2tags");
190 def
->kinds
= Txt2tagsKinds
;
191 def
->kindCount
= KIND_COUNT (Txt2tagsKinds
);
192 def
->patterns
= patterns
;
193 def
->extensions
= extensions
;
194 def
->parser
= findTxt2tagsTags
;