xref: /Universal-ctags/parsers/xslt.c (revision cbabd2be65f08cf776f1bc4c0a4f16fdf7bc9d39)
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