Icon creation in only one function
[wmaker-crm.git] / WINGs / findfile.c
blobeb50609d84d2bf4f4df87d78361803d1dfe820c6
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., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include "wconfig.h"
23 #include "WUtil.h"
25 #include <sys/stat.h>
26 #include <errno.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <pwd.h>
32 #include <limits.h>
34 #ifndef PATH_MAX
35 #define PATH_MAX 1024
36 #endif
38 #define RETRY( x ) do { x; } while (errno == EINTR);
40 char *wgethomedir()
42 static char *home = NULL;
43 char *tmp;
44 struct passwd *user;
46 if (home)
47 return home;
49 tmp = getenv("HOME");
50 if (tmp) {
51 home = wstrdup(tmp);
52 return home;
55 user = getpwuid(getuid());
56 if (!user) {
57 werror(_("could not get password entry for UID %i"), getuid());
58 home = "/";
61 if (!user->pw_dir)
62 home = "/";
63 else
64 home = wstrdup(user->pw_dir);
66 return home;
69 static char *getuserhomedir(const char *username)
71 static char *home = NULL;
72 struct passwd *user;
74 if (home)
75 return home;
77 user = getpwnam(username);
78 if (!user) {
79 werror(_("could not get password entry for user %s"), username);
80 return NULL;
82 if (!user->pw_dir)
83 home = "/";
84 else
85 home = wstrdup(user->pw_dir);
87 return home;
90 char *wexpandpath(char *path)
92 char *origpath = path;
93 char buffer2[PATH_MAX + 2];
94 char buffer[PATH_MAX + 2];
95 int i;
97 memset(buffer, 0, PATH_MAX + 2);
99 if (*path == '~') {
100 char *home;
102 path++;
103 if (*path == '/' || *path == 0) {
104 home = wgethomedir();
105 if (strlen(home) > PATH_MAX ||
106 wstrlcpy(buffer, home, sizeof(buffer)) >= sizeof(buffer))
107 goto error;
108 } else {
109 int j;
110 j = 0;
111 while (*path != 0 && *path != '/') {
112 if (j > PATH_MAX)
113 goto error;
114 buffer2[j++] = *path;
115 buffer2[j] = 0;
116 path++;
118 home = getuserhomedir(buffer2);
119 if (!home || wstrlcat(buffer, home, sizeof(buffer)) >= sizeof(buffer))
120 goto error;
124 i = strlen(buffer);
126 while (*path != 0 && i <= PATH_MAX) {
127 char *tmp;
129 if (*path == '$') {
130 int j = 0;
131 path++;
132 /* expand $(HOME) or $HOME style environment variables */
133 if (*path == '(') {
134 path++;
135 while (*path != 0 && *path != ')') {
136 if (j > PATH_MAX)
137 goto error;
138 buffer2[j++] = *(path++);
139 buffer2[j] = 0;
141 if (*path == ')') {
142 path++;
143 tmp = getenv(buffer2);
144 } else {
145 tmp = NULL;
147 if (!tmp) {
148 if ((i += strlen(buffer2) + 2) > PATH_MAX)
149 goto error;
150 buffer[i] = 0;
151 if (wstrlcat(buffer, "$(", sizeof(buffer)) >= sizeof(buffer) ||
152 wstrlcat(buffer, buffer2, sizeof(buffer)) >= sizeof(buffer))
153 goto error;
154 if (*(path-1)==')') {
155 if (++i > PATH_MAX ||
156 wstrlcat(buffer, ")", sizeof(buffer)) >= sizeof(buffer))
157 goto error;
159 } else {
160 if ((i += strlen(tmp)) > PATH_MAX ||
161 wstrlcat(buffer, tmp, sizeof(buffer)) >= sizeof(buffer))
162 goto error;
164 } else {
165 while (*path != 0 && *path != '/') {
166 if (j > PATH_MAX)
167 goto error;
168 buffer2[j++] = *(path++);
169 buffer2[j] = 0;
171 tmp = getenv(buffer2);
172 if (!tmp) {
173 if ((i += strlen(buffer2) + 1) > PATH_MAX ||
174 wstrlcat(buffer, "$", sizeof(buffer)) >= sizeof(buffer) ||
175 wstrlcat(buffer, buffer2, sizeof(buffer)) >= sizeof(buffer))
176 goto error;
177 } else {
178 if ((i += strlen(tmp)) > PATH_MAX ||
179 wstrlcat(buffer, tmp, sizeof(buffer)) >= sizeof(buffer))
180 goto error;
183 } else {
184 buffer[i++] = *path;
185 path++;
189 if (*path!=0)
190 goto error;
192 return wstrdup(buffer);
194 error:
195 errno = ENAMETOOLONG;
196 werror(_("could not expand %s"), origpath);
198 return NULL;
201 /* return address of next char != tok or end of string whichever comes first */
202 static char *skipchar(char *string, char tok)
204 while (*string != 0 && *string == tok)
205 string++;
207 return string;
210 /* return address of next char == tok or end of string whichever comes first */
211 static char *nextchar(char *string, char tok)
213 while (*string != 0 && *string != tok)
214 string++;
216 return string;
220 *----------------------------------------------------------------------
221 * findfile--
222 * Finds a file in a : separated list of paths. ~ expansion is also
223 * done.
225 * Returns:
226 * The complete path for the file (in a newly allocated string) or
227 * NULL if the file was not found.
229 * Side effects:
230 * A new string is allocated. It must be freed later.
232 *----------------------------------------------------------------------
234 char *wfindfile(char *paths, char *file)
236 char *path;
237 char *tmp, *tmp2;
238 int len, flen;
239 char *fullpath;
241 if (!file)
242 return NULL;
244 if (*file == '/' || *file == '~' || *file == '$' || !paths || *paths == 0) {
245 if (access(file, F_OK) < 0) {
246 fullpath = wexpandpath(file);
247 if (!fullpath)
248 return NULL;
250 if (access(fullpath, F_OK) < 0) {
251 wfree(fullpath);
252 return NULL;
253 } else {
254 return fullpath;
256 } else {
257 return wstrdup(file);
261 flen = strlen(file);
262 tmp = paths;
263 while (*tmp) {
264 tmp = skipchar(tmp, ':');
265 if (*tmp == 0)
266 break;
267 tmp2 = nextchar(tmp, ':');
268 len = tmp2 - tmp;
269 path = wmalloc(len + flen + 2);
270 path = memcpy(path, tmp, len);
271 path[len] = 0;
272 if (path[len - 1] != '/' &&
273 wstrlcat(path, "/", len + flen + 2) >= len + flen + 2) {
274 wfree(path);
275 return NULL;
278 if (wstrlcat(path, file, len + flen + 2) >= len + flen + 2) {
279 wfree(path);
280 return NULL;
283 fullpath = wexpandpath(path);
284 wfree(path);
286 if (fullpath) {
287 if (access(fullpath, F_OK) == 0) {
288 return fullpath;
290 wfree(fullpath);
292 tmp = tmp2;
295 return NULL;
298 char *wfindfileinlist(char **path_list, char *file)
300 int i;
301 char *path;
302 int len, flen;
303 char *fullpath;
305 if (!file)
306 return NULL;
308 if (*file == '/' || *file == '~' || !path_list) {
309 if (access(file, F_OK) < 0) {
310 fullpath = wexpandpath(file);
311 if (!fullpath)
312 return NULL;
314 if (access(fullpath, F_OK) < 0) {
315 wfree(fullpath);
316 return NULL;
317 } else {
318 return fullpath;
320 } else {
321 return wstrdup(file);
325 flen = strlen(file);
326 for (i = 0; path_list[i] != NULL; i++) {
327 len = strlen(path_list[i]);
328 path = wmalloc(len + flen + 2);
329 path = memcpy(path, path_list[i], len);
330 path[len] = 0;
331 if (wstrlcat(path, "/", len + flen + 2) >= len + flen + 2 ||
332 wstrlcat(path, file, len + flen + 2) >= len + flen + 2) {
333 wfree(path);
334 return NULL;
336 /* expand tilde */
337 fullpath = wexpandpath(path);
338 wfree(path);
339 if (fullpath) {
340 /* check if file exists */
341 if (access(fullpath, F_OK) == 0) {
342 return fullpath;
344 wfree(fullpath);
348 return NULL;
351 char *wfindfileinarray(WMPropList * array, char *file)
353 int i;
354 char *path;
355 int len, flen;
356 char *fullpath;
358 if (!file)
359 return NULL;
361 if (*file == '/' || *file == '~' || !array) {
362 if (access(file, F_OK) < 0) {
363 fullpath = wexpandpath(file);
364 if (!fullpath)
365 return NULL;
367 if (access(fullpath, F_OK) < 0) {
368 wfree(fullpath);
369 return NULL;
370 } else {
371 return fullpath;
373 } else {
374 return wstrdup(file);
378 flen = strlen(file);
379 for (i = 0; i < WMGetPropListItemCount(array); i++) {
380 WMPropList *prop;
381 char *p;
383 prop = WMGetFromPLArray(array, i);
384 if (!prop)
385 continue;
386 p = WMGetFromPLString(prop);
388 len = strlen(p);
389 path = wmalloc(len + flen + 2);
390 path = memcpy(path, p, len);
391 path[len] = 0;
392 if (wstrlcat(path, "/", len + flen + 2) >= len + flen + 2 ||
393 wstrlcat(path, file, len + flen + 2) >= len + flen + 2) {
394 wfree(path);
395 return NULL;
397 /* expand tilde */
398 fullpath = wexpandpath(path);
399 wfree(path);
400 if (fullpath) {
401 /* check if file exists */
402 if (access(fullpath, F_OK) == 0) {
403 return fullpath;
405 wfree(fullpath);
408 return NULL;
411 int wcopy_file(char *dir, char *src_file, char *dest_file)
413 FILE *src, *dst;
414 size_t nread, nwritten;
415 char *dstpath;
416 struct stat st;
417 char buf[4096];
419 /* only to a directory */
420 if (stat(dir, &st) != 0 || !S_ISDIR(st.st_mode))
421 return -1;
422 /* only copy files */
423 if (stat(src_file, &st) != 0 || !S_ISREG(st.st_mode))
424 return -1;
426 RETRY( src = fopen(src_file, "rb") )
427 if (src == NULL) {
428 werror(_("Could not open %s"), src_file);
429 return -1;
432 dstpath = wstrconcat(dir, dest_file);
433 RETRY( dst = fopen(dstpath, "wb") )
434 if (dst == NULL) {
435 werror(_("Could not create %s"), dstpath);
436 wfree(dstpath);
437 RETRY( fclose(src) )
438 return -1;
441 do {
442 RETRY( nread = fread(buf, 1, sizeof(buf), src) )
443 if (ferror(src))
444 break;
446 RETRY( nwritten = fwrite(buf, 1, nread, dst) )
447 if (ferror(dst) || feof(src) || nread != nwritten)
448 break;
450 } while (1);
452 if (ferror(src) || ferror(dst))
453 unlink(dstpath);
455 RETRY( fclose(src) )
456 fchmod(fileno(dst), st.st_mode);
457 fsync(fileno(dst));
458 RETRY( fclose(dst) )
459 wfree(dstpath);
461 return 0;