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 property list defined
10 * in http://www.apple.com/DTDs/PropertyList-1.0.dtd.
11 */
12
13 #include "general.h" /* must always come first */
14
15 #include <string.h>
16
17 #include "entry.h"
18 #include "parse.h"
19 #include "read.h"
20 #include "routines.h"
21 #include "strlist.h"
22 #include "xml.h"
23
24
25 typedef enum {
26 K_KEY,
27 } plistKind;
28
29 static kindDefinition PlistKinds [] = {
30 { true, 'k', "key", "keys" },
31 };
32
33 static void plistFindTagsUnderKey (xmlNode *node,
34 const char *xpath,
35 const struct sTagXpathRecurSpec *spec,
36 xmlXPathContext *ctx,
37 void *userData);
38
39 static void makeTagWithScope (xmlNode *node,
40 const char *xpath,
41 const struct sTagXpathMakeTagSpec *spec,
42 struct sTagEntryInfo *tag,
43 void *userData);
44
45 static tagXpathTable plistXpathMainTable[] = {
46 { "///plist//dict/key",
47 LXPATH_TABLE_DO_RECUR,
48 .spec.recurSpec = {
49 plistFindTagsUnderKey
50 }
51 },
52 };
53
54 static tagXpathTable plistXpathTextTable[] = {
55 { "text()",
56 LXPATH_TABLE_DO_MAKE,
57 .spec.makeTagSpec = {
58 K_KEY, ROLE_DEFINITION_INDEX,
59 makeTagWithScope
60 }
61 },
62 };
63
64 enum plistXpathTable {
65 TABLE_MAIN,
66 TABLE_TEXT,
67 };
68
69 static tagXpathTableTable plistXpathTableTable[] = {
70 [TABLE_MAIN] = { ARRAY_AND_SIZE(plistXpathMainTable) },
71 [TABLE_TEXT] = { ARRAY_AND_SIZE(plistXpathTextTable) },
72 };
73
isCompoundElement(xmlNode * node)74 static bool isCompoundElement (xmlNode *node)
75 {
76 return !! (node->name
77 && ((strcmp ((char *)(node->name), "dict") == 0)
78 || (strcmp ((char *)(node->name), "array") == 0)));
79 }
80
getPrevKeyElement(xmlNode * node)81 static xmlNode *getPrevKeyElement (xmlNode *node)
82 {
83 xmlNode *prev;
84
85 prev = xmlPreviousElementSibling (node);
86 if (prev)
87 {
88 if (strcmp ((char *)prev->name, "key") == 0)
89 return prev;
90 else
91 prev = NULL;
92 }
93 return prev;
94 }
95
plistFindTagsUnderKey(xmlNode * node,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathRecurSpec * spec CTAGS_ATTR_UNUSED,xmlXPathContext * ctx,void * userData CTAGS_ATTR_UNUSED)96 static void plistFindTagsUnderKey (xmlNode *node,
97 const char *xpath CTAGS_ATTR_UNUSED,
98 const struct sTagXpathRecurSpec *spec CTAGS_ATTR_UNUSED,
99 xmlXPathContext *ctx,
100 void *userData CTAGS_ATTR_UNUSED)
101 {
102 xmlNode *current;
103 xmlNode *prev;
104 stringList *queue;
105 vString* path;
106 vString* v;
107 int c;
108
109 queue = stringListNew ();
110 current = node;
111 for (current = node; current; current = current->parent)
112 {
113 if (isCompoundElement (current)
114 && (prev = getPrevKeyElement (current)))
115 {
116 char* parent = (char *)xmlNodeGetContent (prev);
117 if (parent)
118 {
119 v = vStringNewInit (parent);
120 stringListAdd (queue, v);
121 xmlFree (parent);
122 }
123 }
124 }
125
126 path = vStringNew ();
127 while ((c = stringListCount (queue)) > 0)
128 {
129 v = stringListLast (queue);
130 vStringCat (path, v);
131 vStringDelete (v);
132 stringListRemoveLast (queue);
133 if (c != 1)
134 vStringPut (path, '.');
135 }
136 stringListDelete (queue);
137
138 findXMLTags (ctx, node,
139 TABLE_TEXT, (vStringLength (path) > 0)? vStringValue (path): NULL);
140
141 vStringDelete (path);
142 }
143
makeTagWithScope(xmlNode * node CTAGS_ATTR_UNUSED,const char * xpath CTAGS_ATTR_UNUSED,const struct sTagXpathMakeTagSpec * spec CTAGS_ATTR_UNUSED,struct sTagEntryInfo * tag,void * userData)144 static void makeTagWithScope (xmlNode *node CTAGS_ATTR_UNUSED,
145 const char *xpath CTAGS_ATTR_UNUSED,
146 const struct sTagXpathMakeTagSpec *spec CTAGS_ATTR_UNUSED,
147 struct sTagEntryInfo *tag,
148 void *userData)
149 {
150 tag->extensionFields.scopeKindIndex = userData? K_KEY: KIND_GHOST_INDEX;
151 tag->extensionFields.scopeName = userData;
152 makeTagEntry (tag);
153 }
154
155 static void
findPlistTags(void)156 findPlistTags (void)
157 {
158 scheduleRunningBaseparser (RUN_DEFAULT_SUBPARSERS);
159 }
160
161 static void
runXPathEngine(xmlSubparser * s,xmlXPathContext * ctx,xmlNode * root)162 runXPathEngine(xmlSubparser *s,
163 xmlXPathContext *ctx, xmlNode *root)
164 {
165 findXMLTags (ctx, root, TABLE_MAIN, NULL);
166 }
167
168 static xmlSubparser plistSubparser = {
169 .subparser = {
170 .direction = SUBPARSER_BI_DIRECTION,
171 },
172 .runXPathEngine = runXPathEngine,
173 };
174
175 extern parserDefinition*
PlistXMLParser(void)176 PlistXMLParser (void)
177 {
178 static const char *const extensions [] = { "plist", NULL };
179 parserDefinition* const def = parserNew ("PlistXML");
180 static parserDependency dependencies [] = {
181 [0] = { DEPTYPE_SUBPARSER, "XML", &plistSubparser },
182 };
183
184 def->kindTable = PlistKinds;
185 def->kindCount = ARRAY_SIZE (PlistKinds);
186 def->extensions = extensions;
187 def->parser = findPlistTags;
188 def->tagXpathTableTable = plistXpathTableTable;
189 def->tagXpathTableCount = ARRAY_SIZE (plistXpathTableTable);
190 def->dependencies = dependencies;
191 def->dependencyCount = ARRAY_SIZE (dependencies);
192
193 return def;
194 }
195