applied glib-tml-981120-0, change log appended below.
[platform/upstream/glib.git] / gutils.c
index 8528163..bc4c452 100644 (file)
--- a/gutils.c
+++ b/gutils.c
@@ -1,5 +1,5 @@
 /* GLIB - Library of useful routines for C programming
- * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 1995-1998  Peter Mattis, Spencer Kimball and Josh MacDonald
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glibconfig.h"
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 #include <stdarg.h>
-#include <stdio.h>
 #include <stdlib.h>
+#include <stdio.h>
 #include <string.h>
-#include <locale.h>
-#include <ctype.h>             /* For tolower() */
+#include <errno.h>
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef NATIVE_WIN32
+#  define STRICT                       /* Strict typing, please */
+#  include <windows.h>
+#  include <direct.h>
+#  include <errno.h>
+#  include <ctype.h>
+#  ifdef _MSC_VER
+#    include <io.h>
+#  endif /* _MSC_VER */
+#endif /* NATIVE_WIN32 */
+
+/* implement Glib's inline functions
+ */
+#define        G_INLINE_FUNC extern
+#define        G_CAN_INLINE 1
 #include "glib.h"
 
+#ifdef MAXPATHLEN
+#define        G_PATH_LENGTH   (MAXPATHLEN + 1)
+#elif  defined (PATH_MAX)
+#define        G_PATH_LENGTH   (PATH_MAX + 1)
+#else  /* !MAXPATHLEN */
+#define G_PATH_LENGTH   (2048 + 1)
+#endif /* !MAXPATHLEN && !PATH_MAX */
+
 const guint glib_major_version = GLIB_MAJOR_VERSION;
 const guint glib_minor_version = GLIB_MINOR_VERSION;
 const guint glib_micro_version = GLIB_MICRO_VERSION;
+const guint glib_interface_age = GLIB_INTERFACE_AGE;
+const guint glib_binary_age = GLIB_BINARY_AGE;
+
+#if defined (NATIVE_WIN32) && defined (__LCC__)
+int __stdcall 
+LibMain (void         *hinstDll,
+        unsigned long dwReason,
+        void         *reserved)
+{
+  return 1;
+}
+#endif /* NATIVE_WIN32 && __LCC__ */
 
-extern char* g_vsprintf (const gchar *fmt, va_list *args, va_list *args2);
+void
+g_atexit (GVoidFunc func)
+{
+  gint result;
+  gchar *error = NULL;
+
+  /* keep this in sync with glib.h */
+
+#ifdef G_NATIVE_ATEXIT
+  result = ATEXIT (func);
+  if (result)
+    error = g_strerror (errno);
+#elif defined (HAVE_ATEXIT)
+#  ifdef NeXT /* @#%@! NeXTStep */
+  result = !atexit ((void (*)(void)) func);
+  if (result)
+    error = g_strerror (errno);
+#  else
+  result = atexit ((void (*)(void)) func);
+  if (result)
+    error = g_strerror (errno);
+#  endif /* NeXT */
+#elif defined (HAVE_ON_EXIT)
+  result = on_exit ((void (*)(int, void *)) func, NULL);
+  if (result)
+    error = g_strerror (errno);
+#else
+  result = 0;
+  error = "no implementation";
+#endif /* G_NATIVE_ATEXIT */
 
-gchar*
-g_strdup (const gchar *str)
+  if (error)
+    g_error ("Could not register atexit() function: %s", error);
+}
+
+gint
+g_snprintf (gchar      *str,
+           gulong       n,
+           gchar const *fmt,
+           ...)
 {
-  gchar *new_str;
+#ifdef HAVE_VSNPRINTF
+  va_list args;
+  gint retval;
   
-  new_str = NULL;
-  if (str)
-    {
-      new_str = g_new (char, strlen (str) + 1);
-      strcpy (new_str, str);
-    }
+  va_start (args, fmt);
+  retval = vsnprintf (str, n, fmt, args);
+  va_end (args);
+  
+  return retval;
+#else  /* !HAVE_VSNPRINTF */
+  gchar *printed;
+  va_list args;
+  
+  va_start (args, fmt);
+  printed = g_strdup_vprintf (fmt, args);
+  va_end (args);
   
-  return new_str;
+  strncpy (str, printed, n);
+  str[n-1] = '\0';
+
+  g_free (printed);
+  
+  return strlen (str);
+#endif /* !HAVE_VSNPRINTF */
 }
 
