Merge pull request #5353 from jonpryor/jonp-mono-api-html-ignore-class-removal
[mono.git] / mono / eglib / gpath.c
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 *
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*
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 *
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 *
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 #ifndef HAVE_STRTOK_R
164 // This is from BSD's strtok_r
165
166 char *
167 strtok_r(char *s, const char *delim, char **last)
168 {
169         char *spanp;
170         int c, sc;
171         char *tok;
172         
173         if (s == NULL && (s = *last) == NULL)
174                 return NULL;
175         
176         /*
177          * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
178          */
179 cont:
180         c = *s++;
181         for (spanp = (char *)delim; (sc = *spanp++) != 0; ){
182                 if (c == sc)
183                         goto cont;
184         }
185
186         if (c == 0){         /* no non-delimiter characters */
187                 *last = NULL;
188                 return NULL;
189         }
190         tok = s - 1;
191
192         /*
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.
195          */
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';
206                                 }
207                                 *last = s;
208                                 return tok;
209                         }
210                 }
211                 while (sc != 0);
212         }
213         /* NOTREACHED */
214 }
215 #endif
216
217 gchar *
218 g_find_program_in_path (const gchar *program)
219 {
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
230
231         g_return_val_if_fail (program != NULL, NULL);
232         x = p = g_strdup (g_getenv ("PATH"));
233
234         if (x == NULL || *x == '\0') {
235                 curdir = g_get_current_dir ();
236                 x = curdir;
237         }
238
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++]);
245         }
246 #endif
247
248         while ((l = strtok_r (x, G_SEARCHPATH_SEPARATOR_S, &save)) != NULL){
249                 char *probe_path; 
250                 
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;
257                 }
258                 g_free (probe_path);
259
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;
272                                 }
273                                 listx++;
274                                 g_free (probe_path);
275                                 g_free (program_exe);
276                         }
277                 }
278 #endif
279         }
280         g_free (curdir);
281         g_free (p);
282         return NULL;
283 }
284
285 static char *name;
286
287 void
288 g_set_prgname (const gchar *prgname)
289 {
290         name = g_strdup (prgname);
291 }
292
293 gchar *
294 g_get_prgname (void)
295 {
296         return name;
297 }
298
299 gboolean
300 g_ensure_directory_exists (const gchar *filename)
301 {
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;
307         
308         if (!dir_utf8 || !dir_utf8 [0])
309                 return FALSE;
310
311         dir_utf16 = g_utf8_to_utf16 (dir_utf8, strlen (dir_utf8), NULL, NULL, NULL);
312         g_free (dir_utf8);
313
314         if (!dir_utf16)
315                 return FALSE;
316
317         p = dir_utf16;
318
319         /* make life easy and only use one directory seperator */
320         while (*p != '\0')
321         {
322                 if (*p == '/')
323                         *p = '\\';
324                 p++;
325         }
326
327         p = dir_utf16;
328
329         /* get past C:\ )*/
330         while (*p++ != '\\')    
331         {
332         }
333
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;
343                 }
344                 if (!p)
345                         break;
346                 *p++ = '\\';
347         }
348         
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;
356         
357         if (!dir || !dir [0]) {
358                 g_free (dir);
359                 return FALSE;
360         }
361         
362         if (stat (dir, &sbuf) == 0 && S_ISDIR (sbuf.st_mode)) {
363                 g_free (dir);
364                 return TRUE;
365         }
366         
367         p = dir;
368         while (*p == '/')
369                 p++;
370
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;
379                 }
380                 if (!p)
381                         break;
382                 *p++ = '/';
383         }
384         
385         g_free (dir);
386         return TRUE;
387 #endif
388 }
389