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