-gchar*
-g_strconcat (const gchar *string1, ...)
+gint
+g_vsnprintf (gchar      *str,
+            gulong       n,
+            gchar const *fmt,
+            va_list      args)
 {
-  guint          l;
-  va_list args;
-  gchar          *s;
-  gchar          *concat;
+#ifdef HAVE_VSNPRINTF
+  gint retval;
   
-  g_return_val_if_fail (string1 != NULL, NULL);
+  retval = vsnprintf (str, n, fmt, args);
   
-  l = 1 + strlen (string1);
-  va_start (args, string1);
-  s = va_arg (args, gchar*);
-  while (s)
-    {
-      l += strlen (s);
-      s = va_arg (args, gchar*);
-    }
-  va_end (args);
+  return retval;
+#else  /* !HAVE_VSNPRINTF */
+  gchar *printed;
+  
+  printed = g_strdup_vprintf (fmt, args);
+  strncpy (str, printed, n);
+  str[n-1] = '\0';
+
+  g_free (printed);
+  
+  return strlen (str);
+#endif /* !HAVE_VSNPRINTF */
+}
+
+guint       
+g_parse_debug_string  (const gchar *string, 
+                      GDebugKey   *keys, 
+                      guint        nkeys)
+{
+  guint i;
+  guint result = 0;
   
-  concat = g_new (gchar, l);
-  concat[0] = 0;
+  g_return_val_if_fail (string != NULL, 0);
   
-  strcat (concat, string1);
-  va_start (args, string1);
-  s = va_arg (args, gchar*);
-  while (s)
+  if (!g_strcasecmp (string, "all"))
     {
-      strcat (concat, s);
-      s = va_arg (args, gchar*);
+      for (i=0; i<nkeys; i++)
+       result |= keys[i].value;
+    }
+  else
+    {
+      gchar *str = g_strdup (string);
+      gchar *p = str;
+      gchar *q;
+      gboolean done = FALSE;
+      
+      while (*p && !done)
+       {
+         q = strchr (p, ':');
+         if (!q)
+           {
+             q = p + strlen(p);
+             done = TRUE;
+           }
+         
+         *q = 0;
+         
+         for (i=0; i<nkeys; i++)
+           if (!g_strcasecmp(keys[i].key, p))
+             result |= keys[i].value;
+         
+         p = q+1;
+       }
+      
+      g_free (str);
     }
-  va_end (args);
   
-  return concat;
+  return result;
 }
 
-gdouble
-g_strtod (const gchar *nptr,
-         gchar **endptr)
+gchar*
+g_basename (const gchar           *file_name)
 {
-  gchar *fail_pos_1;
-  gchar *fail_pos_2;
-  gdouble val_1;
-  gdouble val_2 = 0;
+  register gchar *base;
+  
+  g_return_val_if_fail (file_name != NULL, NULL);
+  
+  base = strrchr (file_name, G_DIR_SEPARATOR);
+  if (base)
+    return base + 1;
+
+#ifdef NATIVE_WIN32
+  if (isalpha (file_name[0]) && file_name[1] == ':')
+    return (gchar*) file_name + 2;
+#endif /* NATIVE_WIN32 */
+  
+  return (gchar*) file_name;
+}
 
-  g_return_val_if_fail (nptr != NULL, 0);
+gboolean
+g_path_is_absolute (const gchar *file_name)
+{
+  g_return_val_if_fail (file_name != NULL, FALSE);
+  
+  if (file_name[0] == G_DIR_SEPARATOR)
+    return TRUE;
 
-  fail_pos_1 = NULL;
-  fail_pos_2 = NULL;
+#ifdef NATIVE_WIN32
+  if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
+    return TRUE;
+#endif
 
-  val_1 = strtod (nptr, &fail_pos_1);
+  return FALSE;
+}
 
-  if (fail_pos_1 && fail_pos_1[0] != 0)
-    {
-      gchar *old_locale;
+gchar*
+g_path_skip_root (gchar *file_name)
+{
+  g_return_val_if_fail (file_name != NULL, NULL);
+  
+  if (file_name[0] == G_DIR_SEPARATOR)
+    return file_name + 1;
 
-      old_locale = setlocale (LC_NUMERIC, "C");
-      val_2 = strtod (nptr, &fail_pos_2);
-      setlocale (LC_NUMERIC, old_locale);
-    }
+#ifdef NATIVE_WIN32
+  if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
+    return file_name + 3;
+#endif
 
-  if (!fail_pos_1 || fail_pos_1[0] == 0 || fail_pos_1 >= fail_pos_2)
-    {
-      if (endptr)
-       *endptr = fail_pos_1;
-      return val_1;
-    }
-  else
-    {
-      if (endptr)
-       *endptr = fail_pos_2;
-      return val_2;
-    }
+  return NULL;
 }
 
 gchar*
