* Change xml parsing to pass the parent node, rather than the first
[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 static GHashTable *callbacks;
11
12 static void destfunc(struct Callback *c)
13 {
14     g_free(c->tag);
15     g_free(c);
16 }
17
18 void parse_startup()
19 {
20     callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
21                                       (GDestroyNotify)destfunc);
22 }
23
24 void parse_shutdown()
25 {
26     g_hash_table_destroy(callbacks);
27 }
28
29 void parse_register(const char *tag, ParseCallback func, void *data)
30 {
31     struct Callback *c;
32
33     if ((c = g_hash_table_lookup(callbacks, tag))) {
34         g_warning("tag '%s' already registered", tag);
35         return;
36     }
37
38     c = g_new(struct Callback, 1);
39     c->tag = g_strdup(tag);
40     c->func = func;
41     c->data = data;
42     g_hash_table_insert(callbacks, c->tag, c);
43 }
44
45 gboolean parse_load_rc(xmlDocPtr *doc, xmlNodePtr *root)
46 {
47     char *path;
48     gboolean r = FALSE;
49
50     path = g_build_filename(g_get_home_dir(), ".openbox", "rc3", NULL);
51     if (parse_load(path, "openbox_config", doc, root)) {
52         r = TRUE;
53     } else {
54         g_free(path);
55         path = g_build_filename(RCDIR, "rc3", NULL);
56         if (parse_load(path, "openbox_config", doc, root)) {
57             r = TRUE;
58         }
59     }
60     g_free(path);
61     if (!r)
62         g_message("unable to find a valid config file, using defaults");
63     return r;
64 }
65
66 gboolean parse_load(const char *path, const char *rootname,
67                     xmlDocPtr *doc, xmlNodePtr *root)
68 {
69
70     xmlLineNumbersDefault(1);
71
72     if ((*doc = xmlParseFile(path))) {
73         *root = xmlDocGetRootElement(*doc);
74         if (!*root) {
75             xmlFreeDoc(*doc);
76             *doc = NULL;
77             g_warning("%s is an empty document", path);
78         } else {
79             if (xmlStrcasecmp((*root)->name, (const xmlChar*)rootname)) {
80                 xmlFreeDoc(*doc);
81                 *doc = NULL;
82                 g_warning("document %s is of wrong type. root *root is "
83                           "not 'openbox_config'", path);
84             }
85         }
86     }
87     if (!*doc)
88         return FALSE;
89     return TRUE;
90 }
91
92 void parse_close(xmlDocPtr doc)
93 {
94     xmlFree(doc);
95 }
96
97 void parse_tree(xmlDocPtr doc, xmlNodePtr node, void *nothing)
98 {
99     while (node) {
100         struct Callback *c = g_hash_table_lookup(callbacks, node->name);
101
102         if (c)
103             c->func(doc, node, c->data);
104
105         node = node->next;
106     }
107 }
108
109 char *parse_string(xmlDocPtr doc, xmlNodePtr node)
110 {
111     xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
112     char *s = g_strdup((char*)c);
113     xmlFree(c);
114     return s;
115 }
116
117 int parse_int(xmlDocPtr doc, xmlNodePtr node)
118 {
119     xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
120     int i = atoi((char*)c);
121     xmlFree(c);
122     return i;
123 }
124
125 gboolean parse_bool(xmlDocPtr doc, xmlNodePtr node)
126 {
127     xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
128     gboolean b = FALSE;
129     if (!xmlStrcasecmp(c, (const xmlChar*) "true"))
130         b = TRUE;
131     else if (!xmlStrcasecmp(c, (const xmlChar*) "yes"))
132         b = TRUE;
133     else if (!xmlStrcasecmp(c, (const xmlChar*) "on"))
134         b = TRUE;
135     xmlFree(c);
136     return b;
137 }
138
139 gboolean parse_contains(const char *val, xmlDocPtr doc, xmlNodePtr node)
140 {
141     xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
142     gboolean r;
143     r = !xmlStrcasecmp(c, (const xmlChar*) val);
144     xmlFree(c);
145     return r;
146 }
147
148 xmlNodePtr parse_find_node(const char *tag, xmlNodePtr node)
149 {
150     while (node) {
151         if (!xmlStrcasecmp(node->name, (const xmlChar*) tag))
152             return node;
153         node = node->next;
154     }
155     return NULL;
156 }
157
158 gboolean parse_attr_int(const char *name, xmlNodePtr node, int *value)
159 {
160     xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
161     gboolean r = FALSE;
162     if (c) {
163         *value = atoi((char*)c);
164         r = TRUE;
165     }
166     xmlFree(c);
167     return r;
168 }
169
170 gboolean parse_attr_string(const char *name, xmlNodePtr node, char **value)
171 {
172     xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
173     gboolean r = FALSE;
174     if (c) {
175         *value = g_strdup((char*)c);
176         r = TRUE;
177     }
178     xmlFree(c);
179     return r;
180 }
181
182 gboolean parse_attr_contains(const char *val, xmlNodePtr node,
183                              const char *name)
184 {
185     xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
186     gboolean r;
187     r = !xmlStrcasecmp(c, (const xmlChar*) val);
188     xmlFree(c);
189     return r;
190 }