Make g_get_current_dir work on systems with unlimited pathname length like
[platform/upstream/glib.git] / gutils.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1998  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
22  * file for a list of people on the GLib Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 /* 
28  * MT safe for the unix part, FIXME: make the win32 part MT safe as well.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
34
35 #include "glibconfig.h"
36
37 #ifdef HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 #include <stdarg.h>
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <errno.h>
45 #ifdef HAVE_PWD_H
46 #include <pwd.h>
47 #endif
48 #include <sys/types.h>
49 #ifdef HAVE_SYS_PARAM_H
50 #include <sys/param.h>
51 #endif
52
53 #ifdef G_OS_WIN32
54 #  define STRICT                        /* Strict typing, please */
55 #  include <windows.h>
56 #  include <errno.h>
57 #  include <ctype.h>
58 #  ifdef _MSC_VER
59 #    include <io.h>
60 #  endif /* _MSC_VER */
61 #endif /* G_OS_WIN32 */
62
63 /* implement Glib's inline functions
64  */
65 #define G_INLINE_FUNC extern
66 #define G_CAN_INLINE 1
67 #include "glib.h"
68
69 #ifdef  MAXPATHLEN
70 #define G_PATH_LENGTH   MAXPATHLEN
71 #elif   defined (PATH_MAX)
72 #define G_PATH_LENGTH   PATH_MAX
73 #elif   defined (_PC_PATH_MAX)
74 #define G_PATH_LENGTH   sysconf(_PC_PATH_MAX)
75 #else   
76 #define G_PATH_LENGTH   2048
77 #endif
78
79 const guint glib_major_version = GLIB_MAJOR_VERSION;
80 const guint glib_minor_version = GLIB_MINOR_VERSION;
81 const guint glib_micro_version = GLIB_MICRO_VERSION;
82 const guint glib_interface_age = GLIB_INTERFACE_AGE;
83 const guint glib_binary_age = GLIB_BINARY_AGE;
84
85 #if !defined (HAVE_MEMMOVE) && !defined (HAVE_WORKING_BCOPY)
86 void 
87 g_memmove (gpointer dest, gconstpointer src, gulong len)
88 {
89   gchar* destptr = dest;
90   const gchar* srcptr = src;
91   if (src + len < dest || dest + len < src)
92     {
93       bcopy (src, dest, len);
94       return;
95     }
96   else if (dest <= src)
97     {
98       while (len--)
99         *(destptr++) = *(srcptr++);
100     }
101   else
102     {
103       destptr += len;
104       srcptr += len;
105       while (len--)
106         *(--destptr) = *(--srcptr);
107     }
108 }
109 #endif /* !HAVE_MEMMOVE && !HAVE_WORKING_BCOPY */
110
111 void
112 g_atexit (GVoidFunc func)
113 {
114   gint result;
115   gchar *error = NULL;
116
117   /* keep this in sync with glib.h */
118
119 #ifdef  G_NATIVE_ATEXIT
120   result = ATEXIT (func);
121   if (result)
122     error = g_strerror (errno);
123 #elif defined (HAVE_ATEXIT)
124 #  ifdef NeXT /* @#%@! NeXTStep */
125   result = !atexit ((void (*)(void)) func);
126   if (result)
127     error = g_strerror (errno);
128 #  else
129   result = atexit ((void (*)(void)) func);
130   if (result)
131     error = g_strerror (errno);
132 #  endif /* NeXT */
133 #elif defined (HAVE_ON_EXIT)
134   result = on_exit ((void (*)(int, void *)) func, NULL);
135   if (result)
136     error = g_strerror (errno);
137 #else
138   result = 0;
139   error = "no implementation";
140 #endif /* G_NATIVE_ATEXIT */
141
142   if (error)
143     g_error ("Could not register atexit() function: %s", error);
144 }
145
146 gint
147 g_snprintf (gchar       *str,
148             gulong       n,
149             gchar const *fmt,
150             ...)
151 {
152 #ifdef  HAVE_VSNPRINTF
153   va_list args;
154   gint retval;
155   
156   va_start (args, fmt);
157   retval = vsnprintf (str, n, fmt, args);
158   va_end (args);
159
160   if (retval < 0)
161     {
162       str[n-1] = '\0';
163       retval = strlen (str);
164     }
165
166   return retval;
167 #else   /* !HAVE_VSNPRINTF */
168   gchar *printed;
169   va_list args;
170   
171   va_start (args, fmt);
172   printed = g_strdup_vprintf (fmt, args);
173   va_end (args);
174   
175   strncpy (str, printed, n);
176   str[n-1] = '\0';
177
178   g_free (printed);
179   
180   return strlen (str);
181 #endif  /* !HAVE_VSNPRINTF */
182 }
183
184 gint
185 g_vsnprintf (gchar       *str,
186              gulong       n,
187              gchar const *fmt,
188              va_list      args)
189 {
190 #ifdef  HAVE_VSNPRINTF
191   gint retval;
192   
193   retval = vsnprintf (str, n, fmt, args);
194   
195   if (retval < 0)
196     {
197       str[n-1] = '\0';
198       retval = strlen (str);
199     }
200
201   return retval;
202 #else   /* !HAVE_VSNPRINTF */
203   gchar *printed;
204   
205   printed = g_strdup_vprintf (fmt, args);
206   strncpy (str, printed, n);
207   str[n-1] = '\0';
208
209   g_free (printed);
210   
211   return strlen (str);
212 #endif /* !HAVE_VSNPRINTF */
213 }
214
215 guint        
216 g_parse_debug_string  (const gchar *string, 
217                        GDebugKey   *keys, 
218                        guint        nkeys)
219 {
220   guint i;
221   guint result = 0;
222   
223   g_return_val_if_fail (string != NULL, 0);
224   
225   if (!g_strcasecmp (string, "all"))
226     {
227       for (i=0; i<nkeys; i++)
228         result |= keys[i].value;
229     }
230   else
231     {
232       gchar *str = g_strdup (string);
233       gchar *p = str;
234       gchar *q;
235       gboolean done = FALSE;
236       
237       while (*p && !done)
238         {
239           q = strchr (p, ':');
240           if (!q)
241             {
242               q = p + strlen(p);
243               done = TRUE;
244             }
245           
246           *q = 0;
247           
248           for (i=0; i<nkeys; i++)
249             if (!g_strcasecmp(keys[i].key, p))
250               result |= keys[i].value;
251           
252           p = q+1;
253         }
254       
255       g_free (str);
256     }
257   
258   return result;
259 }
260
261 gchar*
262 g_basename (const gchar    *file_name)
263 {
264   register gchar *base;
265   
266   g_return_val_if_fail (file_name != NULL, NULL);
267   
268   base = strrchr (file_name, G_DIR_SEPARATOR);
269   if (base)
270     return base + 1;
271
272 #ifdef G_OS_WIN32
273   if (isalpha (file_name[0]) && file_name[1] == ':')
274     return (gchar*) file_name + 2;
275 #endif /* G_OS_WIN32 */
276   
277   return (gchar*) file_name;
278 }
279
280 gboolean
281 g_path_is_absolute (const gchar *file_name)
282 {
283   g_return_val_if_fail (file_name != NULL, FALSE);
284   
285   if (file_name[0] == G_DIR_SEPARATOR)
286     return TRUE;
287
288 #ifdef G_OS_WIN32
289   if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
290     return TRUE;
291 #endif
292
293   return FALSE;
294 }
295
296 gchar*
297 g_path_skip_root (gchar *file_name)
298 {
299   g_return_val_if_fail (file_name != NULL, NULL);
300   
301   if (file_name[0] == G_DIR_SEPARATOR)
302     return file_name + 1;
303
304 #ifdef G_OS_WIN32
305   if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
306     return file_name + 3;
307 #endif
308
309   return NULL;
310 }
311
312 gchar*
313 g_dirname (const gchar     *file_name)
314 {
315   register gchar *base;
316   register guint len;
317   
318   g_return_val_if_fail (file_name != NULL, NULL);
319   
320   base = strrchr (file_name, G_DIR_SEPARATOR);
321   if (!base)
322     return g_strdup (".");
323   while (base > file_name && *base == G_DIR_SEPARATOR)
324     base--;
325   len = (guint) 1 + base - file_name;
326   
327   base = g_new (gchar, len + 1);
328   g_memmove (base, file_name, len);
329   base[len] = 0;
330   
331   return base;
332 }
333
334 gchar*
335 g_get_current_dir (void)
336 {
337   gchar *buffer;
338   gchar *dir;
339   static gulong max_len = (G_PATH_LENGTH == -1) ? 2048 : G_PATH_LENGTH;
340   
341   /* We don't use getcwd(3) on SUNOS, because, it does a popen("pwd")
342    * and, if that wasn't bad enough, hangs in doing so.
343    */
344 #if     defined (sun) && !defined (__SVR4)
345   buffer = g_new (gchar, max_len + 1);
346   *buffer = 0;
347   dir = getwd (buffer);
348 #else   /* !sun */
349   while (1)
350     {
351       buffer = g_new (gchar, max_len + 1);
352       *buffer = 0;
353       dir = getcwd (buffer, max_len);
354
355       if (dir || errno != ERANGE)
356         break;
357
358       g_free (buffer);
359       max_len *= 2;
360     }
361 #endif  /* !sun */
362   
363   if (!dir || !*buffer)
364     {
365       /* hm, should we g_error() out here?
366        * this can happen if e.g. "./" has mode \0000
367        */
368       buffer[0] = G_DIR_SEPARATOR;
369       buffer[1] = 0;
370     }
371
372   dir = g_strdup (buffer);
373   g_free (buffer);
374   
375   return dir;
376 }
377
378 gchar*
379 g_getenv (const gchar *variable)
380 {
381 #ifndef G_OS_WIN32
382   g_return_val_if_fail (variable != NULL, NULL);
383
384   return getenv (variable);
385 #else
386   gchar *v;
387   guint k;
388   static gchar *p = NULL;
389   static gint l;
390   gchar dummy[2];
391
392   g_return_val_if_fail (variable != NULL, NULL);
393   
394   v = getenv (variable);
395   if (!v)
396     return NULL;
397   
398   /* On Windows NT, it is relatively typical that environment variables
399    * contain references to other environment variables. Handle that by
400    * calling ExpandEnvironmentStrings.
401    */
402
403   /* First check how much space we need */
404   k = ExpandEnvironmentStrings (v, dummy, 2);
405   /* Then allocate that much, and actualy do the expansion */
406   if (p == NULL)
407     {
408       p = g_malloc (k);
409       l = k;
410     }
411   else if (k > l)
412     {
413       p = g_realloc (p, k);
414       l = k;
415     }
416   ExpandEnvironmentStrings (v, p, k);
417   return p;
418 #endif
419 }
420
421
422 G_LOCK_DEFINE_STATIC (g_utils_global);
423
424 static  gchar   *g_tmp_dir = NULL;
425 static  gchar   *g_user_name = NULL;
426 static  gchar   *g_real_name = NULL;
427 static  gchar   *g_home_dir = NULL;
428
429 /* HOLDS: g_utils_global_lock */
430 static void
431 g_get_any_init (void)
432 {
433   if (!g_tmp_dir)
434     {
435       g_tmp_dir = g_strdup (g_getenv ("TMPDIR"));
436       if (!g_tmp_dir)
437         g_tmp_dir = g_strdup (g_getenv ("TMP"));
438       if (!g_tmp_dir)
439         g_tmp_dir = g_strdup (g_getenv ("TEMP"));
440       
441 #ifdef P_tmpdir
442       if (!g_tmp_dir)
443         {
444           int k;
445           g_tmp_dir = g_strdup (P_tmpdir);
446           k = strlen (g_tmp_dir);
447           if (g_tmp_dir[k-1] == G_DIR_SEPARATOR)
448             g_tmp_dir[k-1] = '\0';
449         }
450 #endif
451       
452       if (!g_tmp_dir)
453         {
454 #ifndef G_OS_WIN32
455           g_tmp_dir = g_strdup ("/tmp");
456 #else /* G_OS_WIN32 */
457           g_tmp_dir = g_strdup ("C:\\");
458 #endif /* G_OS_WIN32 */
459         }
460       
461       if (!g_home_dir)
462         g_home_dir = g_strdup (g_getenv ("HOME"));
463       
464 #ifdef G_OS_WIN32
465       if (!g_home_dir)
466         {
467           /* The official way to specify a home directory on NT is
468            * the HOMEDRIVE and HOMEPATH environment variables.
469            *
470            * This is inside #ifdef G_OS_WIN32 because with the cygwin dll,
471            * HOME should be a POSIX style pathname.
472            */
473           
474           if (getenv ("HOMEDRIVE") != NULL && getenv ("HOMEPATH") != NULL)
475             {
476               gchar *homedrive, *homepath;
477               
478               homedrive = g_strdup (g_getenv ("HOMEDRIVE"));
479               homepath = g_strdup (g_getenv ("HOMEPATH"));
480               
481               g_home_dir = g_strconcat (homedrive, homepath, NULL);
482               g_free (homedrive);
483               g_free (homepath);
484             }
485         }
486 #endif /* !G_OS_WIN32 */
487       
488 #ifdef HAVE_PWD_H
489       {
490         struct passwd *pw = NULL;
491         gpointer buffer = NULL;
492         
493 #  ifdef HAVE_GETPWUID_R
494         struct passwd pwd;
495 #    ifdef _SC_GETPW_R_SIZE_MAX  
496         /* This reurns the maximum length */
497         guint bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
498 #    else /* _SC_GETPW_R_SIZE_MAX */
499         guint bufsize = 64;
500 #    endif /* _SC_GETPW_R_SIZE_MAX */
501         gint error;
502         
503         do
504           {
505             g_free (buffer);
506             buffer = g_malloc (bufsize);
507             errno = 0;
508             
509 #    ifdef HAVE_GETPWUID_R_POSIX
510             error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw);
511             error = error < 0 ? errno : error;
512 #    else /* !HAVE_GETPWUID_R_POSIX */
513 #      ifdef _AIX
514             error = getpwuid_r (getuid (), &pwd, buffer, bufsize);
515             pw = error == 0 ? &pwd : NULL;
516 #      else /* !_AIX */
517             pw = getpwuid_r (getuid (), &pwd, buffer, bufsize);
518             error = pw ? 0 : errno;
519 #      endif /* !_AIX */            
520 #    endif /* !HAVE_GETPWUID_R_POSIX */
521             
522             if (!pw)
523               {
524                 /* we bail out prematurely if the user id can't be found
525                  * (should be pretty rare case actually), or if the buffer
526                  * should be sufficiently big and lookups are still not
527                  * successfull.
528                  */
529                 if (error == 0 || error == ENOENT)
530                   {
531                     g_warning ("getpwuid_r(): failed due to unknown user id (%lu)",
532                                (gulong) getuid ());
533                     break;
534                   }
535                 if (bufsize > 32 * 1024)
536                   {
537                     g_warning ("getpwuid_r(): failed due to: %s.",
538                                g_strerror (error));
539                     break;
540                   }
541                 
542                 bufsize *= 2;
543               }
544           }
545         while (!pw);
546 #  endif /* !HAVE_GETPWUID_R */
547         
548         if (!pw)
549           {
550             setpwent ();
551             pw = getpwuid (getuid ());
552             endpwent ();
553           }
554         if (pw)
555           {
556             g_user_name = g_strdup (pw->pw_name);
557             g_real_name = g_strdup (pw->pw_gecos);
558             if (!g_home_dir)
559               g_home_dir = g_strdup (pw->pw_dir);
560           }
561         g_free (buffer);
562       }
563       
564 #else /* !HAVE_PWD_H */
565       
566 #  ifdef G_OS_WIN32
567       {
568         guint len = 17;
569         gchar buffer[17];
570         
571         if (GetUserName (buffer, &len))
572           {
573             g_user_name = g_strdup (buffer);
574             g_real_name = g_strdup (buffer);
575           }
576       }
577 #  endif /* G_OS_WIN32 */
578       
579 #endif /* !HAVE_PWD_H */
580       
581 #ifdef __EMX__
582       /* change '\\' in %HOME% to '/' */
583       g_strdelimit (g_home_dir, "\\",'/');
584 #endif
585       if (!g_user_name)
586         g_user_name = g_strdup ("somebody");
587       if (!g_real_name)
588         g_real_name = g_strdup ("Unknown");
589       else
590         {
591           gchar *p;
592
593           for (p = g_real_name; *p; p++)
594             if (*p == ',')
595               {
596                 *p = 0;
597                 p = g_strdup (g_real_name);
598                 g_free (g_real_name);
599                 g_real_name = p;
600                 break;
601               }
602         }
603     }
604 }
605
606 gchar*
607 g_get_user_name (void)
608 {
609   G_LOCK (g_utils_global);
610   if (!g_tmp_dir)
611     g_get_any_init ();
612   G_UNLOCK (g_utils_global);
613   
614   return g_user_name;
615 }
616
617 gchar*
618 g_get_real_name (void)
619 {
620   G_LOCK (g_utils_global);
621   if (!g_tmp_dir)
622     g_get_any_init ();
623   G_UNLOCK (g_utils_global);
624  
625   return g_real_name;
626 }
627
628 /* Return the home directory of the user. If there is a HOME
629  * environment variable, its value is returned, otherwise use some
630  * system-dependent way of finding it out. If no home directory can be
631  * deduced, return NULL.
632  */
633
634 gchar*
635 g_get_home_dir (void)
636 {
637   G_LOCK (g_utils_global);
638   if (!g_tmp_dir)
639     g_get_any_init ();
640   G_UNLOCK (g_utils_global);
641   
642   return g_home_dir;
643 }
644
645 /* Return a directory to be used to store temporary files. This is the
646  * value of the TMPDIR, TMP or TEMP environment variables (they are
647  * checked in that order). If none of those exist, use P_tmpdir from
648  * stdio.h.  If that isn't defined, return "/tmp" on POSIXly systems,
649  * and C:\ on Windows.
650  */
651
652 gchar*
653 g_get_tmp_dir (void)
654 {
655   G_LOCK (g_utils_global);
656   if (!g_tmp_dir)
657     g_get_any_init ();
658   G_UNLOCK (g_utils_global);
659   
660   return g_tmp_dir;
661 }
662
663 static gchar *g_prgname = NULL;
664
665 gchar*
666 g_get_prgname (void)
667 {
668   gchar* retval;
669
670   G_LOCK (g_utils_global);
671   retval = g_prgname;
672   G_UNLOCK (g_utils_global);
673
674   return retval;
675 }
676
677 void
678 g_set_prgname (const gchar *prgname)
679 {
680   gchar *c;
681     
682   G_LOCK (g_utils_global);
683   c = g_prgname;
684   g_prgname = g_strdup (prgname);
685   g_free (c);
686   G_UNLOCK (g_utils_global);
687 }
688
689 guint
690 g_direct_hash (gconstpointer v)
691 {
692   return GPOINTER_TO_UINT (v);
693 }
694
695 gint
696 g_direct_equal (gconstpointer v1,
697                 gconstpointer v2)
698 {
699   return v1 == v2;
700 }
701
702 gint
703 g_int_equal (gconstpointer v1,
704              gconstpointer v2)
705 {
706   return *((const gint*) v1) == *((const gint*) v2);
707 }
708
709 guint
710 g_int_hash (gconstpointer v)
711 {
712   return *(const gint*) v;
713 }