create ObParseInst structuer which can be then used to parse more than one file/memor...
[dana/openbox.git] / parser / parse.c
1 #include "parse.h"
2 #include <glib.h>
3
4 struct Callback {
5     char *tag;
6     ParseCallback func;
7     void *data;
8 };
9
10 struct _ObParseInst {
11     GHashTable *callbacks;
12 };
13
14 static void destfunc(struct Callback *c)
15 {
16     g_free(c->tag);
17     g_free(c);
18 }
19
20 ObParseInst* parse_startup()
21 {
22     ObParseInst *i = g_new(ObParseInst, 1);
23     i->callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
24                                          (GDestroyNotify)destfunc);
25     return i;
26 }
27
28 void parse_shutdown(ObParseInst *i)
29 {
30     if (i) {
31         g_hash_table_destroy(i->callbacks);
32         g_free(i);
33     }
34 }
35
36 void parse_register(ObParseInst *i, const char *tag,
37                     ParseCallback func, void *data)
38 {
39     struct Callback *c;
40
41     if ((c = g_hash_table_lookup(i->callbacks, tag))) {
42         g_warning("tag '%s' already registered", tag);
43         return;
44     }
45
46     c = g_new(struct Callback, 1);
47     c->tag = g_strdup(tag);
48     c->func = func;
49     c->data = data;
50     g_hash_table_insert(i->callbacks, c->tag, c);
51 }
52
53 gboolean parse_load_rc(xmlDocPtr *doc, xmlNodePtr *root)
54 {
55     char *path;
56     gboolean r = FALSE;
57
58     path = g_build_filename(g_get_home_dir(), ".openbox", "rc3", NULL);
59     if (parse_load(path, "openbox_config", doc, root)) {
60         r = TRUE;
61     } else {
62         g_free(path);
63         path = g_build_filename(RCDIR, "rc3", NULL);
64         if (parse_load(path, "openbox_config", doc, root)) {
65             r = TRUE;
66         }
67     }
68     g_free(path);
69     if (!r)
70         g_warning("unable to find a valid config file, using defaults");
71     return r;
72 }
73
74 gboolean parse_load(const char *path, const char *rootname,
75                     xmlDocPtr *doc, xmlNodePtr *root)
76 {
77     xmlLineNumbersDefault(1);
78
79     if ((*doc = xmlParseFile(path))) {
80         *root = xmlDocGetRootElement(*doc);
81         if (!*root) {
82             xmlFreeDoc(*doc);
83             *doc = NULL;
84             g_warning("%s is an empty document", path);
85         } else {
86             if (xmlStrcasecmp((*root)->name, (const xmlChar*)rootname)) {
87                 xmlFreeDoc(*doc);
88                 *doc = NULL;
89                 g_warning("document %s is of wrong type. root node is "
90                           "not '%s'", path, rootname);
91             }
92         }
93     }
94     if (!*doc)
95         return FALSE;
96     return TRUE;
97 }
98
99 gboolean parse_load_mem(gpointer data, guint len, const char *rootname,
100                         xmlDocPtr *doc, xmlNodePtr *root)
101 {
102     xmlLineNumbersDefault(1);
103
104     if ((*doc = xmlParseMemory(data, len))) {
105         *root = xmlDocGetRootElement(*doc);
106         if (!*root) {
107             xmlFreeDoc(*doc);
108             *doc = NULL;
109             g_warning("Given memory is an empty document");
110         } else {
111             if (xmlStrcasecmp((*root)->name, (const xmlChar*)rootname)) {
112                 xmlFreeDoc(*doc);
113                 *doc = NULL;
114                 g_warning("document in given memory is of wrong type. root "
115                           "node is not '%s'", rootname);
116             }
117         }
118     }
119     if (!*doc)
120         return FALSE;
121     return TRUE;
122 }
123
124 void parse_close(xmlDocPtr doc)
125 {
126     xmlFree(doc);
127 }
128
129 void parse_tree(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
130 {
131     while (node) {
132         struct Callback *c = g_hash_table_lookup(i->callbacks, node->name);
133
134         if (c)
135             c->func(i, doc, node, c->data);
136
137         node = node->next;
138     }
139 }
140
141 char *parse_string(xmlDocPtr doc, xmlNodePtr node)
142 {
143     xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
144     char *s = g_strdup(c ? (char*)c : "");
145     xmlFree(c);
146     return s;
147 }
148
149 int parse_int(xmlDocPtr doc, xmlNodePtr node)
150 {
151     xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
152     int i = atoi((char*)c);
153     xmlFree(c);
154     return i;
155 }
156
157 gboolean parse_bool(xmlDocPtr doc, xmlNodePtr node)
158 {
159     xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
160     gboolean b = FALSE;
161     if (!xmlStrcasecmp(c, (const xmlChar*) "true"))
162         b = TRUE;
163     else if (!xmlStrcasecmp(c, (const xmlChar*) "yes"))
164         b = TRUE;
165     else if (!xmlStrcasecmp(c, (const xmlChar*) "on"))
166         b = TRUE;
167     xmlFree(c);
168     return b;
169 }
170
171 gboolean parse_contains(const char *val, xmlDocPtr doc, xmlNodePtr node)
172 {
173     xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
174     gboolean r;
175     r = !xmlStrcasecmp(c, (const xmlChar*) val);
176     xmlFree(c);
177     return r;
178 }
179
180 xmlNodePtr parse_find_node(const char *tag, xmlNodePtr node)
181 {
182     while (node) {
183         if (!xmlStrcasecmp(node->name, (const xmlChar*) tag))
184             return node;
185         node = node->next;
186     }
187     return NULL;
188 }
189
190 gboolean parse_attr_int(const char *name, xmlNodePtr node, int *value)
191 {
192     xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
193     gboolean r = FALSE;
194     if (c) {
195         *value = atoi((char*)c);
196         r = TRUE;
197     }
198     xmlFree(c);
199     return r;
200 }
201
202 gboolean parse_attr_string(const char *name, xmlNodePtr node, char **value)
203 {
204     xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
205     gboolean r = FALSE;
206     if (c) {
207         *value = g_strdup((char*)c);
208         r = TRUE;
209     }
210     xmlFree(c);
211     return r;
212 }
213
214 gboolean parse_attr_contains(const char *val, xmlNodePtr node,
215                              const char *name)
216 {
217     xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
218     gboolean r;
219     r = !xmlStrcasecmp(c, (const xmlChar*) val);
220     xmlFree(c);
221     return r;
222 }