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