1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1998 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
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.
21 * MT safe for the unix part, FIXME: make the win32 part MT safe as well.
28 #include "glibconfig.h"
41 #include <sys/types.h>
42 #ifdef HAVE_SYS_PARAM_H
43 #include <sys/param.h>
47 # define STRICT /* Strict typing, please */
54 # endif /* _MSC_VER */
55 #endif /* NATIVE_WIN32 */
57 /* implement Glib's inline functions
59 #define G_INLINE_FUNC extern
60 #define G_CAN_INLINE 1
64 #define G_PATH_LENGTH (MAXPATHLEN + 1)
65 #elif defined (PATH_MAX)
66 #define G_PATH_LENGTH (PATH_MAX + 1)
67 #else /* !MAXPATHLEN */
68 #define G_PATH_LENGTH (2048 + 1)
69 #endif /* !MAXPATHLEN && !PATH_MAX */
71 const guint glib_major_version
= GLIB_MAJOR_VERSION
;
72 const guint glib_minor_version
= GLIB_MINOR_VERSION
;
73 const guint glib_micro_version
= GLIB_MICRO_VERSION
;
74 const guint glib_interface_age
= GLIB_INTERFACE_AGE
;
75 const guint glib_binary_age
= GLIB_BINARY_AGE
;
77 #if defined (NATIVE_WIN32) && defined (__LCC__)
79 LibMain (void *hinstDll
,
80 unsigned long dwReason
,
85 #endif /* NATIVE_WIN32 && __LCC__ */
88 g_atexit (GVoidFunc func
)
93 /* keep this in sync with glib.h */
95 #ifdef G_NATIVE_ATEXIT
96 result
= ATEXIT (func
);
98 error
= g_strerror (errno
);
99 #elif defined (HAVE_ATEXIT)
100 # ifdef NeXT /* @#%@! NeXTStep */
101 result
= !atexit ((void (*)(void)) func
);
103 error
= g_strerror (errno
);
105 result
= atexit ((void (*)(void)) func
);
107 error
= g_strerror (errno
);
109 #elif defined (HAVE_ON_EXIT)
110 result
= on_exit ((void (*)(int, void *)) func
, NULL
);
112 error
= g_strerror (errno
);
115 error
= "no implementation";
116 #endif /* G_NATIVE_ATEXIT */
119 g_error ("Could not register atexit() function: %s", error
);
123 g_snprintf (gchar
*str
,
128 #ifdef HAVE_VSNPRINTF
132 va_start (args
, fmt
);
133 retval
= vsnprintf (str
, n
, fmt
, args
);
137 #else /* !HAVE_VSNPRINTF */
141 va_start (args
, fmt
);
142 printed
= g_strdup_vprintf (fmt
, args
);
145 strncpy (str
, printed
, n
);
151 #endif /* !HAVE_VSNPRINTF */
155 g_vsnprintf (gchar
*str
,
160 #ifdef HAVE_VSNPRINTF
163 retval
= vsnprintf (str
, n
, fmt
, args
);
166 #else /* !HAVE_VSNPRINTF */
169 printed
= g_strdup_vprintf (fmt
, args
);
170 strncpy (str
, printed
, n
);
176 #endif /* !HAVE_VSNPRINTF */
180 g_parse_debug_string (const gchar
*string
,
187 g_return_val_if_fail (string
!= NULL
, 0);
189 if (!g_strcasecmp (string
, "all"))
191 for (i
=0; i
<nkeys
; i
++)
192 result
|= keys
[i
].value
;
196 gchar
*str
= g_strdup (string
);
199 gboolean done
= FALSE
;
212 for (i
=0; i
<nkeys
; i
++)
213 if (!g_strcasecmp(keys
[i
].key
, p
))
214 result
|= keys
[i
].value
;
226 g_basename (const gchar
*file_name
)
228 register gchar
*base
;
230 g_return_val_if_fail (file_name
!= NULL
, NULL
);
232 base
= strrchr (file_name
, G_DIR_SEPARATOR
);
237 if (isalpha (file_name
[0]) && file_name
[1] == ':')
238 return (gchar
*) file_name
+ 2;
239 #endif /* NATIVE_WIN32 */
241 return (gchar
*) file_name
;
245 g_path_is_absolute (const gchar
*file_name
)
247 g_return_val_if_fail (file_name
!= NULL
, FALSE
);
249 if (file_name
[0] == G_DIR_SEPARATOR
)
253 if (isalpha (file_name
[0]) && file_name
[1] == ':' && file_name
[2] == G_DIR_SEPARATOR
)
261 g_path_skip_root (gchar
*file_name
)
263 g_return_val_if_fail (file_name
!= NULL
, NULL
);
265 if (file_name
[0] == G_DIR_SEPARATOR
)
266 return file_name
+ 1;
269 if (isalpha (file_name
[0]) && file_name
[1] == ':' && file_name
[2] == G_DIR_SEPARATOR
)
270 return file_name
+ 3;
277 g_dirname (const gchar
*file_name
)
279 register gchar
*base
;
282 g_return_val_if_fail (file_name
!= NULL
, NULL
);
284 base
= strrchr (file_name
, G_DIR_SEPARATOR
);
286 return g_strdup (".");
287 while (base
> file_name
&& *base
== G_DIR_SEPARATOR
)
289 len
= (guint
) 1 + base
- file_name
;
291 base
= g_new (gchar
, len
+ 1);
292 g_memmove (base
, file_name
, len
);
299 g_get_current_dir (void)
304 buffer
= g_new (gchar
, G_PATH_LENGTH
);
307 /* We don't use getcwd(3) on SUNOS, because, it does a popen("pwd")
308 * and, if that wasn't bad enough, hangs in doing so.
310 #if defined (sun) && !defined (__SVR4)
311 dir
= getwd (buffer
);
313 dir
= getcwd (buffer
, G_PATH_LENGTH
- 1);
316 if (!dir
|| !*buffer
)
318 /* hm, should we g_error() out here?
319 * this can happen if e.g. "./" has mode \0000
321 buffer
[0] = G_DIR_SEPARATOR
;
325 dir
= g_strdup (buffer
);
332 g_getenv (const gchar
*variable
)
335 g_return_val_if_fail (variable
!= NULL
, NULL
);
337 return getenv (variable
);
341 static gchar
*p
= NULL
;
345 g_return_val_if_fail (variable
!= NULL
, NULL
);
347 v
= getenv (variable
);
351 /* On Windows NT, it is relatively typical that environment variables
352 * contain references to other environment variables. Handle that by
353 * calling ExpandEnvironmentStrings.
356 /* First check how much space we need */
357 k
= ExpandEnvironmentStrings (v
, dummy
, 2);
358 /* Then allocate that much, and actualy do the expansion */
366 p
= g_realloc (p
, k
);
369 ExpandEnvironmentStrings (v
, p
, k
);
375 G_LOCK_DECLARE_STATIC (g_utils_global
);
377 static gchar
*g_tmp_dir
= NULL
;
378 static gchar
*g_user_name
= NULL
;
379 static gchar
*g_real_name
= NULL
;
380 static gchar
*g_home_dir
= NULL
;
382 /* HOLDS: g_utils_global_lock */
384 g_get_any_init (void)
388 g_tmp_dir
= g_strdup (g_getenv ("TMPDIR"));
390 g_tmp_dir
= g_strdup (g_getenv ("TMP"));
392 g_tmp_dir
= g_strdup (g_getenv ("TEMP"));
398 g_tmp_dir
= g_strdup (P_tmpdir
);
399 k
= strlen (g_tmp_dir
);
400 if (g_tmp_dir
[k
-1] == G_DIR_SEPARATOR
)
401 g_tmp_dir
[k
-1] = '\0';
408 g_tmp_dir
= g_strdup ("/tmp");
409 #else /* NATIVE_WIN32 */
410 g_tmp_dir
= g_strdup ("C:\\");
411 #endif /* NATIVE_WIN32 */
415 g_home_dir
= g_strdup (g_getenv ("HOME"));
420 /* The official way to specify a home directory on NT is
421 * the HOMEDRIVE and HOMEPATH environment variables.
423 * This is inside #ifdef NATIVE_WIN32 because with the cygwin dll,
424 * HOME should be a POSIX style pathname.
427 if (getenv ("HOMEDRIVE") != NULL
&& getenv ("HOMEPATH") != NULL
)
429 gchar
*homedrive
, *homepath
;
431 homedrive
= g_strdup (g_getenv ("HOMEDRIVE"));
432 homepath
= g_strdup (g_getenv ("HOMEPATH"));
434 g_home_dir
= g_strconcat (homedrive
, homepath
, NULL
);
439 #endif /* !NATIVE_WIN32 */
443 struct passwd
*pw
= NULL
;
444 gpointer buffer
= NULL
;
446 # ifdef HAVE_GETPWUID_R
454 buffer
= g_malloc (bufsize
);
457 # ifdef HAVE_GETPWUID_R_POSIX
458 error
= getpwuid_r (getuid (), &pwd
, buffer
, bufsize
, &pw
);
459 error
= error
< 0 ? errno
: error
;
460 # else /* !HAVE_GETPWUID_R_POSIX */
461 pw
= getpwuid_r (getuid (), &pwd
, buffer
, bufsize
);
462 error
= pw
? 0 : errno
;
463 # endif /* !HAVE_GETPWUID_R_POSIX */
465 /* Now there are actually only 3 cases to leave the loop:
466 1. pw != NULL -> all went fine.
467 2. pw == NULL && ( error == 0 || error == ENOENT )
468 -> no such user (unlikely in the case of getuid ())
469 3. bufsize > 32k -> the problem can't be of ERANGE type */
473 if (pw
== NULL
&& ( error
== 0 || error
== ENOENT
))
475 g_warning ("getpwuid_r(): failed due to: No such user %d.",
480 if (bufsize
> 32 * 1024)
482 g_warning ("getpwuid_r(): failed due to: %s.",
489 # endif /* !HAVE_GETPWUID_R */
494 pw
= getpwuid (getuid ());
499 g_user_name
= g_strdup (pw
->pw_name
);
500 g_real_name
= g_strdup (pw
->pw_gecos
);
502 g_home_dir
= g_strdup (pw
->pw_dir
);
507 #else /* !HAVE_PWD_H */
514 if (GetUserName (buffer
, &len
))
516 g_user_name
= g_strdup (buffer
);
517 g_real_name
= g_strdup (buffer
);
520 # endif /* NATIVE_WIN32 */
522 #endif /* !HAVE_PWD_H */
525 g_user_name
= g_strdup ("somebody");
527 g_real_name
= g_strdup ("Unknown");
532 g_get_user_name (void)
534 G_LOCK (g_utils_global
);
537 G_UNLOCK (g_utils_global
);
543 g_get_real_name (void)
545 G_LOCK (g_utils_global
);
548 G_UNLOCK (g_utils_global
);
553 /* Return the home directory of the user. If there is a HOME
554 * environment variable, its value is returned, otherwise use some
555 * system-dependent way of finding it out. If no home directory can be
556 * deduced, return NULL.
560 g_get_home_dir (void)
562 G_LOCK (g_utils_global
);
565 G_UNLOCK (g_utils_global
);
570 /* Return a directory to be used to store temporary files. This is the
571 * value of the TMPDIR, TMP or TEMP environment variables (they are
572 * checked in that order). If none of those exist, use P_tmpdir from
573 * stdio.h. If that isn't defined, return "/tmp" on POSIXly systems,
574 * and C:\ on Windows.
580 G_LOCK (g_utils_global
);
583 G_UNLOCK (g_utils_global
);
588 static gchar
*g_prgname
= NULL
;
595 G_LOCK (g_utils_global
);
597 G_UNLOCK (g_utils_global
);
603 g_set_prgname (const gchar
*prgname
)
607 G_LOCK (g_utils_global
);
609 g_prgname
= g_strdup (prgname
);
611 G_UNLOCK (g_utils_global
);
615 g_direct_hash (gconstpointer v
)
617 return GPOINTER_TO_UINT (v
);
621 g_direct_equal (gconstpointer v1
,
624 return GPOINTER_TO_UINT (v1
) == GPOINTER_TO_UINT (v2
);
628 g_int_equal (gconstpointer v1
,
631 return *((const gint
*) v1
) == *((const gint
*) v2
);
635 g_int_hash (gconstpointer v
)
637 return *(const gint
*) v
;
640 #if 0 /* Old IO Channels */
643 g_iochannel_new (gint fd
)
645 GIOChannel
*channel
= g_new (GIOChannel
, 1);
651 channel
->peer_fd
= 0;
653 channel
->need_wakeups
= 0;
654 #endif /* NATIVE_WIN32 */
660 g_iochannel_free (GIOChannel
*channel
)
662 g_return_if_fail (channel
!= NULL
);
668 g_iochannel_close_and_free (GIOChannel
*channel
)
670 g_return_if_fail (channel
!= NULL
);
674 g_iochannel_free (channel
);
677 #undef g_iochannel_wakeup_peer
680 g_iochannel_wakeup_peer (GIOChannel
*channel
)
683 static guint message
= 0;
686 g_return_if_fail (channel
!= NULL
);
690 message
= RegisterWindowMessage ("gdk-pipe-readable");
693 g_print ("g_iochannel_wakeup_peer: calling PostThreadMessage (%#x, %d, %d, %d)\n",
694 channel
->peer
, message
, channel
->peer_fd
, channel
->offset
);
696 PostThreadMessage (channel
->peer
, message
,
697 channel
->peer_fd
, channel
->offset
);
698 #endif /* NATIVE_WIN32 */
701 #endif /* Old IO Channels */
707 gwin_ftruncate (gint fd
,
713 g_return_val_if_fail (fd
>= 0, -1);
715 hfile
= (HANDLE
) _get_osfhandle (fd
);
716 curpos
= SetFilePointer (hfile
, 0, NULL
, FILE_CURRENT
);
717 if (curpos
== 0xFFFFFFFF
718 || SetFilePointer (hfile
, size
, NULL
, FILE_BEGIN
) == 0xFFFFFFFF
719 || !SetEndOfFile (hfile
))
721 gint error
= GetLastError ();
725 case ERROR_INVALID_HANDLE
:
740 gwin_opendir (const char *dirname
)
746 g_return_val_if_fail (dirname
!= NULL
, NULL
);
748 result
= g_new0 (DIR, 1);
749 result
->find_file_data
= g_new0 (WIN32_FIND_DATA
, 1);
750 result
->dir_name
= g_strdup (dirname
);
752 k
= strlen (result
->dir_name
);
753 if (k
&& result
->dir_name
[k
- 1] == '\\')
755 result
->dir_name
[k
- 1] = '\0';
758 mask
= g_strdup_printf ("%s\\*", result
->dir_name
);
760 result
->find_file_handle
= (guint
) FindFirstFile (mask
,
761 (LPWIN32_FIND_DATA
) result
->find_file_data
);
764 if (result
->find_file_handle
== (guint
) INVALID_HANDLE_VALUE
)
766 int error
= GetLastError ();
768 g_free (result
->dir_name
);
769 g_free (result
->find_file_data
);
778 result
->just_opened
= TRUE
;
784 gwin_readdir (DIR *dir
)
786 static struct dirent result
;
788 g_return_val_if_fail (dir
!= NULL
, NULL
);
790 if (dir
->just_opened
)
791 dir
->just_opened
= FALSE
;
794 if (!FindNextFile ((HANDLE
) dir
->find_file_handle
,
795 (LPWIN32_FIND_DATA
) dir
->find_file_data
))
797 int error
= GetLastError ();
801 case ERROR_NO_MORE_FILES
:
809 strcpy (result
.d_name
, g_basename (((LPWIN32_FIND_DATA
) dir
->find_file_data
)->cFileName
));
815 gwin_rewinddir (DIR *dir
)
819 g_return_if_fail (dir
!= NULL
);
821 if (!FindClose ((HANDLE
) dir
->find_file_handle
))
822 g_warning ("gwin_rewinddir(): FindClose() failed\n");
824 mask
= g_strdup_printf ("%s\\*", dir
->dir_name
);
825 dir
->find_file_handle
= (guint
) FindFirstFile (mask
,
826 (LPWIN32_FIND_DATA
) dir
->find_file_data
);
829 if (dir
->find_file_handle
== (guint
) INVALID_HANDLE_VALUE
)
831 int error
= GetLastError ();
840 dir
->just_opened
= TRUE
;
844 gwin_closedir (DIR *dir
)
846 g_return_val_if_fail (dir
!= NULL
, -1);
848 if (!FindClose ((HANDLE
) dir
->find_file_handle
))
850 int error
= GetLastError ();
855 errno
= EIO
; return -1;
859 g_free (dir
->dir_name
);
860 g_free (dir
->find_file_data
);
866 #endif /* _MSC_VER */
868 #endif /* NATIVE_WIN32 */