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