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