NetSurf
filepath.c
Go to the documentation of this file.
1/*
2 * Copyright 2010 Vincent Sanders <vince@kyllikki.org>
3 *
4 * This file is part of NetSurf, http://www.netsurf-browser.org/
5 *
6 * NetSurf 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; version 2 of the License.
9 *
10 * NetSurf is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/**
20 * \file
21 * Provides utility functions for finding readable files.
22 *
23 * These functions are intended to make finding resource files more
24 * straightforward.
25 */
26
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <stdarg.h>
30#include <limits.h>
31#include <stdio.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <string.h>
35
36#include "utils/dirent.h" /** \todo why is this necessary for atari to get PATH_MAX and is there a better way */
37#include "utils/utils.h"
38#include "utils/config.h"
39#include "utils/filepath.h"
40
41/** maximum number of elements in the resource vector */
42#define MAX_RESPATH 128
43
44/* exported interface documented in filepath.h */
45char *filepath_vsfindfile(char *str, const char *format, va_list ap)
46{
47 char *realpathname;
48 char *pathname;
49 int len;
50
51 pathname = malloc(PATH_MAX);
52 if (pathname == NULL)
53 return NULL; /* unable to allocate memory */
54
55 len = vsnprintf(pathname, PATH_MAX, format, ap);
56
57 if ((len < 0) || (len >= PATH_MAX)) {
58 /* error or output exceeded PATH_MAX length so
59 * operation is doomed to fail.
60 */
61 free(pathname);
62 return NULL;
63 }
64
65 realpathname = realpath(pathname, str);
66
67 free(pathname);
68
69 if (realpathname != NULL) {
70 /* sucessfully expanded pathname */
71 if (access(realpathname, R_OK) != 0) {
72 /* unable to read the file */
73 return NULL;
74 }
75 }
76
77 return realpathname;
78}
79
80
81/* exported interface documented in filepath.h */
82char *filepath_sfindfile(char *str, const char *format, ...)
83{
84 va_list ap;
85 char *ret;
86
87 va_start(ap, format);
88 ret = filepath_vsfindfile(str, format, ap);
89 va_end(ap);
90
91 return ret;
92}
93
94
95/* exported interface documented in filepath.h */
96char *filepath_findfile(const char *format, ...)
97{
98 char *ret;
99 va_list ap;
100
101 va_start(ap, format);
102 ret = filepath_vsfindfile(NULL, format, ap);
103 va_end(ap);
104
105 return ret;
106}
107
108/* exported interface documented in filepath.h */
109char *filepath_sfind(char **respathv, char *filepath, const char *filename)
110{
111 int respathc = 0;
112
113 if ((respathv == NULL) || (respathv[0] == NULL) || (filepath == NULL))
114 return NULL;
115
116 while (respathv[respathc] != NULL) {
117 if (filepath_sfindfile(filepath, "%s/%s", respathv[respathc], filename) != NULL) {
118 return filepath;
119 }
120
121 respathc++;
122 }
123
124 return NULL;
125}
126
127
128/* exported interface documented in filepath.h */
129char *filepath_find(char **respathv, const char *filename)
130{
131 char *ret;
132 char *filepath;
133
134 if ((respathv == NULL) || (respathv[0] == NULL))
135 return NULL;
136
137 filepath = malloc(PATH_MAX);
138 if (filepath == NULL)
139 return NULL;
140
141 ret = filepath_sfind(respathv, filepath, filename);
142
143 if (ret == NULL)
144 free(filepath);
145
146 return ret;
147}
148
149
150/* exported interface documented in filepath.h */
151char *
152filepath_sfinddef(char **respathv,
153 char *filepath,
154 const char *filename,
155 const char *def)
156{
157 char t[PATH_MAX];
158 char *ret;
159
160 if ((respathv == NULL) || (respathv[0] == NULL) || (filepath == NULL))
161 return NULL;
162
163 ret = filepath_sfind(respathv, filepath, filename);
164
165 if ((ret == NULL) && (def != NULL)) {
166 /* search failed, return the path specified */
167 ret = filepath;
168 if (def[0] == '~') {
169 snprintf(t, PATH_MAX, "%s/%s/%s", getenv("HOME"), def + 1, filename);
170 } else {
171 snprintf(t, PATH_MAX, "%s/%s", def, filename);
172 }
173 if (realpath(t, ret) == NULL) {
174 strncpy(ret, t, PATH_MAX);
175 }
176
177 }
178 return ret;
179}
180
181
182/* exported interface documented in filepath.h */
183char **
184filepath_generate(char * const *pathv, const char * const *langv)
185{
186 char **respath; /* resource paths vector */
187 int pathc = 0;
188 int langc = 0;
189 int respathc = 0;
190 struct stat dstat;
191 char *tmppath;
192 int tmppathlen;
193
194 respath = calloc(MAX_RESPATH, sizeof(char *));
195
196 while ((respath != NULL) &&
197 (pathv[pathc] != NULL)) {
198 if ((stat(pathv[pathc], &dstat) == 0) &&
199 S_ISDIR(dstat.st_mode)) {
200 /* path element exists and is a directory */
201 langc = 0;
202 while (langv[langc] != NULL) {
203 tmppathlen = snprintf(NULL,
204 0,
205 "%s/%s",
206 pathv[pathc],
207 langv[langc]);
208 tmppath = malloc(tmppathlen + 1);
209 if (tmppath == NULL) {
210 break;
211 }
212 snprintf(tmppath,
213 tmppathlen + 1,
214 "%s/%s",
215 pathv[pathc],
216 langv[langc]);
217
218 if ((stat(tmppath, &dstat) == 0) &&
219 S_ISDIR(dstat.st_mode)) {
220 /* path element exists and is a directory */
221 respath[respathc++] = tmppath;
222 } else {
223 free(tmppath);
224 }
225
226 langc++;
227 }
228 respath[respathc++] = strdup(pathv[pathc]);
229 }
230 pathc++;
231 }
232 return respath;
233}
234
235
236/**
237 * expand ${} in a string into environment variables.
238 *
239 * @param path The pathname to expand.
240 * @param pathlen The length of the path element.
241 * @return A string with the expanded path or NULL on empty expansion or error.
242 */
243static char *
244expand_path(const char *path, int pathlen)
245{
246 char *exp;
247 int explen;
248 int cstart = -1;
249 int cloop = 0;
250 char *envv;
251 int envlen;
252 int replen; /* length of replacement */
253
254 exp = malloc(pathlen + 1);
255 if (exp == NULL)
256 return NULL;
257
258 memcpy(exp, path, pathlen);
259 exp[pathlen] = 0;
260
261 explen = pathlen;
262
263 while (exp[cloop] != 0) {
264 if ((exp[cloop] == '$') &&
265 (exp[cloop + 1] == '{')) {
266 cstart = cloop;
267 cloop++;
268 }
269
270 if ((cstart != -1) &&
271 (exp[cloop] == '}')) {
272 replen = cloop - cstart;
273 exp[cloop] = 0;
274 envv = getenv(exp + cstart + 2);
275 if (envv == NULL) {
276 memmove(exp + cstart,
277 exp + cloop + 1,
278 explen - cloop);
279 explen -= replen;
280 } else {
281 char *tmp;
282 envlen = strlen(envv);
283 tmp = realloc(exp, explen + envlen - replen);
284 if (tmp == NULL) {
285 free(exp);
286 return NULL;
287 }
288 exp = tmp;
289 memmove(exp + cstart + envlen,
290 exp + cloop + 1,
291 explen - cloop );
292 memmove(exp + cstart, envv, envlen);
293 explen += envlen - replen;
294 }
295 cloop -= replen;
296 cstart = -1;
297 }
298
299 cloop++;
300 }
301
302 if (explen == 1) {
303 free(exp);
304 exp = NULL;
305 }
306
307 return exp;
308}
309
310
311/* exported interface documented in filepath.h */
312char **
314{
315 char **strvec;
316 int strc = 0;
317 const char *estart; /* path element start */
318 const char *eend; /* path element end */
319 int elen;
320
321 strvec = calloc(MAX_RESPATH, sizeof(char *));
322 if (strvec == NULL)
323 return NULL;
324
325 estart = eend = path;
326
327 while (strc < (MAX_RESPATH - 2)) {
328 while ( (*eend != 0) && (*eend != ':') )
329 eend++;
330 elen = eend - estart;
331
332 if (elen > 1) {
333 /* more than an empty colon */
334 strvec[strc] = expand_path(estart, elen);
335 if (strvec[strc] != NULL) {
336 /* successfully expanded an element */
337 strc++;
338 }
339 }
340
341 /* skip colons */
342 while (*eend == ':')
343 eend++;
344
345 /* check for termination */
346 if (*eend == 0)
347 break;
348
349 estart = eend;
350 }
351 return strvec;
352}
353
354
355/* exported interface documented in filepath.h */
356void filepath_free_strvec(char **pathv)
357{
358 int p = 0;
359
360 while (pathv[p] != NULL) {
361 free(pathv[p++]);
362 }
363 free(pathv);
364}
#define PATH_MAX
Definition: gui.h:31
directory traversal and entry
char ** filepath_path_to_strvec(const char *path)
Convert a colon separated list of path elements into a string vector.
Definition: filepath.c:313
char * filepath_sfind(char **respathv, char *filepath, const char *filename)
Searches an array of resource paths for a file.
Definition: filepath.c:109
char * filepath_sfindfile(char *str, const char *format,...)
Create a normalised file name.
Definition: filepath.c:82
#define MAX_RESPATH
maximum number of elements in the resource vector
Definition: filepath.c:42
char * filepath_find(char **respathv, const char *filename)
Searches an array of resource paths for a file.
Definition: filepath.c:129
char * filepath_vsfindfile(char *str, const char *format, va_list ap)
Create a normalised file name.
Definition: filepath.c:45
char * filepath_sfinddef(char **respathv, char *filepath, const char *filename, const char *def)
Searches an array of resource paths for a file optionally forcing a default.
Definition: filepath.c:152
char * filepath_findfile(const char *format,...)
Create a normalised file name.
Definition: filepath.c:96
void filepath_free_strvec(char **pathv)
Free a string vector.
Definition: filepath.c:356
static char * expand_path(const char *path, int pathlen)
expand ${} in a string into environment variables.
Definition: filepath.c:244
char ** filepath_generate(char *const *pathv, const char *const *langv)
Merge two string vectors into a resource search path vector.
Definition: filepath.c:184
Utility routines to obtain paths to file resources.
char * realpath(const char *f, char *buf)
Definition: gui.cpp:230
Interface to utility string handling.
Interface to a number of general purpose functionality.
static nserror path(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, const float transform[6])
Plots a path.
Definition: plot.c:821