WINGs: Added 'const' attribute to function 'WMCreateHashTable'
[wmaker-crm.git] / WINGs / findfile.c
blob42845d03c55f8912c8aa65e817a746f3b18770a1
1 /*
2 * Window Maker miscelaneous function library
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
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.
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.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
22 #include "wconfig.h"
24 #include "WUtil.h"
26 #include <sys/stat.h>
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <pwd.h>
33 #include <limits.h>
35 #ifndef PATH_MAX
36 #define PATH_MAX 1024
37 #endif
39 #define RETRY( x ) do { x; } while (errno == EINTR);
41 char *wgethomedir()
43 static char *home = NULL;
44 char *tmp;
45 struct passwd *user;
47 if (home)
48 return home;
50 tmp = getenv("HOME");
51 if (tmp) {
52 home = wstrdup(tmp);
53 return home;
56 user = getpwuid(getuid());
57 if (!user) {
58 werror(_("could not get password entry for UID %i"), getuid());
59 home = "/";
62 if (!user->pw_dir)
63 home = "/";
64 else
65 home = wstrdup(user->pw_dir);
67 return home;
71 * Return the home directory for the specified used
73 * If user not found, returns NULL, otherwise always returns a path that is
74 * statically stored.
76 * Please note you must use the path before any other call to 'getpw*' or it
77 * may be erased. This is a design choice to avoid duplication considering
78 * the use case for this function.
80 static const char *getuserhomedir(const char *username)
82 static const char default_home[] = "/";
83 struct passwd *user;
85 user = getpwnam(username);
86 if (!user) {
87 werror(_("could not get password entry for user %s"), username);
88 return NULL;
90 if (!user->pw_dir)
91 return default_home;
92 else
93 return user->pw_dir;
97 char *wexpandpath(const char *path)
99 const char *origpath = path;
100 char buffer2[PATH_MAX + 2];
101 char buffer[PATH_MAX + 2];
102 int i;
104 memset(buffer, 0, PATH_MAX + 2);
106 if (*path == '~') {
107 const char *home;
109 path++;
110 if (*path == '/' || *path == 0) {
111 home = wgethomedir();
112 if (strlen(home) > PATH_MAX ||
113 wstrlcpy(buffer, home, sizeof(buffer)) >= sizeof(buffer))
114 goto error;
115 } else {
116 int j;
117 j = 0;
118 while (*path != 0 && *path != '/') {
119 if (j > PATH_MAX)
120 goto error;
121 buffer2[j++] = *path;
122 buffer2[j] = 0;
123 path++;
125 home = getuserhomedir(buffer2);
126 if (!home || wstrlcat(buffer, home, sizeof(buffer)) >= sizeof(buffer))
127 goto error;
131 i = strlen(buffer);
133 while (*path != 0 && i <= PATH_MAX) {
134 char *tmp;
136 if (*path == '$') {
137 int j = 0;
138 path++;
139 /* expand $(HOME) or $HOME style environment variables */
140 if (*path == '(') {
141 path++;
142 while (*path != 0 && *path != ')') {
143 if (j > PATH_MAX)
144 goto error;
145 buffer2[j++] = *(path++);
146 buffer2[j] = 0;
148 if (*path == ')') {
149 path++;
150 tmp = getenv(buffer2);
151 } else {
152 tmp = NULL;
154 if (!tmp) {
155 if ((i += strlen(buffer2) + 2) > PATH_MAX)
156 goto error;
157 buffer[i] = 0;
158 if (wstrlcat(buffer, "$(", sizeof(buffer)) >= sizeof(buffer) ||
159 wstrlcat(buffer, buffer2, sizeof(buffer)) >= sizeof(buffer))
160 goto error;
161 if (*(path-1)==')') {
162 if (++i > PATH_MAX ||
163 wstrlcat(buffer, ")", sizeof(buffer)) >= sizeof(buffer))
164 goto error;
166 } else {
167 if ((i += strlen(tmp)) > PATH_MAX ||
168 wstrlcat(buffer, tmp, sizeof(buffer)) >= sizeof(buffer))
169 goto error;
171 } else {
172 while (*path != 0 && *path != '/') {
173 if (j > PATH_MAX)
174 goto error;
175 buffer2[j++] = *(path++);
176 buffer2[j] = 0;
178 tmp = getenv(buffer2);
179 if (!tmp) {
180 if ((i += strlen(buffer2) + 1) > PATH_MAX ||
181 wstrlcat(buffer, "$", sizeof(buffer)) >= sizeof(buffer) ||
182 wstrlcat(buffer, buffer2, sizeof(buffer)) >= sizeof(buffer))
183 goto error;
184 } else {
185 if ((i += strlen(tmp)) > PATH_MAX ||
186 wstrlcat(buffer, tmp, sizeof(buffer)) >= sizeof(buffer))
187 goto error;
190 } else {
191 buffer[i++] = *path;
192 path++;
196 if (*path!=0)
197 goto error;
199 return wstrdup(buffer);
201 error:
202 errno = ENAMETOOLONG;
203 werror(_("could not expand %s"), origpath);
205 return NULL;
208 /* return address of next char != tok or end of string whichever comes first */
209 static const char *skipchar(const char *string, char tok)
211 while (*string != 0 && *string == tok)
212 string++;
214 return string;
217 /* return address of next char == tok or end of string whichever comes first */
218 static const char *nextchar(const char *string, char tok)
220 while (*string != 0 && *string != tok)
221 string++;
223 return string;
227 *----------------------------------------------------------------------
228 * findfile--
229 * Finds a file in a : separated list of paths. ~ expansion is also
230 * done.
232 * Returns:
233 * The complete path for the file (in a newly allocated string) or
234 * NULL if the file was not found.
236 * Side effects:
237 * A new string is allocated. It must be freed later.
239 *----------------------------------------------------------------------
241 char *wfindfile(const char *paths, const char *file)
243 char *path;
244 const char *tmp, *tmp2;
245 int len, flen;
246 char *fullpath;
248 if (!file)
249 return NULL;
251 if (*file == '/' || *file == '~' || *file == '$' || !paths || *paths == 0) {
252 if (access(file, F_OK) < 0) {
253 fullpath = wexpandpath(file);
254 if (!fullpath)
255 return NULL;
257 if (access(fullpath, F_OK) < 0) {
258 wfree(fullpath);
259 return NULL;
260 } else {
261 return fullpath;
263 } else {
264 return wstrdup(file);
268 flen = strlen(file);
269 tmp = paths;
270 while (*tmp) {
271 tmp = skipchar(tmp, ':');
272 if (*tmp == 0)
273 break;
274 tmp2 = nextchar(tmp, ':');
275 len = tmp2 - tmp;
276 path = wmalloc(len + flen + 2);
277 path = memcpy(path, tmp, len);
278 path[len] = 0;
279 if (path[len - 1] != '/' &&
280 wstrlcat(path, "/", len + flen + 2) >= len + flen + 2) {
281 wfree(path);
282 return NULL;
285 if (wstrlcat(path, file, len + flen + 2) >= len + flen + 2) {
286 wfree(path);
287 return NULL;
290 fullpath = wexpandpath(path);
291 wfree(path);
293 if (fullpath) {
294 if (access(fullpath, F_OK) == 0) {
295 return fullpath;
297 wfree(fullpath);
299 tmp = tmp2;
302 return NULL;
305 char *wfindfileinlist(char *const *path_list, const char *file)
307 int i;
308 char *path;
309 int len, flen;
310 char *fullpath;
312 if (!file)
313 return NULL;
315 if (*file == '/' || *file == '~' || !path_list) {
316 if (access(file, F_OK) < 0) {
317 fullpath = wexpandpath(file);
318 if (!fullpath)
319 return NULL;
321 if (access(fullpath, F_OK) < 0) {
322 wfree(fullpath);
323 return NULL;
324 } else {
325 return fullpath;
327 } else {
328 return wstrdup(file);
332 flen = strlen(file);
333 for (i = 0; path_list[i] != NULL; i++) {
334 len = strlen(path_list[i]);
335 path = wmalloc(len + flen + 2);
336 path = memcpy(path, path_list[i], len);
337 path[len] = 0;
338 if (wstrlcat(path, "/", len + flen + 2) >= len + flen + 2 ||
339 wstrlcat(path, file, len + flen + 2) >= len + flen + 2) {
340 wfree(path);
341 return NULL;
343 /* expand tilde */
344 fullpath = wexpandpath(path);
345 wfree(path);
346 if (fullpath) {
347 /* check if file exists */
348 if (access(fullpath, F_OK) == 0) {
349 return fullpath;
351 wfree(fullpath);
355 return NULL;
358 char *wfindfileinarray(WMPropList *array, const char *file)
360 int i;
361 char *path;
362 int len, flen;
363 char *fullpath;
365 if (!file)
366 return NULL;
368 if (*file == '/' || *file == '~' || !array) {
369 if (access(file, F_OK) < 0) {
370 fullpath = wexpandpath(file);
371 if (!fullpath)
372 return NULL;
374 if (access(fullpath, F_OK) < 0) {
375 wfree(fullpath);
376 return NULL;
377 } else {
378 return fullpath;
380 } else {
381 return wstrdup(file);
385 flen = strlen(file);
386 for (i = 0; i < WMGetPropListItemCount(array); i++) {
387 WMPropList *prop;
388 char *p;
390 prop = WMGetFromPLArray(array, i);
391 if (!prop)
392 continue;
393 p = WMGetFromPLString(prop);
395 len = strlen(p);
396 path = wmalloc(len + flen + 2);
397 path = memcpy(path, p, len);
398 path[len] = 0;
399 if (wstrlcat(path, "/", len + flen + 2) >= len + flen + 2 ||
400 wstrlcat(path, file, len + flen + 2) >= len + flen + 2) {
401 wfree(path);
402 return NULL;
404 /* expand tilde */
405 fullpath = wexpandpath(path);
406 wfree(path);
407 if (fullpath) {
408 /* check if file exists */
409 if (access(fullpath, F_OK) == 0) {
410 return fullpath;
412 wfree(fullpath);
415 return NULL;
418 int wcopy_file(const char *dir, const char *src_file, const char *dest_file)
420 FILE *src, *dst;
421 size_t nread, nwritten;
422 char *dstpath;
423 struct stat st;
424 char buf[4096];
426 /* only to a directory */
427 if (stat(dir, &st) != 0 || !S_ISDIR(st.st_mode))
428 return -1;
429 /* only copy files */
430 if (stat(src_file, &st) != 0 || !S_ISREG(st.st_mode))
431 return -1;
433 RETRY( src = fopen(src_file, "rb") )
434 if (src == NULL) {
435 werror(_("Could not open %s"), src_file);
436 return -1;
439 dstpath = wstrconcat(dir, dest_file);
440 RETRY( dst = fopen(dstpath, "wb") )
441 if (dst == NULL) {
442 werror(_("Could not create %s"), dstpath);
443 wfree(dstpath);
444 RETRY( fclose(src) )
445 return -1;
448 do {
449 RETRY( nread = fread(buf, 1, sizeof(buf), src) )
450 if (ferror(src))
451 break;
453 RETRY( nwritten = fwrite(buf, 1, nread, dst) )
454 if (ferror(dst) || feof(src) || nread != nwritten)
455 break;
457 } while (1);
459 if (ferror(src) || ferror(dst))
460 unlink(dstpath);
462 RETRY( fclose(src) )
463 fchmod(fileno(dst), st.st_mode);
464 fsync(fileno(dst));
465 RETRY( fclose(dst) )
466 wfree(dstpath);
468 return 0;