11 #include <Ecore_File.h>
13 /* define macros and variable for using the eina logging system */
14 #define EFREET_MODULE_LOG_DOM _efreet_xml_log_dom
15 static int _efreet_xml_log_dom = -1;
18 #include "efreet_private.h"
19 #include "efreet_xml.h"
22 static void efreet_xml_dump(Efreet_Xml *xml, int level);
25 static Efreet_Xml *efreet_xml_parse(char **data, int *size);
26 static int efreet_xml_tag_parse(char **data, int *size, const char **tag);
27 static void efreet_xml_attributes_parse(char **data, int *size,
28 Efreet_Xml_Attribute ***attributes);
29 static void efreet_xml_text_parse(char **data, int *size, const char **text);
31 static int efreet_xml_tag_empty(char **data, int *size);
32 static int efreet_xml_tag_close(char **data, int *size, const char *tag);
34 static void efreet_xml_cb_attribute_free(void *data);
35 static void efreet_xml_comment_skip(char **data, int *size);
39 static int _efreet_xml_init_count = 0;
43 * @return Returns > 0 on success or 0 on failure
44 * @brief Initialize the XML parser subsystem
49 _efreet_xml_init_count++;
50 if (_efreet_xml_init_count > 1) return _efreet_xml_init_count;
51 _efreet_xml_log_dom = eina_log_domain_register
52 ("efreet_xml", EFREET_DEFAULT_LOG_COLOR);
53 if (_efreet_xml_log_dom < 0)
55 _efreet_xml_init_count--;
56 EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_xml.");
57 return _efreet_xml_init_count;
59 return _efreet_xml_init_count;
64 * @returns the number of initializations left for this system
65 * @brief Attempts to shut down the subsystem if nothing else is using it
68 efreet_xml_shutdown(void)
70 _efreet_xml_init_count--;
71 if (_efreet_xml_init_count > 0) return;
72 eina_log_domain_unregister(_efreet_xml_log_dom);
73 _efreet_xml_log_dom = -1;
78 * @param file The file to parse
79 * @return Returns an Efreet_Xml structure for the given file @a file or
81 * @brief Parses the given file into an Efreet_Xml structure.
84 efreet_xml_new(const char *file)
86 Efreet_Xml *xml = NULL;
88 char *data = MAP_FAILED;
90 if (!file) return NULL;
91 if (!ecore_file_exists(file)) return NULL;
93 size = ecore_file_size(file);
94 if (size <= 0) goto efreet_error;
96 fd = open(file, O_RDONLY);
97 if (fd == -1) goto efreet_error;
99 /* let's make mmap safe and just get 0 pages for IO erro */
100 eina_mmap_safety_enabled_set(EINA_TRUE);
102 data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
103 if (data == MAP_FAILED) goto efreet_error;
106 xml = efreet_xml_parse(&data, &size);
107 if (!xml || error) goto efreet_error;
114 ERR("could not parse xml file");
115 if (data != MAP_FAILED) munmap(data, size);
116 if (fd != -1) close(fd);
117 if (xml) efreet_xml_del(xml);
123 * @param xml The Efree_Xml to free
124 * @return Returns no value
125 * @brief Frees up the given Efreet_Xml structure
128 efreet_xml_del(Efreet_Xml *xml)
130 IF_FREE_LIST(xml->children, efreet_xml_cb_attribute_free);
132 if (xml->tag) eina_stringshare_del(xml->tag);
135 Efreet_Xml_Attribute **curr;
137 curr = xml->attributes;
140 eina_stringshare_del((*curr)->key);
141 eina_stringshare_del((*curr)->value);
146 FREE(xml->attributes);
148 IF_RELEASE(xml->text);
153 * @param xml The xml struct to work with
154 * @param key The attribute key to look for
155 * @return Returns the value for the given key, or NULL if none found
156 * @brief Retrieves the value for the given attribute key
159 efreet_xml_attribute_get(Efreet_Xml *xml, const char *key)
161 Efreet_Xml_Attribute **curr;
163 if (!xml || !key || !xml->attributes) return NULL;
165 for (curr = xml->attributes; *curr; curr++)
167 if (!strcmp((*curr)->key, key))
168 return (*curr)->value;
174 efreet_xml_cb_attribute_free(void *data)
176 efreet_xml_del(data);
181 efreet_xml_dump(Efreet_Xml *xml, int level)
185 for (i = 0; i < level; i++)
187 printf("<%s", xml->tag);
190 Efreet_Xml_Attribute **curr;
191 for (curr = xml->attributes; *curr; curr++)
192 printf(" %s=\"%s\"", (*curr)->key, (*curr)->value);
202 EINA_LIST_FOREACH(xml->children, l, child)
203 efreet_xml_dump(child, level + 1);
205 for (i = 0; i < level; i++)
207 printf("</%s>", xml->tag);
210 printf(">%s</%s>\n", xml->text, xml->tag);
217 efreet_xml_parse(char **data, int *size)
219 Efreet_Xml *xml, *sub_xml;
220 const char *tag = NULL;
223 if (!efreet_xml_tag_parse(data, size, &(tag))) return NULL;
224 xml = NEW(Efreet_Xml, 1);
227 eina_stringshare_del(tag);
231 xml->children = NULL;
234 efreet_xml_attributes_parse(data, size, &(xml->attributes));
236 /* Check wether element is empty */
237 if (efreet_xml_tag_empty(data, size)) return xml;
238 efreet_xml_text_parse(data, size, &(xml->text));
240 /* Check wether element is closed */
241 if (efreet_xml_tag_close(data, size, xml->tag)) return xml;
243 while ((sub_xml = efreet_xml_parse(data, size)))
244 xml->children = eina_list_append(xml->children, sub_xml);
246 efreet_xml_tag_close(data, size, xml->tag);
252 efreet_xml_tag_parse(char **data, int *size, const char **tag)
254 const char *start = NULL, *end = NULL;
261 /* Check for tag start */
264 /* Check for end tag */
265 if (*(*data + 1) == '/') return 0;
268 if (*size > 3 && *(*data + 1) == '!' && *(*data + 2) == '-' && *(*data + 3) == '-')
272 efreet_xml_comment_skip(data, size);
276 /* Check for xml directives (and ignore them) */
277 else if ((*(*data + 1) != '!') && (*(*data + 1) != '?'))
291 ERR("missing start tag");
298 if (!isalpha(**data))
309 ERR("no end of tag");
314 buf_size = end - start + 1;
322 if (buf_size > 256) buf_size = 256;
323 memcpy(buf, start, buf_size - 1);
324 buf[buf_size - 1] = '\0';
325 *tag = eina_stringshare_add(buf);
331 efreet_xml_attributes_parse(char **data, int *size,
332 Efreet_Xml_Attribute ***attributes)
334 Efreet_Xml_Attribute attr[10];
345 else if ((count < 10) && (isalpha(**data)))
347 /* beginning of key */
348 const char *start = NULL, *end = NULL;
352 attr[count].key = NULL;
353 attr[count].value = NULL;
356 while ((*size > 0) && ((isalpha(**data)) || (**data == '_')))
363 buf_size = end - start + 1;
366 ERR("zero length key");
370 if (buf_size > 256) buf_size = 256;
371 memcpy(buf, start, buf_size - 1);
372 buf[buf_size - 1] = '\0';
373 attr[count].key = eina_stringshare_add(buf);
375 /* search for '=', key/value seperator */
390 ERR("missing value for attribute!");
394 /* search for '"', beginning of value */
409 ERR("erroneous value for attribute!");
418 /* search for '"', end of value */
433 ERR("erroneous value for attribute!");
437 buf_size = end - start + 1;
440 ERR("zero length value");
444 if (buf_size > 256) buf_size = 256;
445 memcpy(buf, start, buf_size - 1);
446 buf[buf_size - 1] = '\0';
447 attr[count].value = eina_stringshare_add(buf);
456 *attributes = NEW(Efreet_Xml_Attribute *, count + 1);
457 if (!*attributes) goto efreet_error;
458 for (i = 0; i < count; i++)
460 (*attributes)[i] = malloc(sizeof(Efreet_Xml_Attribute));
461 (*attributes)[i]->key = attr[i].key;
462 (*attributes)[i]->value = attr[i].value;
469 if (attr[count].key) eina_stringshare_del(attr[count].key);
470 if (attr[count].value) eina_stringshare_del(attr[count].value);
478 efreet_xml_text_parse(char **data, int *size, const char **text)
480 const char *start = NULL, *end = NULL;
483 /* skip leading whitespace */
486 if (!isspace(**data))
510 /* skip trailing whitespace */
511 while (isspace(*(end - 1))) end--;
514 buf_size = end - start + 1;
515 if (buf_size <= 1) return;
517 *text = eina_stringshare_add_length(start, buf_size - 1);
521 efreet_xml_tag_empty(char **data, int *size)
536 else if (**data == '>')
545 ERR("missing end of tag");
552 efreet_xml_tag_close(char **data, int *size, const char *tag)
558 if (*(*data + 1) == '/')
562 if ((int)strlen(tag) > *size)
564 ERR("wrong end tag");
572 while ((*tag) && (*tmp == *tag))
580 ERR("wrong end tag");
596 efreet_xml_comment_skip(char **data, int *size)
600 if (**data == '-' && *(*data + 1) == '-' && *(*data + 2) == '>')