xref: /Universal-ctags/parsers/xml.c (revision aa4def1793bf3cadfdb89c325d093e28cb67adc1)
1c3416965SMasatake YAMATO /*
2c3416965SMasatake YAMATO *
3c3416965SMasatake YAMATO *   Copyright (c) 2019, Masatake YAMATO
4c3416965SMasatake YAMATO *   Copyright (c) 2019, Red Hat, K.K.
5c3416965SMasatake YAMATO *
6c3416965SMasatake YAMATO *   This source code is released for free distribution under the terms of the
7c3416965SMasatake YAMATO *   GNU General Public License version 2 or (at your option) any later version.
8c3416965SMasatake YAMATO *
9c3416965SMasatake YAMATO *   This module contains functions for generating tags for id="..." in a XML file
10c3416965SMasatake YAMATO */
11c3416965SMasatake YAMATO 
12c3416965SMasatake YAMATO #include "general.h"	/* must always come first */
13c3416965SMasatake YAMATO #include "entry.h"
14c3416965SMasatake YAMATO #include "options.h"
15c3416965SMasatake YAMATO #include "parse.h"
16c3416965SMasatake YAMATO #include "read.h"
17c3416965SMasatake YAMATO #include "routines.h"
18c3416965SMasatake YAMATO #include "selectors.h"
19bbc76549SMasatake YAMATO #include "subparser.h"
20bbc76549SMasatake YAMATO #include "xml.h"
21bbc76549SMasatake YAMATO 
22bbc76549SMasatake YAMATO static void makeTagWithNotification (xmlNode *node,
23bbc76549SMasatake YAMATO 									 const char *xpath,
24bbc76549SMasatake YAMATO 									 const tagXpathMakeTagSpec *spec,
25bbc76549SMasatake YAMATO 									 tagEntryInfo *tag,
26bbc76549SMasatake YAMATO 									 void *userData);
27c3416965SMasatake YAMATO 
28c3416965SMasatake YAMATO typedef enum {
29c3416965SMasatake YAMATO 	K_ID,
30b0667671SMasatake YAMATO 	K_NSPREFIX,
31ce60e3e5SMasatake YAMATO 	K_ROOT,
32c3416965SMasatake YAMATO } xmlKind;
33c3416965SMasatake YAMATO 
34ce60e3e5SMasatake YAMATO #define ROOT_ELT_LETTER 'r'
35ce60e3e5SMasatake YAMATO static const char ROOT_ELT_LETTER_STR[2] = {ROOT_ELT_LETTER, '\0'};
36c3416965SMasatake YAMATO static kindDefinition XmlKinds [] = {
37c3416965SMasatake YAMATO 	{ true, 'i', "id", "id attributes" },
38b0667671SMasatake YAMATO 	{ true, 'n', "nsprefix", "namespace prefixes" },
39ce60e3e5SMasatake YAMATO 	{ true, ROOT_ELT_LETTER, "root", "root elements" },
40c3416965SMasatake YAMATO };
41c3416965SMasatake YAMATO 
42c3416965SMasatake YAMATO enum xmlXpathTables {
43c3416965SMasatake YAMATO 	TABLE_MAIN,
44b0667671SMasatake YAMATO 	TABLE_ID,
45c3416965SMasatake YAMATO };
46c3416965SMasatake YAMATO 
47b0667671SMasatake YAMATO typedef enum {
48b0667671SMasatake YAMATO 	F_NS_URI,
49b0667671SMasatake YAMATO } xmlField;
50b0667671SMasatake YAMATO 
51b0667671SMasatake YAMATO static fieldDefinition XmlFields [] = {
52b0667671SMasatake YAMATO 	{
53b0667671SMasatake YAMATO 		.name = "uri",
54b0667671SMasatake YAMATO 		.description = "uri associated with name prefix",
55b0667671SMasatake YAMATO 		.enabled = true,
56b0667671SMasatake YAMATO 	}
57b0667671SMasatake YAMATO };
58b0667671SMasatake YAMATO 
59b0667671SMasatake YAMATO static void findNsPrefix (xmlNode *node,
60b0667671SMasatake YAMATO 					   const char *xpath,
61b0667671SMasatake YAMATO 					   const struct sTagXpathRecurSpec *spec,
62b0667671SMasatake YAMATO 					   xmlXPathContext *ctx,
63b0667671SMasatake YAMATO 					   void *userData);
64b0667671SMasatake YAMATO 
65c3416965SMasatake YAMATO static tagXpathTable XmlXpathMainTable [] = {
66b0667671SMasatake YAMATO 	{ "//*",
67b0667671SMasatake YAMATO 	  LXPATH_TABLE_DO_RECUR,
68b0667671SMasatake YAMATO 	  { .recurSpec = { .enter = findNsPrefix, .nextTable = TABLE_ID } }
69b0667671SMasatake YAMATO 	},
70b0667671SMasatake YAMATO };
71b0667671SMasatake YAMATO 
72b0667671SMasatake YAMATO static tagXpathTable XmlXpathIdTable [] = {
73b0667671SMasatake YAMATO 	{ "./@id",
74c3416965SMasatake YAMATO 	  LXPATH_TABLE_DO_MAKE,
75bbc76549SMasatake YAMATO 	  { .makeTagSpec = { K_ID, ROLE_DEFINITION_INDEX,
76bbc76549SMasatake YAMATO 						 .make = makeTagWithNotification,} }
77c3416965SMasatake YAMATO 	},
78c3416965SMasatake YAMATO };
79c3416965SMasatake YAMATO 
80c3416965SMasatake YAMATO static tagXpathTableTable xmlXpathTableTable[] = {
81c3416965SMasatake YAMATO 	[TABLE_MAIN] = { ARRAY_AND_SIZE (XmlXpathMainTable) },
82b0667671SMasatake YAMATO 	[TABLE_ID]   = { ARRAY_AND_SIZE (XmlXpathIdTable) },
83c3416965SMasatake YAMATO };
84c3416965SMasatake YAMATO 
85ce60e3e5SMasatake YAMATO /* Pick up the root element specifier from "<!DOCTYPE...", and
86ce60e3e5SMasatake YAMATO  * run DTD parser for the "[" ... "]>" area.
87ce60e3e5SMasatake YAMATO  *
88ce60e3e5SMasatake YAMATO  * optlib2c translates the following .ctags elements:
89ce60e3e5SMasatake YAMATO  * ==========================================================
90ce60e3e5SMasatake YAMATO  * --langdef=Xml
91ce60e3e5SMasatake YAMATO  * --kinddef-Xml=r,root,root elements
92ce60e3e5SMasatake YAMATO  * --mline-regex-Xml=/<!DOCTYPE[[:space:]]+([a-zA-Z0-9]+)[[:space:]]+[^[]+\[((.|[\n])+)\]>/\1/r/{mgroup=1}{_guest=DTD,2start,2end}
93ce60e3e5SMasatake YAMATO  * ==========================================================
94ce60e3e5SMasatake YAMATO  */
95ce60e3e5SMasatake YAMATO static tagRegexTable XmlTagRegexTable [] = {
96ce60e3e5SMasatake YAMATO 	{"<!DOCTYPE[[:space:]]+([a-zA-Z0-9]+)[[:space:]]+[^[]*\\[((.|[\n])+)\\]>", "\\1",
97ce60e3e5SMasatake YAMATO 	 ROOT_ELT_LETTER_STR, "{mgroup=1}{_guest=DTD,2start,2end}", NULL, true},
98ce60e3e5SMasatake YAMATO };
99ce60e3e5SMasatake YAMATO 
makeTagWithNotificationCommon(tagEntryInfo * tag,xmlNode * node)100bbc76549SMasatake YAMATO static int makeTagWithNotificationCommon (tagEntryInfo *tag,
101bbc76549SMasatake YAMATO 										   xmlNode *node)
102bbc76549SMasatake YAMATO {
103bbc76549SMasatake YAMATO 	int n = makeTagEntry (tag);
104bbc76549SMasatake YAMATO 
105bbc76549SMasatake YAMATO 	subparser *sub;
106bbc76549SMasatake YAMATO 	foreachSubparser (sub, false)
107bbc76549SMasatake YAMATO 	{
108bbc76549SMasatake YAMATO 		xmlSubparser *xmlsub = (xmlSubparser *)sub;
109bbc76549SMasatake YAMATO 
110bbc76549SMasatake YAMATO 		if (xmlsub->makeTagEntryWithNodeNotify)
111bbc76549SMasatake YAMATO 		{
112bbc76549SMasatake YAMATO 			enterSubparser(sub);
113bbc76549SMasatake YAMATO 			xmlsub->makeTagEntryWithNodeNotify (xmlsub, node, tag);
114bbc76549SMasatake YAMATO 			leaveSubparser();
115bbc76549SMasatake YAMATO 		}
116bbc76549SMasatake YAMATO 	}
117bbc76549SMasatake YAMATO 	return n;
118bbc76549SMasatake YAMATO }
119bbc76549SMasatake YAMATO 
makeTagWithNotification(xmlNode * node,const char * xpath CTAGS_ATTR_UNUSED,const tagXpathMakeTagSpec * spec CTAGS_ATTR_UNUSED,tagEntryInfo * tag,void * userData CTAGS_ATTR_UNUSED)120bbc76549SMasatake YAMATO static void makeTagWithNotification (xmlNode *node,
121bbc76549SMasatake YAMATO 									 const char *xpath CTAGS_ATTR_UNUSED,
122bbc76549SMasatake YAMATO 									 const tagXpathMakeTagSpec *spec CTAGS_ATTR_UNUSED,
123bbc76549SMasatake YAMATO 									 tagEntryInfo *tag,
124bbc76549SMasatake YAMATO 									 void *userData CTAGS_ATTR_UNUSED)
125bbc76549SMasatake YAMATO {
126bbc76549SMasatake YAMATO 	makeTagWithNotificationCommon (tag, node);
127bbc76549SMasatake YAMATO }
128bbc76549SMasatake YAMATO 
makeNsPrefixTag(const char * name,xmlNode * node,xmlNsPtr ns)129b0667671SMasatake YAMATO static int makeNsPrefixTag (const char *name, xmlNode *node, xmlNsPtr ns)
130b0667671SMasatake YAMATO {
131b0667671SMasatake YAMATO 	int n = CORK_NIL;
132b0667671SMasatake YAMATO 	tagEntryInfo tag;
1330376b965SMasatake YAMATO 	vString *anon = NULL;
134b0667671SMasatake YAMATO 
1350376b965SMasatake YAMATO 	if (name)
136b0667671SMasatake YAMATO 		initTagEntry (&tag, name, K_NSPREFIX);
1370376b965SMasatake YAMATO 	else
1380376b965SMasatake YAMATO 	{
1390376b965SMasatake YAMATO 		anon = anonGenerateNew ("ns", K_NSPREFIX);
1400376b965SMasatake YAMATO 		initTagEntry (&tag, vStringValue (anon), K_NSPREFIX);
1410376b965SMasatake YAMATO 		markTagExtraBit (&tag, XTAG_ANONYMOUS);
1420376b965SMasatake YAMATO 	}
143b0667671SMasatake YAMATO 	/* TODO
144b0667671SMasatake YAMATO 	 * - move this code block to lxpath.c.
145b0667671SMasatake YAMATO 	 * - adjust the line number for nsprefixes forward. */
146b0667671SMasatake YAMATO 	tag.lineNumber = XML_GET_LINE (node);
147b0667671SMasatake YAMATO 	tag.filePosition = getInputFilePositionForLine (tag.lineNumber);
148b0667671SMasatake YAMATO 	char *p = (char *)xmlGetNodePath (node);
149b0667671SMasatake YAMATO 	if (ns->href && *ns->href)
150*aa4def17SMasatake YAMATO 		attachParserField (&tag, false, XmlFields [F_NS_URI].ftype, (char *)ns->href);
151b0667671SMasatake YAMATO 
152bbc76549SMasatake YAMATO 	n = makeTagWithNotificationCommon (&tag, node);
153b0667671SMasatake YAMATO 	if (p)
154b0667671SMasatake YAMATO 		xmlFree (p);
1550376b965SMasatake YAMATO 	if (anon)
1560376b965SMasatake YAMATO 		vStringDelete (anon);
157b0667671SMasatake YAMATO 
158b0667671SMasatake YAMATO 	return n;
159b0667671SMasatake YAMATO }
160b0667671SMasatake YAMATO 
findNsPrefix(xmlNode * node,const char * xpath,const struct sTagXpathRecurSpec * spec,xmlXPathContext * ctx,void * userData)161b0667671SMasatake YAMATO static void findNsPrefix (xmlNode *node,
162b0667671SMasatake YAMATO 					   const char *xpath,
163b0667671SMasatake YAMATO 					   const struct sTagXpathRecurSpec *spec,
164b0667671SMasatake YAMATO 					   xmlXPathContext *ctx,
165b0667671SMasatake YAMATO 					   void *userData)
166b0667671SMasatake YAMATO {
167b0667671SMasatake YAMATO 	for (xmlNsPtr ns = node->nsDef; ns; ns = ns->next)
168b0667671SMasatake YAMATO 		makeNsPrefixTag ((char *)ns->prefix, node, ns);
169b0667671SMasatake YAMATO 
170b0667671SMasatake YAMATO 	findXMLTags (ctx, node, spec->nextTable, userData);
171b0667671SMasatake YAMATO }
172b0667671SMasatake YAMATO 
runAfter(xmlXPathContext * ctx,xmlNode * root,void * user_data)173f511f9ebSMasatake YAMATO static void runAfter (xmlXPathContext *ctx, xmlNode *root, void *user_data)
174f511f9ebSMasatake YAMATO {
175f511f9ebSMasatake YAMATO 	subparser *sub;
176f511f9ebSMasatake YAMATO 	foreachSubparser (sub, false)
177f511f9ebSMasatake YAMATO 	{
178f511f9ebSMasatake YAMATO 		xmlSubparser *xmlsub = (xmlSubparser *)sub;
179f511f9ebSMasatake YAMATO 		if (xmlsub->runXPathEngine)
180f511f9ebSMasatake YAMATO 		{
181f511f9ebSMasatake YAMATO 			enterSubparser(sub);
182f511f9ebSMasatake YAMATO 			xmlsub->runXPathEngine (xmlsub, ctx, root);
183f511f9ebSMasatake YAMATO 			leaveSubparser();
184f511f9ebSMasatake YAMATO 		}
185f511f9ebSMasatake YAMATO 	}
186f511f9ebSMasatake YAMATO }
187f511f9ebSMasatake YAMATO 
188c3416965SMasatake YAMATO static void
findXmlTags(void)189c3416965SMasatake YAMATO findXmlTags (void)
190c3416965SMasatake YAMATO {
191f511f9ebSMasatake YAMATO 	findXMLTagsFull (NULL, NULL, TABLE_MAIN, runAfter, NULL);
192c3416965SMasatake YAMATO }
193c3416965SMasatake YAMATO 
194c3416965SMasatake YAMATO extern parserDefinition*
XmlParser(void)195c3416965SMasatake YAMATO XmlParser (void)
196c3416965SMasatake YAMATO {
197c3416965SMasatake YAMATO 	static const char *const extensions [] = { "xml", NULL };
198c3416965SMasatake YAMATO 	parserDefinition* const def = parserNew ("XML");
199c3416965SMasatake YAMATO 	static selectLanguage selectors[] = { selectByXpathFileSpec, NULL };
200c3416965SMasatake YAMATO 
201c3416965SMasatake YAMATO 	def->kindTable     = XmlKinds;
202c3416965SMasatake YAMATO 	def->kindCount     = ARRAY_SIZE (XmlKinds);
203c3416965SMasatake YAMATO 	def->extensions    = extensions;
204c3416965SMasatake YAMATO 	def->parser        = findXmlTags;
205c3416965SMasatake YAMATO 	def->tagXpathTableTable = xmlXpathTableTable;
206c3416965SMasatake YAMATO 	def->tagXpathTableCount = ARRAY_SIZE (xmlXpathTableTable);
207c3416965SMasatake YAMATO 	def->selectLanguage = selectors;
208b0667671SMasatake YAMATO 	def->fieldTable = XmlFields;
209b0667671SMasatake YAMATO 	def->fieldCount = ARRAY_SIZE (XmlFields);
210ce60e3e5SMasatake YAMATO 	def->tagRegexTable = XmlTagRegexTable;
211ce60e3e5SMasatake YAMATO 	def->tagRegexCount = ARRAY_SIZE(XmlTagRegexTable);
212b0667671SMasatake YAMATO 
213c3416965SMasatake YAMATO 	return def;
214c3416965SMasatake YAMATO }
215