-g_strerror (gint errnum)
+g_dirname (const gchar    *file_name)
 {
-  static char msg[64];
+  register gchar *base;
+  register guint len;
+  
+  g_return_val_if_fail (file_name != NULL, NULL);
   
-#ifdef HAVE_STRERROR
-  return strerror (errnum);
-#elif NO_SYS_ERRLIST
-  switch (errnum)
+  base = strrchr (file_name, G_DIR_SEPARATOR);
+  if (!base)
+    return g_strdup (".");
+  while (base > file_name && *base == G_DIR_SEPARATOR)
+    base--;
+  len = (guint) 1 + base - file_name;
+  
+  base = g_new (gchar, len + 1);
+  g_memmove (base, file_name, len);
+  base[len] = 0;
+  
+  return base;
+}
+
+gchar*
+g_get_current_dir (void)
+{
+  gchar *buffer;
+  gchar *dir;
+
+  buffer = g_new (gchar, G_PATH_LENGTH);
+  *buffer = 0;
+  
+  /* We don't use getcwd(3) on SUNOS, because, it does a popen("pwd")
+   * and, if that wasn't bad enough, hangs in doing so.
+   */
+#if    defined (sun) && !defined (__SVR4)
+  dir = getwd (buffer);
+#else  /* !sun */
+  dir = getcwd (buffer, G_PATH_LENGTH - 1);
+#endif /* !sun */
+  
+  if (!dir || !*buffer)
     {
-#ifdef E2BIG
-    case E2BIG: return "argument list too long";
-#endif
-#ifdef EACCES
-    case EACCES: return "permission denied";
-#endif
-#ifdef EADDRINUSE
-    case EADDRINUSE: return "address already in use";
-#endif
-#ifdef EADDRNOTAVAIL
-    case EADDRNOTAVAIL: return "can't assign requested address";
-#endif
-#ifdef EADV
-    case EADV: return "advertise error";
-#endif
-#ifdef EAFNOSUPPORT
-    case EAFNOSUPPORT: return "address family not supported by protocol family";
-#endif
-#ifdef EAGAIN
-    case EAGAIN: return "try again";
-#endif
-#ifdef EALIGN
-    case EALIGN: return "EALIGN";
-#endif
-#ifdef EALREADY
-    case EALREADY: return "operation already in progress";
-#endif
-#ifdef EBADE
-    case EBADE: return "bad exchange descriptor";
-#endif
-#ifdef EBADF
-    case EBADF: return "bad file number";
-#endif
-#ifdef EBADFD
-    case EBADFD: return "file descriptor in bad state";
-#endif
-#ifdef EBADMSG
-    case EBADMSG: return "not a data message";
-#endif
-#ifdef EBADR
-    case EBADR: return "bad request descriptor";
-#endif
-#ifdef EBADRPC
-    case EBADRPC: return "RPC structure is bad";
-#endif
-#ifdef EBADRQC
-    case EBADRQC: return "bad request code";
-#endif
-#ifdef EBADSLT
-    case EBADSLT: return "invalid slot";
-#endif
-#ifdef EBFONT
-    case EBFONT: return "bad font file format";
-#endif
-#ifdef EBUSY
-    case EBUSY: return "mount device busy";
-#endif
-#ifdef ECHILD
-    case ECHILD: return "no children";
-#endif
-#ifdef ECHRNG
-    case ECHRNG: return "channel number out of range";
-#endif
-#ifdef ECOMM
-    case ECOMM: return "communication error on send";
-#endif
-#ifdef ECONNABORTED
-    case ECONNABORTED: return "software caused connection abort";
-#endif
-#ifdef ECONNREFUSED
-    case ECONNREFUSED: return "connection refused";
-#endif
-#ifdef ECONNRESET
-    case ECONNRESET: return "connection reset by peer";
-#endif
-#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK))
-    case EDEADLK: return "resource deadlock avoided";
-#endif
-#ifdef EDEADLOCK
-    case EDEADLOCK: return "resource deadlock avoided";
-#endif
-#ifdef EDESTADDRREQ
-    case EDESTADDRREQ: return "destination address required";
-#endif
-#ifdef EDIRTY
-    case EDIRTY: return "mounting a dirty fs w/o force";
-#endif
-#ifdef EDOM
-    case EDOM: return "math argument out of range";
-#endif
-#ifdef EDOTDOT
-    case EDOTDOT: return "cross mount point";
-#endif
-#ifdef EDQUOT
-    case EDQUOT: return "disk quota exceeded";
-#endif
-#ifdef EDUPPKG
-    case EDUPPKG: return "duplicate package name";
-#endif
-#ifdef EEXIST
-    case EEXIST: return "file already exists";
-#endif
-#ifdef EFAULT
-    case EFAULT: return "bad address in system call argument";
-#endif
-#ifdef EFBIG
-    case EFBIG: return "file too large";
-#endif
-#ifdef EHOSTDOWN
-    case EHOSTDOWN: return "host is down";
-#endif
-#ifdef EHOSTUNREACH
-    case EHOSTUNREACH: return "host is unreachable";
-#endif
-#ifdef EIDRM
-    case EIDRM: return "identifier removed";
-#endif
-#ifdef EINIT
-    case EINIT: return "initialization error";
-#endif
-#ifdef EINPROGRESS
-    case EINPROGRESS: return "operation now in progress";
-#endif
-#ifdef EINTR
-    case EINTR: return "interrupted system call";
-#endif
-#ifdef EINVAL
-    case EINVAL: return "invalid argument";
-#endif
-#ifdef EIO
-    case EIO: return "I/O error";
-#endif
-#ifdef EISCONN
-    case EISCONN: return "socket is already connected";
-#endif
-#ifdef EISDIR
-    case EISDIR: return "illegal operation on a directory";
-#endif
-#ifdef EISNAME
-    case EISNAM: return "is a name file";
-#endif
-#ifdef ELBIN
-    case ELBIN: return "ELBIN";
-#endif
-#ifdef EL2HLT
-    case EL2HLT: return "level 2 halted";
-#endif
-#ifdef EL2NSYNC
-    case EL2NSYNC: return "level 2 not synchronized";
-#endif
-#ifdef EL3HLT
-    case EL3HLT: return "level 3 halted";
-#endif
-#ifdef EL3RST
-    case EL3RST: return "level 3 reset";
-#endif
-#ifdef ELIBACC
-    case ELIBACC: return "can not access a needed shared library";
-#endif
-#ifdef ELIBBAD
-    case ELIBBAD: return "accessing a corrupted shared library";
-#endif
-#ifdef ELIBEXEC
-    case ELIBEXEC: return "can not exec a shared library directly";
-#endif
-#ifdef ELIBMAX
-    case ELIBMAX: return "attempting to link in more shared libraries than system limit";
-#endif
-#ifdef ELIBSCN
-    case ELIBSCN: return ".lib section in a.out corrupted";
-#endif
-#ifdef ELNRNG
-    case ELNRNG: return "link number out of range";
-#endif
-#ifdef ELOOP
-    case ELOOP: return "too many levels of symbolic links";
-#endif
-#ifdef EMFILE
-    case EMFILE: return "too many open files";
-#endif
-#ifdef EMLINK
-    case EMLINK: return "too many links";
-#endif
-#ifdef EMSGSIZE
-    case EMSGSIZE: return "message too long";
-#endif
-#ifdef EMULTIHOP
-    case EMULTIHOP: return "multihop attempted";
-#endif
-#ifdef ENAMETOOLONG
-    case ENAMETOOLONG: return "file name too long";
-#endif
-#ifdef ENAVAIL
-    case ENAVAIL: return "not available";
-#endif
-#ifdef ENET
-    case ENET: return "ENET";
-#endif
-#ifdef ENETDOWN
-    case ENETDOWN: return "network is down";
-#endif
-#ifdef ENETRESET
-    case ENETRESET: return "network dropped connection on reset";
-#endif
-#ifdef ENETUNREACH
-    case ENETUNREACH: return "network is unreachable";
-#endif
-#ifdef ENFILE
-    case ENFILE: return "file table overflow";
-#endif
-#ifdef ENOANO
-    case ENOANO: return "anode table overflow";
-#endif
-#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR))
-    case ENOBUFS: return "no buffer space available";
-#endif
-#ifdef ENOCSI
-    case ENOCSI: return "no CSI structure available";
-#endif
-#ifdef ENODATA
-    case ENODATA: return "no data available";
-#endif
-#ifdef ENODEV
-    case ENODEV: return "no such device";
-#endif
-#ifdef ENOENT
-    case ENOENT: return "no such file or directory";
-#endif
-#ifdef ENOEXEC
-    case ENOEXEC: return "exec format error";
-#endif
-#ifdef ENOLCK
-    case ENOLCK: return "no locks available";
-#endif
-#ifdef ENOLINK
-    case ENOLINK: return "link has be severed";
-#endif
-#ifdef ENOMEM
-    case ENOMEM: return "not enough memory";
-#endif
-#ifdef ENOMSG
-    case ENOMSG: return "no message of desired type";
-#endif
-#ifdef ENONET
-    case ENONET: return "machine is not on the network";
-#endif
-#ifdef ENOPKG
-    case ENOPKG: return "package not installed";
-#endif
-#ifdef ENOPROTOOPT
-    case ENOPROTOOPT: return "bad proocol option";
-#endif
-#ifdef ENOSPC
-    case ENOSPC: return "no space left on device";
-#endif
-#ifdef ENOSR
-    case ENOSR: return "out of stream resources";
-#endif
-#ifdef ENOSTR
-    case ENOSTR: return "not a stream device";
-#endif
-#ifdef ENOSYM
-    case ENOSYM: return "unresolved symbol name";
-#endif
-#ifdef ENOSYS
-    case ENOSYS: return "function not implemented";
-#endif
-#ifdef ENOTBLK
-    case ENOTBLK: return "block device required";
-#endif
-#ifdef ENOTCONN
-    case ENOTCONN: return "socket is not connected";
-#endif
-#ifdef ENOTDIR
-    case ENOTDIR: return "not a directory";
-#endif
-#ifdef ENOTEMPTY
-    case ENOTEMPTY: return "directory not empty";
-#endif
-#ifdef ENOTNAM
-    case ENOTNAM: return "not a name file";
-#endif
-#ifdef ENOTSOCK
-    case ENOTSOCK: return "socket operation on non-socket";
-#endif
-#ifdef ENOTTY
-    case ENOTTY: return "inappropriate device for ioctl";
-#endif
-#ifdef ENOTUNIQ
-    case ENOTUNIQ: return "name not unique on network";
-#endif
-#ifdef ENXIO
-    case ENXIO: return "no such device or address";
-#endif
-#ifdef EOPNOTSUPP
-    case EOPNOTSUPP: return "operation not supported on socket";
-#endif
-#ifdef EPERM
-    case EPERM: return "not owner";
-#endif
-#ifdef EPFNOSUPPORT
-    case EPFNOSUPPORT: return "protocol family not supported";
-#endif
-#ifdef EPIPE
-    case EPIPE: return "broken pipe";
-#endif
-#ifdef EPROCLIM
-    case EPROCLIM: return "too many processes";
-#endif
-#ifdef EPROCUNAVAIL
-    case EPROCUNAVAIL: return "bad procedure for program";
-#endif
-#ifdef EPROGMISMATCH
-    case EPROGMISMATCH: return "program version wrong";
-#endif
-#ifdef EPROGUNAVAIL
-    case EPROGUNAVAIL: return "RPC program not available";
-#endif
-#ifdef EPROTO
-    case EPROTO: return "protocol error";
-#endif
-#ifdef EPROTONOSUPPORT
-    case EPROTONOSUPPORT: return "protocol not suppored";
-#endif
-#ifdef EPROTOTYPE
-    case EPROTOTYPE: return "protocol wrong type for socket";
-#endif
-#ifdef ERANGE
-    case ERANGE: return "math result unrepresentable";
-#endif
-#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED))
-    case EREFUSED: return "EREFUSED";
-#endif
-#ifdef EREMCHG
-    case EREMCHG: return "remote address changed";
-#endif
-#ifdef EREMDEV
-    case EREMDEV: return "remote device";
-#endif
-#ifdef EREMOTE
-    case EREMOTE: return "pathname hit remote file system";
-#endif
-#ifdef EREMOTEIO
-    case EREMOTEIO: return "remote i/o error";
-#endif
-#ifdef EREMOTERELEASE
-    case EREMOTERELEASE: return "EREMOTERELEASE";
-#endif
-#ifdef EROFS
-    case EROFS: return "read-only file system";
-#endif
-#ifdef ERPCMISMATCH
-    case ERPCMISMATCH: return "RPC version is wrong";
-#endif
-#ifdef ERREMOTE
-    case ERREMOTE: return "object is remote";
-#endif
-#ifdef ESHUTDOWN
-    case ESHUTDOWN: return "can't send afer socket shutdown";
-#endif
-#ifdef ESOCKTNOSUPPORT
-    case ESOCKTNOSUPPORT: return "socket type not supported";
-#endif
-#ifdef ESPIPE
-    case ESPIPE: return "invalid seek";
-#endif
-#ifdef ESRCH
-    case ESRCH: return "no such process";
-#endif
-#ifdef ESRMNT
-    case ESRMNT: return "srmount error";
-#endif
-#ifdef ESTALE
-    case ESTALE: return "stale remote file handle";
-#endif
-#ifdef ESUCCESS
-    case ESUCCESS: return "Error 0";
-#endif
-#ifdef ETIME
-    case ETIME: return "timer expired";
-#endif
-#ifdef ETIMEDOUT
-    case ETIMEDOUT: return "connection timed out";
-#endif
-#ifdef ETOOMANYREFS
-    case ETOOMANYREFS: return "too many references: can't splice";
-#endif
-#ifdef ETXTBSY
-    case ETXTBSY: return "text file or pseudo-device busy";
-#endif
-#ifdef EUCLEAN
-    case EUCLEAN: return "structure needs cleaning";
-#endif
-#ifdef EUNATCH
-    case EUNATCH: return "protocol driver not attached";
-#endif
-#ifdef EUSERS
-    case EUSERS: return "too many users";
-#endif
-#ifdef EVERSION
-    case EVERSION: return "version mismatch";
-#endif
-#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
-    case EWOULDBLOCK: return "operation would block";
-#endif
-#ifdef EXDEV
-    case EXDEV: return "cross-domain link";
-#endif
-#ifdef EXFULL
-    case EXFULL: return "message tables full";
-#endif
+      /* hm, should we g_error() out here?
+       * this can happen if e.g. "./" has mode \0000
+       */
+      buffer[0] = G_DIR_SEPARATOR;
+      buffer[1] = 0;
     }
-#else /* NO_SYS_ERRLIST */
-  extern int sys_nerr;
-  extern char *sys_errlist[];
-
-  if ((errnum > 0) && (errnum <= sys_nerr))
-    return sys_errlist [errnum];
-#endif /* NO_SYS_ERRLIST */
 
-  sprintf (msg, "unknown error (%d)", errnum);
-  return msg;
+  dir = g_strdup (buffer);
+  g_free (buffer);
+  
+  return dir;
 }
 
 gchar*
