Merged pull request #88 from skolima/msbuild-merge.
[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 gchar *
92 g_path_get_dirname (const gchar *filename)
93 {
94         char *p, *r;
95         size_t count;
96         g_return_val_if_fail (filename != NULL, NULL);
97
98         p = strrchr (filename, G_DIR_SEPARATOR);
99         if (p == NULL)
100                 return g_strdup (".");
101         if (p == filename)
102                 return g_strdup ("/");
103         count = p - filename;
104         r = g_malloc (count + 1);
105         strncpy (r, filename, count);
106         r [count] = 0;
107
108         return r;
109 }
110
111 gchar *
112 g_path_get_basename (const char *filename)
113 {
114         char *r;
115         g_return_val_if_fail (filename != NULL, NULL);
116
117         /* Empty filename -> . */
118         if (!*filename)
119                 return g_strdup (".");
120
121         /* No separator -> filename */
122         r = strrchr (filename, G_DIR_SEPARATOR);
123         if (r == NULL)
124                 return g_strdup (filename);
125
126         /* Trailing slash, remove component */
127         if (r [1] == 0){
128                 char *copy = g_strdup (filename);
129                 copy [r-filename] = 0;
130                 r = strrchr (copy, G_DIR_SEPARATOR);
131
132                 if (r == NULL){
133                         g_free (copy);                  
134                         return g_strdup ("/");
135                 }
136                 r = g_strdup (&r[1]);
137                 g_free (copy);
138                 return r;
139         }
140
141         return g_strdup (&r[1]);
142 }
143
144 #ifndef HAVE_STRTOK_R
145 // This is from BSD's strtok_r
146
147 char *
148 strtok_r(char *s, const char *delim, char **last)
149 {
150         char *spanp;
151         int c, sc;
152         char *tok;
153         
154         if (s == NULL && (s = *last) == NULL)
155                 return NULL;
156         
157         /*
158          * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
159          */
160 cont:
161         c = *s++;
162         for (spanp = (char *)delim; (sc = *spanp++) != 0; ){
163                 if (c == sc)
164                         goto cont;
165         }
166
167         if (c == 0){         /* no non-delimiter characters */
168                 *last = NULL;
169                 return NULL;
170         }
171         tok = s - 1;
172
173         /*
174          * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
175          * Note that delim must have one NUL; we stop if we see that, too.
176          */
177         for (;;){
178                 c = *s++;
179                 spanp = (char *)delim;
180                 do {
181                         if ((sc = *spanp++) == c) {
182                                 if (c == 0)
183                                         s = NULL;
184                                 else {
185                                         char *w = s - 1;
186                                         *w = '\0';
187                                 }
188                                 *last = s;
189                                 return tok;
190                         }
191                 }
192                 while (sc != 0);
193         }
194         /* NOTREACHED */
195 }
196 #endif
197
198 gchar *
199 g_find_program_in_path (const gchar *program)
200 {
201         char *p = g_strdup (g_getenv ("PATH"));
202         char *x = p, *l;
203         gchar *curdir = NULL;
204         char *save = NULL;
205 #ifdef G_OS_WIN32
206         char *program_exe;
207         char *suffix_list[5] = {".exe",".cmd",".bat",".com",NULL};
208         int listx;
209         gboolean hasSuffix;
210 #endif
211
212         g_return_val_if_fail (program != NULL, NULL);
213
214         if (x == NULL || *x == '\0') {
215                 curdir = g_get_current_dir ();
216                 x = curdir;
217         }
218
219 #ifdef G_OS_WIN32
220         /* see if program already has a suffix */
221         listx = 0;
222         hasSuffix = FALSE;
223         while (!hasSuffix && suffix_list[listx]) {
224                 hasSuffix = g_str_has_suffix(program,suffix_list[listx++]);
225         }
226 #endif
227
228         while ((l = strtok_r (x, G_SEARCHPATH_SEPARATOR_S, &save)) != NULL){
229                 char *probe_path; 
230                 
231                 x = NULL;
232                 probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program, NULL);
233                 if (access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */
234                         g_free (curdir);
235                         g_free (p);
236                         return probe_path;
237                 }
238                 g_free (probe_path);
239
240 #ifdef G_OS_WIN32
241                 /* check for program with a suffix attached */
242                 if (!hasSuffix) {
243                         listx = 0;
244                         while (suffix_list[listx]) {
245                                 program_exe = g_strjoin(NULL,program,suffix_list[listx],NULL);
246                                 probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program_exe, NULL);
247                                 if (access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */
248                                         g_free (curdir);
249                                         g_free (p);
250                                         g_free (program_exe);
251                                         return probe_path;
252                                 }
253                                 listx++;
254                                 g_free (probe_path);
255                                 g_free (program_exe);
256                         }
257                 }
258 #endif
259         }
260         g_free (curdir);
261         g_free (p);
262         return NULL;
263 }
264
265 static char *name;
266
267 void
268 g_set_prgname (const gchar *prgname)
269 {
270         name = g_strdup (prgname);
271 }
272
273 gchar *
274 g_get_prgname (void)
275 {
276         return name;
277 }