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
10 * <!DOCTYPE node PUBLIC
11 * "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
12 * "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
13 * and
14 *
15 * <!DOCTYPE node PUBLIC
16 * "-//freedesktop//DTD D-BUS Introspection 0.1//EN"
17 * "http://www.freedesktop.org/software/dbus/introspection.dtd">
18 **
19 */
20
21 #include "general.h" /* must always come first */
22 #include "entry.h"
23 #include "parse.h"
24 #include "read.h"
25 #include "routines.h"
26 #include "selectors.h"
27 #include "xml.h"
28
29 #include <string.h>
30
31
32 typedef enum {
33 K_ARG, K_INTERFACE, K_METHOD, K_SIGNAL, K_PROPERTY, K_NODE,
34 } dbusIntrospectKind;
35
36 static kindDefinition DbusIntrospectKinds [] = {
37 { true, 'a', "arg", "arguments" },
38 { true, 'i', "interface", "interfaces" },
39 { true, 'm', "method", "methods" },
40 { true, 's', "signal", "signals" },
41 { true, 'p', "property", "properties" },
42 { true, 'n', "node", "nodes" },
43 };
44
45 static void dbusIntrospectFindTagsUnderMain (xmlNode *node,
46 const char *xpath,
47 const struct sTagXpathRecurSpec *spec,
48 xmlXPathContext *ctx,
49 void *userData);
50 static void makeTagForMainName (xmlNode *node,
51 const char *xpath,
52 const struct sTagXpathMakeTagSpec *spec,
53 struct sTagEntryInfo *tag,
54 void *userData);
55 static void makeTagWithScope (xmlNode *node,
56 const char *xpath,
57 const struct sTagXpathMakeTagSpec *spec,
58 struct sTagEntryInfo *tag,
59 void *userData);
60 static int decideKindForMainName (xmlNode *node,
61 const char *xpath,
62 const struct sTagXpathMakeTagSpec *spec,
63 void *userData);
64
65 struct dbusIntrospectData {
66 int scopeIndex;
67 int kindForName;
68 };
69
70 static tagXpathTable dbusIntrospectXpathArgTable [] = {
71 { "arg",
72 LXPATH_TABLE_DO_RECUR,
73 { .recurSpec = { dbusIntrospectFindTagsUnderMain,
74 -1 } },
75 },
76 };
77
78 enum dbusIntrospectXpathTable {
79 TABLE_ROOT, TABLE_MAIN, TABLE_INTERFACE, TABLE_MAIN_NAME, TABLE_ARG,
80 };
81
82 static tagXpathTable dbusIntrospectXpathInterfaceTable [] = {
83 { "method",
84 LXPATH_TABLE_DO_RECUR,
85 { .recurSpec = { dbusIntrospectFindTagsUnderMain,
86 TABLE_ARG, } }
87 },
88 { "signal",
89 LXPATH_TABLE_DO_RECUR,
90 { .recurSpec = { dbusIntrospectFindTagsUnderMain,
91 TABLE_ARG, } }
92 },
93 { "property/@name",
94 LXPATH_TABLE_DO_MAKE,
95 { .makeTagSpec = { K_PROPERTY, ROLE_DEFINITION_INDEX,
96 makeTagWithScope, } }
97 },
98 };
99
100 static tagXpathTable dbusIntrospectXpathMainTable [] = {
101 { "interface",
102 LXPATH_TABLE_DO_RECUR,
103 { .recurSpec = { dbusIntrospectFindTagsUnderMain,
104 TABLE_INTERFACE, } }
105 },
106 { "node",
107 LXPATH_TABLE_DO_RECUR,
108 { .recurSpec = { dbusIntrospectFindTagsUnderMain,
109 TABLE_MAIN, } }
110 },
111 };
112
113 static tagXpathTable dbusIntrospectXpathMainNameTable [] = {
114 { "@name",
115 LXPATH_TABLE_DO_MAKE,
116 { .makeTagSpec = { KIND_GHOST_INDEX, ROLE_DEFINITION_INDEX,
117 makeTagForMainName,
118 decideKindForMainName } }
119 },
120 };
121
122 static tagXpathTable dbusIntrospectXpathRootTable [] = {
123 { "/node",
124 LXPATH_TABLE_DO_RECUR,
125 { .recurSpec = { dbusIntrospectFindTagsUnderMain,
126 TABLE_MAIN, } }
127 },
128 };
129
130 static tagXpathTableTable dbusIntrospectXpathTableTable[] = {
131 [TABLE_ROOT] = { ARRAY_AND_SIZE (dbusIntrospectXpathRootTable) },
132 [TABLE_MAIN] = { ARRAY_AND_SIZE (dbusIntrospectXpathMainTable) },
133 [TABLE_INTERFACE] = { ARRAY_AND_SIZE (dbusIntrospectXpathInterfaceTable)},
134 [TABLE_MAIN_NAME] = { ARRAY_AND_SIZE (dbusIntrospectXpathMainNameTable) },
135 [TABLE_ARG] = { ARRAY_AND_SIZE (dbusIntrospectXpathArgTable) },
136 };
137
dbusIntrospectFindTagsUnderMain(xmlNode * node,const char * xpath,const struct sTagXpathRecurSpec * spec,xmlXPathContext * ctx,void * userData)138 static void dbusIntrospectFindTagsUnderMain (xmlNode *node,
139 const char *xpath,
140 const struct sTagXpathRecurSpec *spec,
141 xmlXPathContext *ctx,
142 void *userData)
143 {
144 struct dbusIntrospectData *data = userData;
145 int scopeIndex = data->scopeIndex;
146
147 if (!strcmp(xpath, "interface"))
148 data->kindForName = K_INTERFACE;
149 else if (!strcmp (xpath, "method"))
150 data->kindForName = K_METHOD;
151 else if (!strcmp (xpath, "signal"))
152 data->kindForName = K_SIGNAL;
153 else if (!strcmp (xpath, "arg"))
154 data->kindForName = K_ARG;
155 else
156 data->kindForName = K_NODE;
157
158 findXMLTags (ctx, node, TABLE_MAIN_NAME, data);
159 if (spec->nextTable >= 0)
160 findXMLTags (ctx, node, spec->nextTable, data);
161 data->scopeIndex = scopeIndex;
162 }
163
makeTagWithScope(xmlNode * node CTAGS_ATTR_UNUSED,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathMakeTagSpec * spec CTAGS_ATTR_UNUSED,struct sTagEntryInfo * tag,void * userData)164 static void makeTagWithScope (xmlNode *node CTAGS_ATTR_UNUSED,
165 const char *xpath CTAGS_ATTR_UNUSED,
166 const struct sTagXpathMakeTagSpec *spec CTAGS_ATTR_UNUSED,
167 struct sTagEntryInfo *tag,
168 void *userData)
169 {
170 struct dbusIntrospectData *data = userData;
171
172 tag->extensionFields.scopeKindIndex = KIND_GHOST_INDEX;
173 tag->extensionFields.scopeName = NULL;
174 tag->extensionFields.scopeIndex = data->scopeIndex;
175
176 makeTagEntry (tag);
177 }
178
makeTagForMainName(xmlNode * node CTAGS_ATTR_UNUSED,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathMakeTagSpec * spec CTAGS_ATTR_UNUSED,struct sTagEntryInfo * tag,void * userData)179 static void makeTagForMainName (xmlNode *node CTAGS_ATTR_UNUSED,
180 const char *xpath CTAGS_ATTR_UNUSED,
181 const struct sTagXpathMakeTagSpec *spec CTAGS_ATTR_UNUSED,
182 struct sTagEntryInfo *tag,
183 void *userData)
184 {
185 struct dbusIntrospectData *data = userData;
186
187 tag->extensionFields.scopeKindIndex = KIND_GHOST_INDEX;
188 tag->extensionFields.scopeName = NULL;
189 tag->extensionFields.scopeIndex = data->scopeIndex;
190
191 data->scopeIndex = makeTagEntry (tag);
192 }
193
decideKindForMainName(xmlNode * node CTAGS_ATTR_UNUSED,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathMakeTagSpec * spec CTAGS_ATTR_UNUSED,void * userData)194 static int decideKindForMainName (xmlNode *node CTAGS_ATTR_UNUSED,
195 const char *xpath CTAGS_ATTR_UNUSED,
196 const struct sTagXpathMakeTagSpec *spec CTAGS_ATTR_UNUSED,
197 void *userData)
198 {
199 return ((struct dbusIntrospectData *)userData)->kindForName;
200 }
201
202 static void
findDbusIntrospectTags(void)203 findDbusIntrospectTags (void)
204 {
205 scheduleRunningBaseparser (RUN_DEFAULT_SUBPARSERS);
206 }
207
208 static void
runXPathEngine(xmlSubparser * s,xmlXPathContext * ctx,xmlNode * root)209 runXPathEngine(xmlSubparser *s,
210 xmlXPathContext *ctx, xmlNode *root)
211 {
212 struct dbusIntrospectData data = {
213 .scopeIndex = CORK_NIL,
214 .kindForName = KIND_GHOST_INDEX,
215 };
216 findXMLTags (ctx, root, TABLE_ROOT, &data);
217 }
218
219 static xmlSubparser dbusIntrospectSubparser = {
220 .subparser = {
221 .direction = SUBPARSER_BI_DIRECTION,
222 },
223 .runXPathEngine = runXPathEngine,
224 };
225
226 extern parserDefinition*
DbusIntrospectParser(void)227 DbusIntrospectParser (void)
228 {
229 static const char *const extensions [] = { "xml", NULL };
230 parserDefinition* const def = parserNew ("DBusIntrospect");
231 static selectLanguage selectors[] = { selectByXpathFileSpec, NULL };
232
233 static xpathFileSpec xpathFileSpecs[] = {
234 {
235 /* <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
236 "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
237 <node ... */
238 .externalID = "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN",
239 .systemID = "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd",
240 },
241 {
242 .externalID = "-//freedesktop//DTD D-BUS Introspection 0.1//EN",
243 .systemID = "http://www.freedesktop.org/software/dbus/introspection.dtd",
244 },
245 /* TODO: the following rule is too strong; parsers may conflicts each other
246 * when we implement more xpath based parsers. */
247 {
248 .rootElementName = "node",
249 .nameInDTD = "",
250 .externalID = "",
251 .systemID = "",
252 .rootNSPrefix = "",
253 .rootNSHref = "",
254 },
255 };
256 static parserDependency dependencies [] = {
257 [0] = { DEPTYPE_SUBPARSER, "XML", &dbusIntrospectSubparser },
258 };
259 def->kindTable = DbusIntrospectKinds;
260 def->kindCount = ARRAY_SIZE (DbusIntrospectKinds);
261 def->extensions = extensions;
262 def->parser = findDbusIntrospectTags;
263 def->tagXpathTableTable = dbusIntrospectXpathTableTable;
264 def->tagXpathTableCount = ARRAY_SIZE (dbusIntrospectXpathTableTable);
265 def->useCork = CORK_QUEUE;
266 def->selectLanguage = selectors;
267 def->xpathFileSpecs = xpathFileSpecs;
268 def->xpathFileSpecCount = ARRAY_SIZE (xpathFileSpecs);
269 def->dependencies = dependencies;
270 def->dependencyCount = ARRAY_SIZE (dependencies);
271
272 return def;
273 }
274