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