applied glib-tml-981101-1 patch from Tor Lillqvist (ChangeLog entry
[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 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include "glibconfig.h"
25
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <errno.h>
34 #ifdef HAVE_PWD_H
35 #include <pwd.h>
36 #endif
37 #include <sys/types.h>
38 #ifdef HAVE_SYS_PARAM_H
39 #include <sys/param.h>
40 #endif
41
42 #ifdef NATIVE_WIN32
43 #  define STRICT                        /* Strict typing, please */
44 #  include <windows.h>
45 #  include <direct.h>
46 #  include <errno.h>
47 #  include <ctype.h>
48 #  ifdef _MSC_VER
49 #    include <io.h>
50 #  endif /* _MSC_VER */
51 #endif /* NATIVE_WIN32 */
52
53 /* implement Glib's inline functions
54  */
55 #define G_INLINE_FUNC extern
56 #define G_CAN_INLINE 1
57 #include "glib.h"
58
59 #ifdef  MAXPATHLEN
60 #define G_PATH_LENGTH   (MAXPATHLEN + 1)
61 #elif   defined (PATH_MAX)
62 #define G_PATH_LENGTH   (PATH_MAX + 1)
63 #else   /* !MAXPATHLEN */
64 #define G_PATH_LENGTH   (2048 + 1)
65 #endif  /* !MAXPATHLEN && !PATH_MAX */
66
67 const guint glib_major_version = GLIB_MAJOR_VERSION;
68 const guint glib_minor_version = GLIB_MINOR_VERSION;
69 const guint glib_micro_version = GLIB_MICRO_VERSION;
70 const guint glib_interface_age = GLIB_INTERFACE_AGE;
71 const guint glib_binary_age = GLIB_BINARY_AGE;
72
73 #if defined (NATIVE_WIN32) && defined (__LCC__)
74 int __stdcall 
75 LibMain (void         *hinstDll,
76          unsigned long dwReason,
77          void         *reserved)
78 {
79   return 1;
80 }
81 #endif /* NATIVE_WIN32 && __LCC__ */
82
83 void
84 g_atexit (GVoidFunc func)
85 {
86   gint result;
87   gchar *error = NULL;
88
89   /* keep this in sync with glib.h */
90
91 #ifdef  G_NATIVE_ATEXIT
92   result = ATEXIT (func);
93   if (result)
94     error = g_strerror (errno);
95 #elif defined (HAVE_ATEXIT)
96 #  ifdef NeXT /* @#%@! NeXTStep */
97   result = !atexit ((void (*)(void)) func);
98   if (result)
99     error = g_strerror (errno);
100 #  else
101   result = atexit ((void (*)(void)) func);
102   if (result)
103     error = g_strerror (errno);
104 #  endif /* NeXT */
105 #elif defined (HAVE_ON_EXIT)
106   result = on_exit ((void (*)(int, void *)) func, NULL);
107   if (result)
108     error = g_strerror (errno);
109 #else
110   result = 0;
111   error = "no implementation";
112 #endif /* G_NATIVE_ATEXIT */
113
114   if (error)
115     g_error ("Could not register atexit() function: %s", error);
116 }
117
118 gint
119 g_snprintf (gchar       *str,
120             gulong       n,
121             gchar const *fmt,
122             ...)
123 {
124 #ifdef  HAVE_VSNPRINTF
125   va_list args;
126   gint retval;
127   
128   va_start (args, fmt);
129   retval = vsnprintf (str, n, fmt, args);
130   va_end (args);
131   
132   return retval;
133 #else   /* !HAVE_VSNPRINTF */
134   gchar *printed;
135   va_list args;
136   
137   va_start (args, fmt);
138   printed = g_strdup_vprintf (fmt, args);
139   va_end (args);
140   
141   strncpy (str, printed, n);
142   str[n-1] = '\0';
143
144   g_free (printed);
145   
146   return strlen (str);
147 #endif  /* !HAVE_VSNPRINTF */
148 }
149
150 gint
151 g_vsnprintf (gchar       *str,
152              gulong       n,
153              gchar const *fmt,
154              va_list      args)
155 {
156 #ifdef  HAVE_VSNPRINTF
157   gint retval;
158   
159   retval = vsnprintf (str, n, fmt, args);
160   
161   return retval;
162 #else   /* !HAVE_VSNPRINTF */
163   gchar *printed;
164   
165   printed = g_strdup_vprintf (fmt, args);
166   strncpy (str, printed, n);
167   str[n-1] = '\0';
168
169   g_free (printed);
170   
171   return strlen (str);
172 #endif /* !HAVE_VSNPRINTF */
173 }
174
175 guint        
176 g_parse_debug_string  (const gchar *string, 
177                        GDebugKey   *keys, 
178                        guint        nkeys)
179 {
180   guint i;
181   guint result = 0;
182   
183   g_return_val_if_fail (string != NULL, 0);
184   
185   if (!g_strcasecmp (string, "all"))
186     {
187       for (i=0; i<nkeys; i++)
188         result |= keys[i].value;
189     }
190   else
191     {
192       gchar *str = g_strdup (string);
193       gchar *p = str;
194       gchar *q;
195       gboolean done = FALSE;
196       
197       while (*p && !done)
198         {
199           q = strchr (p, ':');
200           if (!q)
201             {
202               q = p + strlen(p);
203               done = TRUE;
204             }
205           
206           *q = 0;
207           
208           for (i=0; i<nkeys; i++)
209             if (!g_strcasecmp(keys[i].key, p))
210               result |= keys[i].value;
211           
212           p = q+1;
213         }
214       
215       g_free (str);
216     }
217   
218   return result;
219 }
220
221 gchar*
222 g_basename (const gchar    *file_name)
223 {
224   register gchar *base;
225   
226   g_return_val_if_fail (file_name != NULL, NULL);
227   
228   base = strrchr (file_name, G_DIR_SEPARATOR);
229   if (base)
230     return base + 1;
231
232 #ifdef NATIVE_WIN32
233   if (isalpha (file_name[0]) && file_name[1] == ':')
234     return (gchar*) file_name + 2;
235 #endif /* NATIVE_WIN32 */
236   
237   return (gchar*) file_name;
238 }
239
240 gboolean
241 g_path_is_absolute (const gchar *file_name)
242 {
243   g_return_val_if_fail (file_name != NULL, FALSE);
244   
245   if (file_name[0] == G_DIR_SEPARATOR)
246     return TRUE;
247
248 #ifdef NATIVE_WIN32
249   if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
250     return TRUE;
251 #endif
252
253   return FALSE;
254 }
255
256 gchar*
257 g_path_skip_root (gchar *file_name)
258 {
259   g_return_val_if_fail (file_name != NULL, NULL);
260   
261   if (file_name[0] == G_DIR_SEPARATOR)
262     return file_name + 1;
263
264 #ifdef NATIVE_WIN32
265   if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
266     return file_name + 3;
267 #endif
268
269   return NULL;
270 }
271
272 gchar*
273 g_dirname (const gchar     *file_name)
274 {
275   register gchar *base;
276   register guint len;
277   
278   g_return_val_if_fail (file_name != NULL, NULL);
279   
280   base = strrchr (file_name, G_DIR_SEPARATOR);
281   if (!base)
282     return g_strdup (".");
283   while (base > file_name && *base == G_DIR_SEPARATOR)
284     base--;
285   len = (guint) 1 + base - file_name;
286   
287   base = g_new (gchar, len + 1);
288   g_memmove (base, file_name, len);
289   base[len] = 0;
290   
291   return base;
292 }
293
294 gchar*
295 g_get_current_dir (void)
296 {
297   gchar *buffer;
298   gchar *dir;
299
300   buffer = g_new (gchar, G_PATH_LENGTH);
301   *buffer = 0;
302   
303   /* We don't use getcwd(3) on SUNOS, because, it does a popen("pwd")
304    * and, if that wasn't bad enough, hangs in doing so.
305    */
306 #if     defined (sun) && !defined (__SVR4)
307   dir = getwd (buffer);
308 #else   /* !sun */
309   dir = getcwd (buffer, G_PATH_LENGTH - 1);
310 #endif  /* !sun */
311   
312   if (!dir || !*buffer)
313     {
314       /* hm, should we g_error() out here?
315        * this can happen if e.g. "./" has mode \0000
316        */
317       buffer[0] = G_DIR_SEPARATOR;
318       buffer[1] = 0;
319     }
320
321   dir = g_strdup (buffer);
322   g_free (buffer);
323   
324   return dir;
325 }
326
327 gchar*
328 g_getenv (const gchar *variable)
329 {
330 #ifndef NATIVE_WIN32
331   g_return_val_if_fail (variable != NULL, NULL);
332
333   return getenv (variable);
334 #else
335   gchar *v;
336   guint k;
337   static gchar *p = NULL;
338   static gint l;
339   gchar dummy[2];
340
341   g_return_val_if_fail (variable != NULL, NULL);
342   
343   v = getenv (variable);
344   if (!v)
345     return NULL;
346   
347   /* On Windows NT, it is relatively typical that environment variables
348    * contain references to other environment variables. Handle that by
349    * calling ExpandEnvironmentStrings.
350    */
351
352   /* First check how much space we need */
353   k = ExpandEnvironmentStrings (v, dummy, 2);
354   /* Then allocate that much, and actualy do the expansion */
355   if (p == NULL)
356     {
357       p = g_malloc (k);
358       l = k;
359     }
360   else if (k > l)
361     {
362       p = g_realloc (p, k);
363       l = k;
364     }
365   ExpandEnvironmentStrings (v, p, k);
366   return p;
367 #endif
368 }
369
370 static  gchar   *g_tmp_dir = NULL;
371 static  gchar   *g_user_name = NULL;
372 static  gchar   *g_real_name = NULL;
373 static  gchar   *g_home_dir = NULL;
374
375 static void
376 g_get_any_init (void)
377 {
378   if (!g_tmp_dir)
379     {
380 #ifdef HAVE_PWD_H
381       struct passwd *pw;
382 #endif
383
384       g_tmp_dir = g_strdup (g_getenv ("TMPDIR"));
385       if (!g_tmp_dir)
386         g_tmp_dir = g_strdup (g_getenv ("TMP"));
387       if (!g_tmp_dir)
388         g_tmp_dir = g_strdup (g_getenv ("TEMP"));
389       
390 #ifdef P_tmpdir
391       if (!g_tmp_dir)
392         {
393           int k;
394           g_tmp_dir = g_strdup (P_tmpdir);
395           k = strlen (g_tmp_dir);
396           if (g_tmp_dir[k-1] == G_DIR_SEPARATOR)
397             g_tmp_dir[k-1] = '\0';
398         }
399 #endif
400       if (!g_tmp_dir)
401         {
402 #ifndef NATIVE_WIN32
403           g_tmp_dir = g_strdup ("/tmp");
404 #else /* NATIVE_WIN32 */
405           g_tmp_dir = g_strdup ("C:\\");
406 #endif /* NATIVE_WIN32 */
407         }
408       
409       g_home_dir = g_strdup (g_getenv ("HOME"));
410       
411 #ifdef HAVE_PWD_H
412       setpwent ();
413       pw = getpwuid (getuid ());
414       endpwent ();
415       
416       if (pw)
417         {
418           g_user_name = g_strdup (pw->pw_name);
419           g_real_name = g_strdup (pw->pw_gecos);
420           if (!g_home_dir)
421             g_home_dir = g_strdup (pw->pw_dir);
422         }
423 #else /* !HAVE_PWD_H */
424 #  ifdef NATIVE_WIN32
425       {
426         guint len = 17;
427         
428         g_user_name = g_new (gchar, len);
429         
430         if (!GetUserName (g_user_name, &len))
431           {
432             g_free (g_user_name);
433             g_user_name = g_strdup ("somebody");
434             g_real_name = g_strdup ("Unknown");
435           }
436         else
437           g_real_name = g_strdup (g_user_name);
438       }
439 #  else /* !NATIVE_WIN32 */
440       g_user_name = g_strdup ("somebody");
441       g_real_name = g_strdup ("Unknown");
442       g_home_dir = NULL;
443 #  endif /* !NATIVE_WIN32 */
444 #endif /* !HAVE_PWD_H */
445     }
446 }
447
448 gchar*
449 g_get_user_name (void)
450 {
451   if (!g_tmp_dir)
452     g_get_any_init ();
453   
454   return g_user_name;
455 }
456
457 gchar*
458 g_get_real_name (void)
459 {
460   if (!g_tmp_dir)
461     g_get_any_init ();
462   
463   return g_real_name;
464 }
465
466 /* Return the home directory of the user. If there is a HOME
467  * environment variable, its value is returned, otherwise use some
468  * system-dependent way of finding it out. If no home directory can be
469  * deduced, return NULL.
470  */
471
472 gchar*
473 g_get_home_dir (void)
474 {
475   if (!g_tmp_dir)
476     g_get_any_init ();
477   
478   return g_home_dir;
479 }
480
481 /* Return a directory to be used to store temporary files. This is the
482  * value of the TMPDIR, TMP or TEMP environment variables (they are
483  * checked in that order). If none of those exist, use P_tmpdir from
484  * stdio.h.  If that isn't defined, return "/tmp" on POSIXly systems,
485  * and C:\ on Windows.
486  */
487
488 gchar*
489 g_get_tmp_dir (void)
490 {
491   if (!g_tmp_dir)
492     g_get_any_init ();
493   
494   return g_tmp_dir;
495 }
496
497 static gchar *g_prgname = NULL;
498
499 gchar*
500 g_get_prgname (void)
501 {
502   return g_prgname;
503 }
504
505 void
506 g_set_prgname (const gchar *prgname)
507 {
508   gchar *c = g_prgname;
509   
510   g_prgname = g_strdup (prgname);
511   g_free (c);
512 }
513
514 guint
515 g_direct_hash (gconstpointer v)
516 {
517   return GPOINTER_TO_UINT (v);
518 }
519
520 gint
521 g_direct_equal (gconstpointer v1,
522                 gconstpointer v2)
523 {
524   return GPOINTER_TO_UINT (v1) == GPOINTER_TO_UINT (v2);
525 }
526
527 gint
528 g_int_equal (gconstpointer v1,
529              gconstpointer v2)
530 {
531   return *((const gint*) v1) == *((const gint*) v2);
532 }
533
534 guint
535 g_int_hash (gconstpointer v)
536 {
537   return *(const gint*) v;
538 }
539
540 GIOChannel*
541 g_iochannel_new (gint fd)
542 {
543   GIOChannel *channel = g_new (GIOChannel, 1);
544
545   channel->fd = fd;
546
547 #ifdef NATIVE_WIN32
548   channel->peer = 0;
549   channel->peer_fd = 0;
550   channel->offset = 0;
551   channel->peer_offset = 0;
552 #endif /* NATIVE_WIN32 */
553
554   return channel;
555 }
556
557 void
558 g_iochannel_free (GIOChannel *channel)
559 {
560   g_return_if_fail (channel != NULL);
561
562   g_free (channel);
563 }
564
565 void
566 g_iochannel_close_and_free (GIOChannel *channel)
567 {
568   g_return_if_fail (channel != NULL);
569
570   close (channel->fd);
571
572   g_iochannel_free (channel);
573 }
574
575 #undef g_iochannel_wakeup_peer
576
577 void
578 g_iochannel_wakeup_peer (GIOChannel *channel)
579 {
580 #ifdef NATIVE_WIN32
581   static guint message = 0;
582 #endif
583
584   g_return_if_fail (channel != NULL);
585
586 #ifdef NATIVE_WIN32
587   if (message == 0)
588     message = RegisterWindowMessage ("gdk-pipe-readable");
589
590 #  if 0
591   g_print ("g_iochannel_wakeup_peer: calling PostThreadMessage (%#x, %d, %d, %d)\n",
592            channel->peer, message, channel->peer_fd, channel->offset);
593 #  endif
594   PostThreadMessage (channel->peer, message,
595                      channel->peer_fd, channel->offset);
596 #endif /* NATIVE_WIN32 */
597 }
598
599
600 #ifdef NATIVE_WIN32
601 #ifdef _MSC_VER
602
603 int
604 gwin_ftruncate (gint  fd,
605                 guint size)
606 {
607   HANDLE hfile;
608   guint curpos;
609
610   g_return_val_if_fail (fd >= 0, -1);
611   
612   hfile = (HANDLE) _get_osfhandle (fd);
613   curpos = SetFilePointer (hfile, 0, NULL, FILE_CURRENT);
614   if (curpos == 0xFFFFFFFF
615       || SetFilePointer (hfile, size, NULL, FILE_BEGIN) == 0xFFFFFFFF
616       || !SetEndOfFile (hfile))
617     {
618       gint error = GetLastError ();
619
620       switch (error)
621         {
622         case ERROR_INVALID_HANDLE:
623           errno = EBADF;
624           break;
625         default:
626           errno = EIO;
627           break;
628         }
629
630       return -1;
631     }
632
633   return 0;
634 }
635
636 DIR*
637 gwin_opendir (const char *dirname)
638 {
639   DIR *result;
640   gchar *mask;
641   guint k;
642
643   g_return_val_if_fail (dirname != NULL, NULL);
644
645   result = g_new0 (DIR, 1);
646   result->find_file_data = g_new0 (WIN32_FIND_DATA, 1);
647   result->dir_name = g_strdup (dirname);
648   
649   k = strlen (result->dir_name);
650   if (k && result->dir_name[k - 1] == '\\')
651     {
652       result->dir_name[k - 1] = '\0';
653       k--;
654     }
655   mask = g_strdup_printf ("%s\\*", result->dir_name);
656
657   result->find_file_handle = (guint) FindFirstFile (mask,
658                                              (LPWIN32_FIND_DATA) result->find_file_data);
659   g_free (mask);
660
661   if (result->find_file_handle == (guint) INVALID_HANDLE_VALUE)
662     {
663       int error = GetLastError ();
664
665       g_free (result->dir_name);
666       g_free (result->find_file_data);
667       g_free (result);
668       switch (error)
669         {
670         default:
671           errno = EIO;
672           return NULL;
673         }
674     }
675   result->just_opened = TRUE;
676
677   return result;
678 }
679
680 struct dirent*
681 gwin_readdir (DIR *dir)
682 {
683   static struct dirent result;
684
685   g_return_val_if_fail (dir != NULL, NULL);
686
687   if (dir->just_opened)
688     dir->just_opened = FALSE;
689   else
690     {
691       if (!FindNextFile ((HANDLE) dir->find_file_handle,
692                          (LPWIN32_FIND_DATA) dir->find_file_data))
693         {
694           int error = GetLastError ();
695
696           switch (error)
697             {
698             case ERROR_NO_MORE_FILES:
699               return NULL;
700             default:
701               errno = EIO;
702               return NULL;
703             }
704         }
705     }
706   strcpy (result.d_name, g_basename (((LPWIN32_FIND_DATA) dir->find_file_data)->cFileName));
707       
708   return &result;
709 }
710
711 void
712 gwin_rewinddir (DIR *dir)
713 {
714   gchar *mask;
715
716   g_return_if_fail (dir != NULL);
717
718   if (!FindClose ((HANDLE) dir->find_file_handle))
719     g_warning ("gwin_rewinddir(): FindClose() failed\n");
720
721   mask = g_strdup_printf ("%s\\*", dir->dir_name);
722   dir->find_file_handle = (guint) FindFirstFile (mask,
723                                           (LPWIN32_FIND_DATA) dir->find_file_data);
724   g_free (mask);
725
726   if (dir->find_file_handle == (guint) INVALID_HANDLE_VALUE)
727     {
728       int error = GetLastError ();
729
730       switch (error)
731         {
732         default:
733           errno = EIO;
734           return;
735         }
736     }
737   dir->just_opened = TRUE;
738 }  
739
740 gint
741 gwin_closedir (DIR *dir)
742 {
743   g_return_val_if_fail (dir != NULL, -1);
744
745   if (!FindClose ((HANDLE) dir->find_file_handle))
746     {
747       int error = GetLastError ();
748
749       switch (error)
750         {
751         default:
752           errno = EIO; return -1;
753         }
754     }
755
756   g_free (dir->dir_name);
757   g_free (dir->find_file_data);
758   g_free (dir);
759
760   return 0;
761 }
762
763 #endif /* _MSC_VER */
764
765 #endif /* NATIVE_WIN32 */