~ubuntu-branches/debian/sid/openbox/sid

« back to all changes in this revision

Viewing changes to parser/parse.c

  • Committer: Bazaar Package Importer
  • Author(s): Nico Golde, Nico Golde, Eugenio Paolantonio
  • Date: 2011-10-03 22:59:30 UTC
  • mfrom: (1.1.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20111003225930-tdvyax5tx63dyoez
Tags: 3.5.0-1
[Nico Golde]
* New upstream release (Closes: #638783).
  - Fix crashes in the menu code (Closes: #563891).
* Add Brazilian translation to openbox.desktop,
  thanks Sérgio Cipolla (Closes: #627912).
* Remove 06_fix_swap_byte_order.patch, applied upstream.
* Bump debhelper dependency to >= 7.0.50~ due to override.
* Remove CHANGELOG from openbox.docs to prevent double installation.
* Add 02_fix_freedesktop_compliance.dpatch desktop file to
  /usr/share/applications.

[Eugenio Paolantonio]
* debian/patches:
  - Disabled 03_place_windows_in_quadrants.patch
  - Updated 01_rc.xml.patch and 06_fix_swap_byte_order.patch
  - Removed 04_fix_ftbfs_no-add-needed.patch and 20_24bits_support.patch
* debian/control:
  - Added myself to the Uploaders.
  - Build-Depends: removed libxau-dev, libxft-dev and python-xdg;
    added libimlib2-dev
  - openbox Suggests: added python-xdg
  - libobrender21 renamed to libobrender27
  - libobparser21 renamed to libobt0
* debian/rules:
  - Rewrote using a simpler debhelper syntax
  - Moved the install pass to openbox.install
* debian/*.{install,links,dirs}:
  - Updated.
* debian/openbox.xsession:
  - Removed. Openbox now ships it by default.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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-2007   Dana 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 <errno.h>
23
 
#include <sys/stat.h>
24
 
#include <sys/types.h>
25
 
#include <unistd.h>
26
 
 
27
 
static gboolean xdg_start;
28
 
static gchar   *xdg_config_home_path;
29
 
static gchar   *xdg_data_home_path;
30
 
static GSList  *xdg_config_dir_paths;
31
 
static GSList  *xdg_data_dir_paths;
32
 
 
33
 
struct Callback {
34
 
    gchar *tag;
35
 
    ParseCallback func;
36
 
    gpointer data;
37
 
};
38
 
 
39
 
struct _ObParseInst {
40
 
    GHashTable *callbacks;
41
 
};
42
 
 
43
 
static void destfunc(struct Callback *c)
44
 
{
45
 
    g_free(c->tag);
46
 
    g_free(c);
47
 
}
48
 
 
49
 
ObParseInst* parse_startup(void)
50
 
{
51
 
    ObParseInst *i = g_new(ObParseInst, 1);
52
 
    i->callbacks = g_hash_table_new_full(g_str_hash, g_str_equal, NULL,
53
 
                                         (GDestroyNotify)destfunc);
54
 
    return i;
55
 
}
56
 
 
57
 
void parse_shutdown(ObParseInst *i)
58
 
{
59
 
    if (i) {
60
 
        g_hash_table_destroy(i->callbacks);
61
 
        g_free(i);
62
 
    }
63
 
}
64
 
 
65
 
void parse_register(ObParseInst *i, const gchar *tag,
66
 
                    ParseCallback func, gpointer data)
67
 
{
68
 
    struct Callback *c;
69
 
 
70
 
    if ((c = g_hash_table_lookup(i->callbacks, tag))) {
71
 
        g_error("Tag '%s' already registered", tag);
72
 
        return;
73
 
    }
74
 
 
75
 
    c = g_new(struct Callback, 1);
76
 
    c->tag = g_strdup(tag);
77
 
    c->func = func;
78
 
    c->data = data;
79
 
    g_hash_table_insert(i->callbacks, c->tag, c);
80
 
}
81
 
 
82
 
gboolean parse_load_rc(const gchar *file, xmlDocPtr *doc, xmlNodePtr *root)
83
 
{
84
 
    GSList *it;
85
 
    gboolean r = FALSE;
86
 
 
87
 
    if (file && parse_load(file, "openbox_config", doc, root))
88
 
        return TRUE;
89
 
 
90
 
    for (it = xdg_config_dir_paths; !r && it; it = g_slist_next(it)) {
91
 
        gchar *path;
92
 
 
93
 
        path = g_build_filename(it->data, "openbox", "rc.xml", NULL);
94
 
        r = parse_load(path, "openbox_config", doc, root);
95
 
        g_free(path);
96
 
    }
97
 
 
98
 
    return r;
99
 
}
100
 
 
101
 
gboolean parse_load_theme(const gchar *name, xmlDocPtr *doc, xmlNodePtr *root,
102
 
                          gchar **retpath)
103
 
{
104
 
    GSList *it;
105
 
    gchar *path;
106
 
    gboolean r = FALSE;
107
 
    gchar *eng;
108
 
 
109
 
    /* backward compatibility.. */
110
 
    path = g_build_filename(g_get_home_dir(), ".themes", name,
111
 
                            "openbox-3", "themerc.xml", NULL);
112
 
    if (parse_load(path, "openbox_theme", doc, root) &&
113
 
        parse_attr_string("engine", *root, &eng))
114
 
    {
115
 
        if (!strcmp(eng, "box")) {
116
 
            *retpath = g_path_get_dirname(path);
117
 
            r = TRUE;
118
 
        }
119
 
        g_free(eng);
120
 
    }
121
 
    g_free(path);
122
 
 
123
 
    if (!r) {
124
 
        for (it = xdg_data_dir_paths; !r && it; it = g_slist_next(it)) {
125
 
            path = g_build_filename(it->data, "themes", name, "openbox-3",
126
 
                                    "themerc.xml", NULL);
127
 
            if (parse_load(path, "openbox_theme", doc, root) &&
128
 
                parse_attr_string("engine", *root, &eng))
129
 
            {
130
 
                if (!strcmp(eng, "box")) {
131
 
                    *retpath = g_path_get_dirname(path);
132
 
                    r = TRUE;
133
 
                }
134
 
                g_free(eng);
135
 
            }
136
 
            g_free(path);
137
 
        }
138
 
    }
139
 
    return r;
140
 
}
141
 
 
142
 
gboolean parse_load_menu(const gchar *file, xmlDocPtr *doc, xmlNodePtr *root)
143
 
{
144
 
    GSList *it;
145
 
    gchar *path;
146
 
    gboolean r = FALSE;
147
 
 
148
 
    if (file[0] == '/') {
149
 
        r = parse_load(file, "openbox_menu", doc, root);
150
 
    } else {
151
 
        for (it = xdg_config_dir_paths; !r && it; it = g_slist_next(it)) {
152
 
            path = g_build_filename(it->data, "openbox", file, NULL);
153
 
            r = parse_load(path, "openbox_menu", doc, root);
154
 
            g_free(path);
155
 
        }
156
 
    }
157
 
    return r;
158
 
}
159
 
 
160
 
gboolean parse_load(const gchar *path, const gchar *rootname,
161
 
                    xmlDocPtr *doc, xmlNodePtr *root)
162
 
{
163
 
    struct stat s;
164
 
 
165
 
    if (stat(path, &s) < 0)
166
 
        return FALSE;
167
 
 
168
 
    /* XML_PARSE_BLANKS is needed apparently. When it loads a theme file,
169
 
       without this option, the tree is weird and has extra nodes in it. */
170
 
    if ((*doc = xmlReadFile(path, NULL,
171
 
                            XML_PARSE_NOBLANKS | XML_PARSE_RECOVER))) {
172
 
        *root = xmlDocGetRootElement(*doc);
173
 
        if (!*root) {
174
 
            xmlFreeDoc(*doc);
175
 
            *doc = NULL;
176
 
            g_message("%s is an empty document", path);
177
 
        } else {
178
 
            if (xmlStrcmp((*root)->name, (const xmlChar*)rootname)) {
179
 
                xmlFreeDoc(*doc);
180
 
                *doc = NULL;
181
 
                g_message("XML Document %s is of wrong type. Root "
182
 
                          "node is not '%s'", path, rootname);
183
 
            }
184
 
        }
185
 
    }
186
 
    if (!*doc)
187
 
        return FALSE;
188
 
    return TRUE;
189
 
}
190
 
 
191
 
gboolean parse_load_mem(gpointer data, guint len, const gchar *rootname,
192
 
                        xmlDocPtr *doc, xmlNodePtr *root)
193
 
{
194
 
    if ((*doc = xmlParseMemory(data, len))) {
195
 
        *root = xmlDocGetRootElement(*doc);
196
 
        if (!*root) {
197
 
            xmlFreeDoc(*doc);
198
 
            *doc = NULL;
199
 
            g_message("Given memory is an empty document");
200
 
        } else {
201
 
            if (xmlStrcmp((*root)->name, (const xmlChar*)rootname)) {
202
 
                xmlFreeDoc(*doc);
203
 
                *doc = NULL;
204
 
                g_message("XML Document in given memory is of wrong "
205
 
                          "type. Root node is not '%s'\n", rootname);
206
 
            }
207
 
        }
208
 
    }
209
 
    if (!*doc)
210
 
        return FALSE;
211
 
    return TRUE;
212
 
}
213
 
 
214
 
void parse_close(xmlDocPtr doc)
215
 
{
216
 
    xmlFreeDoc(doc);
217
 
}
218
 
 
219
 
void parse_tree(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
220
 
{
221
 
    while (node) {
222
 
        if (node->name) {
223
 
            struct Callback *c = g_hash_table_lookup(i->callbacks, node->name);
224
 
 
225
 
            if (c)
226
 
                c->func(i, doc, node, c->data);
227
 
        }
228
 
 
229
 
        node = node->next;
230
 
    }
231
 
}
232
 
 
233
 
gchar *parse_string(xmlDocPtr doc, xmlNodePtr node)
234
 
{
235
 
    xmlChar *c = xmlNodeListGetString(doc, node->children, TRUE);
236
 
    gchar *s;
237
 
    if (c) g_strstrip((char*)c);
238
 
    s = g_strdup(c ? (gchar*)c : "");
239
 
    xmlFree(c);
240
 
    return s;
241
 
}
242
 
 
243
 
gint parse_int(xmlDocPtr doc, xmlNodePtr node)
244
 
{
245
 
    xmlChar *c = xmlNodeListGetString(doc, node->children, TRUE);
246
 
    gint i;
247
 
    if (c) g_strstrip((char*)c);
248
 
    i = c ? atoi((gchar*)c) : 0;
249
 
    xmlFree(c);
250
 
    return i;
251
 
}
252
 
 
253
 
gboolean parse_bool(xmlDocPtr doc, xmlNodePtr node)
254
 
{
255
 
    xmlChar *c = xmlNodeListGetString(doc, node->children, TRUE);
256
 
    gboolean b = FALSE;
257
 
    if (c) g_strstrip((char*)c);
258
 
    if (c && !xmlStrcasecmp(c, (const xmlChar*) "true"))
259
 
        b = TRUE;
260
 
    else if (c && !xmlStrcasecmp(c, (const xmlChar*) "yes"))
261
 
        b = TRUE;
262
 
    else if (c && !xmlStrcasecmp(c, (const xmlChar*) "on"))
263
 
        b = TRUE;
264
 
    xmlFree(c);
265
 
    return b;
266
 
}
267
 
 
268
 
gboolean parse_contains(const gchar *val, xmlDocPtr doc, xmlNodePtr node)
269
 
{
270
 
    xmlChar *c = xmlNodeListGetString(doc, node->children, TRUE);
271
 
    gboolean r;
272
 
    if (c) g_strstrip((char*)c); /* strip leading/trailing whitespace */
273
 
    r = !xmlStrcasecmp(c, (const xmlChar*) val);
274
 
    xmlFree(c);
275
 
    return r;
276
 
}
277
 
 
278
 
xmlNodePtr parse_find_node(const gchar *tag, xmlNodePtr node)
279
 
{
280
 
    while (node) {
281
 
        if (!xmlStrcmp(node->name, (const xmlChar*) tag))
282
 
            return node;
283
 
        node = node->next;
284
 
    }
285
 
    return NULL;
286
 
}
287
 
 
288
 
gboolean parse_attr_bool(const gchar *name, xmlNodePtr node, gboolean *value)
289
 
{
290
 
    xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
291
 
    gboolean r = FALSE;
292
 
    if (c) {
293
 
        g_strstrip((char*)c); /* strip leading/trailing whitespace */
294
 
        if (!xmlStrcasecmp(c, (const xmlChar*) "true"))
295
 
            *value = TRUE, r = TRUE;
296
 
        else if (!xmlStrcasecmp(c, (const xmlChar*) "yes"))
297
 
            *value = TRUE, r = TRUE;
298
 
        else if (!xmlStrcasecmp(c, (const xmlChar*) "on"))
299
 
            *value = TRUE, r = TRUE;
300
 
        else if (!xmlStrcasecmp(c, (const xmlChar*) "false"))
301
 
            *value = FALSE, r = TRUE;
302
 
        else if (!xmlStrcasecmp(c, (const xmlChar*) "no"))
303
 
            *value = FALSE, r = TRUE;
304
 
        else if (!xmlStrcasecmp(c, (const xmlChar*) "off"))
305
 
            *value = FALSE, r = TRUE;
306
 
    }
307
 
    xmlFree(c);
308
 
    return r;
309
 
}
310
 
 
311
 
gboolean parse_attr_int(const gchar *name, xmlNodePtr node, gint *value)
312
 
{
313
 
    xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
314
 
    gboolean r = FALSE;
315
 
    if (c) {
316
 
        g_strstrip((char*)c); /* strip leading/trailing whitespace */
317
 
        *value = atoi((gchar*)c);
318
 
        r = TRUE;
319
 
    }
320
 
    xmlFree(c);
321
 
    return r;
322
 
}
323
 
 
324
 
gboolean parse_attr_string(const gchar *name, xmlNodePtr node, gchar **value)
325
 
{
326
 
    xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
327
 
    gboolean r = FALSE;
328
 
    if (c) {
329
 
        g_strstrip((char*)c); /* strip leading/trailing whitespace */
330
 
        *value = g_strdup((gchar*)c);
331
 
        r = TRUE;
332
 
    }
333
 
    xmlFree(c);
334
 
    return r;
335
 
}
336
 
 
337
 
gboolean parse_attr_contains(const gchar *val, xmlNodePtr node,
338
 
                             const gchar *name)
339
 
{
340
 
    xmlChar *c = xmlGetProp(node, (const xmlChar*) name);
341
 
    gboolean r = FALSE;
342
 
    if (c) {
343
 
        g_strstrip((char*)c);
344
 
        r = !xmlStrcasecmp(c, (const xmlChar*) val);
345
 
    }
346
 
    xmlFree(c);
347
 
    return r;
348
 
}
349
 
 
350
 
static gint slist_path_cmp(const gchar *a, const gchar *b)
351
 
{
352
 
    return strcmp(a, b);
353
 
}
354
 
 
355
 
typedef GSList* (*GSListFunc) (gpointer list, gconstpointer data);
356
 
 
357
 
static GSList* slist_path_add(GSList *list, gpointer data, GSListFunc func)
358
 
{
359
 
    g_assert(func);
360
 
 
361
 
    if (!data)
362
 
        return list;
363
 
 
364
 
    if (!g_slist_find_custom(list, data, (GCompareFunc) slist_path_cmp))
365
 
        list = func(list, data);
366
 
    else
367
 
        g_free(data);
368
 
 
369
 
    return list;
370
 
}
371
 
 
372
 
static GSList* split_paths(const gchar *paths)
373
 
{
374
 
    GSList *list = NULL;
375
 
    gchar **spl, **it;
376
 
 
377
 
    if (!paths)
378
 
        return NULL;
379
 
    spl = g_strsplit(paths, ":", -1);
380
 
    for (it = spl; *it; ++it)
381
 
        list = slist_path_add(list, *it, (GSListFunc) g_slist_append);
382
 
    g_free(spl);
383
 
    return list;
384
 
}
385
 
 
386
 
void parse_paths_startup(void)
387
 
{
388
 
    const gchar *path;
389
 
 
390
 
    if (xdg_start)
391
 
        return;
392
 
    xdg_start = TRUE;
393
 
 
394
 
    path = g_getenv("XDG_CONFIG_HOME");
395
 
    if (path && path[0] != '\0') /* not unset or empty */
396
 
        xdg_config_home_path = g_build_filename(path, NULL);
397
 
    else
398
 
        xdg_config_home_path = g_build_filename(g_get_home_dir(), ".config",
399
 
                                                NULL);
400
 
 
401
 
    path = g_getenv("XDG_DATA_HOME");
402
 
    if (path && path[0] != '\0') /* not unset or empty */
403
 
        xdg_data_home_path = g_build_filename(path, NULL);
404
 
    else
405
 
        xdg_data_home_path = g_build_filename(g_get_home_dir(), ".local",
406
 
                                              "share", NULL);
407
 
 
408
 
    path = g_getenv("XDG_CONFIG_DIRS");
409
 
    if (path && path[0] != '\0') /* not unset or empty */
410
 
        xdg_config_dir_paths = split_paths(path);
411
 
    else {
412
 
        xdg_config_dir_paths = slist_path_add(xdg_config_dir_paths,
413
 
                                              g_strdup(CONFIGDIR),
414
 
                                              (GSListFunc) g_slist_append);
415
 
        xdg_config_dir_paths = slist_path_add(xdg_config_dir_paths,
416
 
                                              g_build_filename
417
 
                                              (G_DIR_SEPARATOR_S,
418
 
                                               "etc", "xdg", NULL),
419
 
                                              (GSListFunc) g_slist_append);
420
 
    }
421
 
    xdg_config_dir_paths = slist_path_add(xdg_config_dir_paths,
422
 
                                          g_strdup(xdg_config_home_path),
423
 
                                          (GSListFunc) g_slist_prepend);
424
 
 
425
 
    path = g_getenv("XDG_DATA_DIRS");
426
 
    if (path && path[0] != '\0') /* not unset or empty */
427
 
        xdg_data_dir_paths = split_paths(path);
428
 
    else {
429
 
        xdg_data_dir_paths = slist_path_add(xdg_data_dir_paths,
430
 
                                            g_strdup(DATADIR),
431
 
                                            (GSListFunc) g_slist_append);
432
 
        xdg_data_dir_paths = slist_path_add(xdg_data_dir_paths,
433
 
                                            g_build_filename
434
 
                                            (G_DIR_SEPARATOR_S,
435
 
                                             "usr", "local", "share", NULL),
436
 
                                            (GSListFunc) g_slist_append);
437
 
        xdg_data_dir_paths = slist_path_add(xdg_data_dir_paths,
438
 
                                            g_build_filename
439
 
                                            (G_DIR_SEPARATOR_S,
440
 
                                             "usr", "share", NULL),
441
 
                                            (GSListFunc) g_slist_append);
442
 
    }
443
 
    xdg_data_dir_paths = slist_path_add(xdg_data_dir_paths,
444
 
                                        g_strdup(xdg_data_home_path),
445
 
                                        (GSListFunc) g_slist_prepend);
446
 
}
447
 
 
448
 
void parse_paths_shutdown(void)
449
 
{
450
 
    GSList *it;
451
 
 
452
 
    if (!xdg_start)
453
 
        return;
454
 
    xdg_start = FALSE;
455
 
 
456
 
    for (it = xdg_config_dir_paths; it; it = g_slist_next(it))
457
 
        g_free(it->data);
458
 
    g_slist_free(xdg_config_dir_paths);
459
 
    xdg_config_dir_paths = NULL;
460
 
    for (it = xdg_data_dir_paths; it; it = g_slist_next(it))
461
 
        g_free(it->data);
462
 
    g_slist_free(xdg_data_dir_paths);
463
 
    xdg_data_dir_paths = NULL;
464
 
    g_free(xdg_config_home_path);
465
 
    xdg_config_home_path = NULL;
466
 
    g_free(xdg_data_home_path);
467
 
    xdg_data_home_path = NULL;
468
 
}
469
 
 
470
 
gchar *parse_expand_tilde(const gchar *f)
471
 
{
472
 
    gchar *ret;
473
 
    GRegex *regex;
474
 
 
475
 
    if (!f)
476
 
        return NULL;
477
 
 
478
 
    regex = g_regex_new("(?:^|(?<=[ \\t]))~(?:(?=[/ \\t])|$)",
479
 
                        G_REGEX_MULTILINE | G_REGEX_RAW, 0, NULL);
480
 
    ret = g_regex_replace_literal(regex, f, -1, 0, g_get_home_dir(), 0, NULL);
481
 
    g_regex_unref(regex);
482
 
 
483
 
    return ret;
484
 
}
485
 
 
486
 
gboolean parse_mkdir(const gchar *path, gint mode)
487
 
{
488
 
    gboolean ret = TRUE;
489
 
 
490
 
    g_return_val_if_fail(path != NULL, FALSE);
491
 
    g_return_val_if_fail(path[0] != '\0', FALSE);
492
 
 
493
 
    if (!g_file_test(path, G_FILE_TEST_IS_DIR))
494
 
        if (mkdir(path, mode) == -1)
495
 
            ret = FALSE;
496
 
 
497
 
    return ret;
498
 
}
499
 
 
500
 
gboolean parse_mkdir_path(const gchar *path, gint mode)
501
 
{
502
 
    gboolean ret = TRUE;
503
 
 
504
 
    g_return_val_if_fail(path != NULL, FALSE);
505
 
    g_return_val_if_fail(path[0] == '/', FALSE);
506
 
 
507
 
    if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
508
 
        gchar *c, *e;
509
 
 
510
 
        c = g_strdup(path);
511
 
        e = c;
512
 
        while ((e = strchr(e + 1, '/'))) {
513
 
            *e = '\0';
514
 
            if (!(ret = parse_mkdir(c, mode)))
515
 
                goto parse_mkdir_path_end;
516
 
            *e = '/';
517
 
        }
518
 
        ret = parse_mkdir(c, mode);
519
 
 
520
 
    parse_mkdir_path_end:
521
 
        g_free(c);
522
 
    }
523
 
 
524
 
    return ret;
525
 
}
526
 
 
527
 
const gchar* parse_xdg_config_home_path(void)
528
 
{
529
 
    return xdg_config_home_path;
530
 
}
531
 
 
532
 
const gchar* parse_xdg_data_home_path(void)
533
 
{
534
 
    return xdg_data_home_path;
535
 
}
536
 
 
537
 
GSList* parse_xdg_config_dir_paths(void)
538
 
{
539
 
    return xdg_config_dir_paths;
540
 
}
541
 
 
542
 
GSList* parse_xdg_data_dir_paths(void)
543
 
{
544
 
    return xdg_data_dir_paths;
545
 
}