always define G_GNUC_EXTENSION, even when not needed by GLib. That's
[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 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 #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 #ifdef G_OS_WIN32
52 #  define STRICT                        /* Strict typing, please */
53 #  include <windows.h>
54 #  include <errno.h>
55 #  include <ctype.h>
56 #  ifdef _MSC_VER
57 #    include <io.h>
58 #  endif /* _MSC_VER */
59 #endif /* G_OS_WIN32 */
60
61 /* implement Glib's inline functions
62  */
63 #define G_INLINE_FUNC extern
64 #define G_CAN_INLINE 1
65 #include "glib.h"
66
67 #ifdef  MAXPATHLEN
68 #define G_PATH_LENGTH   MAXPATHLEN
69 #elif   defined (PATH_MAX)
70 #define G_PATH_LENGTH   PATH_MAX
71 #elif   defined (_PC_PATH_MAX)
72 #define G_PATH_LENGTH   sysconf(_PC_PATH_MAX)
73 #else   
74 #define G_PATH_LENGTH   2048
75 #endif
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 = NULL;
336   gchar *dir = NULL;
337   static gulong max_len = (G_PATH_LENGTH == -1) ? 2048 : G_PATH_LENGTH;
338   
339   /* We don't use getcwd(3) on SUNOS, because, it does a popen("pwd")
340    * and, if that wasn't bad enough, hangs in doing so.
341    */
342 #if     defined (sun) && !defined (__SVR4)
343   buffer = g_new (gchar, max_len + 1);
344   *buffer = 0;
345   dir = getwd (buffer);
346 #else   /* !sun */
347   while (max_len < 128 * 1024)
348     {
349       buffer = g_new (gchar, max_len + 1);
350       *buffer = 0;
351       dir = getcwd (buffer, max_len);
352
353       if (dir || errno != ERANGE)
354         break;
355
356       g_free (buffer);
357       max_len *= 2;
358     }
359 #endif  /* !sun */
360   
361   if (!dir || !*buffer)
362     {
363       /* hm, should we g_error() out here?
364        * this can happen if e.g. "./" has mode \0000
365        */
366       buffer[0] = G_DIR_SEPARATOR;
367       buffer[1] = 0;
368     }
369
370   dir = g_strdup (buffer);
371   g_free (buffer);
372   
373   return dir;
374 }
375
376 gchar*
377 g_getenv (const gchar *variable)
378 {
379 #ifndef G_OS_WIN32
380   g_return_val_if_fail (variable != NULL, NULL);
381
382   return getenv (variable);
383 #else
384   gchar *v;
385   guint k;
386   static gchar *p = NULL;
387   static gint l;
388   gchar dummy[2];
389
390   g_return_val_if_fail (variable != NULL, NULL);
391   
392   v = getenv (variable);
393   if (!v)
394     return NULL;
395   
396   /* On Windows NT, it is relatively typical that environment variables
397    * contain references to other environment variables. Handle that by
398    * calling ExpandEnvironmentStrings.
399    */
400
401   /* First check how much space we need */
402   k = ExpandEnvironmentStrings (v, dummy, 2);
403   /* Then allocate that much, and actualy do the expansion */
404   if (p == NULL)
405     {
406       p = g_malloc (k);
407       l = k;
408     }
409   else if (k > l)
410     {
411       p = g_realloc (p, k);
412       l = k;
413     }
414   ExpandEnvironmentStrings (v, p, k);
415   return p;
416 #endif
417 }
418
419
420 G_LOCK_DEFINE_STATIC (g_utils_global);
421
422 static  gchar   *g_tmp_dir = NULL;
423 static  gchar   *g_user_name = NULL;
424 static  gchar   *g_real_name = NULL;
425 static  gchar   *g_home_dir = NULL;
426
427 /* HOLDS: g_utils_global_lock */
428 static void
429 g_get_any_init (void)
430 {
431   if (!g_tmp_dir)
432     {
433       g_tmp_dir = g_strdup (g_getenv ("TMPDIR"));
434       if (!g_tmp_dir)
435         g_tmp_dir = g_strdup (g_getenv ("TMP"));
436       if (!g_tmp_dir)
437         g_tmp_dir = g_strdup (g_getenv ("TEMP"));
438       
439 #ifdef P_tmpdir
440       if (!g_tmp_dir)
441         {
442           int k;
443           g_tmp_dir = g_strdup (P_tmpdir);
444           k = strlen (g_tmp_dir);
445           if (g_tmp_dir[k-1] == G_DIR_SEPARATOR)
446             g_tmp_dir[k-1] = '\0';
447         }
448 #endif
449       
450       if (!g_tmp_dir)
451         {
452 #ifndef G_OS_WIN32
453           g_tmp_dir = g_strdup ("/tmp");
454 #else /* G_OS_WIN32 */
455           g_tmp_dir = g_strdup ("C:\\");
456 #endif /* G_OS_WIN32 */
457         }
458       
459       if (!g_home_dir)
460         g_home_dir = g_strdup (g_getenv ("HOME"));
461       
462 #ifdef G_OS_WIN32
463       if (!g_home_dir)
464         {
465           /* The official way to specify a home directory on NT is
466            * the HOMEDRIVE and HOMEPATH environment variables.
467            *
468            * This is inside #ifdef G_OS_WIN32 because with the cygwin dll,
469            * HOME should be a POSIX style pathname.
470            */
471           
472           if (getenv ("HOMEDRIVE") != NULL && getenv ("HOMEPATH") != NULL)
473             {
474               gchar *homedrive, *homepath;
475               
476               homedrive = g_strdup (g_getenv ("HOMEDRIVE"));
477               homepath = g_strdup (g_getenv ("HOMEPATH"));
478               
479               g_home_dir = g_strconcat (homedrive, homepath, NULL);
480               g_free (homedrive);
481               g_free (homepath);
482             }
483         }
484 #endif /* !G_OS_WIN32 */
485       
486 #ifdef HAVE_PWD_H
487       {
488         struct passwd *pw = NULL;
489         gpointer buffer = NULL;
490         
491 #  ifdef HAVE_GETPWUID_R
492         struct passwd pwd;
493 #    ifdef _SC_GETPW_R_SIZE_MAX  
494         /* This reurns the maximum length */
495         guint bufsize = sysconf (_SC_GETPW_R_SIZE_MAX);
496 #    else /* _SC_GETPW_R_SIZE_MAX */
497         guint bufsize = 64;
498 #    endif /* _SC_GETPW_R_SIZE_MAX */
499         gint error;
500         
501         do
502           {
503             g_free (buffer);
504             buffer = g_malloc (bufsize);
505             errno = 0;
506             
507 #    ifdef HAVE_GETPWUID_R_POSIX
508             error = getpwuid_r (getuid (), &pwd, buffer, bufsize, &pw);
509             error = error < 0 ? errno : error;
510 #    else /* !HAVE_GETPWUID_R_POSIX */
511 #      ifdef _AIX
512             error = getpwuid_r (getuid (), &pwd, buffer, bufsize);
513             pw = error == 0 ? &pwd : NULL;
514 #      else /* !_AIX */
515             pw = getpwuid_r (getuid (), &pwd, buffer, bufsize);
516             error = pw ? 0 : errno;
517 #      endif /* !_AIX */            
518 #    endif /* !HAVE_GETPWUID_R_POSIX */
519             
520             if (!pw)
521               {
522                 /* we bail out prematurely if the user id can't be found
523                  * (should be pretty rare case actually), or if the buffer
524                  * should be sufficiently big and lookups are still not
525                  * successfull.
526                  */
527                 if (error == 0 || error == ENOENT)
528                   {
529                     g_warning ("getpwuid_r(): failed due to unknown user id (%lu)",
530                                (gulong) getuid ());
531                     break;
532                   }
533                 if (bufsize > 32 * 1024)
534                   {
535                     g_warning ("getpwuid_r(): failed due to: %s.",
536                                g_strerror (error));
537                     break;
538                   }
539                 
540                 bufsize *= 2;
541               }
542           }
543         while (!pw);
544 #  endif /* !HAVE_GETPWUID_R */
545         
546         if (!pw)
547           {
548             setpwent ();
549             pw = getpwuid (getuid ());
550             endpwent ();
551           }
552         if (pw)
553           {
554             g_user_name = g_strdup (pw->pw_name);
555             g_real_name = g_strdup (pw->pw_gecos);
556             if (!g_home_dir)
557               g_home_dir = g_strdup (pw->pw_dir);
558           }
559         g_free (buffer);
560       }
561       
562 #else /* !HAVE_PWD_H */
563       
564 #  ifdef G_OS_WIN32
565       {
566         guint len = 17;
567         gchar buffer[17];
568         
569         if (GetUserName (buffer, &len))
570           {
571             g_user_name = g_strdup (buffer);
572             g_real_name = g_strdup (buffer);
573           }
574       }
575 #  endif /* G_OS_WIN32 */
576       
577 #endif /* !HAVE_PWD_H */
578       
579 #ifdef __EMX__
580       /* change '\\' in %HOME% to '/' */
581       g_strdelimit (g_home_dir, "\\",'/');
582 #endif
583       if (!g_user_name)
584         g_user_name = g_strdup ("somebody");
585       if (!g_real_name)
586         g_real_name = g_strdup ("Unknown");
587       else
588         {
589           gchar *p;
590
591           for (p = g_real_name; *p; p++)
592             if (*p == ',')
593               {
594                 *p = 0;
595                 p = g_strdup (g_real_name);
596                 g_free (g_real_name);
597                 g_real_name = p;
598                 break;
599               }
600         }
601     }
602 }
603
604 gchar*
605 g_get_user_name (void)
606 {
607   G_LOCK (g_utils_global);
608   if (!g_tmp_dir)
609     g_get_any_init ();
610   G_UNLOCK (g_utils_global);
611   
612   return g_user_name;
613 }
614
615 gchar*
616 g_get_real_name (void)
617 {
618   G_LOCK (g_utils_global);
619   if (!g_tmp_dir)
620     g_get_any_init ();
621   G_UNLOCK (g_utils_global);
622  
623   return g_real_name;
624 }
625
626 /* Return the home directory of the user. If there is a HOME
627  * environment variable, its value is returned, otherwise use some
628  * system-dependent way of finding it out. If no home directory can be
629  * deduced, return NULL.
630  */
631
632 gchar*
633 g_get_home_dir (void)
634 {
635   G_LOCK (g_utils_global);
636   if (!g_tmp_dir)
637     g_get_any_init ();
638   G_UNLOCK (g_utils_global);
639   
640   return g_home_dir;
641 }
642
643 /* Return a directory to be used to store temporary files. This is the
644  * value of the TMPDIR, TMP or TEMP environment variables (they are
645  * checked in that order). If none of those exist, use P_tmpdir from
646  * stdio.h.  If that isn't defined, return "/tmp" on POSIXly systems,
647  * and C:\ on Windows.
648  */
649
650 gchar*
651 g_get_tmp_dir (void)
652 {
653   G_LOCK (g_utils_global);
654   if (!g_tmp_dir)
655     g_get_any_init ();
656   G_UNLOCK (g_utils_global);
657   
658   return g_tmp_dir;
659 }
660
661 static gchar *g_prgname = NULL;
662
663 gchar*
664 g_get_prgname (void)
665 {
666   gchar* retval;
667
668   G_LOCK (g_utils_global);
669   retval = g_prgname;
670   G_UNLOCK (g_utils_global);
671
672   return retval;
673 }
674
675 void
676 g_set_prgname (const gchar *prgname)
677 {
678   gchar *c;
679     
680   G_LOCK (g_utils_global);
681   c = g_prgname;
682   g_prgname = g_strdup (prgname);
683   g_free (c);
684   G_UNLOCK (g_utils_global);
685 }
686
687 guint
688 g_direct_hash (gconstpointer v)
689 {
690   return GPOINTER_TO_UINT (v);
691 }
692
693 gint
694 g_direct_equal (gconstpointer v1,
695                 gconstpointer v2)
696 {
697   return v1 == v2;
698 }
699
700 gint
701 g_int_equal (gconstpointer v1,
702              gconstpointer v2)
703 {
704   return *((const gint*) v1) == *((const gint*) v2);
705 }
706
707 guint
708 g_int_hash (gconstpointer v)
709 {
710   return *(const gint*) v;
711 }