-g_strsignal (gint signum)
+g_getenv (const gchar *variable)
 {
-  static char msg[64];
+#ifndef NATIVE_WIN32
+  g_return_val_if_fail (variable != NULL, NULL);
+
+  return getenv (variable);
+#else
+  gchar *v;
+  guint k;
+  static gchar *p = NULL;
+  static gint l;
+  gchar dummy[2];
 
-#ifdef HAVE_STRSIGNAL
-  extern char *strsignal (int sig);
-  return strsignal (signum);
-#elif NO_SYS_SIGLIST
-  switch (signum)
+  g_return_val_if_fail (variable != NULL, NULL);
+  
+  v = getenv (variable);
+  if (!v)
+    return NULL;
+  
+  /* On Windows NT, it is relatively typical that environment variables
+   * contain references to other environment variables. Handle that by
+   * calling ExpandEnvironmentStrings.
+   */
+
+  /* First check how much space we need */
+  k = ExpandEnvironmentStrings (v, dummy, 2);
+  /* Then allocate that much, and actualy do the expansion */
+  if (p == NULL)
     {
-#ifdef SIGHUP
-    case SIGHUP: return "Hangup";
-#endif
-#ifdef SIGINT
-    case SIGINT: return "Interrupt";
-#endif
-#ifdef SIGQUIT
-    case SIGQUIT: return "Quit";
-#endif
-#ifdef SIGILL
-    case SIGILL: return "Illegal instruction";
-#endif
-#ifdef SIGTRAP
-    case SIGTRAP: return "Trace/breakpoint trap";
-#endif
-#ifdef SIGABRT
-    case SIGABRT: return "IOT trap/Abort";
-#endif
-#ifdef SIGBUS
-    case SIGBUS: return "Bus error";
-#endif
-#ifdef SIGFPE
-    case SIGFPE: return "Floating point exception";
-#endif
-#ifdef SIGKILL
-    case SIGKILL: return "Killed";
-#endif
-#ifdef SIGUSR1
-    case SIGUSR1: return "User defined signal 1";
-#endif
-#ifdef SIGSEGV
-    case SIGSEGV: return "Segmentation fault";
-#endif
-#ifdef SIGUSR2
-    case SIGUSR2: return "User defined signal 2";
-#endif
-#ifdef SIGPIPE
-    case SIGPIPE: return "Broken pipe";
-#endif
-#ifdef SIGALRM
-    case SIGALRM: return "Alarm clock";
-#endif
-#ifdef SIGTERM
-    case SIGTERM: return "Terminated";
-#endif
-#ifdef SIGSTKFLT
-    case SIGSTKFLT: return "Stack fault";
-#endif
-#ifdef SIGCHLD
-    case SIGCHLD: return "Child exited";
-#endif
-#ifdef SIGCONT
-    case SIGCONT: return "Continued";
-#endif
-#ifdef SIGSTOP
-    case SIGSTOP: return "Stopped (signal)";
-#endif
-#ifdef SIGTSTP
-    case SIGTSTP: return "Stopped";
-#endif
-#ifdef SIGTTIN
-    case SIGTTIN: return "Stopped (tty input)";
-#endif
-#ifdef SIGTTOU
-    case SIGTTOU: return "Stopped (tty output)";
-#endif
-#ifdef SIGURG
-    case SIGURG: return "Urgent condition";
-#endif
-#ifdef SIGXCPU
-    case SIGXCPU: return "CPU time limit exceeded";
-#endif
-#ifdef SIGXFSZ
-    case SIGXFSZ: return "File size limit exceeded";
-#endif
-#ifdef SIGVTALRM
-    case SIGVTALRM: return "Virtual time alarm";
-#endif
-#ifdef SIGPROF
-    case SIGPROF: return "Profile signal";
-#endif
-#ifdef SIGWINCH
-    case SIGWINCH: return "Window size changed";
-#endif
-#ifdef SIGIO
-    case SIGIO: return "Possible I/O";
+      p = g_malloc (k);
+      l = k;
+    }
+  else if (k > l)
+    {
+      p = g_realloc (p, k);
+      l = k;
+    }
+  ExpandEnvironmentStrings (v, p, k);
+  return p;
 #endif
-#ifdef SIGPWR
-    case SIGPWR: return "Power failure";
+}
+
+static gchar   *g_tmp_dir = NULL;
+static gchar   *g_user_name = NULL;
+static gchar   *g_real_name = NULL;
+static gchar   *g_home_dir = NULL;
+
+static void
+g_get_any_init (void)
+{
+  if (!g_tmp_dir)
+    {
+#ifdef HAVE_PWD_H
+      struct passwd *pw;
 #endif
-#ifdef SIGUNUSED
-    case SIGUNUSED: return "Unused signal";
+
+      g_tmp_dir = g_strdup (g_getenv ("TMPDIR"));
+      if (!g_tmp_dir)
+       g_tmp_dir = g_strdup (g_getenv ("TMP"));
+      if (!g_tmp_dir)
+       g_tmp_dir = g_strdup (g_getenv ("TEMP"));
+      
+#ifdef P_tmpdir
+      if (!g_tmp_dir)
+       {
+         int k;
+         g_tmp_dir = g_strdup (P_tmpdir);
+         k = strlen (g_tmp_dir);
+         if (g_tmp_dir[k-1] == G_DIR_SEPARATOR)
+           g_tmp_dir[k-1] = '\0';
+       }
 #endif
+      if (!g_tmp_dir)
+       {
+#ifndef NATIVE_WIN32
+         g_tmp_dir = g_strdup ("/tmp");
+#else /* NATIVE_WIN32 */
+         g_tmp_dir = g_strdup ("C:\\");
+#endif /* NATIVE_WIN32 */
+       }
+      
+      g_home_dir = g_strdup (g_getenv ("HOME"));
+      
+#ifdef HAVE_PWD_H
+      setpwent ();
+      pw = getpwuid (getuid ());
+      endpwent ();
+      
+      if (pw)
+       {
+         g_user_name = g_strdup (pw->pw_name);
+         g_real_name = g_strdup (pw->pw_gecos);
+         if (!g_home_dir)
+           g_home_dir = g_strdup (pw->pw_dir);
+       }
+#else /* !HAVE_PWD_H */
+#  ifdef NATIVE_WIN32
+      {
+       guint len = 17;
+       
+       g_user_name = g_new (gchar, len);
+       
+       if (!GetUserName (g_user_name, &len))
+         {
+           g_free (g_user_name);
+           g_user_name = g_strdup ("somebody");
+           g_real_name = g_strdup ("Unknown");
+         }
+       else
+         g_real_name = g_strdup (g_user_name);
+      }
+#  else /* !NATIVE_WIN32 */
+      g_user_name = g_strdup ("somebody");
+      g_real_name = g_strdup ("Unknown");
+      g_home_dir = NULL;
+#  endif /* !NATIVE_WIN32 */
+#endif /* !HAVE_PWD_H */
     }
-#else /* NO_SYS_SIGLIST */
-  extern char *sys_siglist[];
-  return sys_siglist [signum];
-#endif /* NO_SYS_SIGLIST */
-
-  sprintf (msg, "unknown signal (%d)", signum);
-  return msg;
 }
 
