on success, close the pipes from the child. Fix from Tim.
[platform/upstream/glib.git] / glib / 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 Lesser 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  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser 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-2000.  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 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #include <stdarg.h>
39 #include <stdlib.h>
40 #include <stdio.h>
41 #include <string.h>
42 #include <errno.h>
43 #ifdef HAVE_PWD_H
44 #include <pwd.h>
45 #endif
46 #include <sys/types.h>
47 #ifdef HAVE_SYS_PARAM_H
48 #include <sys/param.h>
49 #endif
50
51 /* implement gutils's inline functions
52  */
53 #define G_IMPLEMENT_INLINES 1
54 #define __G_UTILS_C__
55 #include "glib.h"
56
57 #ifdef  MAXPATHLEN
58 #define G_PATH_LENGTH   MAXPATHLEN
59 #elif   defined (PATH_MAX)
60 #define G_PATH_LENGTH   PATH_MAX
61 #elif   defined (_PC_PATH_MAX)
62 #define G_PATH_LENGTH   sysconf(_PC_PATH_MAX)
63 #else   
64 #define G_PATH_LENGTH   2048
65 #endif
66
67 #ifdef G_PLATFORM_WIN32
68 #  define STRICT                /* Strict typing, please */
69 #  include <windows.h>
70 #  undef STRICT
71 #  include <lmcons.h>           /* For UNLEN */
72 #  include <ctype.h>
73 #endif /* G_PLATFORM_WIN32 */
74
75 #ifdef G_OS_WIN32
76 #  include <direct.h>
77 #endif
78
79 #ifdef HAVE_CODESET
80 #include <langinfo.h>
81 #endif
82
83 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
84 #include <libintl.h>
85 #endif
86
87 const guint glib_major_version = GLIB_MAJOR_VERSION;
88 const guint glib_minor_version = GLIB_MINOR_VERSION;
89 const guint glib_micro_version = GLIB_MICRO_VERSION;
90 const guint glib_interface_age = GLIB_INTERFACE_AGE;
91 const guint glib_binary_age = GLIB_BINARY_AGE;
92
93 #if !defined (HAVE_MEMMOVE) && !defined (HAVE_WORKING_BCOPY)
94 void 
95 g_memmove (gpointer dest, gconstpointer src, gulong len)
96 {
97   gchar* destptr = dest;
98   const gchar* srcptr = src;
99   if (src + len < dest || dest + len < src)
100     {
101       bcopy (src, dest, len);
102       return;
103     }
104   else if (dest <= src)
105     {
106       while (len--)
107         *(destptr++) = *(srcptr++);
108     }
109   else
110     {
111       destptr += len;
112       srcptr += len;
113       while (len--)
114         *(--destptr) = *(--srcptr);
115     }
116 }
117 #endif /* !HAVE_MEMMOVE && !HAVE_WORKING_BCOPY */
118
119 void
120 g_atexit (GVoidFunc func)
121 {
122   gint result;
123   const gchar *error = NULL;
124
125   /* keep this in sync with glib.h */
126
127 #ifdef  G_NATIVE_ATEXIT
128   result = ATEXIT (func);
129   if (result)
130     error = g_strerror (errno);
131 #elif defined (HAVE_ATEXIT)
132 #  ifdef NeXT /* @#%@! NeXTStep */
133   result = !atexit ((void (*)(void)) func);
134   if (result)
135     error = g_strerror (errno);
136 #  else
137   result = atexit ((void (*)(void)) func);
138   if (result)
139     error = g_strerror (errno);
140 #  endif /* NeXT */
141 #elif defined (HAVE_ON_EXIT)
142   result = on_exit ((void (*)(int, void *)) func, NULL);
143   if (result)
144     error = g_strerror (errno);
145 #else
146   result = 0;
147   error = "no implementation";
148 #endif /* G_NATIVE_ATEXIT */
149
150   if (error)
151     g_error ("Could not register atexit() function: %s", error);
152 }
153
154 /* Based on execvp() from GNU Libc.
155  * Some of this code is cut-and-pasted into gspawn.c
156  */
157
158 static gchar*
159 my_strchrnul (const gchar *str, gchar c)
160 {
161   gchar *p = (gchar*)str;
162   while (*p && (*p != c))
163     ++p;
164
165   return p;
166 }
167
168 #ifdef G_OS_WIN32
169
170 gchar *inner_find_program_in_path (const gchar *program);
171
172 gchar*
173 g_find_program_in_path (const gchar *program)
174 {
175   const gchar *last_dot = strrchr (program, '.');
176
177   if (last_dot == NULL || strchr (last_dot, '\\') != NULL)
178     {
179       const gint program_length = strlen (program);
180       const gchar *pathext = getenv ("PATHEXT");
181       const gchar *p;
182       gchar *decorated_program;
183       gchar *retval;
184
185       if (pathext == NULL)
186         pathext = ".com;.exe;.bat";
187
188       p = pathext;
189       do
190         {
191           pathext = p;
192           p = my_strchrnul (pathext, ';');
193
194           decorated_program = g_malloc (program_length + (p-pathext) + 1);
195           memcpy (decorated_program, program, program_length);
196           memcpy (decorated_program+program_length, pathext, p-pathext);
197           decorated_program [program_length + (p-pathext)] = '\0';
198           
199           retval = inner_find_program_in_path (decorated_program);
200           g_free (decorated_program);
201
202           if (retval != NULL)
203             return retval;
204         } while (*p++ != '\0');
205       return NULL;
206     }
207   else
208     return inner_find_program_in_path (program);
209 }
210
211 #define g_find_program_in_path inner_find_program_in_path
212 #endif
213
214 /**
215  * g_find_program_in_path:
216  * @program: a program name
217  * 
218  * Locates the first executable named @program in the user's path, in the
219  * same way that execvp() would locate it. Returns an allocated string
220  * with the absolute path name, or NULL if the program is not found in
221  * the path. If @program is already an absolute path, returns a copy of
222  * @program if @program exists and is executable, and NULL otherwise.
223  * 
224  * On Windows, if @program does not have a file type suffix, tries to
225  * append the suffixes in the PATHEXT environment variable (if that
226  * doesn't exists, the suffixes .com, .exe, and .bat) in turn, and
227  * then look for the resulting file name in the same way as
228  * CreateProcess() would. This means first in the directory where the
229  * program was loaded from, then in the current directory, then in the
230  * Windows 32-bit system directory, then in the Windows directory, and
231  * finally in the directories in the PATH environment variable. If
232  * the program is found, the return value contains the full name
233  * including the type suffix.
234  *
235  * Return value: absolute path, or NULL
236  **/
237 gchar*
238 g_find_program_in_path (const gchar *program)
239 {
240   const gchar *path, *p;
241   gchar *name, *freeme;
242 #ifdef G_OS_WIN32
243   gchar *path_tmp;
244 #endif
245   size_t len;
246   size_t pathlen;
247
248   g_return_val_if_fail (program != NULL, NULL);
249
250   /* If it is an absolute path, or a relative path including subdirectories,
251    * don't look in PATH.
252    */
253   if (g_path_is_absolute (program)
254       || strchr (program, G_DIR_SEPARATOR) != NULL)
255     {
256       if (g_file_test (program, G_FILE_TEST_IS_EXECUTABLE))
257         return g_strdup (program);
258       else
259         return NULL;
260     }
261   
262   path = g_getenv ("PATH");
263 #ifdef G_OS_UNIX
264   if (path == NULL)
265     {
266       /* There is no `PATH' in the environment.  The default
267        * search path in GNU libc is the current directory followed by
268        * the path `confstr' returns for `_CS_PATH'.
269        */
270       
271       /* In GLib we put . last, for security, and don't use the
272        * unportable confstr(); UNIX98 does not actually specify
273        * what to search if PATH is unset. POSIX may, dunno.
274        */
275       
276       path = "/bin:/usr/bin:.";
277     }
278 #else
279   {
280     gchar *tmp;
281     gchar moddir[MAXPATHLEN], sysdir[MAXPATHLEN], windir[MAXPATHLEN];
282
283     GetModuleFileName (NULL, moddir, sizeof (moddir));
284     tmp = g_path_get_dirname (moddir);
285     GetSystemDirectory (sysdir, sizeof (sysdir));
286     GetWindowsDirectory (windir, sizeof (windir));
287     path_tmp = g_strconcat (tmp, ";.;", sysdir, ";", windir,
288                             (path != NULL ? ";" : NULL),
289                             (path != NULL ? path : NULL),
290                             NULL);
291     g_free (tmp);
292     path = path_tmp;
293   }
294 #endif
295   
296   len = strlen (program) + 1;
297   pathlen = strlen (path);
298   freeme = name = g_malloc (pathlen + len + 1);
299   
300   /* Copy the file name at the top, including '\0'  */
301   memcpy (name + pathlen + 1, program, len);
302   name = name + pathlen;
303   /* And add the slash before the filename  */
304   *name = G_DIR_SEPARATOR;
305   
306   p = path;
307   do
308     {
309       char *startp;
310
311       path = p;
312       p = my_strchrnul (path, G_SEARCHPATH_SEPARATOR);
313
314       if (p == path)
315         /* Two adjacent colons, or a colon at the beginning or the end
316          * of `PATH' means to search the current directory.
317          */
318         startp = name + 1;
319       else
320         startp = memcpy (name - (p - path), path, p - path);
321
322       if (g_file_test (startp, G_FILE_TEST_IS_EXECUTABLE))
323         {
324           gchar *ret;
325           ret = g_strdup (startp);
326           g_free (freeme);
327 #ifdef G_OS_WIN32
328           g_free (path_tmp);
329 #endif
330           return ret;
331         }
332     }
333   while (*p++ != '\0');
334   
335   g_free (freeme);
336 #ifdef G_OS_WIN32
337   g_free (path_tmp);
338 #endif
339
340   return NULL;
341 }
342
343 gint
344 g_snprintf (gchar       *str,
345             gulong       n,
346             gchar const *fmt,
347             ...)
348 {
349   va_list args;
350   gint retval;
351
352   va_start (args, fmt);
353   retval = g_vsnprintf (str, n, fmt, args);
354   va_end (args);
355   
356   return retval;
357 }
358
359 gint
360 g_vsnprintf (gchar       *str,
361              gulong       n,
362              gchar const *fmt,
363              va_list      args)
364 {
365 #ifdef  HAVE_VSNPRINTF_C99
366   g_return_val_if_fail (n == 0 || str != NULL, 0);
367   g_return_val_if_fail (fmt != NULL, 0);
368
369   return vsnprintf (str, n, fmt, args);
370 #else   /* !HAVE_VSNPRINTF_C99 */
371   gchar *printed;
372   gint retval;
373
374   g_return_val_if_fail (n == 0 || str != NULL, 0);
375   g_return_val_if_fail (fmt != NULL, 0);
376
377   printed = g_strdup_vprintf (fmt, args);
378   retval = strlen (printed);
379   if (n > 0)
380     {
381       strncpy (str, printed, n - 1);
382       str[n-1] = '\0';
383     }
384
385   g_free (printed);
386   
387   return retval;
388 #endif /* !HAVE_VSNPRINTF_C99 */
389 }
390
391 guint        
392 g_parse_debug_string  (const gchar     *string, 
393                        const GDebugKey *keys, 
394                        guint            nkeys)
395 {
396   guint i;
397   guint result = 0;
398   
399   g_return_val_if_fail (string != NULL, 0);
400   
401   if (!g_ascii_strcasecmp (string, "all"))
402     {
403       for (i=0; i<nkeys; i++)
404         result |= keys[i].value;
405     }
406   else
407     {
408       const gchar *p = string;
409       const gchar *q;
410       gboolean done = FALSE;
411       
412       while (*p && !done)
413         {
414           q = strchr (p, ':');
415           if (!q)
416             {
417               q = p + strlen(p);
418               done = TRUE;
419             }
420           
421           for (i=0; i<nkeys; i++)
422             if (g_ascii_strncasecmp(keys[i].key, p, q - p) == 0 &&
423                 keys[i].key[q - p] == '\0')
424               result |= keys[i].value;
425           
426           p = q + 1;
427         }
428     }
429   
430   return result;
431 }
432
433 G_CONST_RETURN gchar*
434 g_basename (const gchar    *file_name)
435 {
436   register gchar *base;
437   
438   g_return_val_if_fail (file_name != NULL, NULL);
439   
440   base = strrchr (file_name, G_DIR_SEPARATOR);
441   if (base)
442     return base + 1;
443
444 #ifdef G_OS_WIN32
445   if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
446     return (gchar*) file_name + 2;
447 #endif /* G_OS_WIN32 */
448   
449   return (gchar*) file_name;
450 }
451
452 gchar*
453 g_path_get_basename (const gchar   *file_name)
454 {
455   register gssize base;             
456   register gssize last_nonslash;    
457   gsize len;    
458   gchar *retval;
459  
460   g_return_val_if_fail (file_name != NULL, NULL);
461
462   if (file_name[0] == '\0')
463     /* empty string */
464     return g_strdup (".");
465   
466   last_nonslash = strlen (file_name) - 1;
467
468   while (last_nonslash >= 0 && file_name [last_nonslash] == G_DIR_SEPARATOR)
469     last_nonslash--;
470
471   if (last_nonslash == -1)
472     /* string only containing slashes */
473     return g_strdup (G_DIR_SEPARATOR_S);
474
475 #ifdef G_OS_WIN32
476   if (last_nonslash == 1 && g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
477     /* string only containing slashes and a drive */
478     return g_strdup (G_DIR_SEPARATOR_S);
479 #endif /* G_OS_WIN32 */
480
481   base = last_nonslash;
482
483   while (base >=0 && file_name [base] != G_DIR_SEPARATOR)
484     base--;
485
486 #ifdef G_OS_WIN32
487   if (base == -1 && g_ascii_isalpha (file_name[0]) && file_name[1] == ':')
488     base = 1;
489 #endif /* G_OS_WIN32 */
490
491   len = last_nonslash - base;
492   retval = g_malloc (len + 1);
493   memcpy (retval, file_name + base + 1, len);
494   retval [len] = '\0';
495   return retval;
496 }
497
498 gboolean
499 g_path_is_absolute (const gchar *file_name)
500 {
501   g_return_val_if_fail (file_name != NULL, FALSE);
502   
503   if (file_name[0] == G_DIR_SEPARATOR
504 #ifdef G_OS_WIN32
505       || file_name[0] == '/'
506 #endif
507                                      )
508     return TRUE;
509
510 #ifdef G_OS_WIN32
511   /* Recognize drive letter on native Windows */
512   if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':' && (file_name[2] == G_DIR_SEPARATOR || file_name[2] == '/'))
513     return TRUE;
514 #endif /* G_OS_WIN32 */
515
516   return FALSE;
517 }
518
519 G_CONST_RETURN gchar*
520 g_path_skip_root (const gchar *file_name)
521 {
522   g_return_val_if_fail (file_name != NULL, NULL);
523   
524 #ifdef G_PLATFORM_WIN32
525   /* Skip \\server\share (Win32) or //server/share (Cygwin) */
526   if (file_name[0] == G_DIR_SEPARATOR &&
527       file_name[1] == G_DIR_SEPARATOR &&
528       file_name[2])
529     {
530       gchar *p;
531
532       if ((p = strchr (file_name + 2, G_DIR_SEPARATOR)) > file_name + 2 &&
533           p[1])
534         {
535           file_name = p + 1;
536
537           while (file_name[0] && file_name[0] != G_DIR_SEPARATOR)
538             file_name++;
539
540           /* Possibly skip a backslash after the share name */
541           if (file_name[0] == G_DIR_SEPARATOR)
542             file_name++;
543
544           return (gchar *)file_name;
545         }
546     }
547 #endif
548   
549   /* Skip initial slashes */
550   if (file_name[0] == G_DIR_SEPARATOR)
551     {
552       while (file_name[0] == G_DIR_SEPARATOR)
553         file_name++;
554       return (gchar *)file_name;
555     }
556
557 #ifdef G_OS_WIN32
558   /* Skip X:\ */
559   if (g_ascii_isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
560     return (gchar *)file_name + 3;
561 #endif
562
563   return NULL;
564 }
565
566 gchar*
567 g_path_get_dirname (const gchar    *file_name)
568 {
569   register gchar *base;
570   register gsize len;    
571   
572   g_return_val_if_fail (file_name != NULL, NULL);
573   
574   base = strrchr (file_name, G_DIR_SEPARATOR);
575   if (!base)
576     return g_strdup (".");
577   while (base > file_name && *base == G_DIR_SEPARATOR)
578     base--;
579   len = (guint) 1 + base - file_name;
580   
581   base = g_new (gchar, len + 1);
582   g_memmove (base, file_name, len);
583   base[len] = 0;
584   
585   return base;
586 }
587
588 gchar*
589 g_get_current_dir (void)
590 {
591   gchar *buffer = NULL;
592   gchar *dir = NULL;
593   static gulong max_len = 0;
594
595   if (max_len == 0) 
596     max_len = (G_PATH_LENGTH == -1) ? 2048 : G_PATH_LENGTH;
597   
598   /* We don't use getcwd(3) on SUNOS, because, it does a popen("pwd")
599    * and, if that wasn't bad enough, hangs in doing so.
600    */
601 #if     (defined (sun) && !defined (__SVR4)) || !defined(HAVE_GETCWD)
602   buffer = g_new (gchar, max_len + 1);
603   *buffer = 0;
604   dir = getwd (buffer);
605 #else   /* !sun || !HAVE_GETCWD */
606   while (max_len < G_MAXULONG / 2)
607     {
608       buffer = g_new (gchar, max_len + 1);
609       *buffer = 0;
610       dir = getcwd (buffer, max_len);
611
612       if (dir || errno != ERANGE)
613         break;
614
615       g_free (buffer);
616       max_len *= 2;
617     }
618 #endif  /* !sun || !HAVE_GETCWD */
619   
620   if (!dir || !*buffer)
621     {
622       /* hm, should we g_error() out here?
623        * this can happen if e.g. "./" has mode \0000
624        */
625       buffer[0] = G_DIR_SEPARATOR;
626       buffer[1] = 0;
627     }
628
629   dir = g_strdup (buffer);
630   g_free (buffer);
631   
632   return dir;
633 }
634
635 G_CONST_RETURN gchar*
636 g_getenv (const gchar *variable)
637 {
638 #ifndef G_OS_WIN32
639   g_return_val_if_fail (variable != NULL, NULL);
640
641   return getenv (variable);
642 #else
643   G_LOCK_DEFINE_STATIC (getenv);
644   struct env_struct
645   {
646     gchar *key;
647     gchar *value;
648   } *env;
649   static GArray *environs = NULL;
650   gchar *system_env;
651   guint length, i;
652   gchar dummy[2];
653
654   g_return_val_if_fail (variable != NULL, NULL);
655   
656   G_LOCK (getenv);
657
658   if (!environs)
659     environs = g_array_new (FALSE, FALSE, sizeof (struct env_struct));
660
661   /* First we try to find the envinronment variable inside the already
662    * found ones.
663    */
664
665   for (i = 0; i < environs->len; i++)
666     {
667       env = &g_array_index (environs, struct env_struct, i);
668       if (strcmp (env->key, variable) == 0)
669         {
670           g_assert (env->value);
671           G_UNLOCK (getenv);
672           return env->value;
673         }
674     }
675
676   /* If not found, we ask the system */
677
678   system_env = getenv (variable);
679   if (!system_env)
680     {
681       G_UNLOCK (getenv);
682       return NULL;
683     }
684
685   /* On Windows NT, it is relatively typical that environment variables
686    * contain references to other environment variables. Handle that by
687    * calling ExpandEnvironmentStrings.
688    */
689
690   g_array_set_size (environs, environs->len + 1);
691
692   env = &g_array_index (environs, struct env_struct, environs->len - 1);
693
694   /* First check how much space we need */
695   length = ExpandEnvironmentStrings (system_env, dummy, 2);
696
697   /* Then allocate that much, and actualy do the expansion and insert
698    * the new found pair into our buffer 
699    */
700
701   env->value = g_malloc (length);
702   env->key = g_strdup (variable);
703
704   ExpandEnvironmentStrings (system_env, env->value, length);
705
706   G_UNLOCK (getenv);
707   return env->value;
708 #endif
709 }
710
711
712 G_LOCK_DEFINE_STATIC (g_utils_global);
713
714 static  gchar   *g_tmp_dir = NULL;
715 static  gchar   *g_user_name = NULL;
716 static  gchar   *g_real_name = NULL;
717 static  gchar   *g_home_dir = NULL;
718
719 /* HOLDS: g_utils_global_lock */
720 static void
721 g_get_any_init (void)
722 {
723   if (!g_tmp_dir)
724     {
725       g_tmp_dir = g_strdup (g_getenv ("TMPDIR"));
726       if (!g_tmp_dir)
727         g_tmp_dir = g_strdup (g_getenv ("TMP"));
728       if (!g_tmp_dir)
729         g_tmp_dir = g_strdup (g_getenv ("TEMP"));
730       
731 #ifdef P_tmpdir
732       if (!g_tmp_dir)
733         {
734           gsize k;    
735           g_tmp_dir = g_strdup (P_tmpdir);
736           k = strlen (g_tmp_dir);
737           if (k > 1 && g_tmp_dir[k - 1] == G_DIR_SEPARATOR)
738             g_tmp_dir[k - 1] = '\0';
739         }
740 #endif
741       
742       if (!g_tmp_dir)
743         {
744 #ifndef G_OS_WIN32
745           g_tmp_dir = g_strdup ("/tmp");
746 #else /* G_OS_WIN32 */
747           g_tmp_dir = g_strdup ("C:\\");
748 #endif /* G_OS_WIN32 */
749         }
750       
751 #ifdef G_OS_WIN32
752       /* We check $HOME first for Win32, though it is a last resort for Unix
753        * where we prefer the results of getpwuid().
754        */
755       g_home_dir = g_strdup (g_getenv ("HOME"));
756       
757       /* In case HOME is Unix-style (it happens), convert it to
758        * Windows style.
759        */
760       if (g_home_dir)
761         {
762           gchar *p;
763           while ((p = strchr (g_home_dir, '/')) != NULL)
764             *p = '\\';
765         }
766
767       if (!g_home_dir)
768         {
769           /* USERPROFILE is probably the closest equivalent to $HOME? */
770           if (getenv ("USERPROFILE") != NULL)
771             g_home_dir = g_strdup (g_getenv ("USERPROFILE"));
772         }
773
774       if (!g_home_dir)
775         {
776           /* At least at some time, HOMEDRIVE and HOMEPATH were used
777            * to point to the home directory, I think. But on Windows
778            * 2000 HOMEDRIVE seems to be equal to SYSTEMDRIVE, and
779            * HOMEPATH is its root "\"?
780            */
781           if (getenv ("HOMEDRIVE") != NULL && getenv ("HOMEPATH") != NULL)
782             {
783               gchar *homedrive, *homepath;
784               
785               homedrive = g_strdup (g_getenv ("HOMEDRIVE"));
786               homepath = g_strdup (g_getenv ("HOMEPATH"));
787               
788               g_home_dir = g_strconcat (homedrive, homepath, NULL);
789               g_free (homedrive);
790               g_free (homepath);
791             }
792         }
793 #endif /* G_OS_WIN32 */
794       
795 #ifdef HAVE_PWD_H
796       {
797         struct passwd *pw = NULL;
798         gpointer buffer = NULL;
799         gint error;
800         
801 #  if defined (HAVE_POSIX_GETPWUID_R) || defined (HAVE_NONPOSIX_GETPWUID_R)
802         struct passwd pwd;
803 #    ifdef _SC_GETPW_R_SIZE_MAX  
804         /* This reurns the maximum length */
805         glong bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
806         
807         if (bufsize < 0)
808           bufsize = 64;
809 #    else /* _SC_GETPW_R_SIZE_MAX */
810         glong bufsize = 64;
811 #    endif /* _SC_GETPW_R_SIZE_MAX */
812         
813         do
814           {
815             g_free (buffer);
816             buffer = g_malloc (bufsize);
817             errno = 0;
818             
819 #    ifdef HAVE_POSIX_GETPWUID_R
820             error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw);
821             error = error < 0 ? errno : error;
822 #    else /* HAVE_NONPOSIX_GETPWUID_R */
823 #      ifdef _AIX
824             error = getpwuid_r (getuid (), &pwd, buffer, bufsize);
825             pw = error == 0 ? &pwd : NULL;
826 #      else /* !_AIX */
827             pw = getpwuid_r (getuid (), &pwd, buffer, bufsize);
828             error = pw ? 0 : errno;
829 #      endif /* !_AIX */            
830 #    endif /* HAVE_NONPOSIX_GETPWUID_R */
831             
832             if (!pw)
833               {
834                 /* we bail out prematurely if the user id can't be found
835                  * (should be pretty rare case actually), or if the buffer
836                  * should be sufficiently big and lookups are still not
837                  * successfull.
838                  */
839                 if (error == 0 || error == ENOENT)
840                   {
841                     g_warning ("getpwuid_r(): failed due to unknown user id (%lu)",
842                                (gulong) getuid ());
843                     break;
844                   }
845                 if (bufsize > 32 * 1024)
846                   {
847                     g_warning ("getpwuid_r(): failed due to: %s.",
848                                g_strerror (error));
849                     break;
850                   }
851                 
852                 bufsize *= 2;
853               }
854           }
855         while (!pw);
856 #  endif /* HAVE_POSIX_GETPWUID_R || HAVE_NONPOSIX_GETPWUID_R */
857         
858         if (!pw)
859           {
860             setpwent ();
861             pw = getpwuid (getuid ());
862             endpwent ();
863           }
864         if (pw)
865           {
866             g_user_name = g_strdup (pw->pw_name);
867             g_real_name = g_strdup (pw->pw_gecos);
868             if (!g_home_dir)
869               g_home_dir = g_strdup (pw->pw_dir);
870           }
871         g_free (buffer);
872       }
873       
874 #else /* !HAVE_PWD_H */
875       
876 #  ifdef G_OS_WIN32
877       {
878         guint len = UNLEN+1;
879         gchar buffer[UNLEN+1];
880         
881         if (GetUserName ((LPTSTR) buffer, (LPDWORD) &len))
882           {
883             g_user_name = g_strdup (buffer);
884             g_real_name = g_strdup (buffer);
885           }
886       }
887 #  endif /* G_OS_WIN32 */
888
889 #endif /* !HAVE_PWD_H */
890
891       if (!g_home_dir)
892         g_home_dir = g_strdup (g_getenv ("HOME"));
893       
894 #ifdef __EMX__
895       /* change '\\' in %HOME% to '/' */
896       g_strdelimit (g_home_dir, "\\",'/');
897 #endif
898       if (!g_user_name)
899         g_user_name = g_strdup ("somebody");
900       if (!g_real_name)
901         g_real_name = g_strdup ("Unknown");
902       else
903         {
904           gchar *p;
905
906           for (p = g_real_name; *p; p++)
907             if (*p == ',')
908               {
909                 *p = 0;
910                 p = g_strdup (g_real_name);
911                 g_free (g_real_name);
912                 g_real_name = p;
913                 break;
914               }
915         }
916     }
917 }
918
919 G_CONST_RETURN gchar*
920 g_get_user_name (void)
921 {
922   G_LOCK (g_utils_global);
923   if (!g_tmp_dir)
924     g_get_any_init ();
925   G_UNLOCK (g_utils_global);
926   
927   return g_user_name;
928 }
929
930 G_CONST_RETURN gchar*
931 g_get_real_name (void)
932 {
933   G_LOCK (g_utils_global);
934   if (!g_tmp_dir)
935     g_get_any_init ();
936   G_UNLOCK (g_utils_global);
937  
938   return g_real_name;
939 }
940
941 /* Return the home directory of the user. If there is a HOME
942  * environment variable, its value is returned, otherwise use some
943  * system-dependent way of finding it out. If no home directory can be
944  * deduced, return NULL.
945  */
946
947 G_CONST_RETURN gchar*
948 g_get_home_dir (void)
949 {
950   G_LOCK (g_utils_global);
951   if (!g_tmp_dir)
952     g_get_any_init ();
953   G_UNLOCK (g_utils_global);
954   
955   return g_home_dir;
956 }
957
958 /* Return a directory to be used to store temporary files. This is the
959  * value of the TMPDIR, TMP or TEMP environment variables (they are
960  * checked in that order). If none of those exist, use P_tmpdir from
961  * stdio.h.  If that isn't defined, return "/tmp" on POSIXly systems,
962  * and C:\ on Windows.
963  */
964
965 G_CONST_RETURN gchar*
966 g_get_tmp_dir (void)
967 {
968   G_LOCK (g_utils_global);
969   if (!g_tmp_dir)
970     g_get_any_init ();
971   G_UNLOCK (g_utils_global);
972   
973   return g_tmp_dir;
974 }
975
976 G_LOCK_DEFINE (g_prgname);
977 static gchar *g_prgname = NULL;
978
979 gchar*
980 g_get_prgname (void)
981 {
982   gchar* retval;
983
984   G_LOCK (g_prgname);
985   retval = g_prgname;
986   G_UNLOCK (g_prgname);
987
988   return retval;
989 }
990
991 void
992 g_set_prgname (const gchar *prgname)
993 {
994   G_LOCK (g_prgname);
995   g_free (g_prgname);
996   g_prgname = g_strdup (prgname);
997   G_UNLOCK (g_prgname);
998 }
999
1000 guint
1001 g_direct_hash (gconstpointer v)
1002 {
1003   return GPOINTER_TO_UINT (v);
1004 }
1005
1006 gboolean
1007 g_direct_equal (gconstpointer v1,
1008                 gconstpointer v2)
1009 {
1010   return v1 == v2;
1011 }
1012
1013 gboolean
1014 g_int_equal (gconstpointer v1,
1015              gconstpointer v2)
1016 {
1017   return *((const gint*) v1) == *((const gint*) v2);
1018 }
1019
1020 guint
1021 g_int_hash (gconstpointer v)
1022 {
1023   return *(const gint*) v;
1024 }
1025
1026 /**
1027  * g_nullify_pointer:
1028  * @nullify_location: the memory address of the pointer.
1029  * 
1030  * Set the pointer at the specified location to %NULL.
1031  **/
1032 void
1033 g_nullify_pointer (gpointer *nullify_location)
1034 {
1035   g_return_if_fail (nullify_location != NULL);
1036
1037   *nullify_location = NULL;
1038 }
1039
1040 /**
1041  * g_get_codeset:
1042  * 
1043  * Get the codeset for the current locale.
1044  * 
1045  * Return value: a newly allocated string containing the name
1046  * of the codeset. This string must be freed with g_free().
1047  **/
1048 gchar *
1049 g_get_codeset (void)
1050 {
1051 #ifdef HAVE_CODESET  
1052   char *result = nl_langinfo (CODESET);
1053   return g_strdup (result);
1054 #else
1055 #ifdef G_PLATFORM_WIN32
1056   return g_strdup_printf ("CP%d", GetACP ());
1057 #else
1058   /* FIXME: Do something more intelligent based on setlocale (LC_CTYPE, NULL)
1059    */
1060   return g_strdup ("ISO-8859-1");
1061 #endif
1062 #endif
1063 }
1064
1065 #ifdef ENABLE_NLS
1066
1067 #include <libintl.h>
1068
1069 #ifdef G_PLATFORM_WIN32
1070
1071 G_WIN32_DLLMAIN_FOR_DLL_NAME (static, dll_name)
1072
1073 static const gchar *
1074 _glib_get_locale_dir (void)
1075 {
1076   static const gchar *cache = NULL;
1077   if (cache == NULL)
1078     cache = g_win32_get_package_installation_subdirectory
1079       (GETTEXT_PACKAGE, dll_name, "lib\\locale");
1080
1081   return cache;
1082 }
1083
1084 #undef GLIB_LOCALE_DIR
1085 #define GLIB_LOCALE_DIR _glib_get_locale_dir ()
1086
1087 #endif /* G_PLATFORM_WIN32 */
1088
1089 G_CONST_RETURN gchar *
1090 _glib_gettext (const gchar *str)
1091 {
1092   static gboolean _glib_gettext_initialized = FALSE;
1093
1094   if (!_glib_gettext_initialized)
1095     {
1096       bindtextdomain(GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
1097 #    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
1098       bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1099 #    endif
1100       _glib_gettext_initialized = TRUE;
1101     }
1102   
1103   return dgettext (GETTEXT_PACKAGE, str);
1104 }
1105
1106 #endif /* ENABLE_NLS */