New test.
[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 #define _GNU_SOURCE
29 #include <stdio.h>
30 #include <glib.h>
31 #include <unistd.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <pwd.h>
35 #include <pthread.h>
36
37 gchar *
38 g_build_path (const gchar *separator, const gchar *first_element, ...)
39 {
40         GString *result;
41         const char *s, *p, *next;
42         int slen;
43         va_list args;
44         
45         g_return_val_if_fail (separator != NULL, NULL);
46         g_return_val_if_fail (first_element != NULL, NULL);
47
48         result = g_string_sized_new (48);
49
50         slen = strlen (separator);
51         
52         va_start (args, first_element);
53         for (s = first_element; s != NULL; s = next){
54                 next = va_arg (args, char *);
55                 p = (s + strlen (s));
56
57                 if (next && p - slen > s){
58                         for (; strncmp (p-slen, separator, slen) == 0; ){
59                                 p -= slen;
60                         }
61                 }
62                 g_string_append_len (result, s, p - s);
63
64                 if (next){
65                         g_string_append (result, separator);
66
67                         for (; strncmp (next, separator, slen) == 0; )
68                                 next += slen;
69                 }
70         }
71         va_end (args);
72
73         return g_string_free (result, FALSE);
74 }
75
76 gchar *
77 g_path_get_dirname (const gchar *filename)
78 {
79         char *p, *r;
80         int count;
81         g_return_val_if_fail (filename != NULL, NULL);
82
83         p = strrchr (filename, G_DIR_SEPARATOR);
84         if (p == NULL)
85                 return g_strdup ("");
86         count = p - filename;
87         r = g_malloc (count + 1);
88         strncpy (r, filename, count);
89         r [count] = 0;
90
91         return r;
92 }
93
94 gchar *
95 g_path_get_basename (const char *filename)
96 {
97         char *r;
98         g_return_val_if_fail (filename != NULL, NULL);
99
100         /* Empty filename -> . */
101         if (!*filename)
102                 return g_strdup (".");
103
104         /* No separator -> filename */
105         r = strrchr (filename, G_DIR_SEPARATOR);
106         if (r == NULL)
107                 return g_strdup (filename);
108
109         /* Trailing slash, remove component */
110         if (r [1] == 0){
111                 char *copy = g_strdup (filename);
112                 copy [r-filename] = 0;
113                 r = strrchr (copy, G_DIR_SEPARATOR);
114
115                 if (r == NULL){
116                         g_free (copy);                  
117                         return g_strdup ("/");
118                 }
119                 r = g_strdup (&r[1]);
120                 g_free (copy);
121                 return r;
122         }
123
124         return g_strdup (&r[1]);
125 }
126
127 gboolean
128 g_path_is_absolute (const char *filename)
129 {
130         g_return_val_if_fail (filename != NULL, FALSE);
131         return (*filename == '/');
132 }
133
134 gchar *
135 g_find_program_in_path (const gchar *program)
136 {
137         char *p = g_strdup (getenv ("PATH"));
138         char *x = p, *l;
139         gchar *curdir = NULL;
140         char *save;
141
142         g_return_val_if_fail (program != NULL, NULL);
143
144         if (x == NULL || *x == '\0') {
145                 curdir = g_get_current_dir ();
146                 x = curdir;
147         }
148
149         while ((l = strtok_r (x, G_SEARCHPATH_SEPARATOR_S, &save)) != NULL){
150                 char *probe_path; 
151                 
152                 x = NULL;
153                 probe_path = g_build_path (G_DIR_SEPARATOR_S, l, program, NULL);
154                 if (access (probe_path, X_OK) == 0){
155                         g_free (curdir);
156                         g_free (p);
157                         return probe_path;
158                 }
159                 g_free (probe_path);
160         }
161         g_free (curdir);
162         g_free (p);
163         return NULL;
164 }
165
166 gchar *
167 g_get_current_dir (void)
168 {
169         int s = 32;
170         char *buffer = NULL, *r;
171         gboolean fail;
172         
173         do {
174                 buffer = g_realloc (buffer, s);
175                 r = getcwd  (buffer, s);
176                 fail = (r == NULL && errno == ERANGE);
177                 if (fail) {
178                         s <<= 1;
179                 }
180         } while (fail);
181
182         return r;
183 }
184
185 static pthread_mutex_t home_lock = PTHREAD_MUTEX_INITIALIZER;
186 static char *home_dir;
187
188 /* Give preference to /etc/passwd than HOME */
189 const gchar *
190 g_get_home_dir (void)
191 {
192         if (home_dir == NULL){
193                 uid_t uid;
194
195                 pthread_mutex_lock (&home_lock);
196                 if (home_dir == NULL){
197                         struct passwd pwbuf, *track;
198                         char buf [4096];
199                         
200                         uid = getuid ();
201
202                         setpwent ();
203                         
204                         while (getpwent_r (&pwbuf, buf, sizeof (buf), &track) == 0){
205                                 if (pwbuf.pw_uid == uid){
206                                         home_dir = g_strdup (pwbuf.pw_dir);
207                                         break;
208                                 }
209                         }
210                         endpwent ();
211                         if (home_dir == NULL)
212                                 home_dir = getenv ("HOME");
213                         pthread_mutex_unlock (&home_lock);
214                 }
215         }
216         return home_dir;
217 }
218
219 static char *tmp_dir;
220 static pthread_mutex_t tmp_lock = PTHREAD_MUTEX_INITIALIZER;
221
222 const gchar *
223 g_get_tmp_dir (void)
224 {
225         if (tmp_dir == NULL){
226                 pthread_mutex_lock (&tmp_lock);
227                 if (tmp_dir == NULL){
228                         tmp_dir = getenv ("TMPDIR");
229                         if (tmp_dir == NULL){
230                                 tmp_dir = getenv ("TMP");
231                                 if (tmp_dir == NULL){
232                                         tmp_dir = getenv ("TEMP");
233                                         if (tmp_dir == NULL)
234                                                 tmp_dir = "/tmp";
235                                 }
236                         }
237                 }
238                 pthread_mutex_unlock (&tmp_lock);
239         }
240         return tmp_dir;
241 }
242
243 const char *
244 g_get_user_name (void)
245 {
246         return getenv ("USER");
247 }
248
249 static char *name;
250
251 void
252 g_set_prgname (const gchar *prgname)
253 {
254         name = g_strdup (prgname);
255 }
256
257 gchar *
258 g_get_prgname (void)
259 {
260         return name;
261 }