-gint
-g_snprintf (gchar       *str,
-           gulong       n,
-           gchar const *fmt,
-           ...)
+gchar*
+g_get_user_name (void)
 {
-#ifdef HAVE_VSNPRINTF
-  va_list args;
-  gint retval;
+  if (!g_tmp_dir)
+    g_get_any_init ();
   
-  va_start (args, fmt);
-  retval = vsnprintf (str, n, fmt, args);
-  va_end (args);
+  return g_user_name;
+}
 
-  return retval;
+gchar*
+g_get_real_name (void)
+{
+  if (!g_tmp_dir)
+    g_get_any_init ();
+  
+  return g_real_name;
+}
 
-#else
-  gchar *printed;
-  va_list args, args2;
+/* Return the home directory of the user. If there is a HOME
+ * environment variable, its value is returned, otherwise use some
+ * system-dependent way of finding it out. If no home directory can be
+ * deduced, return NULL.
+ */
 
-  va_start (args, fmt);
-  va_start (args2, fmt);
+gchar*
+g_get_home_dir (void)
+{
+  if (!g_tmp_dir)
+    g_get_any_init ();
   
-  printed = g_vsprintf (fmt, &args, &args2);
-  strncpy (str, printed, n);
-  str[n-1] = '\0';
+  return g_home_dir;
+}
+
+/* Return a directory to be used to store temporary files. This is the
+ * value of the TMPDIR, TMP or TEMP environment variables (they are
+ * checked in that order). If none of those exist, use P_tmpdir from
+ * stdio.h.  If that isn't defined, return "/tmp" on POSIXly systems,
+ * and C:\ on Windows.
+ */
+
+gchar*
+g_get_tmp_dir (void)
+{
+  if (!g_tmp_dir)
+    g_get_any_init ();
   
-  va_end (args2);
-  va_end (args);
+  return g_tmp_dir;
+}
 
