1 /*
2 * Portable Utility Functions
3 *
4 * Author:
5 * Miguel de Icaza (miguel@novell.com)
6 *
7 * (C) 2006 Novell, Inc.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining
10 * a copy of this software and associated documentation files (the
11 * "Software"), to deal in the Software without restriction, including
12 * without limitation the rights to use, copy, modify, merge, publish,
13 * distribute, sublicense, and/or sell copies of the Software, and to
14 * permit persons to whom the Software is furnished to do so, subject to
15 * the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 */
28 #include <config.h>
29 #include <stdio.h>
30 #include <glib.h>
31 #include <errno.h>
32 #include <sys/stat.h>
33
34 #ifdef G_OS_WIN32
35 #include <direct.h>
36 #endif
37
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41
42 gchar *
g_build_path(const gchar * separator,const gchar * first_element,...)43 g_build_path (const gchar *separator, const gchar *first_element, ...)
44 {
45 const char *elem, *next, *endptr;
46 gboolean trimmed;
47 GString *path;
48 va_list args;
49 size_t slen;
50
51 g_return_val_if_fail (separator != NULL, NULL);
52
53 path = g_string_sized_new (48);
54 slen = strlen (separator);
55
56 va_start (args, first_element);
57 for (elem = first_element; elem != NULL; elem = next) {
58 /* trim any trailing separators from @elem */
59 endptr = elem + strlen (elem);
60 trimmed = FALSE;
61
62 while (endptr >= elem + slen) {
63 if (strncmp (endptr - slen, separator, slen) != 0)
64 break;
65
66 endptr -= slen;
67 trimmed = TRUE;
68 }
69
70 /* append elem, not including any trailing separators */
71 if (endptr > elem)
72 g_string_append_len (path, elem, endptr - elem);
73
74 /* get the next element */
75 do {
76 if (!(next = va_arg (args, char *)))
77 break;
78
79 /* remove leading separators */
80 while (!strncmp (next, separator, slen))
81 next += slen;
82 } while (*next == '\0');
83
84 if (next || trimmed)
85 g_string_append_len (path, separator, slen);
86 }
87 va_end (args);
88
89 return g_string_free (path, FALSE);
90 }
91
92 static gchar*
strrchr_seperator(const gchar * filename)93 strrchr_seperator (const gchar* filename)
94 {
95 #ifdef G_OS_WIN32
96 char *p2;
97 #endif
98 char *p;
99
100 p = strrchr (filename, G_DIR_SEPARATOR);
101 #ifdef G_OS_WIN32
102 p2 = strrchr (filename, '/');
103 if (p2 > p)
104 p = p2;
105 #endif
106
107 return p;
108 }
109
110 gchar *
g_path_get_dirname(const gchar * filename)111 g_path_get_dirname (const gchar *filename)
112 {
113 char *p, *r;
114 size_t count;
115 g_return_val_if_fail (filename != NULL, NULL);
116
117 p = strrchr_seperator (filename);
118 if (p == NULL)
119 return g_strdup (".");
120 if (p == filename)
121 return g_strdup ("/");
122 count = p - filename;
123 r = g_malloc (count + 1);
124 strncpy (r, filename, count);
125 r [count] = 0;
126
127 return r;
128 }
129
130 gchar *
g_path_get_basename(const char * filename)131 g_path_get_basename (const char *filename)
132 {
133 char *r;
134 g_return_val_if_fail (filename != NULL, NULL);
135
136 /* Empty filename -> . */
137 if (!*filename)
138 return g_strdup (".");
139
140 /* No separator -> filename */
141 r = strrchr_seperator (filename);
142 if (r == NULL)
143 return g_strdup (filename);
144
145 /* Trailing slash, remove component */
146 if (r [1] == 0){
147 char *copy = g_strdup (filename);
148 copy [r-filename] = 0;
149 r = strrchr_seperator (copy);
150
151 if (r == NULL){
152 g_free (copy);
153 return g_strdup ("/");
154 }
155 r = g_strdup (&r[1]);
156 g_free (copy);
157 return r;
158 }
159
160 return g_strdup (&r[1]);
161 }
162
163 //wasm does have strtok_r even though autoconf fails to find
164 #if !defined (HAVE_STRTOK_R) && !defined (HOST_WASM)
165 // This is from BSD's strtok_r
166
167 char *
strtok_r(char * s,const char * delim,char ** last)168 strtok_r(char *s, const char *delim, char **last)
169 {
170 char *spanp;
171 int c, sc;
172 char *tok;
173
174 if (s == NULL && (s = *last) == NULL)
175 return NULL;
176
177 /*
178 * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
179 */
180 cont:
181 c = *s++;
182 for (spanp = (char *)delim; (sc = *spanp++) != 0; ){
183 if (c == sc)
184 goto cont;
185 }
186
187 if (c == 0){ /* no non-delimiter characters */
188 *last = NULL;
189 return NULL;
190 }
191 tok = s - 1;
192
193 /*
194 * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
195 * Note that delim must have one NUL; we stop if we see that, too.
196 */
197 for (;;){
198 c = *s++;
199 spanp = (char *)delim;
200 do {
201 if ((sc = *spanp++) == c) {
202 if (c == 0)
203 s = NULL;
204 else {
205 char *w = s - 1;
206 *w = '\0';
207 }
208 *last = s;
209 return tok;
210 }
211 }
212 while (sc != 0);
213 }
214 /* NOTREACHED */
215 }
216 #endif
217
218 gchar *
g_find_program_in_path(const gchar * program)219 g_find_program_in_path (const gchar *program)
220 {
221 char *p;
222 char *x, *l;
223 gchar *curdir = NULL;
224 char *save = NULL;
225 #ifdef G_OS_WIN32
226 char *program_exe;
227 char *suffix_list[5] = {".exe",".cmd",".bat",".com",NULL};
228 int listx;
229 gboolean hasSuffix;
230 #endif
231
232 g_return_val_if_fail (program != NULL, NULL);
233 x = p = g_strdup (g_getenv ("PATH"));
234
235 if (x == NULL || *x == '\0') {
236 curdir = g_get_current_dir ();
237 x = curdir;
238 }
239
240 #ifdef G_OS_WIN32
241 /* see if program already has a suffix */
242 listx = 0;
243 hasSuffix = FALSE;
244 while (!hasSuffix && suffix_list[listx]) {
245 hasSuffix = g_str_has_suffix(program,suffix_list[listx++]);
246 }
247 #endif
248
249 while ((l = strtok_r (x, G_SEARCHPATH_SEPARATOR_S, &save)) != NULL){
250 char *probe_path;
251
252 x = NULL;
253 probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program, NULL);
254 if (access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */
255 g_free (curdir);
256 g_free (p);
257 return probe_path;
258 }
259 g_free (probe_path);
260
261 #ifdef G_OS_WIN32
262 /* check for program with a suffix attached */
263 if (!hasSuffix) {
264 listx = 0;
265 while (suffix_list[listx]) {
266 program_exe = g_strjoin(NULL,program,suffix_list[listx],NULL);
267 probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program_exe, NULL);
268 if (access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */
269 g_free (curdir);
270 g_free (p);
271 g_free (program_exe);
272 return probe_path;
273 }
274 listx++;
275 g_free (probe_path);
276 g_free (program_exe);
277 }
278 }
279 #endif
280 }
281 g_free (curdir);
282 g_free (p);
283 return NULL;
284 }
285
286 static char *name;
287
288 void
g_set_prgname(const gchar * prgname)289 g_set_prgname (const gchar *prgname)
290 {
291 name = g_strdup (prgname);
292 }
293
294 gchar *
g_get_prgname(void)295 g_get_prgname (void)
296 {
297 return name;
298 }
299
300 gboolean
g_ensure_directory_exists(const gchar * filename)301 g_ensure_directory_exists (const gchar *filename)
302 {
303 #ifdef G_OS_WIN32
304 gchar *dir_utf8 = g_path_get_dirname (filename);
305 gunichar2 *p;
306 gunichar2 *dir_utf16 = NULL;
307 int retval;
308
309 if (!dir_utf8 || !dir_utf8 [0])
310 return FALSE;
311
312 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
313 g_free (dir_utf8);
314
315 if (!dir_utf16)
316 return FALSE;
317
318 p = dir_utf16;
319
320 /* make life easy and only use one directory seperator */
321 while (*p != '\0')
322 {
323 if (*p == '/')
324 *p = '\\';
325 p++;
326 }
327
328 p = dir_utf16;
329
330 /* get past C:\ )*/
331 while (*p++ != '\\')
332 {
333 }
334
335 while (1) {
336 gboolean bRet = FALSE;
337 p = wcschr (p, '\\');
338 if (p)
339 *p = '\0';
340 retval = _wmkdir (dir_utf16);
341 if (retval != 0 && errno != EEXIST) {
342 g_free (dir_utf16);
343 return FALSE;
344 }
345 if (!p)
346 break;
347 *p++ = '\\';
348 }
349
350 g_free (dir_utf16);
351 return TRUE;
352 #else
353 char *p;
354 gchar *dir = g_path_get_dirname (filename);
355 int retval;
356 struct stat sbuf;
357
358 if (!dir || !dir [0]) {
359 g_free (dir);
360 return FALSE;
361 }
362
363 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
364 g_free (dir);
365 return TRUE;
366 }
367
368 p = dir;
369 while (*p == '/')
370 p++;
371
372 while (1) {
373 p = strchr (p, '/');
374 if (p)
375 *p = '\0';
376 retval = mkdir (dir, 0777);
377 if (retval != 0 && errno != EEXIST) {
378 g_free (dir);
379 return FALSE;
380 }
381 if (!p)
382 break;
383 *p++ = '/';
384 }
385
386 g_free (dir);
387 return TRUE;
388 #endif
389 }
390
391