Merge main loop into head. This probably breaks Win32, until
[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 #if 0 /* Old IO Channels */
541
542 GIOChannel*
543 g_iochannel_new (gint fd)
544 {
545   GIOChannel *channel = g_new (GIOChannel, 1);
546
547   channel->fd = fd;
548
549 #ifdef NATIVE_WIN32
550   channel->peer = 0;
551   channel->peer_fd = 0;
552   channel->offset = 0;
553   channel->need_wakeups = 0;
554 #endif /* NATIVE_WIN32 */
555
556   return channel;
557 }
558
559 void
560 g_iochannel_free (GIOChannel *channel)
561 {
562   g_return_if_fail (channel != NULL);
563
564   g_free (channel);
565 }
566
567 void
568 g_iochannel_close_and_free (GIOChannel *channel)
569 {
570   g_return_if_fail (channel != NULL);
571
572   close (channel->fd);
573
574   g_iochannel_free (channel);
575 }
576
577 #undef g_iochannel_wakeup_peer
578
579 void
580 g_iochannel_wakeup_peer (GIOChannel *channel)
581 {
582 #ifdef NATIVE_WIN32
583   static guint message = 0;
584 #endif
585
586   g_return_if_fail (channel != NULL);
587
588 #ifdef NATIVE_WIN32
589   if (message == 0)
590     message = RegisterWindowMessage ("gdk-pipe-readable");
591
592 #  if 0
593   g_print ("g_iochannel_wakeup_peer: calling PostThreadMessage (%#x, %d, %d, %d)\n",
594            channel->peer, message, channel->peer_fd, channel->offset);
595 #  endif
596   PostThreadMessage (channel->peer, message,
597                      channel->peer_fd, channel->offset);
598 #endif /* NATIVE_WIN32 */
599 }
600
601 #endif /* Old IO Channels */
602
603 #ifdef NATIVE_WIN32
604 #ifdef _MSC_VER
605
606 int
607 gwin_ftruncate (gint  fd,
608                 guint size)
609 {
610   HANDLE hfile;
611   guint curpos;
612
613   g_return_val_if_fail (fd >= 0, -1);
614   
615   hfile = (HANDLE) _get_osfhandle (fd);
616   curpos = SetFilePointer (hfile, 0, NULL, FILE_CURRENT);
617   if (curpos == 0xFFFFFFFF
618       || SetFilePointer (hfile, size, NULL, FILE_BEGIN) == 0xFFFFFFFF
619       || !SetEndOfFile (hfile))
620     {
621       gint error = GetLastError ();
622
623       switch (error)
624         {
625         case ERROR_INVALID_HANDLE:
626           errno = EBADF;
627           break;
628         default:
629           errno = EIO;
630           break;
631         }
632
633       return -1;
634     }
635
636   return 0;
637 }
638
639 DIR*
640 gwin_opendir (const char *dirname)
641 {
642   DIR *result;
643   gchar *mask;
644   guint k;
645
646   g_return_val_if_fail (dirname != NULL, NULL);
647
648   result = g_new0 (DIR, 1);
649   result->find_file_data = g_new0 (WIN32_FIND_DATA, 1);
650   result->dir_name = g_strdup (dirname);
651   
652   k = strlen (result->dir_name);
653   if (k && result->dir_name[k - 1] == '\\')
654     {
655       result->dir_name[k - 1] = '\0';
656       k--;
657     }
658   mask = g_strdup_printf ("%s\\*", result->dir_name);
659
660   result->find_file_handle = (guint) FindFirstFile (mask,
661                                              (LPWIN32_FIND_DATA) result->find_file_data);
662   g_free (mask);
663
664   if (result->find_file_handle == (guint) INVALID_HANDLE_VALUE)
665     {
666       int error = GetLastError ();
667
668       g_free (result->dir_name);
669       g_free (result->find_file_data);
670       g_free (result);
671       switch (error)
672         {
673         default:
674           errno = EIO;
675           return NULL;
676         }
677     }
678   result->just_opened = TRUE;
679
680   return result;
681 }
682
683 struct dirent*
684 gwin_readdir (DIR *dir)
685 {
686   static struct dirent result;
687
688   g_return_val_if_fail (dir != NULL, NULL);
689
690   if (dir->just_opened)
691     dir->just_opened = FALSE;
692   else
693     {
694       if (!FindNextFile ((HANDLE) dir->find_file_handle,
695                          (LPWIN32_FIND_DATA) dir->find_file_data))
696         {
697           int error = GetLastError ();
698
699           switch (error)
700             {
701             case ERROR_NO_MORE_FILES:
702               return NULL;
703             default:
704               errno = EIO;
705               return NULL;
706             }
707         }
708     }
709   strcpy (result.d_name, g_basename (((LPWIN32_FIND_DATA) dir->find_file_data)->cFileName));
710       
711   return &result;
712 }
713
714 void
715 gwin_rewinddir (DIR *dir)
716 {
717   gchar *mask;
718
719   g_return_if_fail (dir != NULL);
720
721   if (!FindClose ((HANDLE) dir->find_file_handle))
722     g_warning ("gwin_rewinddir(): FindClose() failed\n");
723
724   mask = g_strdup_printf ("%s\\*", dir->dir_name);
725   dir->find_file_handle = (guint) FindFirstFile (mask,
726                                           (LPWIN32_FIND_DATA) dir->find_file_data);
727   g_free (mask);
728
729   if (dir->find_file_handle == (guint) INVALID_HANDLE_VALUE)
730     {
731       int error = GetLastError ();
732
733       switch (error)
734         {
735         default:
736           errno = EIO;
737           return;
738         }
739     }
740   dir->just_opened = TRUE;
741 }  
742
743 gint
744 gwin_closedir (DIR *dir)
745 {
746   g_return_val_if_fail (dir != NULL, -1);
747
748   if (!FindClose ((HANDLE) dir->find_file_handle))
749     {
750       int error = GetLastError ();
751
752       switch (error)
753         {
754         default:
755           errno = EIO; return -1;
756         }
757     }
758
759   g_free (dir->dir_name);
760   g_free (dir->find_file_data);
761   g_free (dir);
762
763   return 0;
764 }
765
766 #endif /* _MSC_VER */
767
768 #endif /* NATIVE_WIN32 */