-  return strlen (str);
+static gchar *g_prgname = NULL;
 
-#endif
+gchar*
+g_get_prgname (void)
+{
+  return g_prgname;
 }
 
 void
-g_strdown (gchar  *string)
+g_set_prgname (const gchar *prgname)
 {
-  register gchar *s;
+  gchar *c = g_prgname;
+  
+  g_prgname = g_strdup (prgname);
+  g_free (c);
+}
 
-  g_return_if_fail (string != NULL);
+guint
+g_direct_hash (gconstpointer v)
+{
+  return GPOINTER_TO_UINT (v);
+}
 
-  s = string;
+gint
+g_direct_equal (gconstpointer v1,
+               gconstpointer v2)
+{
+  return GPOINTER_TO_UINT (v1) == GPOINTER_TO_UINT (v2);
+}
 
-  while (*s)
-    {
-      *s = tolower (*s);
-      s++;
-    }
+gint
+g_int_equal (gconstpointer v1,
+            gconstpointer v2)
+{
+  return *((const gint*) v1) == *((const gint*) v2);
+}
+
+guint
+g_int_hash (gconstpointer v)
+{
+  return *(const gint*) v;
+}
+
+GIOChannel*
+g_iochannel_new (gint fd)
+{
+  GIOChannel *channel = g_new (GIOChannel, 1);
+
+  channel->fd = fd;
+
+#ifdef NATIVE_WIN32
+  channel->peer = 0;
+  channel->peer_fd = 0;
+  channel->offset = 0;
+  channel->need_wakeups = 0;
+#endif /* NATIVE_WIN32 */
+
+  return channel;
 }
 
 void
