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