2007-04-27 Jonathan Chambers <joncham@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         return (*filename == '/');
150 }
151
152 gchar *
153 g_find_program_in_path (const gchar *program)
154 {
155         char *p = g_strdup (g_getenv ("PATH"));
156         char *x = p, *l;
157         gchar *curdir = NULL;
158         char *save;
159
160         g_return_val_if_fail (program != NULL, NULL);
161
162         if (x == NULL || *x == '\0') {
163                 curdir = g_get_current_dir ();
164                 x = curdir;
165         }
166
167         while ((l = strtok_r (x, G_SEARCHPATH_SEPARATOR_S, &save)) != NULL){
168                 char *probe_path; 
169                 
170                 x = NULL;
171                 probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program, NULL);
172                 if (access (probe_path, X_OK) == 0){ /* FIXME: on windows this is just a read permissions test */
173                         g_free (curdir);
174                         g_free (p);
175                         return probe_path;
176                 }
177                 g_free (probe_path);
178         }
179         g_free (curdir);
180         g_free (p);
181         return NULL;
182 }
183
184 gchar *
185 g_get_current_dir (void)
186 {
187         int s = 32;
188         char *buffer = NULL, *r;
189         gboolean fail;
190         
191         do {
192                 buffer = g_realloc (buffer, s);
193                 r = getcwd (buffer, s);
194                 fail = (r == NULL && errno == ERANGE);
195                 if (fail) {
196                         s <<= 1;
197                 }
198         } while (fail);
199
200         return r;
201 }
202
203 #if defined (G_OS_UNIX)
204
205 static pthread_mutex_t home_lock = PTHREAD_MUTEX_INITIALIZER;
206 static const gchar *home_dir;
207
208 /* Give preference to /etc/passwd than HOME */
209 const gchar *
210 g_get_home_dir (void)
211 {
212         if (home_dir == NULL){
213                 uid_t uid;
214
215                 pthread_mutex_lock (&home_lock);
216                 if (home_dir == NULL){
217                         struct passwd pwbuf, *track;
218                         char buf [4096];
219                         
220                         uid = getuid ();
221
222                         setpwent ();
223                         
224                         while (getpwent_r (&pwbuf, buf, sizeof (buf), &track) == 0){
225                                 if (pwbuf.pw_uid == uid){
226                                         home_dir = g_strdup (pwbuf.pw_dir);
227                                         break;
228                                 }
229                         }
230                         endpwent ();
231                         if (home_dir == NULL)
232                                 home_dir = g_getenv ("HOME");
233                         pthread_mutex_unlock (&home_lock);
234                 }
235         }
236         return home_dir;
237 }
238
239 #elif defined (G_OS_WIN32)
240 #include <windows.h>
241
242 const gchar *
243 g_get_home_dir (void)
244 {
245         /* FIXME */
246         const gchar *drive = g_getenv ("HOMEDRIVE");
247         const gchar *path = g_getenv ("HOMEPATH");
248         gchar *home_dir = NULL;
249         
250         if (drive && path) {
251                 home_dir = malloc(strlen(drive) + strlen(path) +1);
252                 if (home_dir) {
253                         sprintf(home_dir, "%s%s", drive, path);
254                 }
255         }
256
257         return home_dir;
258 }
259
260 #else
261
262 const gchar *
263 g_get_home_dir (void)
264 {
265         g_error ("%s", "g_get_home_dir not implemented on this platform");
266         return NULL;
267 }
268
269 #endif
270
271 static const char *tmp_dir;
272
273 #ifdef G_OS_UNIX
274 static pthread_mutex_t tmp_lock = PTHREAD_MUTEX_INITIALIZER;
275 #endif
276
277 const gchar *
278 g_get_tmp_dir (void)
279 {
280         if (tmp_dir == NULL){
281 #ifdef G_OS_UNIX
282                 pthread_mutex_lock (&tmp_lock);
283 #endif
284                 if (tmp_dir == NULL){
285                         tmp_dir = g_getenv ("TMPDIR");
286                         if (tmp_dir == NULL){
287                                 tmp_dir = g_getenv ("TMP");
288                                 if (tmp_dir == NULL){
289                                         tmp_dir = g_getenv ("TEMP");
290                                         if (tmp_dir == NULL)
291 #if defined (G_OS_WIN32)
292                                                 tmp_dir = "C:\\temp";
293 #else
294                                                 tmp_dir = "/tmp";
295 #endif
296                                 }
297                         }
298                 }
299 #ifdef G_OS_UNIX
300                 pthread_mutex_unlock (&tmp_lock);
301 #endif
302         }
303         return tmp_dir;
304 }
305
306 const char *
307 g_get_user_name (void)
308 {
309         return g_getenv ("USER");
310 }
311
312 static char *name;
313
314 void
315 g_set_prgname (const gchar *prgname)
316 {
317         name = g_strdup (prgname);
318 }
319
320 gchar *
321 g_get_prgname (void)
322 {
323         return name;
324 }