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 RelaxNG.
10 *
11 *   https://www.oasis-open.org/committees/relax-ng/spec-20010811.html
12 *
13 */
14 
15 #include "general.h"	/* must always come first */
16 #include "entry.h"
17 #include "parse.h"
18 #include "read.h"
19 #include "xml.h"
20 
21 typedef enum {
22 	K_ELEMENT,
23 	K_ATTRIBUTE,
24 	K_NAMED_PATTERN,
25 } relaxngKind;
26 
27 static kindDefinition RelaxNGKinds [] = {
28 	{ true,  'e', "element",     "elements"       },
29 	{ true,  'a', "attribute",   "attributes"     },
30 	{ true,  'n', "namedPattern", "named patterns" },
31 };
32 
33 enum relaxngXpathTable {
34 	TABLE_MAIN, TABLE_ELEMENT_NAME, TABLE_PATTERN, TABLE_GRAMMAR, TABLE_DEFINE_NAME,
35 };
36 
37 static void relaxngMakeAndFindTagsUnderElement (xmlNode *node,
38 						const char *xpath,
39 						const struct sTagXpathRecurSpec *spec,
40 						xmlXPathContext *ctx,
41 						void *userData);
42 static void relaxngMakeAndFindTagsUnderDefine (xmlNode *node,
43 					       const char *xpath,
44 					       const struct sTagXpathRecurSpec *spec,
45 					       xmlXPathContext *ctx,
46 					       void *userData);
47 
48 static void relaxngFindTags (xmlNode *node,
49 			     const char *xpath,
50 			     const struct sTagXpathRecurSpec *spec,
51 			     xmlXPathContext *ctx,
52 			     void *userData);
53 
54 
55 static tagXpathTable relaxngXpathMainTable [] = {
56 	{ "/*[local-name()='element']",
57 	  LXPATH_TABLE_DO_RECUR,
58 	  { .recurSpec = { relaxngMakeAndFindTagsUnderElement, TABLE_PATTERN } }
59 	},
60 	{ "/*[local-name()='grammar']",
61 	  LXPATH_TABLE_DO_RECUR,
62 	  { .recurSpec = { relaxngFindTags, TABLE_GRAMMAR } }
63 	},
64 };
65 
66 static void makeTagWithScope (xmlNode *node,
67 			      const char *xpath,
68 			      const struct sTagXpathMakeTagSpec *spec,
69 			      struct sTagEntryInfo *tag,
70 			      void *userData);
71 
72 static tagXpathTable relaxngXpathPatternTable [] = {
73 	{ "./*[local-name()='element']",
74 	  LXPATH_TABLE_DO_RECUR,
75 	  { .recurSpec = { relaxngMakeAndFindTagsUnderElement, TABLE_PATTERN } }
76 	},
77 	{ "./*[local-name()='attribute']/@name",
78 	  LXPATH_TABLE_DO_MAKE,
79 	  { .makeTagSpec = { K_ATTRIBUTE, ROLE_DEFINITION_INDEX,
80 			     makeTagWithScope } }
81 	},
82 	{ "./*[not(local-name()='element')][not(local-name()='attribute')]",
83 	  LXPATH_TABLE_DO_RECUR,
84 	  { .recurSpec = { relaxngFindTags, TABLE_PATTERN } }
85 	},
86 };
87 
88 
89 static void makeTagWithUpdatingScope (xmlNode *node,
90 				      const char *xpath,
91 				      const struct sTagXpathMakeTagSpec *spec,
92 				      struct sTagEntryInfo *tag,
93 				      void *userData);
94 
95 static tagXpathTable relaxngXpathElementNameTable [] = {
96 	{ "@name",
97 	  LXPATH_TABLE_DO_MAKE,
98 	  { .makeTagSpec = { K_ELEMENT, ROLE_DEFINITION_INDEX,
99 			     makeTagWithUpdatingScope } }
100 	},
101 };
102 
103 static tagXpathTable relaxngXpathGrammerTable [] = {
104 	{ "./*[local-name()='start']",
105 	  LXPATH_TABLE_DO_RECUR,
106 	  { .recurSpec = { relaxngFindTags, TABLE_PATTERN } }
107 	},
108 	{ "./*[local-name()='define']",
109 	  LXPATH_TABLE_DO_RECUR,
110 	  { .recurSpec = { relaxngMakeAndFindTagsUnderDefine, TABLE_PATTERN } }
111 	}
112 };
113 
114 static tagXpathTable relaxngXpathDefineNameTable [] = {
115 	{ "@name",
116 	  LXPATH_TABLE_DO_MAKE,
117 	  { .makeTagSpec = { K_NAMED_PATTERN, ROLE_DEFINITION_INDEX,
118 			     makeTagWithUpdatingScope } }
119 	},
120 };
121 
122 static tagXpathTableTable relaxngXpathTableTable[] = {
123 	[TABLE_MAIN]         = { ARRAY_AND_SIZE (relaxngXpathMainTable)        },
124 	[TABLE_ELEMENT_NAME] = { ARRAY_AND_SIZE (relaxngXpathElementNameTable) },
125 	[TABLE_PATTERN]      = { ARRAY_AND_SIZE (relaxngXpathPatternTable)     },
126 	[TABLE_GRAMMAR]      = { ARRAY_AND_SIZE (relaxngXpathGrammerTable)     },
127 	[TABLE_DEFINE_NAME]  = { ARRAY_AND_SIZE (relaxngXpathDefineNameTable)  },
128 };
129 
130 
131 static void
relaxngMakeAndFindTags(xmlNode * node,const char * xpath,const struct sTagXpathRecurSpec * spec,xmlXPathContext * ctx,int nextTable,void * userData)132 relaxngMakeAndFindTags(xmlNode *node,
133 		       const char *xpath,
134 		       const struct sTagXpathRecurSpec *spec,
135 		       xmlXPathContext *ctx,
136 		       int nextTable,
137 		       void *userData)
138 {
139 	int corkIndex = *(int *)userData;
140 
141 	findXMLTags (ctx, node, nextTable, &corkIndex);
142 
143 	relaxngFindTags (node, xpath, spec, ctx, &corkIndex);
144 }
145 
146 static void
relaxngMakeAndFindTagsUnderElement(xmlNode * node,const char * xpath,const struct sTagXpathRecurSpec * spec,xmlXPathContext * ctx,void * userData)147 relaxngMakeAndFindTagsUnderElement (xmlNode *node,
148 				    const char *xpath,
149 				    const struct sTagXpathRecurSpec *spec,
150 				    xmlXPathContext *ctx,
151 				    void *userData)
152 {
153 	relaxngMakeAndFindTags (node, xpath, spec, ctx, TABLE_ELEMENT_NAME, userData);
154 }
155 
156 static void
relaxngMakeAndFindTagsUnderDefine(xmlNode * node,const char * xpath,const struct sTagXpathRecurSpec * spec,xmlXPathContext * ctx,void * userData)157 relaxngMakeAndFindTagsUnderDefine (xmlNode *node,
158 				   const char *xpath,
159 				   const struct sTagXpathRecurSpec *spec,
160 				   xmlXPathContext *ctx,
161 				   void *userData)
162 {
163 	relaxngMakeAndFindTags (node, xpath, spec, ctx, TABLE_DEFINE_NAME, userData);
164 }
165 
166 static void
relaxngFindTags(xmlNode * node,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathRecurSpec * spec,xmlXPathContext * ctx,void * userData)167 relaxngFindTags (xmlNode *node,
168 		 const char *xpath CTAGS_ATTR_UNUSED,
169 		 const struct sTagXpathRecurSpec *spec,
170 		 xmlXPathContext *ctx,
171 		 void *userData)
172 {
173 	int corkIndex = *(int *)userData;
174 
175 	findXMLTags (ctx, node, spec->nextTable, &corkIndex);
176 }
177 
178 static void
setScope(struct sTagEntryInfo * tag,int index)179 setScope (struct sTagEntryInfo *tag, int index)
180 {
181 	tag->extensionFields.scopeKindIndex = KIND_GHOST_INDEX;
182 	tag->extensionFields.scopeName  = NULL;
183 	tag->extensionFields.scopeIndex = index;
184 
185 }
186 
187 static void
makeTagWithUpdatingScope(xmlNode * node CTAGS_ATTR_UNUSED,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathMakeTagSpec * spec CTAGS_ATTR_UNUSED,struct sTagEntryInfo * tag,void * userData)188 makeTagWithUpdatingScope (xmlNode *node CTAGS_ATTR_UNUSED,
189 			  const char *xpath CTAGS_ATTR_UNUSED,
190 			  const struct sTagXpathMakeTagSpec *spec CTAGS_ATTR_UNUSED,
191 			  struct sTagEntryInfo *tag,
192 			  void *userData)
193 {
194 	int *corkIndex = userData;
195 
196 
197 #if 0
198 	if (*corkIndex == CORK_NIL)
199 		/* TODO: mark tag as an entry point */
200 		;
201 #endif
202 
203 	setScope (tag, *corkIndex);
204 
205 	*corkIndex = makeTagEntry (tag);
206 }
207 
208 
209 static void
findRelaxNGTags(void)210 findRelaxNGTags (void)
211 {
212 	scheduleRunningBaseparser (RUN_DEFAULT_SUBPARSERS);
213 }
214 
215 static void
makeTagWithScope(xmlNode * node CTAGS_ATTR_UNUSED,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathMakeTagSpec * spec CTAGS_ATTR_UNUSED,struct sTagEntryInfo * tag,void * userData)216 makeTagWithScope (xmlNode *node CTAGS_ATTR_UNUSED,
217 		  const char *xpath CTAGS_ATTR_UNUSED,
218 		  const struct sTagXpathMakeTagSpec *spec CTAGS_ATTR_UNUSED,
219 		  struct sTagEntryInfo *tag,
220 		  void *userData)
221 {
222 	setScope (tag, *(int *)userData);
223 
224 	makeTagEntry (tag);
225 }
226 
227 static void
runXPathEngine(xmlSubparser * s,xmlXPathContext * ctx,xmlNode * root)228 runXPathEngine(xmlSubparser *s,
229 			   xmlXPathContext *ctx, xmlNode *root)
230 {
231 	int corkIndex = CORK_NIL;
232 
233 	findXMLTags (ctx, root, TABLE_MAIN, &corkIndex);
234 }
235 
236 static xmlSubparser relaxngSubparser = {
237 	.subparser = {
238 		.direction = SUBPARSER_BI_DIRECTION,
239 	},
240 	.runXPathEngine = runXPathEngine,
241 };
242 
243 extern parserDefinition*
RelaxNGParser(void)244 RelaxNGParser (void)
245 {
246 	static const char *const extensions [] = { "rng", NULL };
247 	parserDefinition* const def = parserNew ("RelaxNG");
248 	/* static selectLanguage selectors[] = { selectByDTD, NULL }; */
249 	static parserDependency dependencies [] = {
250 		[0] = { DEPTYPE_SUBPARSER, "XML", &relaxngSubparser },
251 	};
252 
253 	def->kindTable         = RelaxNGKinds;
254 	def->kindCount     = ARRAY_SIZE (RelaxNGKinds);
255 	def->extensions    = extensions;
256 	def->parser        = findRelaxNGTags;
257 	def->tagXpathTableTable = relaxngXpathTableTable;
258 	def->tagXpathTableCount = ARRAY_SIZE (relaxngXpathTableTable);
259 	def->useCork = CORK_QUEUE;
260 	/* def->selectLanguage = selectors; */
261 	def->dependencies = dependencies;
262 	def->dependencyCount = ARRAY_SIZE (dependencies);
263 
264 	return def;
265 }
266