xref: /Universal-ctags/parsers/ant.c (revision 6b1a862e526d5017f9f212a321f59d67c859d521)
1 /*
2 *   Copyright (c) 2008, David Fishburn
3 *
4 *   This source code is released for free distribution under the terms of the
5 *   GNU General Public License version 2 or (at your option) any later version.
6 *
7 *   This module contains functions for generating tags for Ant language files.
8 */
9 
10 /*
11 *   INCLUDE FILES
12 */
13 #include "general.h"  /* must always come first */
14 
15 #include <string.h>
16 #include "entry.h"
17 #include "parse.h"
18 #include "routines.h"
19 #ifdef HAVE_LIBXML
20 #include "read.h"
21 #include "selectors.h"
22 #include "xml.h"
23 #endif
24 
25 #ifdef HAVE_LIBXML
26 /*
27 *   FUNCTION PROTOTYPES
28 */
29 static void antFindTagsUnderProject (xmlNode *node,
30 				     const char *xpath,
31 				     const struct sTagXpathRecurSpec *spec,
32 				     xmlXPathContext *ctx,
33 				     void *userData);
34 static void antFindTagsUnderTask (xmlNode *node,
35 				  const char *xpath,
36 				  const struct sTagXpathRecurSpec *spec,
37 				  xmlXPathContext *ctx,
38 				  void *userData);
39 static void makeTagForProjectName (xmlNode *node,
40 				   const char *xpath,
41 				   const struct sTagXpathMakeTagSpec *spec,
42 				   struct sTagEntryInfo *tag,
43 				   void *userData);
44 static void makeTagForTargetName (xmlNode *node,
45 				  const char *xpath,
46 				  const struct sTagXpathMakeTagSpec *spec,
47 				  struct sTagEntryInfo *tag,
48 				  void *userData);
49 static void makeTagWithScope (xmlNode *node,
50 				  const char *xpath,
51 			      const struct sTagXpathMakeTagSpec *spec,
52 			      struct sTagEntryInfo *tag,
53 			      void *userData);
54 #endif
55 
56 #ifdef HAVE_LIBXML
57 typedef enum {
58 	K_PROJECT, K_TARGET, K_PROPERTY, K_IMPORT,
59 } antKind;
60 
61 typedef enum {
62 	R_IMPORT_GENERIC,
63 } antAntfileRole;
64 
65 static roleDefinition AntAntfileRoles [] = {
66         { true, "imported", "imported" },
67 };
68 
69 static kindDefinition AntKinds [] = {
70 	{ true,  'p', "project",  "projects"   },
71 	{ true,  't', "target",   "targets"    },
72 	{ true,  'P', "property", "properties(global)" },
73 	{ true,  'i', "antfile",  "antfiles",
74 	  .referenceOnly = true, ATTACH_ROLES(AntAntfileRoles)},
75 };
76 
77 enum antXpathTable {
78 	TABLE_MAIN, TABLE_PROJECT, TABLE_MAIN_NAME, TABLE_TARGET_NAME,
79 };
80 
81 static tagXpathTable antXpathMainTable [] = {
82 	{ "///project",
83 	  LXPATH_TABLE_DO_RECUR,
84 	  { .recurSpec= { antFindTagsUnderProject } }
85 	},
86 };
87 
88 static tagXpathTable antXpathProjectTable [] = {
89 	{ "target",
90 	  LXPATH_TABLE_DO_RECUR,
91 	  { .recurSpec= { antFindTagsUnderTask, TABLE_TARGET_NAME } }
92 	},
93 	{ "property/@name",
94 	  LXPATH_TABLE_DO_MAKE,
95 	  { .makeTagSpec = { K_PROPERTY, ROLE_DEFINITION_INDEX,
96 			     makeTagWithScope } }
97 	},
98 	{ "import/@file",
99 	  LXPATH_TABLE_DO_MAKE,
100 	  { .makeTagSpec = { K_IMPORT, R_IMPORT_GENERIC,
101 			     makeTagWithScope } }
102 	},
103 };
104 
105 static tagXpathTable antXpathMainNameTable [] = {
106 	{ "@name",
107 	  LXPATH_TABLE_DO_MAKE,
108 	  { .makeTagSpec = { K_PROJECT, ROLE_DEFINITION_INDEX,
109 			     makeTagForProjectName } }
110 	},
111 };
112 
113 static tagXpathTable antXpathTargetNameTable [] = {
114 	{ "@name",
115 	  LXPATH_TABLE_DO_MAKE,
116 	  { .makeTagSpec = { K_TARGET, ROLE_DEFINITION_INDEX,
117 			     makeTagForTargetName} }
118 	},
119 };
120 
121 static tagXpathTableTable antXpathTableTable[] = {
122 	[TABLE_MAIN]        = { ARRAY_AND_SIZE (antXpathMainTable)       },
123 	[TABLE_PROJECT]     = { ARRAY_AND_SIZE (antXpathProjectTable)    },
124 	[TABLE_MAIN_NAME]   = { ARRAY_AND_SIZE (antXpathMainNameTable)   },
125 	[TABLE_TARGET_NAME] = { ARRAY_AND_SIZE (antXpathTargetNameTable) },
126 };
127 
128 #else
129 static tagRegexTable antTagRegexTable [] = {
130 	{"^[ \t]*<[ \t]*project[^>]+name=\"([^\"]+)\".*", "\\1",
131 	 "p,project,projects", NULL},
132 	{"^[ \t]*<[ \t]*target[^>]+name=\"([^\"]+)\".*", "\\1",
133 	 "t,target,targets", NULL},
134 	{"^[ \t]*<[ \t]*property[^>]+name=\"([^\"]+)\".*", "\\1",
135 	 "P,property,property", NULL},
136 };
137 #endif
138 
139 /*
140 *   FUNCTION DEFINITIONS
141 */
142 #ifdef HAVE_LIBXML
143 
144 static void
antFindTagsUnderProject(xmlNode * node,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathRecurSpec * spec CTAGS_ATTR_UNUSED,xmlXPathContext * ctx,void * userData CTAGS_ATTR_UNUSED)145 antFindTagsUnderProject (xmlNode *node,
146 			 const char *xpath CTAGS_ATTR_UNUSED,
147 			 const struct sTagXpathRecurSpec *spec CTAGS_ATTR_UNUSED,
148 			 xmlXPathContext *ctx,
149 			 void *userData CTAGS_ATTR_UNUSED)
150 {
151 	int corkIndex = CORK_NIL;
152 
153 	findXMLTags (ctx, node, TABLE_MAIN_NAME, &corkIndex);
154 	findXMLTags (ctx, node, TABLE_PROJECT, &corkIndex);
155 }
156 
antFindTagsUnderTask(xmlNode * node,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathRecurSpec * spec,xmlXPathContext * ctx,void * userData)157 static void antFindTagsUnderTask (xmlNode *node,
158 				  const char *xpath CTAGS_ATTR_UNUSED,
159 				  const struct sTagXpathRecurSpec *spec,
160 				  xmlXPathContext *ctx,
161 				  void *userData)
162 {
163 	int corkIndex = *(int *)userData;
164 
165 	findXMLTags (ctx, node, spec->nextTable, &corkIndex);
166 }
167 
makeTagForProjectName(xmlNode * node CTAGS_ATTR_UNUSED,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathMakeTagSpec * spec CTAGS_ATTR_UNUSED,struct sTagEntryInfo * tag,void * userData)168 static void makeTagForProjectName (xmlNode *node CTAGS_ATTR_UNUSED,
169 				   const char *xpath CTAGS_ATTR_UNUSED,
170 				   const struct sTagXpathMakeTagSpec *spec CTAGS_ATTR_UNUSED,
171 				   struct sTagEntryInfo *tag,
172 				   void *userData)
173 {
174 	int *corkIndex = userData;
175 
176 	*corkIndex = makeTagEntry (tag);
177 }
178 
makeTagForTargetName(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 makeTagForTargetName (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 	int *corkIndex = (int *)userData;
186 	int parentIndex = *corkIndex;
187 
188 	tag->extensionFields.scopeKindIndex = KIND_GHOST_INDEX;
189 	tag->extensionFields.scopeName  = NULL;
190 	tag->extensionFields.scopeIndex = parentIndex;
191 
192 	*corkIndex = makeTagEntry (tag);
193 }
194 
makeTagWithScope(xmlNode * node CTAGS_ATTR_UNUSED,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathMakeTagSpec * spec CTAGS_ATTR_UNUSED,struct sTagEntryInfo * tag,void * userData)195 static void makeTagWithScope (xmlNode *node CTAGS_ATTR_UNUSED,
196 			      const char *xpath CTAGS_ATTR_UNUSED,
197 			      const struct sTagXpathMakeTagSpec *spec CTAGS_ATTR_UNUSED,
198 			      struct sTagEntryInfo *tag,
199 			      void *userData)
200 {
201 	tag->extensionFields.scopeKindIndex = KIND_GHOST_INDEX;
202 	tag->extensionFields.scopeName  = NULL;
203 	tag->extensionFields.scopeIndex = *(int *)userData;
204 
205 	makeTagEntry (tag);
206 }
207 
208 static void
findAntTags(void)209 findAntTags (void)
210 {
211 	scheduleRunningBaseparser (RUN_DEFAULT_SUBPARSERS);
212 }
213 
214 static void
runXPathEngine(xmlSubparser * s,xmlXPathContext * ctx,xmlNode * root)215 runXPathEngine(xmlSubparser *s,
216 			   xmlXPathContext *ctx, xmlNode *root)
217 {
218 	findXMLTags (ctx, root, TABLE_MAIN, NULL);
219 }
220 
221 static xmlSubparser antSubparser = {
222 	.subparser = {
223 		.direction = SUBPARSER_BI_DIRECTION,
224 	},
225 	.runXPathEngine = runXPathEngine,
226 };
227 #endif
228 
AntParser(void)229 extern parserDefinition* AntParser (void)
230 {
231 	static const char *const extensions [] = { "build.xml", "ant",
232 #ifdef HAVE_LIBXML
233 				/* libxml based selector is needed to select a
234 				 * proper concrete xml parser.*/
235 						   "xml",
236 #endif
237 						   NULL };
238 	static const char *const patterns [] = { "build.xml", NULL };
239 	parserDefinition* const def = parserNew ("Ant");
240 #ifdef HAVE_LIBXML
241 	static selectLanguage selectors[] = { selectByXpathFileSpec, NULL };
242 	static xpathFileSpec xpathFileSpecs[] = {
243 		/* See http://ant.apache.org/faq.html#dtd */
244 		{
245 			.rootElementName = "project",
246 			.nameInDTD       = "",
247 			.externalID      = "",
248 			.systemID        = "",
249 			.rootNSPrefix    = "",
250 			.rootNSHref      = "",
251 		},
252 		{
253 			.rootElementName = "project",
254 			.nameInDTD       = "project",
255 			.externalID      = "",
256 			.systemID        = "",
257 			.rootNSPrefix    = "",
258 			.rootNSHref      = "",
259 		}
260 	};
261 	static parserDependency dependencies [] = {
262 		[0] = { DEPTYPE_SUBPARSER, "XML", &antSubparser },
263 	};
264 #endif
265 	def->extensions = extensions;
266 	def->patterns = patterns;
267 #ifdef HAVE_LIBXML
268 	def->kindTable = AntKinds;
269 	def->kindCount = ARRAY_SIZE (AntKinds);
270 	def->parser = findAntTags;
271 	def->tagXpathTableTable = antXpathTableTable;
272 	def->tagXpathTableCount = ARRAY_SIZE (antXpathTableTable);
273 	def->useCork = CORK_QUEUE;
274 	def->selectLanguage = selectors;
275 	def->xpathFileSpecs = xpathFileSpecs;
276 	def->xpathFileSpecCount = ARRAY_SIZE (xpathFileSpecs);
277 	def->dependencies = dependencies;
278 	def->dependencyCount = ARRAY_SIZE (dependencies);
279 #else
280 	def->tagRegexTable = antTagRegexTable;
281 	def->tagRegexCount = ARRAY_SIZE (antTagRegexTable);
282 	def->method     = METHOD_NOT_CRAFTED|METHOD_REGEX;
283 #endif
284 	return def;
285 }
286