simplified logic of wMaximizeWindow function
[wmaker-crm.git] / WINGs / findfile.c
blobf18aa3ae82feed5cfe3096e63266405708725b66
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;
70 static char *getuserhomedir(const char *username)
72 static char *home = NULL;
73 struct passwd *user;
75 if (home)
76 return home;
78 user = getpwnam(username);
79 if (!user) {
80 werror(_("could not get password entry for user %s"), username);
81 return NULL;
83 if (!user->pw_dir)
84 home = "/";
85 else
86 home = wstrdup(user->pw_dir);
88 return home;
91 char *wexpandpath(const char *path)
93 const char *origpath = path;
94 char buffer2[PATH_MAX + 2];
95 char buffer[PATH_MAX + 2];
96 int i;
98 memset(buffer, 0, PATH_MAX + 2);
100 if (*path == '~') {
101 char *home;
103 path++;
104 if (*path == '/' || *path == 0) {
105 home = wgethomedir();
106 if (strlen(home) > PATH_MAX ||
107 wstrlcpy(buffer, home, sizeof(buffer)) >= sizeof(buffer))
108 goto error;
109 } else {
110 int j;
111 j = 0;
112 while (*path != 0 && *path != '/') {
113 if (j > PATH_MAX)
114 goto error;
115 buffer2[j++] = *path;
116 buffer2[j] = 0;
117 path++;
119 home = getuserhomedir(buffer2);
120 if (!home || wstrlcat(buffer, home, sizeof(buffer)) >= sizeof(buffer))
121 goto error;
125 i = strlen(buffer);
127 while (*path != 0 && i <= PATH_MAX) {
128 char *tmp;
130 if (*path == '$') {
131 int j = 0;
132 path++;
133 /* expand $(HOME) or $HOME style environment variables */
134 if (*path == '(') {
135 path++;
136 while (*path != 0 && *path != ')') {
137 if (j > PATH_MAX)
138 goto error;
139 buffer2[j++] = *(path++);
140 buffer2[j] = 0;
142 if (*path == ')') {
143 path++;
144 tmp = getenv(buffer2);
145 } else {
146 tmp = NULL;
148 if (!tmp) {
149 if ((i += strlen(buffer2) + 2) > PATH_MAX)
150 goto error;
151 buffer[i] = 0;
152 if (wstrlcat(buffer, "$(", sizeof(buffer)) >= sizeof(buffer) ||
153 wstrlcat(buffer, buffer2, sizeof(buffer)) >= sizeof(buffer))
154 goto error;
155 if (*(path-1)==')') {
156 if (++i > PATH_MAX ||
157 wstrlcat(buffer, ")", sizeof(buffer)) >= sizeof(buffer))
158 goto error;
160 } else {
161 if ((i += strlen(tmp)) > PATH_MAX ||
162 wstrlcat(buffer, tmp, sizeof(buffer)) >= sizeof(buffer))
163 goto error;
165 } else {
166 while (*path != 0 && *path != '/') {
167 if (j > PATH_MAX)
168 goto error;
169 buffer2[j++] = *(path++);
170 buffer2[j] = 0;
172 tmp = getenv(buffer2);
173 if (!tmp) {
174 if ((i += strlen(buffer2) + 1) > PATH_MAX ||
175 wstrlcat(buffer, "$", sizeof(buffer)) >= sizeof(buffer) ||
176 wstrlcat(buffer, buffer2, sizeof(buffer)) >= sizeof(buffer))
177 goto error;
178 } else {
179 if ((i += strlen(tmp)) > PATH_MAX ||
180 wstrlcat(buffer, tmp, sizeof(buffer)) >= sizeof(buffer))
181 goto error;
184 } else {
185 buffer[i++] = *path;
186 path++;
190 if (*path!=0)
191 goto error;
193 return wstrdup(buffer);
195 error:
196 errno = ENAMETOOLONG;
197 werror(_("could not expand %s"), origpath);
199 return NULL;
202 /* return address of next char != tok or end of string whichever comes first */
203 static const char *skipchar(const char *string, char tok)
205 while (*string != 0 && *string == tok)
206 string++;
208 return string;
211 /* return address of next char == tok or end of string whichever comes first */
212 static const char *nextchar(const char *string, char tok)
214 while (*string != 0 && *string != tok)
215 string++;
217 return string;
221 *----------------------------------------------------------------------
222 * findfile--
223 * Finds a file in a : separated list of paths. ~ expansion is also
224 * done.
226 * Returns:
227 * The complete path for the file (in a newly allocated string) or
228 * NULL if the file was not found.
230 * Side effects:
231 * A new string is allocated. It must be freed later.
233 *----------------------------------------------------------------------
235 char *wfindfile(const char *paths, const char *file)
237 char *path;
238 const char *tmp, *tmp2;
239 int len, flen;
240 char *fullpath;
242 if (!file)
243 return NULL;
245 if (*file == '/' || *file == '~' || *file == '$' || !paths || *paths == 0) {
246 if (access(file, F_OK) < 0) {
247 fullpath = wexpandpath(file);
248 if (!fullpath)
249 return NULL;
251 if (access(fullpath, F_OK) < 0) {
252 wfree(fullpath);
253 return NULL;
254 } else {
255 return fullpath;
257 } else {
258 return wstrdup(file);
262 flen = strlen(file);
263 tmp = paths;
264 while (*tmp) {
265 tmp = skipchar(tmp, ':');
266 if (*tmp == 0)
267 break;
268 tmp2 = nextchar(tmp, ':');
269 len = tmp2 - tmp;
270 path = wmalloc(len + flen + 2);
271 path = memcpy(path, tmp, len);
272 path[len] = 0;
273 if (path[len - 1] != '/' &&
274 wstrlcat(path, "/", len + flen + 2) >= len + flen + 2) {
275 wfree(path);
276 return NULL;
279 if (wstrlcat(path, file, len + flen + 2) >= len + flen + 2) {
280 wfree(path);
281 return NULL;
284 fullpath = wexpandpath(path);
285 wfree(path);
287 if (fullpath) {
288 if (access(fullpath, F_OK) == 0) {
289 return fullpath;
291 wfree(fullpath);
293 tmp = tmp2;
296 return NULL;
299 char *wfindfileinlist(char *const *path_list, const char *file)
301 int i;
302 char *path;
303 int len, flen;
304 char *fullpath;
306 if (!file)
307 return NULL;
309 if (*file == '/' || *file == '~' || !path_list) {
310 if (access(file, F_OK) < 0) {
311 fullpath = wexpandpath(file);
312 if (!fullpath)
313 return NULL;
315 if (access(fullpath, F_OK) < 0) {
316 wfree(fullpath);
317 return NULL;
318 } else {
319 return fullpath;
321 } else {
322 return wstrdup(file);
326 flen = strlen(file);
327 for (i = 0; path_list[i] != NULL; i++) {
328 len = strlen(path_list[i]);
329 path = wmalloc(len + flen + 2);
330 path = memcpy(path, path_list[i], len);
331 path[len] = 0;
332 if (wstrlcat(path, "/", len + flen + 2) >= len + flen + 2 ||
333 wstrlcat(path, file, len + flen + 2) >= len + flen + 2) {
334 wfree(path);
335 return NULL;
337 /* expand tilde */
338 fullpath = wexpandpath(path);
339 wfree(path);
340 if (fullpath) {
341 /* check if file exists */
342 if (access(fullpath, F_OK) == 0) {
343 return fullpath;
345 wfree(fullpath);
349 return NULL;
352 char *wfindfileinarray(WMPropList *array, const char *file)
354 int i;
355 char *path;
356 int len, flen;
357 char *fullpath;
359 if (!file)
360 return NULL;
362 if (*file == '/' || *file == '~' || !array) {
363 if (access(file, F_OK) < 0) {
364 fullpath = wexpandpath(file);
365 if (!fullpath)
366 return NULL;
368 if (access(fullpath, F_OK) < 0) {
369 wfree(fullpath);
370 return NULL;
371 } else {
372 return fullpath;
374 } else {
375 return wstrdup(file);
379 flen = strlen(file);
380 for (i = 0; i < WMGetPropListItemCount(array); i++) {
381 WMPropList *prop;
382 char *p;
384 prop = WMGetFromPLArray(array, i);
385 if (!prop)
386 continue;
387 p = WMGetFromPLString(prop);
389 len = strlen(p);
390 path = wmalloc(len + flen + 2);
391 path = memcpy(path, p, len);
392 path[len] = 0;
393 if (wstrlcat(path, "/", len + flen + 2) >= len + flen + 2 ||
394 wstrlcat(path, file, len + flen + 2) >= len + flen + 2) {
395 wfree(path);
396 return NULL;
398 /* expand tilde */
399 fullpath = wexpandpath(path);
400 wfree(path);
401 if (fullpath) {
402 /* check if file exists */
403 if (access(fullpath, F_OK) == 0) {
404 return fullpath;
406 wfree(fullpath);
409 return NULL;
412 int wcopy_file(const char *dir, const char *src_file, const char *dest_file)
414 FILE *src, *dst;
415 size_t nread, nwritten;
416 char *dstpath;
417 struct stat st;
418 char buf[4096];
420 /* only to a directory */
421 if (stat(dir, &st) != 0 || !S_ISDIR(st.st_mode))
422 return -1;
423 /* only copy files */
424 if (stat(src_file, &st) != 0 || !S_ISREG(st.st_mode))
425 return -1;
427 RETRY( src = fopen(src_file, "rb") )
428 if (src == NULL) {
429 werror(_("Could not open %s"), src_file);
430 return -1;
433 dstpath = wstrconcat(dir, dest_file);
434 RETRY( dst = fopen(dstpath, "wb") )
435 if (dst == NULL) {
436 werror(_("Could not create %s"), dstpath);
437 wfree(dstpath);
438 RETRY( fclose(src) )
439 return -1;
442 do {
443 RETRY( nread = fread(buf, 1, sizeof(buf), src) )
444 if (ferror(src))
445 break;
447 RETRY( nwritten = fwrite(buf, 1, nread, dst) )
448 if (ferror(dst) || feof(src) || nread != nwritten)
449 break;
451 } while (1);
453 if (ferror(src) || ferror(dst))
454 unlink(dstpath);
456 RETRY( fclose(src) )
457 fchmod(fileno(dst), st.st_mode);
458 fsync(fileno(dst));
459 RETRY( fclose(dst) )
460 wfree(dstpath);
462 return 0;