Merge pull request #819 from brendanzagaeski/patch-1
[mono.git] / eglib / src / 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
33 #ifdef G_OS_WIN32
34 #include <direct.h> 
35 #endif
36
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40
41 gchar *
42 g_build_path (const gchar *separator, const gchar *first_element, ...)
43 {
44         const char *elem, *next, *endptr;
45         gboolean trimmed;
46         GString *path;
47         va_list args;
48         size_t slen;
49         
50         g_return_val_if_fail (separator != NULL, NULL);
51         
52         path = g_string_sized_new (48);
53         slen = strlen (separator);
54         
55         va_start (args, first_element);
56         for (elem = first_element; elem != NULL; elem = next) {
57                 /* trim any trailing separators from @elem */
58                 endptr = elem + strlen (elem);
59                 trimmed = FALSE;
60                 
61                 while (endptr >= elem + slen) {
62                         if (strncmp (endptr - slen, separator, slen) != 0)
63                                 break;
64                         
65                         endptr -= slen;
66                         trimmed = TRUE;
67                 }
68                 
69                 /* append elem, not including any trailing separators */
70                 if (endptr > elem)
71                         g_string_append_len (path, elem, endptr - elem);
72                 
73                 /* get the next element */
74                 do {
75                         if (!(next = va_arg (args, char *)))
76                                 break;
77                         
78                         /* remove leading separators */
79                         while (!strncmp (next, separator, slen))
80                                 next += slen;
81                 } while (*next == '\0');
82                 
83                 if (next || trimmed)
84                         g_string_append_len (path, separator, slen);
85         }
86         va_end (args);
87         
88         return g_string_free (path, FALSE);
89 }
90
91 static gchar*
92 strrchr_seperator (const gchar* filename)
93 {
94 #ifdef G_OS_WIN32
95         char *p2;
96 #endif
97         char *p;
98
99         p = strrchr (filename, G_DIR_SEPARATOR);
100 #ifdef G_OS_WIN32
101         p2 = strrchr (filename, '/');
102         if (p2 > p)
103                 p = p2;
104 #endif
105
106         return p;
107 }
108
109 gchar *
110 g_path_get_dirname (const gchar *filename)
111 {
112         char *p, *r;
113         size_t count;
114         g_return_val_if_fail (filename != NULL, NULL);
115
116         p = strrchr_seperator (filename);
117         if (p == NULL)
118                 return g_strdup (".");
119         if (p == filename)
120                 return g_strdup ("/");
121         count = p - filename;
122         r = g_malloc (count + 1);
123         strncpy (r, filename, count);
124         r [count] = 0;
125
126         return r;
127 }
128
129 gchar *
130 g_path_get_basename (const char *filename)
131 {
132         char *r;
133         g_return_val_if_fail (filename != NULL, NULL);
134
135         /* Empty filename -> . */
136         if (!*filename)
137                 return g_strdup (".");
138
139         /* No separator -> filename */
140         r = strrchr_seperator (filename);
141         if (r == NULL)
142                 return g_strdup (filename);
143
144         /* Trailing slash, remove component */
145         if (r [1] == 0){
146                 char *copy = g_strdup (filename);
147                 copy [r-filename] = 0;
148                 r = strrchr_seperator (copy);
149
150                 if (r == NULL){
151                         g_free (copy);                  
152                         return g_strdup ("/");
153                 }
154                 r = g_strdup (&r[1]);
155                 g_free (copy);
156                 return r;
157         }
158
159         return g_strdup (&r[1]);
160 }
161
162 #ifndef HAVE_STRTOK_R
163 // This is from BSD's strtok_r
164
165 char *
166 strtok_r(char *s, const char *delim, char **last)
167 {
168         char *spanp;
169         int c, sc;
170         char *tok;
171         
172         if (s == NULL && (s = *last) == NULL)
173                 return NULL;
174         
175         /*
176          * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
177          */
178 cont:
179         c = *s++;
180         for (spanp = (char *)delim; (sc = *spanp++) != 0; ){
181                 if (c == sc)
182                         goto cont;
183         }
184
185         if (c == 0){         /* no non-delimiter characters */
186                 *last = NULL;
187                 return NULL;
188         }
189         tok = s - 1;
190
191         /*
192          * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
193          * Note that delim must have one NUL; we stop if we see that, too.
194          */
195         for (;;){
196                 c = *s++;
197                 spanp = (char *)delim;
198                 do {
199                         if ((sc = *spanp++) == c) {
200                                 if (c == 0)
201                                         s = NULL;
202                                 else {
203                                         char *w = s - 1;
204                                         *w = '\0';
205                                 }
206                                 *last = s;
207                                 return tok;
208                         }
209                 }
210                 while (sc != 0);
211         }
212         /* NOTREACHED */
213 }
214 #endif
215
216 gchar *
217 g_find_program_in_path (const gchar *program)
218 {
219         char *p;
220         char *x, *l;
221         gchar *curdir = NULL;
222         char *save = NULL;
223 #ifdef G_OS_WIN32
224         char *program_exe;
225         char *suffix_list[5] = {".exe",".cmd",".bat",".com",NULL};
226         int listx;
227         gboolean hasSuffix;
228 #endif
229
230         g_return_val_if_fail (program != NULL, NULL);
231         x = p = g_strdup (g_getenv ("PATH"));
232
233         if (x == NULL || *x == '\0') {
234                 curdir = g_get_current_dir ();
235                 x = curdir;
236         }
237
238 #ifdef G_OS_WIN32
239         /* see if program already has a suffix */
240         listx = 0;
241         hasSuffix = FALSE;
242         while (!hasSuffix && suffix_list[listx]) {
243                 hasSuffix = g_str_has_suffix(program,suffix_list[listx++]);
244         }
245 #endif
246
247         while ((l = strtok_r (x, G_SEARCHPATH_SEPARATOR_S, &save)) != NULL){
248                 char *probe_path; 
249                 
250                 x = NULL;
251                 probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program, NULL);
252                 if (access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */
253                         g_free (curdir);
254                         g_free (p);
255                         return probe_path;
256                 }
257                 g_free (probe_path);
258
259 #ifdef G_OS_WIN32
260                 /* check for program with a suffix attached */
261                 if (!hasSuffix) {
262                         listx = 0;
263                         while (suffix_list[listx]) {
264                                 program_exe = g_strjoin(NULL,program,suffix_list[listx],NULL);
265                                 probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program_exe, NULL);
266                                 if (access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */
267                                         g_free (curdir);
268                                         g_free (p);
269                                         g_free (program_exe);
270                                         return probe_path;
271                                 }
272                                 listx++;
273                                 g_free (probe_path);
274                                 g_free (program_exe);
275                         }
276                 }
277 #endif
278         }
279         g_free (curdir);
280         g_free (p);
281         return NULL;
282 }
283
284 static char *name;
285
286 void
287 g_set_prgname (const gchar *prgname)
288 {
289         name = g_strdup (prgname);
290 }
291
292 gchar *
293 g_get_prgname (void)
294 {
295         return name;
296 }