1 /*
2 * Attribute support code for Mini-XML, a small XML file parsing library.
3 *
4 * https://www.msweet.org/mxml
5 *
6 * Copyright © 2003-2019 by Michael R Sweet.
7 *
8 * Licensed under Apache License v2.0. See the file "LICENSE" for more
9 * information.
10 */
11
12 /*
13 * Include necessary headers...
14 */
15
16 #include "config.h"
17 #include "mxml-private.h"
18
19
20 /*
21 * Local functions...
22 */
23
24 static int mxml_set_attr(mxml_node_t *node, const char *name, char *value);
25
26
27 /*
28 * 'mxmlElementDeleteAttr()' - Delete an attribute.
29 *
30 * @since Mini-XML 2.4@
31 */
32
33 void
mxmlElementDeleteAttr(mxml_node_t * node,const char * name)34 mxmlElementDeleteAttr(mxml_node_t *node,/* I - Element */
35 const char *name)/* I - Attribute name */
36 {
37 int i; /* Looping var */
38 _mxml_attr_t *attr; /* Cirrent attribute */
39
40
41 #ifdef DEBUG
42 fprintf(stderr, "mxmlElementDeleteAttr(node=%p, name=\"%s\")\n",
43 node, name ? name : "(null)");
44 #endif /* DEBUG */
45
46 /*
47 * Range check input...
48 */
49
50 if (!node || node->type != MXML_ELEMENT || !name)
51 return;
52
53 /*
54 * Look for the attribute...
55 */
56
57 for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
58 i > 0;
59 i --, attr ++)
60 {
61 #ifdef DEBUG
62 printf(" %s=\"%s\"\n", attr->name, attr->value);
63 #endif /* DEBUG */
64
65 if (!strcmp(attr->name, name))
66 {
67 /*
68 * Delete this attribute...
69 */
70
71 free(attr->name);
72 free(attr->value);
73
74 i --;
75 if (i > 0)
76 memmove(attr, attr + 1, i * sizeof(_mxml_attr_t));
77
78 node->value.element.num_attrs --;
79
80 if (node->value.element.num_attrs == 0)
81 free(node->value.element.attrs);
82 return;
83 }
84 }
85 }
86
87
88 /*
89 * 'mxmlElementGetAttr()' - Get an attribute.
90 *
91 * This function returns @code NULL@ if the node is not an element or the
92 * named attribute does not exist.
93 */
94
95 const char * /* O - Attribute value or @code NULL@ */
mxmlElementGetAttr(mxml_node_t * node,const char * name)96 mxmlElementGetAttr(mxml_node_t *node, /* I - Element node */
97 const char *name) /* I - Name of attribute */
98 {
99 int i; /* Looping var */
100 _mxml_attr_t *attr; /* Cirrent attribute */
101
102
103 #ifdef DEBUG
104 fprintf(stderr, "mxmlElementGetAttr(node=%p, name=\"%s\")\n",
105 node, name ? name : "(null)");
106 #endif /* DEBUG */
107
108 /*
109 * Range check input...
110 */
111
112 if (!node || node->type != MXML_ELEMENT || !name)
113 return (NULL);
114
115 /*
116 * Look for the attribute...
117 */
118
119 for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
120 i > 0;
121 i --, attr ++)
122 {
123 #ifdef DEBUG
124 printf(" %s=\"%s\"\n", attr->name, attr->value);
125 #endif /* DEBUG */
126
127 if (!strcmp(attr->name, name))
128 {
129 #ifdef DEBUG
130 printf(" Returning \"%s\"!\n", attr->value);
131 #endif /* DEBUG */
132 return (attr->value);
133 }
134 }
135
136 /*
137 * Didn't find attribute, so return NULL...
138 */
139
140 #ifdef DEBUG
141 puts(" Returning NULL!\n");
142 #endif /* DEBUG */
143
144 return (NULL);
145 }
146
147
148 /*
149 * 'mxmlElementGetAttrByIndex()' - Get an element attribute by index.
150 *
151 * The index ("idx") is 0-based. @code NULL@ is returned if the specified index
152 * is out of range.
153 *
154 * @since Mini-XML 2.11@
155 */
156
157 const char * /* O - Attribute value */
mxmlElementGetAttrByIndex(mxml_node_t * node,int idx,const char ** name)158 mxmlElementGetAttrByIndex(
159 mxml_node_t *node, /* I - Node */
160 int idx, /* I - Attribute index, starting at 0 */
161 const char **name) /* O - Attribute name */
162 {
163 if (!node || node->type != MXML_ELEMENT || idx < 0 || idx >= node->value.element.num_attrs)
164 return (NULL);
165
166 if (name)
167 *name = node->value.element.attrs[idx].name;
168
169 return (node->value.element.attrs[idx].value);
170 }
171
172
173 /*
174 * 'mxmlElementGetAttrCount()' - Get the number of element attributes.
175 *
176 * @since Mini-XML 2.11@
177 */
178
179 int /* O - Number of attributes */
mxmlElementGetAttrCount(mxml_node_t * node)180 mxmlElementGetAttrCount(
181 mxml_node_t *node) /* I - Node */
182 {
183 if (node && node->type == MXML_ELEMENT)
184 return (node->value.element.num_attrs);
185 else
186 return (0);
187 }
188
189
190 /*
191 * 'mxmlElementSetAttr()' - Set an attribute.
192 *
193 * If the named attribute already exists, the value of the attribute
194 * is replaced by the new string value. The string value is copied
195 * into the element node. This function does nothing if the node is
196 * not an element.
197 */
198
199 void
mxmlElementSetAttr(mxml_node_t * node,const char * name,const char * value)200 mxmlElementSetAttr(mxml_node_t *node, /* I - Element node */
201 const char *name, /* I - Name of attribute */
202 const char *value) /* I - Attribute value */
203 {
204 char *valuec; /* Copy of value */
205
206
207 #ifdef DEBUG
208 fprintf(stderr, "mxmlElementSetAttr(node=%p, name=\"%s\", value=\"%s\")\n",
209 node, name ? name : "(null)", value ? value : "(null)");
210 #endif /* DEBUG */
211
212 /*
213 * Range check input...
214 */
215
216 if (!node || node->type != MXML_ELEMENT || !name)
217 return;
218
219 if (value)
220 valuec = strdup(value);
221 else
222 valuec = NULL;
223
224 if (mxml_set_attr(node, name, valuec))
225 free(valuec);
226 }
227
228
229 /*
230 * 'mxmlElementSetAttrf()' - Set an attribute with a formatted value.
231 *
232 * If the named attribute already exists, the value of the attribute
233 * is replaced by the new formatted string. The formatted string value is
234 * copied into the element node. This function does nothing if the node
235 * is not an element.
236 *
237 * @since Mini-XML 2.3@
238 */
239
240 void
mxmlElementSetAttrf(mxml_node_t * node,const char * name,const char * format,...)241 mxmlElementSetAttrf(mxml_node_t *node, /* I - Element node */
242 const char *name, /* I - Name of attribute */
243 const char *format,/* I - Printf-style attribute value */
244 ...) /* I - Additional arguments as needed */
245 {
246 va_list ap; /* Argument pointer */
247 char *value; /* Value */
248
249
250 #ifdef DEBUG
251 fprintf(stderr,
252 "mxmlElementSetAttrf(node=%p, name=\"%s\", format=\"%s\", ...)\n",
253 node, name ? name : "(null)", format ? format : "(null)");
254 #endif /* DEBUG */
255
256 /*
257 * Range check input...
258 */
259
260 if (!node || node->type != MXML_ELEMENT || !name || !format)
261 return;
262
263 /*
264 * Format the value...
265 */
266
267 va_start(ap, format);
268 value = _mxml_vstrdupf(format, ap);
269 va_end(ap);
270
271 if (!value)
272 mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
273 name, node->value.element.name);
274 else if (mxml_set_attr(node, name, value))
275 free(value);
276 }
277
278
279 /*
280 * 'mxml_set_attr()' - Set or add an attribute name/value pair.
281 */
282
283 static int /* O - 0 on success, -1 on failure */
mxml_set_attr(mxml_node_t * node,const char * name,char * value)284 mxml_set_attr(mxml_node_t *node, /* I - Element node */
285 const char *name, /* I - Attribute name */
286 char *value) /* I - Attribute value */
287 {
288 int i; /* Looping var */
289 _mxml_attr_t *attr; /* New attribute */
290
291
292 /*
293 * Look for the attribute...
294 */
295
296 for (i = node->value.element.num_attrs, attr = node->value.element.attrs;
297 i > 0;
298 i --, attr ++)
299 if (!strcmp(attr->name, name))
300 {
301 /*
302 * Free the old value as needed...
303 */
304
305 if (attr->value)
306 free(attr->value);
307
308 attr->value = value;
309
310 return (0);
311 }
312
313 /*
314 * Add a new attribute...
315 */
316
317 if (node->value.element.num_attrs == 0)
318 attr = malloc(sizeof(_mxml_attr_t));
319 else
320 attr = realloc(node->value.element.attrs,
321 (node->value.element.num_attrs + 1) * sizeof(_mxml_attr_t));
322
323 if (!attr)
324 {
325 mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
326 name, node->value.element.name);
327 return (-1);
328 }
329
330 node->value.element.attrs = attr;
331 attr += node->value.element.num_attrs;
332
333 if ((attr->name = strdup(name)) == NULL)
334 {
335 mxml_error("Unable to allocate memory for attribute '%s' in element %s!",
336 name, node->value.element.name);
337 return (-1);
338 }
339
340 attr->value = value;
341
342 node->value.element.num_attrs ++;
343
344 return (0);
345 }
346