not being developed anymore, maybe in the future...
[dana/openbox.git] / openbox / 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 static xmlDocPtr doc_config = NULL;
12
13 static void destfunc(struct Callback *c)
14 {
15     g_free(c->tag);
16     g_free(c);
17 }
18
19 void parse_startup()
20 {
21     callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
22                                       (GDestroyNotify)destfunc);
23 }
24
25 void parse_shutdown()
26 {
27     xmlFree(doc_config);
28     doc_config = NULL;
29
30     g_hash_table_destroy(callbacks);
31 }
32
33 void parse_register(const char *tag, ParseCallback func, void *data)
34 {
35     struct Callback *c;
36
37     if ((c = g_hash_table_lookup(callbacks, tag))) {
38         g_warning("tag '%s' already registered", tag);
39         return;
40     }
41
42     c = g_new(struct Callback, 1);
43     c->tag = g_strdup(tag);
44     c->func = func;
45     c->data = data;
46     g_hash_table_insert(callbacks, c->tag, c);
47 }
48
49 void parse_config()
50 {
51     char *path;
52     xmlNodePtr node = NULL;
53
54     xmlLineNumbersDefault(1);
55
56     path = g_build_filename(g_get_home_dir(), ".openbox", "rc3", NULL);
57     if ((doc_config = xmlParseFile(path))) {
58         node = xmlDocGetRootElement(doc_config);
59         if (!node) {
60             xmlFreeDoc(doc_config);
61             doc_config = NULL;
62             g_warning("%s is an empty document", path);
63         } else {
64             if (xmlStrcasecmp(node->name, (const xmlChar*)"openbox_config")) {
65                 xmlFreeDoc(doc_config);
66                 doc_config = NULL;
67                 g_warning("document %s is of wrong type. root node is "
68                           "not 'openbox_config'", path);
69             }
70         }
71     }
72     g_free(path);
73     if (!doc_config) {
74         path = g_build_filename(RCDIR, "rc3", NULL);
75         if ((doc_config = xmlParseFile(path))) {
76             node = xmlDocGetRootElement(doc_config);
77             if (!node) {
78                 xmlFreeDoc(doc_config);
79                 doc_config = NULL;
80                 g_warning("%s is an empty document", path);
81             } else {
82                 if (xmlStrcasecmp(node->name,
83                                   (const xmlChar*)"openbox_config")) {
84                     xmlFreeDoc(doc_config);
85                     doc_config = NULL;
86                     g_warning("document %s is of wrong type. root node is "
87                               "not 'openbox_config'", path);
88                 }
89             }
90         }
91         g_free(path);
92     }
93     if (!doc_config) {
94         g_message("unable to find a valid config file, using defaults");
95     } else {
96         parse_tree(doc_config, node->xmlChildrenNode, NULL);
97     }
98 }
99
100 void parse_tree(xmlDocPtr doc, xmlNodePtr node, void *nothing)
101 {
102     while (node) {
103         struct Callback *c = g_hash_table_lookup(callbacks, node->name);
104
105         if (c)
106             c->func(doc, node->xmlChildrenNode, c->data);
107
108         node = node->next;
109     }
110 }
111
112 char *parse_string(xmlDocPtr doc, xmlNodePtr node)
113 {
114     xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
115     char *s = g_strdup((char*)c);
116     xmlFree(c);
117     return s;
118 }
119
120 int parse_int(xmlDocPtr doc, xmlNodePtr node)
121 {
122     xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
123     int i = atoi((char*)c);
124     xmlFree(c);
125     return i;
126 }
127
128 gboolean parse_bool(xmlDocPtr doc, xmlNodePtr node)
129 {
130     xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
131     gboolean b = FALSE;
132     if (!xmlStrcasecmp(c, (const xmlChar*) "true"))
133         b = TRUE;
134     else if (!xmlStrcasecmp(c, (const xmlChar*) "yes"))
135         b = TRUE;
136     else if (!xmlStrcasecmp(c, (const xmlChar*) "on"))
137         b = TRUE;
138     xmlFree(c);
139     return b;
140 }
141
142 gboolean parse_contains(const char *val, xmlDocPtr doc, xmlNodePtr node)
143 {
144     xmlChar *c = xmlNodeListGetString(doc, node->xmlChildrenNode, TRUE);
145     gboolean r;
146     r = !xmlStrcasecmp(c, (const xmlChar*) val);
147     xmlFree(c);
148     return r;
149 }
150
151 xmlNodePtr parse_find_node(const char *tag, xmlNodePtr node)
152 {
153     while (node) {
154         if (!xmlStrcasecmp(node->name, (const xmlChar*) tag))
155             return node;
156         node = node->next;
157     }
158     return NULL;
159 }
160
161 gboolean parse_attr_int(const char *name, xmlNodePtr node, int *value)
162 {
163     xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
164     gboolean r = FALSE;
165     if (c) {
166         *value = atoi((char*)c);
167         r = TRUE;
168     }
169     xmlFree(c);
170     return r;
171 }
172
173 gboolean parse_attr_string(const char *name, xmlNodePtr node, char **value)
174 {
175     xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
176     gboolean r = FALSE;
177     if (c) {
178         *value = g_strdup((char*)c);
179         r = TRUE;
180     }
181     xmlFree(c);
182     return r;
183 }
184
185 Action *parse_action(xmlDocPtr doc, xmlNodePtr node)
186 {
187     char *actname;
188     Action *act = NULL;
189     xmlNodePtr n;
190
191     if (parse_attr_string("name", node, &actname)) {
192         if ((act = action_from_string(actname))) {
193             if (act->func == action_execute || act->func == action_restart) {
194                 if ((n = parse_find_node("execute", node->xmlChildrenNode)))
195                     act->data.execute.path = parse_string(doc, n);
196             } else if (act->func == action_showmenu) {
197                 if ((n = parse_find_node("menu", node->xmlChildrenNode)))
198                     act->data.showmenu.name = parse_string(doc, n);
199             } else if (act->func == action_desktop) {
200                 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
201                     act->data.desktop.desk = parse_int(doc, n);
202                 if (act->data.desktop.desk > 0) act->data.desktop.desk--;
203             } else if (act->func == action_send_to_desktop) {
204                 if ((n = parse_find_node("desktop", node->xmlChildrenNode)))
205                     act->data.sendto.desk = parse_int(doc, n);
206                 if (act->data.sendto.desk > 0) act->data.sendto.desk--;
207             } else if (act->func == action_move_relative_horz ||
208                        act->func == action_move_relative_vert ||
209                        act->func == action_resize_relative_horz ||
210                        act->func == action_resize_relative_vert) {
211                 if ((n = parse_find_node("delta", node->xmlChildrenNode)))
212                     act->data.relative.delta = parse_int(doc, n);
213             } else if (act->func == action_desktop_right ||
214                        act->func == action_desktop_left ||
215                        act->func == action_desktop_up ||
216                        act->func == action_desktop_down) {
217                 if ((n = parse_find_node("wrap", node->xmlChildrenNode))) {
218                     g_message("WRAP %d", parse_bool(doc, n));
219                     act->data.desktopdir.wrap = parse_bool(doc, n);
220                 }
221             } else if (act->func == action_send_to_desktop_right ||
222                        act->func == action_send_to_desktop_left ||
223                        act->func == action_send_to_desktop_up ||
224                        act->func == action_send_to_desktop_down) {
225                 if ((n = parse_find_node("wrap", node->xmlChildrenNode)))
226                     act->data.sendtodir.wrap = parse_bool(doc, n);
227                 if ((n = parse_find_node("follow", node->xmlChildrenNode)))
228                     act->data.sendtodir.follow = parse_bool(doc, n);
229             }
230         }
231     }
232     return act;
233 }
234
235 gboolean parse_attr_contains(const char *val, xmlNodePtr node,
236                              const char *name)
237 {
238     xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
239     gboolean r;
240     r = !xmlStrcasecmp(c, (const xmlChar*) val);
241     xmlFree(c);
242     return r;
243 }