-g_strup (gchar  *string)
+g_iochannel_free (GIOChannel *channel)
 {
-  register gchar *s;
+  g_return_if_fail (channel != NULL);
+
+  g_free (channel);
+}
 
-  g_return_if_fail (string != NULL);
+void
+g_iochannel_close_and_free (GIOChannel *channel)
+{
+  g_return_if_fail (channel != NULL);
 
-  s = string;
+  close (channel->fd);
 
-  while (*s)
-    {
-      *s = toupper (*s);
-      s++;
-    }
+  g_iochannel_free (channel);
 }
 
+#undef g_iochannel_wakeup_peer
+
 void
-g_strreverse (gchar       *string)
+g_iochannel_wakeup_peer (GIOChannel *channel)
+{
+#ifdef NATIVE_WIN32
+  static guint message = 0;
+#endif
+
+  g_return_if_fail (channel != NULL);
+
+#ifdef NATIVE_WIN32
+  if (message == 0)
+    message = RegisterWindowMessage ("gdk-pipe-readable");
+
+#  if 0
+  g_print ("g_iochannel_wakeup_peer: calling PostThreadMessage (%#x, %d, %d, %d)\n",
+          channel->peer, message, channel->peer_fd, channel->offset);
+#  endif
+  PostThreadMessage (channel->peer, message,
+                    channel->peer_fd, channel->offset);
+#endif /* NATIVE_WIN32 */
+}
+
+
+#ifdef NATIVE_WIN32
+#ifdef _MSC_VER
+
+int
+gwin_ftruncate (gint  fd,
+               guint size)
 {
-  g_return_if_fail (string != NULL);
+  HANDLE hfile;
+  guint curpos;
 
-  if (*string)
+  g_return_val_if_fail (fd >= 0, -1);
+  
+  hfile = (HANDLE) _get_osfhandle (fd);
+  curpos = SetFilePointer (hfile, 0, NULL, FILE_CURRENT);
+  if (curpos == 0xFFFFFFFF
+      || SetFilePointer (hfile, size, NULL, FILE_BEGIN) == 0xFFFFFFFF
+      || !SetEndOfFile (hfile))
     {
-      register gchar *h, *t;
+      gint error = GetLastError ();
 
-      h = string;
-      t = string + strlen (string) - 1;
-      
-      while (h < t)
+      switch (error)
        {
-         register gchar c;
-         
-         c = *h;
-         *h = *t;
-         h++;
-         *t = c;
-         t--;
+       case ERROR_INVALID_HANDLE:
+         errno = EBADF;
+         break;
+       default:
+         errno = EIO;
+         break;
        }
+
+      return -1;
     }
+
+  return 0;
 }
 
