move the xdg path stuff into obt/paths.[ch], and make render and openbox use it
[dana/openbox.git] / obt / paths.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    obt/paths.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 "obt/paths.h"
20 #include "obt/util.h"
21
22 #ifdef HAVE_SYS_STAT_H
23 #  include <sys/stat.h>
24 #endif
25 #ifdef HAVE_SYS_TYPES_H
26 #  include <sys/types.h>
27 #endif
28 #ifdef HAVE_STRING_H
29 #  include <string.h>
30 #endif
31
32 struct _ObtPaths
33 {
34     gint   ref;
35     gchar  *config_home;
36     gchar  *data_home;
37     GSList *config_dirs;
38     GSList *data_dirs;
39 };
40
41 static gint slist_path_cmp(const gchar *a, const gchar *b)
42 {
43     return strcmp(a, b);
44 }
45
46 typedef GSList* (*GSListFunc) (gpointer list, gconstpointer data);
47
48 static GSList* slist_path_add(GSList *list, gpointer data, GSListFunc func)
49 {
50     g_assert(func);
51
52     if (!data)
53         return list;
54
55     if (!g_slist_find_custom(list, data, (GCompareFunc) slist_path_cmp))
56         list = func(list, data);
57     else
58         g_free(data);
59
60     return list;
61 }
62
63 static GSList* split_paths(const gchar *paths)
64 {
65     GSList *list = NULL;
66     gchar **spl, **it;
67
68     if (!paths)
69         return NULL;
70     spl = g_strsplit(paths, ":", -1);
71     for (it = spl; *it; ++it)
72         list = slist_path_add(list, *it, (GSListFunc) g_slist_append);
73     g_free(spl);
74     return list;
75 }
76
77 ObtPaths* obt_paths_new(void)
78 {
79     ObtPaths *p;
80     const gchar *path;
81
82     p = g_new(ObtPaths, 1);
83     p->ref = 1;
84
85     path = g_getenv("XDG_CONFIG_HOME");
86     if (path && path[0] != '\0') /* not unset or empty */
87         p->config_home = g_build_filename(path, NULL);
88     else
89         p->config_home = g_build_filename(g_get_home_dir(), ".config", NULL);
90
91     path = g_getenv("XDG_DATA_HOME");
92     if (path && path[0] != '\0') /* not unset or empty */
93         p->data_home = g_build_filename(path, NULL);
94     else
95         p->data_home = g_build_filename(g_get_home_dir(), ".local",
96                                         "share", NULL);
97
98     path = g_getenv("XDG_CONFIG_DIRS");
99     if (path && path[0] != '\0') /* not unset or empty */
100         p->config_dirs = split_paths(path);
101     else {
102         p->config_dirs = slist_path_add(p->config_dirs,
103                                         g_strdup(CONFIGDIR),
104                                         (GSListFunc) g_slist_append);
105         p->config_dirs = slist_path_add(p->config_dirs,
106                                         g_build_filename
107                                         (G_DIR_SEPARATOR_S,
108                                          "etc", "xdg", NULL),
109                                         (GSListFunc) g_slist_append);
110     }
111     p->config_dirs = slist_path_add(p->config_dirs,
112                                     g_strdup(p->config_home),
113                                     (GSListFunc) g_slist_prepend);
114
115     path = g_getenv("XDG_DATA_DIRS");
116     if (path && path[0] != '\0') /* not unset or empty */
117         p->data_dirs = split_paths(path);
118     else {
119         p->data_dirs = slist_path_add(p->data_dirs,
120                                       g_strdup(DATADIR),
121                                       (GSListFunc) g_slist_append);
122         p->data_dirs = slist_path_add(p->data_dirs,
123                                       g_build_filename
124                                       (G_DIR_SEPARATOR_S,
125                                        "usr", "local", "share", NULL),
126                                       (GSListFunc) g_slist_append);
127         p->data_dirs = slist_path_add(p->data_dirs,
128                                       g_build_filename
129                                       (G_DIR_SEPARATOR_S,
130                                        "usr", "share", NULL),
131                                       (GSListFunc) g_slist_append);
132     }
133     p->data_dirs = slist_path_add(p->data_dirs,
134                                   g_strdup(p->data_home),
135                                   (GSListFunc) g_slist_prepend);
136     return p;
137 }
138
139 void obt_paths_ref(ObtPaths *p)
140 {
141     ++p->ref;
142 }
143
144 void obt_paths_unref(ObtPaths *p)
145 {
146     if (p && --p->ref == 0) {
147         GSList *it;
148
149         for (it = p->config_dirs; it; it = g_slist_next(it))
150             g_free(it->data);
151         g_slist_free(p->config_dirs);
152         for (it = p->data_dirs; it; it = g_slist_next(it))
153             g_free(it->data);
154         g_slist_free(p->data_dirs);
155         g_free(p->config_home);
156         g_free(p->data_home);
157
158         obt_free0(p, ObtPaths, 1);
159     }
160 }
161
162 gchar *obt_paths_expand_tilde(const gchar *f)
163 {
164     gchar **spl;
165     gchar *ret;
166
167     if (!f)
168         return NULL;
169     spl = g_strsplit(f, "~", 0);
170     ret = g_strjoinv(g_get_home_dir(), spl);
171     g_strfreev(spl);
172     return ret;
173 }
174
175 gboolean obt_paths_mkdir(const gchar *path, gint mode)
176 {
177     gboolean ret = TRUE;
178
179     g_return_val_if_fail(path != NULL, FALSE);
180     g_return_val_if_fail(path[0] != '\0', FALSE);
181
182     if (!g_file_test(path, G_FILE_TEST_IS_DIR))
183         if (mkdir(path, mode) == -1)
184             ret = FALSE;
185
186     return ret;
187 }
188
189 gboolean obt_paths_mkdir_path(const gchar *path, gint mode)
190 {
191     gboolean ret = TRUE;
192
193     g_return_val_if_fail(path != NULL, FALSE);
194     g_return_val_if_fail(path[0] == '/', FALSE);
195
196     if (!g_file_test(path, G_FILE_TEST_IS_DIR)) {
197         gchar *c, *e;
198
199         c = g_strdup(path);
200         e = c;
201         while ((e = strchr(e + 1, '/'))) {
202             *e = '\0';
203             if (!(ret = obt_paths_mkdir(c, mode)))
204                 goto parse_mkdir_path_end;
205             *e = '/';
206         }
207         ret = obt_paths_mkdir(c, mode);
208
209     parse_mkdir_path_end:
210         g_free(c);
211     }
212
213     return ret;
214 }
215
216 const gchar* obt_paths_config_home(ObtPaths *p)
217 {
218     return p->config_home;
219 }
220
221 const gchar* obt_paths_data_home(ObtPaths *p)
222 {
223     return p->data_home;
224 }
225
226 GSList* obt_paths_config_dirs(ObtPaths *p)
227 {
228     return p->config_dirs;
229 }
230
231 GSList* obt_paths_data_dirs(ObtPaths *p)
232 {
233     return p->data_dirs;
234 }