xref: /Universal-ctags/parsers/dbusintrospect.c (revision 6b1a862e526d5017f9f212a321f59d67c859d521)
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