Change to the linux kernel coding style
[wmaker-crm.git] / WINGs / findfile.c
1 /*
2  *  Window Maker miscelaneous function library
3  *
4  *  Copyright (c) 1997-2003 Alfredo K. Kojima
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  *  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.
19  */
20
21 #include "wconfig.h"
22
23 #include "WUtil.h"
24
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <pwd.h>
29 #include <limits.h>
30
31 #ifndef PATH_MAX
32 #define PATH_MAX  1024
33 #endif
34
35 char *wgethomedir()
36 {
37         char *home = getenv("HOME");
38         struct passwd *user;
39
40         if (home)
41                 return home;
42
43         user = getpwuid(getuid());
44         if (!user) {
45                 wsyserror(_("could not get password entry for UID %i"), getuid());
46                 return "/";
47         }
48         if (!user->pw_dir) {
49                 return "/";
50         } else {
51                 return user->pw_dir;
52         }
53 }
54
55 static char *getuserhomedir(char *username)
56 {
57         struct passwd *user;
58
59         user = getpwnam(username);
60         if (!user) {
61                 wsyserror(_("could not get password entry for user %s"), username);
62                 return NULL;
63         }
64         if (!user->pw_dir) {
65                 return "/";
66         } else {
67                 return user->pw_dir;
68         }
69 }
70
71 char *wexpandpath(char *path)
72 {
73         char buffer2[PATH_MAX + 2];
74         char buffer[PATH_MAX + 2];
75         int i;
76
77         memset(buffer, 0, PATH_MAX + 2);
78
79         if (*path == '~') {
80                 char *home;
81
82                 path++;
83                 if (*path == '/' || *path == 0) {
84                         home = wgethomedir();
85                         strcat(buffer, home);
86                 } else {
87                         int j;
88                         j = 0;
89                         while (*path != 0 && *path != '/') {
90                                 buffer2[j++] = *path;
91                                 buffer2[j] = 0;
92                                 path++;
93                         }
94                         home = getuserhomedir(buffer2);
95                         if (!home)
96                                 return NULL;
97                         strcat(buffer, home);
98                 }
99         }
100
101         i = strlen(buffer);
102
103         while (*path != 0) {
104                 char *tmp;
105
106                 if (*path == '$') {
107                         int j = 0;
108                         path++;
109                         /* expand $(HOME) or $HOME style environment variables */
110                         if (*path == '(') {
111                                 path++;
112                                 while (*path != 0 && *path != ')') {
113                                         buffer2[j++] = *(path++);
114                                         buffer2[j] = 0;
115                                 }
116                                 if (*path == ')')
117                                         path++;
118                                 tmp = getenv(buffer2);
119                                 if (!tmp) {
120                                         buffer[i] = 0;
121                                         strcat(buffer, "$(");
122                                         strcat(buffer, buffer2);
123                                         strcat(buffer, ")");
124                                         i += strlen(buffer2) + 3;
125                                 } else {
126                                         strcat(buffer, tmp);
127                                         i += strlen(tmp);
128                                 }
129                         } else {
130                                 while (*path != 0 && *path != '/') {
131                                         buffer2[j++] = *(path++);
132                                         buffer2[j] = 0;
133                                 }
134                                 tmp = getenv(buffer2);
135                                 if (!tmp) {
136                                         strcat(buffer, "$");
137                                         strcat(buffer, buffer2);
138                                         i += strlen(buffer2) + 1;
139                                 } else {
140                                         strcat(buffer, tmp);
141                                         i += strlen(tmp);
142                                 }
143                         }
144                 } else {
145                         buffer[i++] = *path;
146                         path++;
147                 }
148         }
149
150         return wstrdup(buffer);
151 }
152
153 /* return address of next char != tok or end of string whichever comes first */
154 static char *skipchar(char *string, char tok)
155 {
156         while (*string != 0 && *string == tok)
157                 string++;
158
159         return string;
160 }
161
162 /* return address of next char == tok or end of string whichever comes first */
163 static char *nextchar(char *string, char tok)
164 {
165         while (*string != 0 && *string != tok)
166                 string++;
167
168         return string;
169 }
170
171 /*
172  *----------------------------------------------------------------------
173  * findfile--
174  *      Finds a file in a : separated list of paths. ~ expansion is also
175  * done.
176  *
177  * Returns:
178  *      The complete path for the file (in a newly allocated string) or
179  * NULL if the file was not found.
180  *
181  * Side effects:
182  *      A new string is allocated. It must be freed later.
183  *
184  *----------------------------------------------------------------------
185  */
186 char *wfindfile(char *paths, char *file)
187 {
188         char *path;
189         char *tmp, *tmp2;
190         int len, flen;
191         char *fullpath;
192
193         if (!file)
194                 return NULL;
195
196         if (*file == '/' || *file == '~' || *file == '$' || !paths || *paths == 0) {
197                 if (access(file, F_OK) < 0) {
198                         fullpath = wexpandpath(file);
199                         if (!fullpath)
200                                 return NULL;
201
202                         if (access(fullpath, F_OK) < 0) {
203                                 wfree(fullpath);
204                                 return NULL;
205                         } else {
206                                 return fullpath;
207                         }
208                 } else {
209                         return wstrdup(file);
210                 }
211         }
212
213         flen = strlen(file);
214         tmp = paths;
215         while (*tmp) {
216                 tmp = skipchar(tmp, ':');
217                 if (*tmp == 0)
218                         break;
219                 tmp2 = nextchar(tmp, ':');
220                 len = tmp2 - tmp;
221                 path = wmalloc(len + flen + 2);
222                 path = memcpy(path, tmp, len);
223                 path[len] = 0;
224                 if (path[len - 1] != '/')
225                         strcat(path, "/");
226                 strcat(path, file);
227                 fullpath = wexpandpath(path);
228                 wfree(path);
229                 if (fullpath) {
230                         if (access(fullpath, F_OK) == 0) {
231                                 return fullpath;
232                         }
233                         wfree(fullpath);
234                 }
235                 tmp = tmp2;
236         }
237
238         return NULL;
239 }
240
241 char *wfindfileinlist(char **path_list, char *file)
242 {
243         int i;
244         char *path;
245         int len, flen;
246         char *fullpath;
247
248         if (!file)
249                 return NULL;
250
251         if (*file == '/' || *file == '~' || !path_list) {
252                 if (access(file, F_OK) < 0) {
253                         fullpath = wexpandpath(file);
254                         if (!fullpath)
255                                 return NULL;
256
257                         if (access(fullpath, F_OK) < 0) {
258                                 wfree(fullpath);
259                                 return NULL;
260                         } else {
261                                 return fullpath;
262                         }
263                 } else {
264                         return wstrdup(file);
265                 }
266         }
267
268         flen = strlen(file);
269         for (i = 0; path_list[i] != NULL; i++) {
270                 len = strlen(path_list[i]);
271                 path = wmalloc(len + flen + 2);
272                 path = memcpy(path, path_list[i], len);
273                 path[len] = 0;
274                 strcat(path, "/");
275                 strcat(path, file);
276                 /* expand tilde */
277                 fullpath = wexpandpath(path);
278                 wfree(path);
279                 if (fullpath) {
280                         /* check if file exists */
281                         if (access(fullpath, F_OK) == 0) {
282                                 return fullpath;
283                         }
284                         wfree(fullpath);
285                 }
286         }
287         return NULL;
288 }
289
290 char *wfindfileinarray(WMPropList * array, char *file)
291 {
292         int i;
293         char *path;
294         int len, flen;
295         char *fullpath;
296
297         if (!file)
298                 return NULL;
299
300         if (*file == '/' || *file == '~' || !array) {
301                 if (access(file, F_OK) < 0) {
302                         fullpath = wexpandpath(file);
303                         if (!fullpath)
304                                 return NULL;
305
306                         if (access(fullpath, F_OK) < 0) {
307                                 wfree(fullpath);
308                                 return NULL;
309                         } else {
310                                 return fullpath;
311                         }
312                 } else {
313                         return wstrdup(file);
314                 }
315         }
316
317         flen = strlen(file);
318         for (i = 0; i < WMGetPropListItemCount(array); i++) {
319                 WMPropList *prop;
320                 char *p;
321
322                 prop = WMGetFromPLArray(array, i);
323                 if (!prop)
324                         continue;
325                 p = WMGetFromPLString(prop);
326
327                 len = strlen(p);
328                 path = wmalloc(len + flen + 2);
329                 path = memcpy(path, p, len);
330                 path[len] = 0;
331                 strcat(path, "/");
332                 strcat(path, file);
333                 /* expand tilde */
334                 fullpath = wexpandpath(path);
335                 wfree(path);
336                 if (fullpath) {
337                         /* check if file exists */
338                         if (access(fullpath, F_OK) == 0) {
339                                 return fullpath;
340                         }
341                         wfree(fullpath);
342                 }
343         }
344         return NULL;
345 }