1 /*
2 *
3 * Copyright (c) 2016, Masatake YAMATO
4 * Copyright (c) 2016, Red Hat, K.K.
5 *
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License version 2 or (at your option) any later version.
8 *
9 * This module contains functions for generating tags for xslt 1.0.
10 * Reference: https://www.w3.org/1999/11/xslt10.dtd
11 *
12 */
13
14 #include "general.h" /* must always come first */
15
16 #include <string.h>
17
18 #include "entry.h"
19 #include "options.h"
20 #include "parse.h"
21 #include "read.h"
22 #include "routines.h"
23 #include "selectors.h"
24 #include "xml.h"
25
26 typedef enum {
27 K_STYLESHEET,
28 K_PARAMETER,
29 K_MATCHED_TEMPLATE,
30 K_NAMED_TEMPLATE,
31 K_VARIABLE,
32 /* TODO: KEY, DECIMAL-FORMAT, ATTRIBUTE, ATTRIBUTE-SET, ... */
33 } xsltKind;
34
35 typedef enum {
36 R_STYLESHEET_IMPORTED,
37 R_STYLESHEET_INCLUDED,
38 } xsltStylesheetRole;
39 static roleDefinition XsltStylesheetRoles [] = {
40 { true, "imported", "imported" },
41 { true, "included", "included" },
42 };
43
44 typedef enum {
45 R_PARAMETER_BOUND,
46 } xsltParameterRole;
47 static roleDefinition XsltParameterRoles [] = {
48 { true, "bound", "bound to value" },
49 };
50
51 typedef enum {
52 R_MATCHED_TEMPLATE_APPLIED,
53 } xsltMatchedTemplateRole;
54 static roleDefinition XsltMatchedTemplateRoles [] = {
55 { true, "applied", "applied" },
56 };
57
58 typedef enum {
59 R_NAMED_TEMPLATE_CALLED,
60 } xsltNamedTemplateRole;
61 static roleDefinition XsltNamedTemplateRoles [] = {
62 { true, "called", "called" },
63 };
64
65
66 static kindDefinition XsltKinds [] = {
67 { true, 's', "stylesheet", "stylesheets",
68 .referenceOnly = true, ATTACH_ROLES (XsltStylesheetRoles) },
69 { true, 'p', "parameter", "parameters",
70 .referenceOnly = false, ATTACH_ROLES (XsltParameterRoles) },
71 { true, 'm', "matchedTemplate", "matched template",
72 .referenceOnly = false, ATTACH_ROLES (XsltMatchedTemplateRoles) },
73 { true, 'n', "namedTemplate", "named template",
74 .referenceOnly = false, ATTACH_ROLES (XsltNamedTemplateRoles) },
75 { true, 'v', "variable", "variables" },
76 };
77
78 static void makeTagRecursivelyWithVersionVerification (xmlNode *node,
79 const char *xpath,
80 const tagXpathRecurSpec *spec,
81 xmlXPathContext *ctx,
82 void *userData);
83 static void makeTagRecursively (xmlNode *node,
84 const char *xpath,
85 const tagXpathRecurSpec *spec,
86 xmlXPathContext *ctx,
87 void *userData);
88
89 static void makeTagWithProvidingScope (xmlNode *node,
90 const char *xpath,
91 const tagXpathMakeTagSpec *spec,
92 struct sTagEntryInfo *tag,
93 void *userData);
94
95 enum xsltXpathTable {
96 TABLE_MAIN,
97 TABLE_STYLESHEET,
98 TABLE_VERSION_VERIFY,
99 TABLE_TEMPLATE,
100 TABLE_APPLIED_TEMPLATES,
101 TABLE_CALL_TEMPLATE,
102 TABLE_PARAM,
103 TABLE_VARIABLE,
104 TABLE_WITH_PARAM,
105 TABLE_CALL_TEMPLATE_INTERNAL,
106 };
107
108 #define xsltXpathTemplateTableEntry(PREFIX) \
109 { PREFIX "/*[local-name()='template']", \
110 LXPATH_TABLE_DO_RECUR, \
111 { .recurSpec = { makeTagRecursively, TABLE_TEMPLATE} }}
112
113 #define xsltXpathVariableTableEntry(PREFIX) \
114 { PREFIX "/*[local-name()='variable']", \
115 LXPATH_TABLE_DO_RECUR, \
116 { .recurSpec = { makeTagRecursively, TABLE_VARIABLE} }}
117
118 #define xsltXpathParamTableEntry(PREFIX) \
119 { PREFIX "/*[local-name()='param']", \
120 LXPATH_TABLE_DO_RECUR, \
121 { .recurSpec = { makeTagRecursively, TABLE_PARAM} }}
122
123 #define xsltXpathWithParamTableEntry(PREFIX) \
124 { PREFIX "/*[local-name()='with-param']", \
125 LXPATH_TABLE_DO_RECUR, \
126 { .recurSpec = { makeTagRecursively, TABLE_WITH_PARAM} }} \
127
128 static tagXpathTable xsltXpathMainTable[] = {
129 { "(/*[local-name()='stylesheet']|/*[local-name()='transform'])",
130 LXPATH_TABLE_DO_RECUR,
131 { .recurSpec = { makeTagRecursivelyWithVersionVerification } }},
132 };
133
134 static tagXpathTable xsltXpathStylesheetTable[] = {
135 { "./*[local-name()='import']/@href",
136 LXPATH_TABLE_DO_MAKE,
137 { .makeTagSpec = {K_STYLESHEET, R_STYLESHEET_IMPORTED} }},
138 { "./*[local-name()='include']/@href",
139 LXPATH_TABLE_DO_MAKE,
140 { .makeTagSpec = {K_STYLESHEET, R_STYLESHEET_INCLUDED} }},
141
142 xsltXpathTemplateTableEntry ("."),
143 xsltXpathVariableTableEntry ("."),
144 xsltXpathParamTableEntry ("."),
145 };
146
147 static tagXpathTable xsltXpathTemplateTable[] = {
148 { "./@match",
149 LXPATH_TABLE_DO_MAKE,
150 { .makeTagSpec = {K_MATCHED_TEMPLATE, ROLE_DEFINITION_INDEX,
151 makeTagWithProvidingScope } }},
152 { "./@name",
153 LXPATH_TABLE_DO_MAKE,
154 { .makeTagSpec = {K_NAMED_TEMPLATE, ROLE_DEFINITION_INDEX,
155 makeTagWithProvidingScope } }},
156 { ".",
157 LXPATH_TABLE_DO_RECUR,
158 { .recurSpec = { makeTagRecursively, TABLE_CALL_TEMPLATE_INTERNAL } }},
159 };
160
161 static tagXpathTable xsltXpathAppliedTemplatesTable [] = {
162 { "./@select",
163 LXPATH_TABLE_DO_MAKE,
164 { .makeTagSpec = {K_MATCHED_TEMPLATE, R_MATCHED_TEMPLATE_APPLIED,
165 makeTagWithProvidingScope } }},
166 xsltXpathWithParamTableEntry("."),
167 };
168
169 static tagXpathTable xsltXpathCallTemplateTable [] = {
170 { "./@name",
171 LXPATH_TABLE_DO_MAKE,
172 { .makeTagSpec = {K_NAMED_TEMPLATE, R_NAMED_TEMPLATE_CALLED,
173 makeTagWithProvidingScope } }},
174 xsltXpathWithParamTableEntry("."),
175 };
176
177 static tagXpathTable xsltXpathParamTable [] = {
178 { "./@name",
179 LXPATH_TABLE_DO_MAKE,
180 { .makeTagSpec = {K_PARAMETER, ROLE_DEFINITION_INDEX,
181 makeTagWithProvidingScope} }},
182 xsltXpathTemplateTableEntry ("."),
183 };
184
185 static tagXpathTable xsltXpathVariableTable [] = {
186 { "./@name",
187 LXPATH_TABLE_DO_MAKE,
188 { .makeTagSpec = {K_VARIABLE, ROLE_DEFINITION_INDEX,
189 makeTagWithProvidingScope} }},
190 xsltXpathTemplateTableEntry ("."),
191 };
192
193 static tagXpathTable xsltXpathWithParamTable [] = {
194 { "./@name",
195 LXPATH_TABLE_DO_MAKE,
196 { .makeTagSpec = {K_PARAMETER, R_PARAMETER_BOUND,
197 makeTagWithProvidingScope} }},
198 xsltXpathTemplateTableEntry ("."),
199 };
200
201 static tagXpathTable xsltXpathTemplateInternalTable [] = {
202 { "./*[local-name()='apply-templates']",
203 LXPATH_TABLE_DO_RECUR,
204 { .recurSpec = { makeTagRecursively, TABLE_APPLIED_TEMPLATES } }},
205 { "./*[local-name()='call-template']",
206 LXPATH_TABLE_DO_RECUR,
207 { .recurSpec = { makeTagRecursively, TABLE_CALL_TEMPLATE } }},
208 xsltXpathVariableTableEntry ("."),
209 xsltXpathParamTableEntry ("."),
210 { "./node()[not ("
211 "local-name()='apply-templates'"
212 " or "
213 "local-name()='call-template'"
214 " or "
215 "local-name()='variable'"
216 " or "
217 "local-name()='param'"
218 ")]",
219 LXPATH_TABLE_DO_RECUR,
220 { .recurSpec = { makeTagRecursively, TABLE_CALL_TEMPLATE_INTERNAL } }},
221 };
222
verifyVersion(xmlNode * node,const char * xpath CTAGS_ATTR_UNUSED,const tagXpathRecurSpec * spec CTAGS_ATTR_UNUSED,xmlXPathContext * ctx CTAGS_ATTR_UNUSED,void * userData)223 static void verifyVersion (xmlNode *node,
224 const char *xpath CTAGS_ATTR_UNUSED,
225 const tagXpathRecurSpec *spec CTAGS_ATTR_UNUSED,
226 xmlXPathContext *ctx CTAGS_ATTR_UNUSED,
227 void *userData)
228 {
229 bool *acceptable = userData;
230 char *version = (char *)xmlNodeGetContent (node);
231
232 if (version)
233 {
234 if (strcmp (version, "1.0") == 0)
235 {
236 verbose ("xslt: accept version: %s\n", version);
237 *acceptable = true;
238 }
239 else
240 verbose ("xslt: unsupported version: %s\n", version);
241
242 eFree (version);
243 }
244 else
245 verbose ("xslt: version unknown\n");
246 }
247
248 static tagXpathTable xsltXpathVersionVerifyTable [] = {
249 { "./@version",
250 LXPATH_TABLE_DO_RECUR,
251 { .recurSpec = { verifyVersion } }},
252 };
253
254
255 static tagXpathTableTable xsltXpathTableTable[] = {
256 [TABLE_MAIN] = { ARRAY_AND_SIZE (xsltXpathMainTable) },
257 [TABLE_STYLESHEET] = { ARRAY_AND_SIZE (xsltXpathStylesheetTable) },
258 [TABLE_VERSION_VERIFY] = { ARRAY_AND_SIZE (xsltXpathVersionVerifyTable) },
259 [TABLE_TEMPLATE] = { ARRAY_AND_SIZE (xsltXpathTemplateTable) },
260 [TABLE_APPLIED_TEMPLATES] = { ARRAY_AND_SIZE (xsltXpathAppliedTemplatesTable) },
261 [TABLE_CALL_TEMPLATE] = { ARRAY_AND_SIZE (xsltXpathCallTemplateTable) },
262 [TABLE_PARAM] = { ARRAY_AND_SIZE (xsltXpathParamTable) },
263 [TABLE_VARIABLE] = { ARRAY_AND_SIZE (xsltXpathVariableTable) },
264 [TABLE_WITH_PARAM] = { ARRAY_AND_SIZE (xsltXpathWithParamTable) },
265 [TABLE_CALL_TEMPLATE_INTERNAL] = { ARRAY_AND_SIZE (xsltXpathTemplateInternalTable) },
266 };
267
268
makeTagRecursivelyWithVersionVerification(xmlNode * node,const char * xpath CTAGS_ATTR_UNUSED,const tagXpathRecurSpec * spec CTAGS_ATTR_UNUSED,xmlXPathContext * ctx,void * userData)269 static void makeTagRecursivelyWithVersionVerification (xmlNode *node,
270 const char *xpath CTAGS_ATTR_UNUSED,
271 const tagXpathRecurSpec *spec CTAGS_ATTR_UNUSED,
272 xmlXPathContext *ctx,
273 void *userData)
274 {
275 bool acceptable = false;
276 int backup;
277
278 findXMLTags (ctx, node, TABLE_VERSION_VERIFY, &acceptable);
279 if (!acceptable)
280 return;
281
282 backup = *(int *)userData;
283 findXMLTags (ctx, node, TABLE_STYLESHEET, userData);
284
285 *(int *)userData = backup;
286 }
287
makeTagRecursively(xmlNode * node,const char * xpath CTAGS_ATTR_UNUSED,const tagXpathRecurSpec * spec,xmlXPathContext * ctx,void * userData)288 static void makeTagRecursively (xmlNode *node,
289 const char *xpath CTAGS_ATTR_UNUSED,
290 const tagXpathRecurSpec *spec,
291 xmlXPathContext *ctx,
292 void *userData)
293 {
294 int backup = *(int *)userData;
295
296 findXMLTags (ctx, node, spec->nextTable, userData);
297
298 *(int *)userData = backup;
299 }
300
makeTagWithProvidingScope(xmlNode * node CTAGS_ATTR_UNUSED,const char * xpath CTAGS_ATTR_UNUSED,const tagXpathMakeTagSpec * spec CTAGS_ATTR_UNUSED,struct sTagEntryInfo * tag,void * userData)301 static void makeTagWithProvidingScope (xmlNode *node CTAGS_ATTR_UNUSED,
302 const char *xpath CTAGS_ATTR_UNUSED,
303 const tagXpathMakeTagSpec *spec CTAGS_ATTR_UNUSED,
304 struct sTagEntryInfo *tag,
305 void *userData)
306 {
307 int *index = (int *)userData;
308
309 tag->extensionFields.scopeIndex = *index;
310 *index = makeTagEntry (tag);
311 }
312
313 static void
findXsltTags(void)314 findXsltTags (void)
315 {
316 scheduleRunningBaseparser (RUN_DEFAULT_SUBPARSERS);
317 }
318
319 static void
runXPathEngine(xmlSubparser * s,xmlXPathContext * ctx,xmlNode * root)320 runXPathEngine(xmlSubparser *s,
321 xmlXPathContext *ctx, xmlNode *root)
322 {
323 int corkIndex = CORK_NIL;
324
325 findXMLTags (ctx, root, TABLE_MAIN, &corkIndex);
326 }
327
328 static xmlSubparser xsltSubparser = {
329 .subparser = {
330 .direction = SUBPARSER_BI_DIRECTION,
331 },
332 .runXPathEngine = runXPathEngine,
333 };
334
335 extern parserDefinition*
XsltParser(void)336 XsltParser (void)
337 {
338 static const char *const extensions [] = { "xsl", "xslt", NULL };
339 parserDefinition* const def = parserNew ("XSLT");
340 static parserDependency dependencies [] = {
341 [0] = { DEPTYPE_SUBPARSER, "XML", &xsltSubparser },
342 };
343
344 def->kindTable = XsltKinds;
345 def->kindCount = ARRAY_SIZE (XsltKinds);
346 def->extensions = extensions;
347 def->parser = findXsltTags;
348 def->tagXpathTableTable = xsltXpathTableTable;
349 def->tagXpathTableCount = ARRAY_SIZE (xsltXpathTableTable);
350 def->useCork = CORK_QUEUE;
351 def->dependencies = dependencies;
352 def->dependencyCount = ARRAY_SIZE (dependencies);
353
354 return def;
355 }
356