]> Dogcows Code - chaz/openbox/blob - parser/parse.c
changes
[chaz/openbox] / parser / parse.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 parse.c for the Openbox window manager
4 Copyright (c) 2003 Ben Jansens
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 See the COPYING file for a copy of the GNU General Public License.
17 */
18
19 #include "parse.h"
20 #include <glib.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24
25 static gboolean xdg_start;
26 static gchar *xdg_config_home_path;
27 static gchar *xdg_data_home_path;
28 static GSList *xdg_config_dir_paths;
29 static GSList *xdg_data_dir_paths;
30
31 struct Callback {
32 gchar *tag;
33 ParseCallback func;
34 void *data;
35 };
36
37 struct _ObParseInst {
38 GHashTable *callbacks;
39 };
40
41 static void destfunc(struct Callback *c)
42 {
43 g_free(c->tag);
44 g_free(c);
45 }
46
47 ObParseInst* parse_startup()
48 {
49 ObParseInst *i = g_new(ObParseInst, 1);
50 i->callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
51 (GDestroyNotify)destfunc);
52 return i;
53 }
54
55 void parse_shutdown(ObParseInst *i)
56 {
57 if (i) {
58 g_hash_table_destroy(i->callbacks);
59 g_free(i);
60 }
61 }
62
63 void parse_register(ObParseInst *i, const gchar *tag,
64 ParseCallback func, void *data)
65 {
66 struct Callback *c;
67
68 if ((c = g_hash_table_lookup(i->callbacks, tag))) {
69 g_warning("tag '%s' already registered", tag);
70 return;
71 }
72
73 c = g_new(struct Callback, 1);
74 c->tag = g_strdup(tag);
75 c->func = func;
76 c->data = data;
77 g_hash_table_insert(i->callbacks, c->tag, c);
78 }
79
80 gboolean parse_load_rc(xmlDocPtr *doc, xmlNodePtr *root)
81 {
82 GSList *it;
83 gchar *path;
84 gboolean r = FALSE;
85
86 for (it = xdg_config_dir_paths; !r && it; it = g_slist_next(it)) {
87 path = g_build_filename(it->data, "openbox", "rc.xml", NULL);
88 r = parse_load(path, "openbox_config", doc, root);
89 g_free(path);
90 }
91 if (!r)
92 g_warning("unable to find a valid config file, using defaults");
93 return r;
94 }
95
96 gboolean parse_load_menu(const gchar *file, xmlDocPtr *doc, xmlNodePtr *root)
97 {
98 GSList *it;
99 gchar *path;
100 gboolean r = FALSE;
101
102 if (file[0] == '/') {
103 r = parse_load(file, "openbox_menu", doc, root);
104 } else {
105 for (it = xdg_config_dir_paths; !r && it; it = g_slist_next(it)) {
106 path = g_build_filename(it->data, "openbox", file, NULL);
107 r = parse_load(path, "openbox_menu", doc, root);
108 g_free(path);
109 }
110 }
111 if (!r)
112 g_warning("unable to find a valid menu file '%s'", file);
113 return r;
114 }
115
116 gboolean parse_load(const gchar *path, const gchar *rootname,
117 xmlDocPtr *doc, xmlNodePtr *root)
118 {
119 if ((*doc = xmlParseFile(path))) {
120 *root = xmlDocGetRootElement(*doc);
121 if (!*root) {
122 xmlFreeDoc(*doc);
123 *doc = NULL;
124 g_warning("%s is an empty document", path);
125 } else {
126 if (xmlStrcasecmp((*root)->name, (const xmlChar*)rootname)) {
127 xmlFreeDoc(*doc);
128 *doc = NULL;
129 g_warning("document %s is of wrong type. root node is "
130 "not '%s'", path, rootname);
131 }
132 }
133 }
134 if (!*doc)
135 return FALSE;
136 return TRUE;
137 }
138
139 gboolean parse_load_mem(gpointer data, guint len, const gchar *rootname,
140 xmlDocPtr *doc, xmlNodePtr *root)
141 {
142 if ((*doc = xmlParseMemory(data, len))) {
143 *root = xmlDocGetRootElement(*doc);
144 if (!*root) {
145 xmlFreeDoc(*doc);
146 *doc = NULL;
147 g_warning("Given memory is an empty document");
148 } else {
149 if (xmlStrcasecmp((*root)->name, (const xmlChar*)rootname)) {
150 xmlFreeDoc(*doc);
151 *doc = NULL;
152 g_warning("document in given memory is of wrong type. root "
153 "node is not '%s'", rootname);
154 }
155 }
156 }
157 if (!*doc)
158 return FALSE;
159 return TRUE;
160 }
161
162 void parse_close(xmlDocPtr doc)
163 {
164 xmlFreeDoc(doc);
165 }
166
167 void parse_tree(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
168 {
169 while (node) {
170 struct Callback *c = g_hash_table_lookup(i->callbacks, node->name);
171
172 if (c)
173 c->func(i, doc, node, c->data);
174
175 node = node->next;
176 }
177 }
178
179 gchar *parse_string(xmlDocPtr doc, xmlNodePtr node)
180 {
181 xmlChar *c = xmlNodeListGetString(doc, node->children, TRUE);
182 gchar *s = g_strdup(c ? (gchar*)c : "");
183 xmlFree(c);
184 return s;
185 }
186
187 gint parse_int(xmlDocPtr doc, xmlNodePtr node)
188 {
189 xmlChar *c = xmlNodeListGetString(doc, node->children, TRUE);
190 gint i = atoi((gchar*)c);
191 xmlFree(c);
192 return i;
193 }
194
195 gboolean parse_bool(xmlDocPtr doc, xmlNodePtr node)
196 {
197 xmlChar *c = xmlNodeListGetString(doc, node->children, TRUE);
198 gboolean b = FALSE;
199 if (!xmlStrcasecmp(c, (const xmlChar*) "true"))
200 b = TRUE;
201 else if (!xmlStrcasecmp(c, (const xmlChar*) "yes"))
202 b = TRUE;
203 else if (!xmlStrcasecmp(c, (const xmlChar*) "on"))
204 b = TRUE;
205 xmlFree(c);
206 return b;
207 }
208
209 gboolean parse_contains(const gchar *val, xmlDocPtr doc, xmlNodePtr node)
210 {
211 xmlChar *c = xmlNodeListGetString(doc, node->children, TRUE);
212 gboolean r;
213 r = !xmlStrcasecmp(c, (const xmlChar*) val);
214 xmlFree(c);
215 return r;
216 }
217
218 xmlNodePtr parse_find_node(const gchar *tag, xmlNodePtr node)
219 {
220 while (node) {
221 if (!xmlStrcasecmp(node->name, (const xmlChar*) tag))
222 return node;
223 node = node->next;
224 }
225 return NULL;
226 }
227
228 gboolean parse_attr_int(const gchar *name, xmlNodePtr node, gint *value)
229 {
230 xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
231 gboolean r = FALSE;
232 if (c) {
233 *value = atoi((gchar*)c);
234 r = TRUE;
235 }
236 xmlFree(c);
237 return r;
238 }
239
240 gboolean parse_attr_string(const gchar *name, xmlNodePtr node, gchar **value)
241 {
242 xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
243 gboolean r = FALSE;
244 if (c) {
245 *value = g_strdup((gchar*)c);
246 r = TRUE;
247 }
248 xmlFree(c);
249 return r;
250 }
251
252 gboolean parse_attr_contains(const gchar *val, xmlNodePtr node,
253 const gchar *name)
254 {
255 xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
256 gboolean r;
257 r = !xmlStrcasecmp(c, (const xmlChar*) val);
258 xmlFree(c);
259 return r;
260 }
261
262 static GSList* split_paths(const gchar *paths)
263 {
264 GSList *list = NULL;
265 gchar **spl, **it;
266
267 if (!paths)
268 return NULL;
269 spl = g_strsplit(paths, ":", -1);
270 for (it = spl; *it; ++it)
271 list = g_slist_append(list, *it);
272 g_free(spl);
273 return list;
274 }
275
276 void parse_paths_startup()
277 {
278 gchar *path;
279
280 if (xdg_start)
281 return;
282 xdg_start = TRUE;
283
284 path = getenv("XDG_CONFIG_HOME");
285 if (path && path[0] != '\0') /* not unset or empty */
286 xdg_config_home_path = g_build_filename(path, NULL);
287 else
288 xdg_config_home_path = g_build_filename(g_get_home_dir(), ".config",
289 NULL);
290
291 path = getenv("XDG_DATA_HOME");
292 if (path && path[0] != '\0') /* not unset or empty */
293 xdg_data_home_path = g_build_filename(path, NULL);
294 else
295 xdg_data_home_path = g_build_filename(g_get_home_dir(), ".local",
296 "share", NULL);
297
298 path = getenv("XDG_CONFIG_DIRS");
299 if (path && path[0] != '\0') /* not unset or empty */
300 xdg_config_dir_paths = split_paths(path);
301 else {
302 xdg_config_dir_paths = g_slist_append(xdg_config_dir_paths,
303 g_build_filename
304 (G_DIR_SEPARATOR_S,
305 "etc", "xdg", NULL));
306 xdg_config_dir_paths = g_slist_append(xdg_config_dir_paths,
307 g_strdup(CONFIGDIR));
308 }
309 xdg_config_dir_paths = g_slist_prepend(xdg_config_dir_paths,
310 xdg_config_home_path);
311
312 path = getenv("XDG_DATA_DIRS");
313 if (path && path[0] != '\0') /* not unset or empty */
314 xdg_data_dir_paths = split_paths(path);
315 else {
316 xdg_data_dir_paths = g_slist_append(xdg_data_dir_paths,
317 g_build_filename
318 (G_DIR_SEPARATOR_S,
319 "usr", "local", "share", NULL));
320 xdg_data_dir_paths = g_slist_append(xdg_data_dir_paths,
321 g_build_filename
322 (G_DIR_SEPARATOR_S,
323 "usr", "share", NULL));
324 xdg_data_dir_paths = g_slist_append(xdg_data_dir_paths,
325 g_strdup(DATADIR));
326 }
327 xdg_data_dir_paths = g_slist_prepend(xdg_data_dir_paths,
328 xdg_data_home_path);
329 }
330
331 void parse_paths_shutdown()
332 {
333 GSList *it;
334
335 if (!xdg_start)
336 return;
337 xdg_start = FALSE;
338
339 for (it = xdg_config_dir_paths; it; it = g_slist_next(it))
340 g_free(it->data);
341 g_slist_free(xdg_config_dir_paths);
342 xdg_config_dir_paths = NULL;
343 for (it = xdg_data_dir_paths; it; it = g_slist_next(it))
344 g_free(it->data);
345 g_slist_free(xdg_data_dir_paths);
346 xdg_data_dir_paths = NULL;
347 }
348
349 gchar *parse_expand_tilde(const gchar *f)
350 {
351 gchar **spl;
352 gchar *ret;
353
354 if (!f)
355 return NULL;
356 spl = g_strsplit(f, "~", 0);
357 ret = g_strjoinv(g_get_home_dir(), spl);
358 g_strfreev(spl);
359 return ret;
360 }
361
362 void parse_mkdir_path(const gchar *path, gint mode)
363 {
364 gchar *c, *e;
365
366 g_assert(path[0] == '/');
367
368 c = g_strdup(path);
369 e = c;
370 while ((e = strchr(e + 1, '/'))) {
371 *e = '\0';
372 mkdir(c, mode);
373 *e = '/';
374 }
375 mkdir(c, mode);
376 g_free(c);
377 }
378
379 const gchar* parse_xdg_config_home_path()
380 {
381 return xdg_config_home_path;
382 }
383
384 const gchar* parse_xdg_data_home_path()
385 {
386 return xdg_data_home_path;
387 }
388
389 GSList* parse_xdg_config_dir_paths()
390 {
391 return xdg_config_dir_paths;
392 }
393
394 GSList* parse_xdg_data_dir_paths()
395 {
396 return xdg_data_dir_paths;
397 }
This page took 0.055058 seconds and 4 git commands to generate.