xref: /Universal-ctags/main/lxpath.c (revision 27650e323c732d2c8fcc323adfb389577da29d3c)
1a086aff1SMasatake YAMATO /*
2a086aff1SMasatake YAMATO *   Copyright (c) 2015, Masatake YAMATO
3a086aff1SMasatake YAMATO *   Copyright (c) 2015, Red Hat, Inc.
4a086aff1SMasatake YAMATO *
5a086aff1SMasatake YAMATO *   This source code is released for free distribution under the terms of the
6a086aff1SMasatake YAMATO *   GNU General Public License version 2 or (at your option) any later version.
7a086aff1SMasatake YAMATO *
84582fa5cSMasatake YAMATO *   This module contains functions for xpath meta parser.
9a086aff1SMasatake YAMATO */
10a086aff1SMasatake YAMATO 
11a086aff1SMasatake YAMATO #include "general.h"  /* must always come first */
12a086aff1SMasatake YAMATO #include "debug.h"
13a086aff1SMasatake YAMATO #include "entry.h"
14a086aff1SMasatake YAMATO #include "options.h"
150d502ef0SMasatake YAMATO #include "parse_p.h"
16a086aff1SMasatake YAMATO #include "read.h"
17b5df137eSMasatake YAMATO #include "read_p.h"
18a086aff1SMasatake YAMATO #include "routines.h"
19a086aff1SMasatake YAMATO #include "xtag.h"
20a086aff1SMasatake YAMATO 
21a086aff1SMasatake YAMATO #ifdef HAVE_LIBXML
22a086aff1SMasatake YAMATO #include <libxml/xpath.h>
23a086aff1SMasatake YAMATO #include <libxml/tree.h>
24a086aff1SMasatake YAMATO 
simpleXpathMakeTag(xmlNode * node,const char * xpath,const tagXpathMakeTagSpec * spec,void * userData)25a086aff1SMasatake YAMATO static void simpleXpathMakeTag (xmlNode *node,
26513a7223SMasatake YAMATO 				const char *xpath,
27a086aff1SMasatake YAMATO 				const tagXpathMakeTagSpec *spec,
28a086aff1SMasatake YAMATO 				void *userData)
29a086aff1SMasatake YAMATO {
30a086aff1SMasatake YAMATO 	tagEntryInfo tag;
31a086aff1SMasatake YAMATO 	xmlChar* str;
3276a4ccb4SMasatake YAMATO 	char *path;
3327542d8bSMasatake YAMATO 	int kind;
34a086aff1SMasatake YAMATO 
35a086aff1SMasatake YAMATO 	str = xmlNodeGetContent(node);
36a086aff1SMasatake YAMATO 	if (str == NULL)
37a086aff1SMasatake YAMATO 		return;
38a086aff1SMasatake YAMATO 
3927542d8bSMasatake YAMATO 	if (spec->kind == KIND_GHOST_INDEX && spec->decideKind)
40513a7223SMasatake YAMATO 		kind = spec->decideKind (node, xpath, spec, userData);
4127542d8bSMasatake YAMATO 	else
4227542d8bSMasatake YAMATO 		kind = spec->kind;
4327542d8bSMasatake YAMATO 	Assert (kind != KIND_GHOST_INDEX);
4427542d8bSMasatake YAMATO 
4524b256e3SMasatake YAMATO 	if (spec->role == ROLE_DEFINITION_INDEX)
4627542d8bSMasatake YAMATO 		initTagEntry (&tag, (char *)str, kind);
47a086aff1SMasatake YAMATO 	else if (isXtagEnabled(XTAG_REFERENCE_TAGS))
48a086aff1SMasatake YAMATO 		initRefTagEntry (&tag, (char *)str,
4927542d8bSMasatake YAMATO 				 kind,
50a086aff1SMasatake YAMATO 				 spec->role);
51a086aff1SMasatake YAMATO 	else
52a086aff1SMasatake YAMATO 		goto out;
53a086aff1SMasatake YAMATO 
54a086aff1SMasatake YAMATO 
5572b5694cSMasatake YAMATO 	tag.lineNumber = XML_GET_LINE (node);
56a086aff1SMasatake YAMATO 	tag.filePosition = getInputFilePositionForLine (tag.lineNumber);
57a086aff1SMasatake YAMATO 
5876a4ccb4SMasatake YAMATO 	path = (char *)xmlGetNodePath (node);
5976a4ccb4SMasatake YAMATO 	tag.extensionFields.xpath = path;
6076a4ccb4SMasatake YAMATO 
61a086aff1SMasatake YAMATO 	if (spec->make)
62513a7223SMasatake YAMATO 		spec->make (node, xpath, spec, &tag, userData);
63a086aff1SMasatake YAMATO 	else
64a086aff1SMasatake YAMATO 		makeTagEntry (&tag);
65a086aff1SMasatake YAMATO 
6676a4ccb4SMasatake YAMATO 	if (path)
6776a4ccb4SMasatake YAMATO 		xmlFree (path);
68a086aff1SMasatake YAMATO out:
69a086aff1SMasatake YAMATO 	xmlFree (str);
70a086aff1SMasatake YAMATO }
71a086aff1SMasatake YAMATO 
addTagXpath(const langType language CTAGS_ATTR_UNUSED,tagXpathTable * xpathTable)728ccb7ee9SJiří Techet extern void addTagXpath (const langType language CTAGS_ATTR_UNUSED, tagXpathTable *xpathTable)
73a086aff1SMasatake YAMATO {
74a086aff1SMasatake YAMATO 	Assert (xpathTable->xpath);
75a086aff1SMasatake YAMATO 	Assert (!xpathTable->xpathCompiled);
76a086aff1SMasatake YAMATO 
77a086aff1SMasatake YAMATO 	verbose ("compile a xpath expression: %s\n", (xmlChar *)xpathTable->xpath);
78a086aff1SMasatake YAMATO 	xpathTable->xpathCompiled = xmlXPathCompile ((xmlChar *)xpathTable->xpath);
79a086aff1SMasatake YAMATO 	if (!xpathTable->xpathCompiled)
80a086aff1SMasatake YAMATO 		error (WARNING, "Failed to compile the Xpath expression: %s", xpathTable->xpath);
81a086aff1SMasatake YAMATO }
82a086aff1SMasatake YAMATO 
removeTagXpath(const langType language CTAGS_ATTR_UNUSED,tagXpathTable * xpathTable)83eb480042SMasatake YAMATO extern void removeTagXpath (const langType language CTAGS_ATTR_UNUSED, tagXpathTable *xpathTable)
84eb480042SMasatake YAMATO {
85eb480042SMasatake YAMATO 	if (xpathTable->xpathCompiled)
86eb480042SMasatake YAMATO 	{
87eb480042SMasatake YAMATO 		xmlXPathFreeCompExpr (xpathTable->xpathCompiled);
88eb480042SMasatake YAMATO 		xpathTable->xpathCompiled = NULL;
89eb480042SMasatake YAMATO 	}
90eb480042SMasatake YAMATO }
91eb480042SMasatake YAMATO 
findXMLTagsCore(xmlXPathContext * ctx,xmlNode * root,const tagXpathTableTable * xpathTableTable,void * userData)92a086aff1SMasatake YAMATO static void findXMLTagsCore (xmlXPathContext *ctx, xmlNode *root,
93a086aff1SMasatake YAMATO 			     const tagXpathTableTable *xpathTableTable,
94971e7196SMasatake YAMATO 			     void *userData)
95a086aff1SMasatake YAMATO {
96e5f9cc19SMasatake YAMATO 	unsigned int i;
97e5f9cc19SMasatake YAMATO 	int j;
98a086aff1SMasatake YAMATO 	xmlNode * node;
99a086aff1SMasatake YAMATO 
100a086aff1SMasatake YAMATO 	Assert (root);
101a086aff1SMasatake YAMATO 	Assert (xpathTableTable);
102a086aff1SMasatake YAMATO 
103a086aff1SMasatake YAMATO 	for (i = 0; i < xpathTableTable->count; ++i)
104a086aff1SMasatake YAMATO 	{
105a086aff1SMasatake YAMATO 		xmlXPathObject *object;
106a086aff1SMasatake YAMATO 		xmlNodeSet *set;
107a086aff1SMasatake YAMATO 		const tagXpathTable *elt = xpathTableTable->table + i;
108a086aff1SMasatake YAMATO 
109a086aff1SMasatake YAMATO 		if (! elt->xpathCompiled)
110a086aff1SMasatake YAMATO 			continue;
111a086aff1SMasatake YAMATO 
112a086aff1SMasatake YAMATO #if 0
113a086aff1SMasatake YAMATO 		/* Older version of libxml2 doesn't have xmlXPathSetContextNode. */
114a086aff1SMasatake YAMATO 		if (xmlXPathSetContextNode (root, ctx) != 0)
115a086aff1SMasatake YAMATO 		{
116a086aff1SMasatake YAMATO 			error (WARNING, "Failed to set node to XpathContext");
117a086aff1SMasatake YAMATO 			return;
118a086aff1SMasatake YAMATO 		}
119a086aff1SMasatake YAMATO #else
120a086aff1SMasatake YAMATO 		ctx->node = root;
121a086aff1SMasatake YAMATO #endif
122a086aff1SMasatake YAMATO 
123a086aff1SMasatake YAMATO 		object = xmlXPathCompiledEval (elt->xpathCompiled, ctx);
124a086aff1SMasatake YAMATO 		if (!object)
125a086aff1SMasatake YAMATO 			continue;
126a086aff1SMasatake YAMATO 
127a086aff1SMasatake YAMATO 		set = object->nodesetval;
128a086aff1SMasatake YAMATO 
129a086aff1SMasatake YAMATO 		if (set)
130a086aff1SMasatake YAMATO 		{
131a391a8f5SMasatake YAMATO 			for (j = 0; j < xmlXPathNodeSetGetLength (set); ++j)
132a086aff1SMasatake YAMATO 			{
133a391a8f5SMasatake YAMATO 				node = xmlXPathNodeSetItem(set, j);
134a086aff1SMasatake YAMATO 				if (elt->specType == LXPATH_TABLE_DO_MAKE)
135971e7196SMasatake YAMATO 					simpleXpathMakeTag (node, elt->xpath, &(elt->spec.makeTagSpec), userData);
136a086aff1SMasatake YAMATO 				else
137513a7223SMasatake YAMATO 					elt->spec.recurSpec.enter (node, elt->xpath, &(elt->spec.recurSpec), ctx, userData);
138a086aff1SMasatake YAMATO 			}
139a086aff1SMasatake YAMATO 		}
140a086aff1SMasatake YAMATO 		xmlXPathFreeObject (object);
141a086aff1SMasatake YAMATO 	}
142a086aff1SMasatake YAMATO }
143a086aff1SMasatake YAMATO 
suppressWarning(void * ctx CTAGS_ATTR_UNUSED,const char * msg CTAGS_ATTR_UNUSED,...)1448ccb7ee9SJiří Techet static void suppressWarning (void *ctx CTAGS_ATTR_UNUSED, const char *msg CTAGS_ATTR_UNUSED, ...)
1457900fd5dSMasatake YAMATO {
1467900fd5dSMasatake YAMATO }
1477900fd5dSMasatake YAMATO 
makeXMLDoc(void)14831cb4225SMasatake YAMATO static xmlDocPtr makeXMLDoc (void)
14931cb4225SMasatake YAMATO {
15031cb4225SMasatake YAMATO 	const unsigned char* data;
15131cb4225SMasatake YAMATO 	size_t size;
15262c9a9aaSMasatake YAMATO 	xmlDocPtr doc;
15331cb4225SMasatake YAMATO 
154eab04be2SMasatake YAMATO 	doc = getInputFileUserData ();
155eab04be2SMasatake YAMATO 	if (doc)
156eab04be2SMasatake YAMATO 	{
157eab04be2SMasatake YAMATO 		verbose ("reuse xml doc data\n");
158eab04be2SMasatake YAMATO 		return doc;
159eab04be2SMasatake YAMATO 	}
160eab04be2SMasatake YAMATO 
161c0732dcaSMasatake YAMATO 	data = getInputFileData (&size);
16231cb4225SMasatake YAMATO 	if (data)
16331cb4225SMasatake YAMATO 	{
164*27650e32SMasatake YAMATO 		xmlSetGenericErrorFunc (NULL, suppressWarning);
16531cb4225SMasatake YAMATO 		xmlLineNumbersDefault (1);
16631cb4225SMasatake YAMATO 		doc = xmlParseMemory((const char*)data, size);
16731cb4225SMasatake YAMATO 	}
16831cb4225SMasatake YAMATO 
16931cb4225SMasatake YAMATO 	return doc;
17031cb4225SMasatake YAMATO }
17131cb4225SMasatake YAMATO 
findXMLTagsFull(xmlXPathContext * ctx,xmlNode * root,int tableTableIndex,void (* runAfter)(xmlXPathContext *,xmlNode *,void *),void * userData)172f511f9ebSMasatake YAMATO extern void findXMLTagsFull (xmlXPathContext *ctx, xmlNode *root,
1730fde73e0SMasatake YAMATO 			 int tableTableIndex,
174f511f9ebSMasatake YAMATO 			 void (* runAfter) (xmlXPathContext *, xmlNode *, void *),
175971e7196SMasatake YAMATO 			 void *userData)
176a086aff1SMasatake YAMATO {
177ce990805SThomas Braun 	bool usedAsEntryPoint = false;
178a086aff1SMasatake YAMATO 	xmlDocPtr doc = NULL;
179a086aff1SMasatake YAMATO 
1800fde73e0SMasatake YAMATO 	const langType lang = getInputLanguage();
1810fde73e0SMasatake YAMATO 	const tagXpathTableTable *xpathTableTable
1820fde73e0SMasatake YAMATO 		= getXpathTableTable (lang, tableTableIndex);
1830fde73e0SMasatake YAMATO 
184a086aff1SMasatake YAMATO 	if (ctx == NULL)
185a086aff1SMasatake YAMATO 	{
186ce990805SThomas Braun 		usedAsEntryPoint = true;
187a086aff1SMasatake YAMATO 
188a086aff1SMasatake YAMATO 		findRegexTags ();
1897900fd5dSMasatake YAMATO 
19031cb4225SMasatake YAMATO 		doc = makeXMLDoc ();
19131cb4225SMasatake YAMATO 
192a086aff1SMasatake YAMATO 		if (doc == NULL)
193a086aff1SMasatake YAMATO 		{
194a086aff1SMasatake YAMATO 			verbose ("could not parse %s as a XML file\n", getInputFileName());
195a086aff1SMasatake YAMATO 			return;
196a086aff1SMasatake YAMATO 		}
197a086aff1SMasatake YAMATO 
198a086aff1SMasatake YAMATO 		ctx = xmlXPathNewContext (doc);
199a086aff1SMasatake YAMATO 		if (ctx == NULL)
200a086aff1SMasatake YAMATO 			error (FATAL, "failed to make a new xpath context for %s", getInputFileName());
201a086aff1SMasatake YAMATO 
202a086aff1SMasatake YAMATO 		root = xmlDocGetRootElement(doc);
203a086aff1SMasatake YAMATO 		if (root == NULL)
204a086aff1SMasatake YAMATO 		{
205a086aff1SMasatake YAMATO 			verbose ("could not get the root node for %s\n", getInputFileName());
206a086aff1SMasatake YAMATO 			goto out;
207a086aff1SMasatake YAMATO 		}
208a086aff1SMasatake YAMATO 	}
209a086aff1SMasatake YAMATO 
210971e7196SMasatake YAMATO 	findXMLTagsCore (ctx, root, xpathTableTable, userData);
211f511f9ebSMasatake YAMATO 	if (runAfter)
212f511f9ebSMasatake YAMATO 		(* runAfter) (ctx, root, userData);
213a086aff1SMasatake YAMATO 
214a086aff1SMasatake YAMATO out:
215b31c2380SMasatake YAMATO 	if (usedAsEntryPoint)
216a086aff1SMasatake YAMATO 	{
217a086aff1SMasatake YAMATO 		xmlXPathFreeContext (ctx);
218eab04be2SMasatake YAMATO 
219eab04be2SMasatake YAMATO 		if (doc != getInputFileUserData ())
220a086aff1SMasatake YAMATO 			xmlFreeDoc (doc);
221a086aff1SMasatake YAMATO 	}
222a086aff1SMasatake YAMATO }
223a086aff1SMasatake YAMATO 
224a086aff1SMasatake YAMATO #else
225a086aff1SMasatake YAMATO 
addTagXpath(const langType language,tagXpathTable * xpathTable)226a086aff1SMasatake YAMATO extern void addTagXpath (const langType language, tagXpathTable *xpathTable)
227a086aff1SMasatake YAMATO {
228a086aff1SMasatake YAMATO 	xpathTable->xpathCompiled = NULL;
229a086aff1SMasatake YAMATO }
230a086aff1SMasatake YAMATO 
removeTagXpath(const langType language CTAGS_ATTR_UNUSED,tagXpathTable * xpathTable CTAGS_ATTR_UNUSED)231eb480042SMasatake YAMATO extern void removeTagXpath (const langType language CTAGS_ATTR_UNUSED, tagXpathTable *xpathTable CTAGS_ATTR_UNUSED)
232eb480042SMasatake YAMATO {
233eb480042SMasatake YAMATO }
234eb480042SMasatake YAMATO 
findXMLTagsFull(xmlXPathContext * ctx,xmlNode * root,int tableTableIndex,void (* runAfter)(xmlXPathContext *,xmlNode *,void *),void * userData)235f511f9ebSMasatake YAMATO extern void findXMLTagsFull (xmlXPathContext *ctx, xmlNode *root,
236971e7196SMasatake YAMATO 			 int tableTableIndex,
237f511f9ebSMasatake YAMATO 			 void (* runAfter) (xmlXPathContext *, xmlNode *, void *),
238971e7196SMasatake YAMATO 			 void *userData)
239a086aff1SMasatake YAMATO {
240a086aff1SMasatake YAMATO }
241a086aff1SMasatake YAMATO 
242a086aff1SMasatake YAMATO #endif
243f511f9ebSMasatake YAMATO 
findXMLTags(xmlXPathContext * ctx,xmlNode * root,int tableTableIndex,void * userData)244f511f9ebSMasatake YAMATO extern void findXMLTags (xmlXPathContext *ctx, xmlNode *root,
245f511f9ebSMasatake YAMATO 			 int tableTableIndex,
246f511f9ebSMasatake YAMATO 			 void *userData)
247f511f9ebSMasatake YAMATO {
248f511f9ebSMasatake YAMATO 	findXMLTagsFull (ctx, root, tableTableIndex, NULL, userData);
249f511f9ebSMasatake YAMATO }
250