2007-03-19 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 #include <sys/types.h>
33
34 #ifdef G_OS_UNIX
35 #include <pthread.h>
36 #endif
37
38 #ifdef HAVE_PWD_H
39 #include <pwd.h>
40 #endif
41
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45
46 #ifdef G_OS_WIN32
47 #include <direct.h>
48 #include <io.h>
49 #endif
50
51
52 gchar *
53 g_build_path (const gchar *separator, const gchar *first_element, ...)
54 {
55         GString *result;
56         const char *s, *p, *next;
57         size_t slen;
58         va_list args;
59         
60         g_return_val_if_fail (separator != NULL, NULL);
61         g_return_val_if_fail (first_element != NULL, NULL);
62
63         result = g_string_sized_new (48);
64
65         slen = strlen (separator);
66         
67         va_start (args, first_element);
68         for (s = first_element; s != NULL; s = next){
69                 next = va_arg (args, char *);
70                 p = (s + strlen (s));
71
72                 if (next && p - slen > s){
73                         for (; strncmp (p-slen, separator, slen) == 0; ){
74                                 p -= slen;
75                         }
76                 }
77                 g_string_append_len (result, s, p - s);
78
79                 if (next && *next){
80                         g_string_append (result, separator);
81
82                         for (; strncmp (next, separator, slen) == 0; )
83                                 next += slen;
84                 }
85         }
86         g_string_append_c (result, 0);
87         va_end (args);
88
89         return g_string_free (result, FALSE);
90 }
91
92 gchar *
93 g_path_get_dirname (const gchar *filename)
94 {
95         char *p, *r;
96         size_t count;
97         g_return_val_if_fail (filename != NULL, NULL);
98
99         p = strrchr (filename, G_DIR_SEPARATOR);
100         if (p == NULL)
101                 return g_strdup (".");
102         if (p == filename)
103                 return g_strdup ("/");
104         count = p - filename;
105         r = g_malloc (count + 1);
106         strncpy (r, filename, count);
107         r [count] = 0;
108
109         return r;
110 }
111
112 gchar *
113 g_path_get_basename (const char *filename)
114 {
115         char *r;
116         g_return_val_if_fail (filename != NULL, NULL);
117
118         /* Empty filename -> . */
119         if (!*filename)
120                 return g_strdup (".");
121
122         /* No separator -> filename */
123         r = strrchr (filename, G_DIR_SEPARATOR);
124         if (r == NULL)
125                 return g_strdup (filename);
126
127         /* Trailing slash, remove component */
128         if (r [1] == 0){
129                 char *copy = g_strdup (filename);
130                 copy [r-filename] = 0;
131                 r = strrchr (copy, G_DIR_SEPARATOR);
132
133                 if (r == NULL){
134                         g_free (copy);                  
135                         return g_strdup ("/");
136                 }
137                 r = g_strdup (&r[1]);
138                 g_free (copy);
139                 return r;
140         }
141
142         return g_strdup (&r[1]);
143 }
144
145 gboolean
146 g_path_is_absolute (const char *filename)
147 {
148         g_return_val_if_fail (filename != NULL, FALSE);
149 #ifdef G_OS_WIN32
150         if (filename[0] != '\0' && filename[1] != '\0' && filename[1] == ':' && 
151                 filename[2] != '\0' && (filename[2] == '\\' || filename[2] == '/'))
152                 return TRUE;
153         else
154                 return FALSE;
155 #else
156         return (*filename == '/');
157 #endif
158 }
159
160 gchar *
161 g_find_program_in_path (const gchar *program)
162 {
163         char *p = g_strdup (g_getenv ("PATH"));
164         char *x = p, *l;
165         gchar *curdir = NULL;
166         char *save;
167
168         g_return_val_if_fail (program != NULL, NULL);
169
170         if (x == NULL || *x == '\0') {
171                 curdir = g_get_current_dir ();
172                 x = curdir;
173         }
174
175         while ((l = strtok_r (x, G_SEARCHPATH_SEPARATOR_S, &save)) != NULL){
176                 char *probe_path; 
177                 
178                 x = NULL;
179                 probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program, NULL);
180                 if (access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */
181                         g_free (curdir);
182                         g_free (p);
183                         return probe_path;
184                 }
185                 g_free (probe_path);
186         }
187         g_free (curdir);
188         g_free (p);
189         return NULL;
190 }
191
192 gchar *
193 g_get_current_dir (void)
194 {
195         int s = 32;
196         char *buffer = NULL, *r;
197         gboolean fail;
198         
199         do {
200                 buffer = g_realloc (buffer, s);
201                 r = getcwd (buffer, s);
202                 fail = (r == NULL && errno == ERANGE);
203                 if (fail) {
204                         s <<= 1;
205                 }
206         } while (fail);
207
208         return r;
209 }
210
211 #if defined (G_OS_UNIX)
212
213 static pthread_mutex_t home_lock = PTHREAD_MUTEX_INITIALIZER;
214 static const gchar *home_dir;
215
216 /* Give preference to /etc/passwd than HOME */
217 const gchar *
218 g_get_home_dir (void)
219 {
220         if (home_dir == NULL){
221                 pthread_mutex_lock (&home_lock);
222                 if (home_dir == NULL){
223 #ifdef HAVE_GETPWENT_R
224                         struct passwd pwbuf, *track;
225                         char buf [4096];
226                         uid_t uid;
227                         
228                         uid = getuid ();
229
230                         setpwent ();
231                         
232                         while (getpwent_r (&pwbuf, buf, sizeof (buf), &track) == 0){
233                                 if (pwbuf.pw_uid == uid){
234                                         home_dir = g_strdup (pwbuf.pw_dir);
235                                         break;
236                                 }
237                         }
238                         endpwent ();
239 #endif
240                         if (home_dir == NULL)
241                                 home_dir = g_getenv ("HOME");
242                         pthread_mutex_unlock (&home_lock);
243                 }
244         }
245         return home_dir;
246 }
247
248 #elif defined (G_OS_WIN32)
249 #include <windows.h>
250
251 const gchar *
252 g_get_home_dir (void)
253 {
254         /* FIXME */
255         const gchar *drive = g_getenv ("HOMEDRIVE");
256         const gchar *path = g_getenv ("HOMEPATH");
257         gchar *home_dir = NULL;
258         
259         if (drive && path) {
260                 home_dir = malloc(strlen(drive) + strlen(path) +1);
261                 if (home_dir) {
262                         sprintf(home_dir, "%s%s", drive, path);
263                 }
264         }
265
266         return home_dir;
267 }
268
269 #else
270
271 const gchar *
272 g_get_home_dir (void)
273 {
274         g_error ("%s", "g_get_home_dir not implemented on this platform");
275         return NULL;
276 }
277
278 #endif
279
280 static const char *tmp_dir;
281
282 #ifdef G_OS_UNIX
283 static pthread_mutex_t tmp_lock = PTHREAD_MUTEX_INITIALIZER;
284 #endif
285
286 const gchar *
287 g_get_tmp_dir (void)
288 {
289         if (tmp_dir == NULL){
290 #ifdef G_OS_UNIX
291                 pthread_mutex_lock (&tmp_lock);
292 #endif
293                 if (tmp_dir == NULL){
294                         tmp_dir = g_getenv ("TMPDIR");
295                         if (tmp_dir == NULL){
296                                 tmp_dir = g_getenv ("TMP");
297                                 if (tmp_dir == NULL){
298                                         tmp_dir = g_getenv ("TEMP");
299                                         if (tmp_dir == NULL)
300 #if defined (G_OS_WIN32)
301                                                 tmp_dir = "C:\\temp";
302 #else
303                                                 tmp_dir = "/tmp";
304 #endif
305                                 }
306                         }
307                 }
308 #ifdef G_OS_UNIX
309                 pthread_mutex_unlock (&tmp_lock);
310 #endif
311         }
312         return tmp_dir;
313 }
314
315 const char *
316 g_get_user_name (void)
317 {
318         const char * retName = g_getenv ("USER");
319 #if defined (G_OS_WIN32)
320         if (!retName)
321                 retName = g_getenv ("USERNAME");
322 #endif
323         return retName;
324 }
325
326 static char *name;
327
328 void
329 g_set_prgname (const gchar *prgname)
330 {
331         name = g_strdup (prgname);
332 }
333
334 gchar *
335 g_get_prgname (void)
336 {
337         return name;
338 }