-gint
-g_strcasecmp (const gchar *s1,
-             const gchar *s2)
+DIR*
+gwin_opendir (const char *dirname)
 {
-#ifdef HAVE_STRCASECMP
-  return strcasecmp (s1, s2);
-#else
-  gint c1, c2;
+  DIR *result;
+  gchar *mask;
+  guint k;
 
-  while (*s1 && *s2)
+  g_return_val_if_fail (dirname != NULL, NULL);
+
+  result = g_new0 (DIR, 1);
+  result->find_file_data = g_new0 (WIN32_FIND_DATA, 1);
+  result->dir_name = g_strdup (dirname);
+  
+  k = strlen (result->dir_name);
+  if (k && result->dir_name[k - 1] == '\\')
     {
-      /* According to A. Cox, some platforms have islower's that
-       * don't work right on non-uppercase
-       */
-      c1 = isupper ((guchar)*s1) ? tolower ((guchar)*s1) : *s1;
-      c2 = isupper ((guchar)*s2) ? tolower ((guchar)*s2) : *s2;
-      if (c1 != c2)
-        return (c1 - c2);
-      s1++; s2++;
+      result->dir_name[k - 1] = '\0';
+      k--;
     }
+  mask = g_strdup_printf ("%s\\*", result->dir_name);
 
-  return (((gint)(guchar) *s1) - ((gint)(guchar) *s2));
-#endif
+  result->find_file_handle = (guint) FindFirstFile (mask,
+                                            (LPWIN32_FIND_DATA) result->find_file_data);
+  g_free (mask);
+
+  if (result->find_file_handle == (guint) INVALID_HANDLE_VALUE)
+    {
+      int error = GetLastError ();
+
+      g_free (result->dir_name);
+      g_free (result->find_file_data);
+      g_free (result);
+      switch (error)
+       {
+       default:
+         errno = EIO;
+         return NULL;
+       }
+    }
+  result->just_opened = TRUE;
+
+  return result;
 }
 
-void
-g_strdelimit (gchar       *string,
-             const gchar *delimiters,
-             gchar        new_delim)
+struct dirent*
+gwin_readdir (DIR *dir)
 {
-  register gchar *c;
+  static struct dirent result;
 
-  g_return_if_fail (string != NULL);
+  g_return_val_if_fail (dir != NULL, NULL);
 
-  if (!delimiters)
-    delimiters = G_STR_DELIMITERS;
-
-  for (c = string; *c; c++)
+  if (dir->just_opened)
+    dir->just_opened = FALSE;
+  else
     {
-      if (strchr (delimiters, *c))
-       *c = new_delim;
+      if (!FindNextFile ((HANDLE) dir->find_file_handle,
+                        (LPWIN32_FIND_DATA) dir->find_file_data))
+       {
+         int error = GetLastError ();
+
+         switch (error)
+           {
+           case ERROR_NO_MORE_FILES:
+             return NULL;
+           default:
+             errno = EIO;
+             return NULL;
+           }
+       }
     }
+  strcpy (result.d_name, g_basename (((LPWIN32_FIND_DATA) dir->find_file_data)->cFileName));
+      
+  return &result;
 }
 
-guint        
-g_parse_debug_string  (const gchar *string, 
-                      GDebugKey   *keys, 
-                      guint        nkeys)
+void
+gwin_rewinddir (DIR *dir)
 {
-  guint i;
-  guint result = 0;
+  gchar *mask;
 
-  g_return_val_if_fail (string != NULL, 0);
+  g_return_if_fail (dir != NULL);
 
-  if (!g_strcasecmp (string, "all"))
-    {
-      for (i=0; i<nkeys; i++)
-       result |= keys[i].value;
-    }
-  else
+  if (!FindClose ((HANDLE) dir->find_file_handle))
+    g_warning ("gwin_rewinddir(): FindClose() failed\n");
+
+  mask = g_strdup_printf ("%s\\*", dir->dir_name);
+  dir->find_file_handle = (guint) FindFirstFile (mask,
+                                         (LPWIN32_FIND_DATA) dir->find_file_data);
+  g_free (mask);
+
+  if (dir->find_file_handle == (guint) INVALID_HANDLE_VALUE)
     {
-      gchar *str = g_strdup (string);
-      gchar *p = str;
-      gchar *q;
-      gboolean done = FALSE;
+      int error = GetLastError ();
 
-      while (*p && !done)
+      switch (error)
        {
-         q = strchr (p, ':');
-         if (!q)
-           {
-             q = p + strlen(p);
-             done = TRUE;
-           }
+       default:
+         errno = EIO;
+         return;
+       }
+    }
+  dir->just_opened = TRUE;
+}  
 
-         *q = 0;
+gint
+gwin_closedir (DIR *dir)
+{
+  g_return_val_if_fail (dir != NULL, -1);
 
-         for (i=0; i<nkeys; i++)
-           if (!g_strcasecmp(keys[i].key, p))
-             result |= keys[i].value;
+  if (!FindClose ((HANDLE) dir->find_file_handle))
+    {
+      int error = GetLastError ();
 
-         p = q+1;
+      switch (error)
+       {
+       default:
+         errno = EIO; return -1;
        }
-      
-      g_free (str);
     }
 
-  return result;
-}
+  g_free (dir->dir_name);
+  g_free (dir->find_file_data);
+  g_free (dir);
 
-guint
-g_direct_hash(gconstpointer key)
-{
-  return GPOINTER_TO_UINT (key);
+  return 0;
 }
 
+#endif /* _MSC_VER */
+
+#endif /* NATIVE_WIN32 */