]> Dogcows Code - chaz/openbox/blob - parser/parse.c
add copyright headers, adjust --version output to include copyright, and --help outpu...
[chaz/openbox] / parser / parse.c
1 /* -*- indent-tabs-mode: t; 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 char *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 char *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 char *path, const char *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 char *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 xmlFree(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 char *parse_string(xmlDocPtr doc, xmlNodePtr node)
180 {
181 xmlChar *c = xmlNodeListGetString(doc, node->children, TRUE);
182 char *s = g_strdup(c ? (char*)c : "");
183 xmlFree(c);
184 return s;
185 }
186
187 int parse_int(xmlDocPtr doc, xmlNodePtr node)
188 {
189 xmlChar *c = xmlNodeListGetString(doc, node->children, TRUE);
190 int i = atoi((char*)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 char *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 char *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 char *name, xmlNodePtr node, int *value)
229 {
230 xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
231 gboolean r = FALSE;
232 if (c) {
233 *value = atoi((char*)c);
234 r = TRUE;
235 }
236 xmlFree(c);
237 return r;
238 }
239
240 gboolean parse_attr_string(const char *name, xmlNodePtr node, char **value)
241 {
242 xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
243 gboolean r = FALSE;
244 if (c) {
245 *value = g_strdup((char*)c);
246 r = TRUE;
247 }
248 xmlFree(c);
249 return r;
250 }
251
252 gboolean parse_attr_contains(const char *val, xmlNodePtr node,
253 const char *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 *c, *e, *s;
266
267 c = g_strdup(paths);
268 s = c;
269 e = c - 1;
270 g_message("paths %s", paths);
271 while ((e = strchr(e + 1, ':'))) {
272 *e = '\0';
273 g_message("s %s", s);
274 if (s[0] != '\0')
275 list = g_slist_append(list, g_strdup(s));
276 s = e + 1;
277 }
278 if (s[0] != '\0')
279 list = g_slist_append(list, g_strdup(s));
280 g_free(c);
281 return list;
282 }
283
284 void parse_paths_startup()
285 {
286 gchar *path;
287
288 if (xdg_start)
289 return;
290 xdg_start = TRUE;
291
292 path = getenv("XDG_CONFIG_HOME");
293 if (path && path[0] != '\0') /* not unset or empty */
294 xdg_config_home_path = g_build_filename(path, NULL);
295 else
296 xdg_config_home_path = g_build_filename(g_get_home_dir(), ".config",
297 NULL);
298
299 path = getenv("XDG_DATA_HOME");
300 if (path && path[0] != '\0') /* not unset or empty */
301 xdg_data_home_path = g_build_filename(path, NULL);
302 else
303 xdg_data_home_path = g_build_filename(g_get_home_dir(), ".local",
304 "share", NULL);
305
306 path = getenv("XDG_CONFIG_DIRS");
307 if (path && path[0] != '\0') /* not unset or empty */
308 xdg_config_dir_paths = split_paths(path);
309 else {
310 xdg_config_dir_paths = g_slist_append(xdg_config_dir_paths,
311 g_build_filename
312 (G_DIR_SEPARATOR_S,
313 "etc", "xdg", NULL));
314 xdg_config_dir_paths = g_slist_append(xdg_config_dir_paths,
315 g_strdup(CONFIGDIR));
316 }
317 xdg_config_dir_paths = g_slist_prepend(xdg_config_dir_paths,
318 xdg_config_home_path);
319
320 path = getenv("XDG_DATA_DIRS");
321 if (path && path[0] != '\0') /* not unset or empty */
322 xdg_data_dir_paths = split_paths(path);
323 else {
324 xdg_data_dir_paths = g_slist_append(xdg_data_dir_paths,
325 g_build_filename
326 (G_DIR_SEPARATOR_S,
327 "usr", "local", "share", NULL));
328 xdg_data_dir_paths = g_slist_append(xdg_data_dir_paths,
329 g_build_filename
330 (G_DIR_SEPARATOR_S,
331 "usr", "share", NULL));
332 xdg_config_dir_paths = g_slist_append(xdg_config_dir_paths,
333 g_strdup(DATADIR));
334 }
335 xdg_data_dir_paths = g_slist_prepend(xdg_data_dir_paths,
336 xdg_data_home_path);
337 }
338
339 void parse_paths_shutdown()
340 {
341 GSList *it;
342
343 if (!xdg_start)
344 return;
345 xdg_start = FALSE;
346
347 for (it = xdg_config_dir_paths; it; it = g_slist_next(it))
348 g_free(it->data);
349 g_slist_free(xdg_config_dir_paths);
350 xdg_config_dir_paths = NULL;
351 }
352
353 gchar *parse_expand_tilde(const gchar *f)
354 {
355 gchar **spl;
356 gchar *ret;
357
358 if (!f)
359 return NULL;
360 spl = g_strsplit(f, "~", 0);
361 ret = g_strjoinv(g_get_home_dir(), spl);
362 g_strfreev(spl);
363 return ret;
364 }
365
366 void parse_mkdir_path(const gchar *path, gint mode)
367 {
368 gchar *c, *e;
369
370 g_assert(path[0] == '/');
371
372 c = g_strdup(path);
373 e = c;
374 while ((e = strchr(e + 1, '/'))) {
375 *e = '\0';
376 mkdir(c, mode);
377 *e = '/';
378 }
379 mkdir(c, mode);
380 g_free(c);
381 }
382
383 const gchar* parse_xdg_config_home_path()
384 {
385 return xdg_config_home_path;
386 }
387
388 const gchar* parse_xdg_data_home_path()
389 {
390 return xdg_data_home_path;
391 }
392
393 GSList* parse_xdg_config_dir_paths()
394 {
395 return xdg_config_dir_paths;
396 }
397
398 GSList* parse_xdg_data_dir_paths()
399 {
400 return xdg_data_dir_paths;
401 }
This page took 0.055789 seconds and 4 git commands to generate.