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 maven2 project model
10 * defined in http://maven.apache.org/POM/4.0.0,
11 * http://maven.apache.org/maven-v4_0_0.xsd.
12 */
13
14 #include "general.h" /* must always come first */
15
16 #include "entry.h"
17 #include "parse.h"
18 #include "read.h"
19 #include "routines.h"
20 #include "selectors.h"
21 #include "xml.h"
22
23 #include <string.h>
24
25 typedef enum {
26 K_GROUP_ID, K_ARTIFACT_ID, K_PROPERTY, K_REPOSITORY_ID
27 } maven2Kind;
28
29 typedef enum {
30 R_GROUP_ID_PARENT,
31 R_GROUP_ID_DEPENDENCY,
32 } maven2GroupIdRole;
33
34 typedef enum {
35 R_ARTIFACT_ID_PARENT,
36 R_ARTIFACT_ID_DEPENDENCY,
37 } maven2ArtifactIdRole;
38
39 static roleDefinition Maven2GroupIdRoles [] = {
40 { true, "parent", "parent" },
41 { true, "dependency", "dependency" },
42 };
43
44 static roleDefinition Maven2ArtifactIdRoles [] = {
45 { true, "parent", "parent" },
46 { true, "dependency", "dependency" },
47 };
48
49 static kindDefinition Maven2Kinds [] = {
50 { true, 'g', "groupId", "group identifiers",
51 .referenceOnly = false, ATTACH_ROLES (Maven2GroupIdRoles) },
52 { true, 'a', "artifactId", "artifact identifiers",
53 .referenceOnly = false, ATTACH_ROLES (Maven2ArtifactIdRoles) },
54 { true, 'p', "property", "properties" },
55 { true, 'r', "repositoryId", "repository identifiers" },
56 };
57
58 static void makeTagWithScope (xmlNode *node,
59 const char *xpath,
60 const struct sTagXpathMakeTagSpec *spec,
61 struct sTagEntryInfo *tag,
62 void *userData);
63
64 static void makeTagRecursively (xmlNode *node,
65 const char *xpath,
66 const struct sTagXpathRecurSpec *spec,
67 xmlXPathContext *ctx,
68 void *userData);
69
makeTagForProperties(xmlNode * node,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathRecurSpec * spec CTAGS_ATTR_UNUSED,xmlXPathContext * ctx CTAGS_ATTR_UNUSED,void * userData CTAGS_ATTR_UNUSED)70 static void makeTagForProperties (xmlNode *node,
71 const char *xpath CTAGS_ATTR_UNUSED,
72 const struct sTagXpathRecurSpec *spec CTAGS_ATTR_UNUSED,
73 xmlXPathContext *ctx CTAGS_ATTR_UNUSED,
74 void *userData CTAGS_ATTR_UNUSED)
75 {
76 const xmlChar* str;
77 tagEntryInfo tag;
78
79 str = node->name;
80 initTagEntry (&tag, (char *)str, K_PROPERTY);
81 tag.lineNumber = xmlGetLineNo (node);
82 tag.filePosition = getInputFilePositionForLine (tag.lineNumber);
83
84 makeTagEntry (&tag);
85 }
86
87
88 enum maven2XpathTable {
89 TABLE_MAIN,
90 TABLE_PARENT,
91 TABLE_DEPEDENCY,
92 };
93
94 static tagXpathTable maven2XpathMainTable[] = {
95 { "/*[local-name()='project']/*[local-name()='groupId']",
96 LXPATH_TABLE_DO_MAKE,
97 { .makeTagSpec = { K_GROUP_ID, ROLE_DEFINITION_INDEX,
98 makeTagWithScope } }
99 },
100 { "/*[local-name()='project']/*[local-name()='parent']",
101 LXPATH_TABLE_DO_RECUR,
102 { .recurSpec = { makeTagRecursively, TABLE_PARENT } }
103 },
104 { "/*[local-name()='project']/*[local-name()='dependencies']/*[local-name()='dependency']",
105 LXPATH_TABLE_DO_RECUR,
106 { .recurSpec = { makeTagRecursively, TABLE_DEPEDENCY } }
107 },
108 { "/*[local-name()='project']/*[local-name()='artifactId']",
109 LXPATH_TABLE_DO_MAKE,
110 { .makeTagSpec = { K_ARTIFACT_ID, ROLE_DEFINITION_INDEX,
111 makeTagWithScope } }
112 },
113 { "/*[local-name()='project']/*[local-name()='properties']/*",
114 LXPATH_TABLE_DO_RECUR,
115 { .recurSpec = { makeTagForProperties } }
116 },
117 { "/*[local-name()='project']/*[local-name()='repositories']/*[local-name()='repository']/*[local-name()='id']",
118 LXPATH_TABLE_DO_MAKE,
119 { .makeTagSpec = { K_REPOSITORY_ID, ROLE_DEFINITION_INDEX, } }
120 },
121 };
122
123 static tagXpathTable maven2XpathParentTable[] = {
124 { "./*[local-name()='groupId']",
125 LXPATH_TABLE_DO_MAKE,
126 { .makeTagSpec = { K_GROUP_ID, R_GROUP_ID_PARENT,
127 makeTagWithScope } }
128 },
129 { "./*[local-name()='artifactId']",
130 LXPATH_TABLE_DO_MAKE,
131 { .makeTagSpec = { K_ARTIFACT_ID, R_ARTIFACT_ID_PARENT,
132 makeTagWithScope } }
133 },
134 };
135
136 static tagXpathTable maven2XpathDependencyTable[] = {
137 { "./*[local-name()='groupId']",
138 LXPATH_TABLE_DO_MAKE,
139 { .makeTagSpec = { K_GROUP_ID, R_GROUP_ID_DEPENDENCY,
140 makeTagWithScope } }
141 },
142 { "./*[local-name()='artifactId']",
143 LXPATH_TABLE_DO_MAKE,
144 { .makeTagSpec = { K_ARTIFACT_ID, R_ARTIFACT_ID_DEPENDENCY,
145 makeTagWithScope } }
146 },
147 };
148
149 static tagXpathTableTable maven2XpathTableTable[] = {
150 [TABLE_MAIN] = { ARRAY_AND_SIZE(maven2XpathMainTable) },
151 [TABLE_PARENT] = { ARRAY_AND_SIZE(maven2XpathParentTable) },
152 [TABLE_DEPEDENCY] = { ARRAY_AND_SIZE(maven2XpathDependencyTable) },
153 };
154
155 typedef enum {
156 F_VERSION,
157 } maven2Field;
158
159 static fieldDefinition Maven2Fields [] = {
160 {
161 .name = "version",
162 .description = "version of artifact",
163 .enabled = false,
164 }
165 };
166
attachVersionIfExisting(struct sTagEntryInfo * tag,xmlNode * node)167 static char* attachVersionIfExisting (struct sTagEntryInfo *tag, xmlNode *node)
168 {
169 char *version = NULL;
170
171 for (node = node->next; node != NULL; node = node->next)
172 {
173 if (strcmp ((char *)node->name, "version") == 0)
174 {
175 version = (char *)xmlNodeGetContent (node);
176 break;
177 }
178 }
179 if (version)
180 attachParserField (tag, false, Maven2Fields [F_VERSION].ftype, version);
181 return version;
182 }
183
makeTagWithScope(xmlNode * node,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathMakeTagSpec * spec,struct sTagEntryInfo * tag,void * userData)184 static void makeTagWithScope (xmlNode *node,
185 const char *xpath CTAGS_ATTR_UNUSED,
186 const struct sTagXpathMakeTagSpec *spec,
187 struct sTagEntryInfo *tag,
188 void *userData)
189 {
190 int *corkIndexes = userData;
191 int i;
192 char* version = NULL;
193
194 if (tag->kindIndex == K_ARTIFACT_ID)
195 version = attachVersionIfExisting (tag, node);
196
197 i = makeTagEntry (tag);
198
199 if (version)
200 xmlFree (version);
201
202 if ((tag->kindIndex == K_GROUP_ID)
203 || (tag->kindIndex == K_ARTIFACT_ID))
204 corkIndexes [spec->kind] = i;
205 }
206
207 static void
findMaven2TagsForTable(enum maven2XpathTable tindex,xmlNode * node,xmlXPathContext * ctx)208 findMaven2TagsForTable (enum maven2XpathTable tindex,
209 xmlNode *node,
210 xmlXPathContext *ctx)
211 {
212 int corkIndexes [] = {
213 [K_GROUP_ID] = CORK_NIL,
214 [K_ARTIFACT_ID] = CORK_NIL,
215 };
216
217 findXMLTags (ctx, node, tindex, &corkIndexes);
218
219 tagEntryInfo *tag = getEntryInCorkQueue (corkIndexes [K_ARTIFACT_ID]);
220 if (tag && corkIndexes [K_GROUP_ID] != CORK_NIL)
221 tag->extensionFields.scopeIndex = corkIndexes [K_GROUP_ID];
222 }
223
makeTagRecursively(xmlNode * node,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathRecurSpec * spec,xmlXPathContext * ctx,void * userData CTAGS_ATTR_UNUSED)224 static void makeTagRecursively (xmlNode *node,
225 const char *xpath CTAGS_ATTR_UNUSED,
226 const struct sTagXpathRecurSpec *spec,
227 xmlXPathContext *ctx,
228 void *userData CTAGS_ATTR_UNUSED)
229 {
230 findMaven2TagsForTable (spec->nextTable, node, ctx);
231 }
232
233 static void
findMaven2Tags(void)234 findMaven2Tags (void)
235 {
236 scheduleRunningBaseparser (RUN_DEFAULT_SUBPARSERS);
237 }
238
239 static void
runXPathEngine(xmlSubparser * s,xmlXPathContext * ctx,xmlNode * root)240 runXPathEngine(xmlSubparser *s,
241 xmlXPathContext *ctx, xmlNode *root)
242 {
243 findMaven2TagsForTable (TABLE_MAIN, root, ctx);
244 }
245
246 static xmlSubparser maven2Subparser = {
247 .subparser = {
248 .direction = SUBPARSER_BI_DIRECTION,
249 },
250 .runXPathEngine = runXPathEngine,
251 };
252
253 extern parserDefinition*
Maven2Parser(void)254 Maven2Parser (void)
255 {
256 static const char *const extensions [] = { "pom", "xml", NULL };
257 static const char *const patterns [] = { "pom.xml", NULL };
258 parserDefinition* const def = parserNew ("Maven2");
259 static selectLanguage selectors[] = { selectByXpathFileSpec, NULL };
260
261 static xpathFileSpec xpathFileSpecs[] = {
262 {
263 .rootElementName = "project",
264 .rootNSHref = "http://maven.apache.org/POM/4.0.0",
265 },
266 };
267
268 static parserDependency dependencies [] = {
269 [0] = { DEPTYPE_SUBPARSER, "XML", &maven2Subparser },
270 };
271
272 def->dependencies = dependencies;
273 def->dependencyCount = ARRAY_SIZE (dependencies);
274
275 def->kindTable = Maven2Kinds;
276 def->kindCount = ARRAY_SIZE (Maven2Kinds);
277 def->extensions = extensions;
278 def->patterns = patterns;
279 def->parser = findMaven2Tags;
280 def->tagXpathTableTable = maven2XpathTableTable;
281 def->tagXpathTableCount = ARRAY_SIZE (maven2XpathTableTable);
282 def->useCork = CORK_QUEUE;
283 def->selectLanguage = selectors;
284 def->fieldTable = Maven2Fields;
285 def->fieldCount = ARRAY_SIZE (Maven2Fields);
286 def->xpathFileSpecs = xpathFileSpecs;
287 def->xpathFileSpecCount = ARRAY_SIZE (xpathFileSpecs);
288 return def;
289 }
290