Merge pull request #4553 from kumpera/backport-block-rebind-of-banned-assemblies
[mono-project.git] / eglib / src / gpath.c
blob59f5923125bffef92db3ff085e4d4ac12773cbd6
1 /*
2 * Portable Utility Functions
4 * Author:
5 * Miguel de Icaza (miguel@novell.com)
7 * (C) 2006 Novell, Inc.
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:
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
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.
28 #include <config.h>
29 #include <stdio.h>
30 #include <glib.h>
31 #include <errno.h>
32 #include <sys/stat.h>
34 #ifdef G_OS_WIN32
35 #include <direct.h>
36 #endif
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
42 gchar *
43 g_build_path (const gchar *separator, const gchar *first_element, ...)
45 const char *elem, *next, *endptr;
46 gboolean trimmed;
47 GString *path;
48 va_list args;
49 size_t slen;
51 g_return_val_if_fail (separator != NULL, NULL);
53 path = g_string_sized_new (48);
54 slen = strlen (separator);
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;
62 while (endptr >= elem + slen) {
63 if (strncmp (endptr - slen, separator, slen) != 0)
64 break;
66 endptr -= slen;
67 trimmed = TRUE;
70 /* append elem, not including any trailing separators */
71 if (endptr > elem)
72 g_string_append_len (path, elem, endptr - elem);
74 /* get the next element */
75 do {
76 if (!(next = va_arg (args, char *)))
77 break;
79 /* remove leading separators */
80 while (!strncmp (next, separator, slen))
81 next += slen;
82 } while (*next == '\0');
84 if (next || trimmed)
85 g_string_append_len (path, separator, slen);
87 va_end (args);
89 return g_string_free (path, FALSE);
92 static gchar*
93 strrchr_seperator (const gchar* filename)
95 #ifdef G_OS_WIN32
96 char *p2;
97 #endif
98 char *p;
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
107 return p;
110 gchar *
111 g_path_get_dirname (const gchar *filename)
113 char *p, *r;
114 size_t count;
115 g_return_val_if_fail (filename != NULL, NULL);
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;
127 return r;
130 gchar *
131 g_path_get_basename (const char *filename)
133 char *r;
134 g_return_val_if_fail (filename != NULL, NULL);
136 /* Empty filename -> . */
137 if (!*filename)
138 return g_strdup (".");
140 /* No separator -> filename */
141 r = strrchr_seperator (filename);
142 if (r == NULL)
143 return g_strdup (filename);
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);
151 if (r == NULL){
152 g_free (copy);
153 return g_strdup ("/");
155 r = g_strdup (&r[1]);
156 g_free (copy);
157 return r;
160 return g_strdup (&r[1]);
163 #ifndef HAVE_STRTOK_R
164 // This is from BSD's strtok_r
166 char *
167 strtok_r(char *s, const char *delim, char **last)
169 char *spanp;
170 int c, sc;
171 char *tok;
173 if (s == NULL && (s = *last) == NULL)
174 return NULL;
177 * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
179 cont:
180 c = *s++;
181 for (spanp = (char *)delim; (sc = *spanp++) != 0; ){
182 if (c == sc)
183 goto cont;
186 if (c == 0){ /* no non-delimiter characters */
187 *last = NULL;
188 return NULL;
190 tok = s - 1;
193 * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
194 * Note that delim must have one NUL; we stop if we see that, too.
196 for (;;){
197 c = *s++;
198 spanp = (char *)delim;
199 do {
200 if ((sc = *spanp++) == c) {
201 if (c == 0)
202 s = NULL;
203 else {
204 char *w = s - 1;
205 *w = '\0';
207 *last = s;
208 return tok;
211 while (sc != 0);
213 /* NOTREACHED */
215 #endif
217 gchar *
218 g_find_program_in_path (const gchar *program)
220 char *p;
221 char *x, *l;
222 gchar *curdir = NULL;
223 char *save = NULL;
224 #ifdef G_OS_WIN32
225 char *program_exe;
226 char *suffix_list[5] = {".exe",".cmd",".bat",".com",NULL};
227 int listx;
228 gboolean hasSuffix;
229 #endif
231 g_return_val_if_fail (program != NULL, NULL);
232 x = p = g_strdup (g_getenv ("PATH"));
234 if (x == NULL || *x == '\0') {
235 curdir = g_get_current_dir ();
236 x = curdir;
239 #ifdef G_OS_WIN32
240 /* see if program already has a suffix */
241 listx = 0;
242 hasSuffix = FALSE;
243 while (!hasSuffix && suffix_list[listx]) {
244 hasSuffix = g_str_has_suffix(program,suffix_list[listx++]);
246 #endif
248 while ((l = strtok_r (x, G_SEARCHPATH_SEPARATOR_S, &save)) != NULL){
249 char *probe_path;
251 x = NULL;
252 probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program, NULL);
253 if (access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */
254 g_free (curdir);
255 g_free (p);
256 return probe_path;
258 g_free (probe_path);
260 #ifdef G_OS_WIN32
261 /* check for program with a suffix attached */
262 if (!hasSuffix) {
263 listx = 0;
264 while (suffix_list[listx]) {
265 program_exe = g_strjoin(NULL,program,suffix_list[listx],NULL);
266 probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program_exe, NULL);
267 if (access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */
268 g_free (curdir);
269 g_free (p);
270 g_free (program_exe);
271 return probe_path;
273 listx++;
274 g_free (probe_path);
275 g_free (program_exe);
278 #endif
280 g_free (curdir);
281 g_free (p);
282 return NULL;
285 static char *name;
287 void
288 g_set_prgname (const gchar *prgname)
290 name = g_strdup (prgname);
293 gchar *
294 g_get_prgname (void)
296 return name;
299 gboolean
300 g_ensure_directory_exists (const gchar *filename)
302 #ifdef G_OS_WIN32
303 gchar *dir_utf8 = g_path_get_dirname (filename);
304 gunichar2 *p;
305 gunichar2 *dir_utf16 = NULL;
306 int retval;
308 if (!dir_utf8 || !dir_utf8 [0])
309 return FALSE;
311 dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
312 g_free (dir_utf8);
314 if (!dir_utf16)
315 return FALSE;
317 p = dir_utf16;
319 /* make life easy and only use one directory seperator */
320 while (*p != '\0')
322 if (*p == '/')
323 *p = '\\';
324 p++;
327 p = dir_utf16;
329 /* get past C:\ )*/
330 while (*p++ != '\\')
334 while (1) {
335 gboolean bRet = FALSE;
336 p = wcschr (p, '\\');
337 if (p)
338 *p = '\0';
339 retval = _wmkdir (dir_utf16);
340 if (retval != 0 && errno != EEXIST) {
341 g_free (dir_utf16);
342 return FALSE;
344 if (!p)
345 break;
346 *p++ = '\\';
349 g_free (dir_utf16);
350 return TRUE;
351 #else
352 char *p;
353 gchar *dir = g_path_get_dirname (filename);
354 int retval;
355 struct stat sbuf;
357 if (!dir || !dir [0]) {
358 g_free (dir);
359 return FALSE;
362 if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
363 g_free (dir);
364 return TRUE;
367 p = dir;
368 while (*p == '/')
369 p++;
371 while (1) {
372 p = strchr (p, '/');
373 if (p)
374 *p = '\0';
375 retval = mkdir (dir, 0777);
376 if (retval != 0 && errno != EEXIST) {
377 g_free (dir);
378 return FALSE;
380 if (!p)
381 break;
382 *p++ = '/';
385 g_free (dir);
386 return TRUE;
387 #endif