applied glib-tml-981120-0, change log appended below.
[platform/upstream/glib.git] / gutils.c
index 6aac98f..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 <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#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;
 
-extern char* g_vsprintf (const gchar *fmt, va_list *args, va_list *args2);
+#if defined (NATIVE_WIN32) && defined (__LCC__)
+int __stdcall 
+LibMain (void         *hinstDll,
+        unsigned long dwReason,
+        void         *reserved)
+{
+  return 1;
+}
+#endif /* NATIVE_WIN32 && __LCC__ */
+
+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 */
+
+  if (error)
+    g_error ("Could not register atexit() function: %s", error);
+}
 
 gint
 g_snprintf (gchar      *str,
@@ -38,7 +121,7 @@ g_snprintf (gchar    *str,
            gchar const *fmt,
            ...)
 {
-#ifdef HAVE_VSNPRINTF
+#ifdef HAVE_VSNPRINTF
   va_list args;
   gint retval;
   
@@ -47,24 +130,46 @@ g_snprintf (gchar  *str,
   va_end (args);
   
   return retval;
-  
-#else
+#else  /* !HAVE_VSNPRINTF */
   gchar *printed;
-  va_list args, args2;
+  va_list args;
   
   va_start (args, fmt);
-  va_start (args2, fmt);
+  printed = g_strdup_vprintf (fmt, args);
+  va_end (args);
   
-  printed = g_vsprintf (fmt, &args, &args2);
   strncpy (str, printed, n);
   str[n-1] = '\0';
-  
-  va_end (args2);
-  va_end (args);
+
+  g_free (printed);
   
   return strlen (str);
+#endif /* !HAVE_VSNPRINTF */
+}
+
+gint
+g_vsnprintf (gchar      *str,
+            gulong       n,
+            gchar const *fmt,
+            va_list      args)
+{
+#ifdef HAVE_VSNPRINTF
+  gint retval;
   
-#endif
+  retval = vsnprintf (str, n, fmt, 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       
@@ -120,39 +225,146 @@ g_basename (const gchar     *file_name)
   
   g_return_val_if_fail (file_name != NULL, NULL);
   
-  base = strrchr (file_name, '/');
+  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;
 }
 
+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;
+
+#ifdef NATIVE_WIN32
+  if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
+    return TRUE;
+#endif
+
+  return FALSE;
+}
+
 gchar*
-g_getcwd (void)
+g_path_skip_root (gchar *file_name)
 {
-  static gchar g_getcwd_buf[MAXPATHLEN + 1] = { 0 };
-  register gchar *dir;
+  g_return_val_if_fail (file_name != NULL, NULL);
   
-  g_getcwd_buf[0] = 0;
+  if (file_name[0] == G_DIR_SEPARATOR)
+    return file_name + 1;
+
+#ifdef NATIVE_WIN32
+  if (isalpha (file_name[0]) && file_name[1] == ':' && file_name[2] == G_DIR_SEPARATOR)
+    return file_name + 3;
+#endif
+
+  return NULL;
+}
+
+gchar*
+g_dirname (const gchar    *file_name)
+{
+  register gchar *base;
+  register guint len;
+  
+  g_return_val_if_fail (file_name != NULL, NULL);
+  
+  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 (g_getcwd_buf);
+  dir = getwd (buffer);
 #else  /* !sun */
-  dir = getcwd (g_getcwd_buf, MAXPATHLEN);
+  dir = getcwd (buffer, G_PATH_LENGTH - 1);
 #endif /* !sun */
   
-  if (!dir || g_getcwd_buf[0] == 0)
+  if (!dir || !*buffer)
     {
-      /* hm, we should probably g_error() out here...
+      /* hm, should we g_error() out here?
+       * this can happen if e.g. "./" has mode \0000
        */
-      g_getcwd_buf[0] = '/';
-      g_getcwd_buf[1] = 0;
+      buffer[0] = G_DIR_SEPARATOR;
+      buffer[1] = 0;
     }
+
+  dir = g_strdup (buffer);
+  g_free (buffer);
+  
+  return dir;
+}
+
+gchar*
+g_getenv (const gchar *variable)
+{
+#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];
+
+  g_return_val_if_fail (variable != NULL, NULL);
+  
+  v = getenv (variable);
+  if (!v)
+    return NULL;
   
-  return g_getcwd_buf;
+  /* 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)
+    {
+      p = g_malloc (k);
+      l = k;
+    }
+  else if (k > l)
+    {
+      p = g_realloc (p, k);
+      l = k;
+    }
+  ExpandEnvironmentStrings (v, p, k);
+  return p;
+#endif
 }
 
 static gchar   *g_tmp_dir = NULL;
@@ -165,16 +377,38 @@ g_get_any_init (void)
 {
   if (!g_tmp_dir)
     {
+#ifdef HAVE_PWD_H
       struct passwd *pw;
+#endif
+
+      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"));
       
-      g_tmp_dir = g_strdup (getenv ("TMP"));
+#ifdef P_tmpdir
       if (!g_tmp_dir)
-       g_tmp_dir = g_strdup (getenv ("TEMP"));
+       {
+         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)
-       g_tmp_dir = g_strdup ("/tmp");
+       {
+#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 (getenv ("HOME"));
+      g_home_dir = g_strdup (g_getenv ("HOME"));
       
+#ifdef HAVE_PWD_H
       setpwent ();
       pw = getpwuid (getuid ());
       endpwent ();
@@ -186,6 +420,28 @@ g_get_any_init (void)
          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 */
     }
 }
 
@@ -207,6 +463,12 @@ g_get_real_name (void)
   return g_real_name;
 }
 
+/* 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.
+ */
+
 gchar*
 g_get_home_dir (void)
 {
@@ -216,6 +478,13 @@ g_get_home_dir (void)
   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)
 {
@@ -237,27 +506,29 @@ void
 g_set_prgname (const gchar *prgname)
 {
   gchar *c = g_prgname;
-
+  
   g_prgname = g_strdup (prgname);
   g_free (c);
 }
 
 guint
-g_direct_hash(gconstpointer v)
+g_direct_hash (gconstpointer v)
 {
   return GPOINTER_TO_UINT (v);
 }
 
 gint
-g_direct_equal(gconstpointer v, gconstpointer v2)
+g_direct_equal (gconstpointer v1,
+               gconstpointer v2)
 {
-  return GPOINTER_TO_UINT (v) == GPOINTER_TO_UINT (v2);
+  return GPOINTER_TO_UINT (v1) == GPOINTER_TO_UINT (v2);
 }
 
 gint
-g_int_equal (gconstpointer v, gconstpointer v2)
+g_int_equal (gconstpointer v1,
+            gconstpointer v2)
 {
-  return *((const gint*) v) == *((const gint*) v2);
+  return *((const gint*) v1) == *((const gint*) v2);
 }
 
 guint
@@ -265,3 +536,230 @@ 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_iochannel_free (GIOChannel *channel)
+{
+  g_return_if_fail (channel != NULL);
+
+  g_free (channel);
+}
+
+void
+g_iochannel_close_and_free (GIOChannel *channel)
+{
+  g_return_if_fail (channel != NULL);
+
+  close (channel->fd);
+
+  g_iochannel_free (channel);
+}
+
+#undef g_iochannel_wakeup_peer
+
+void
+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)
+{
+  HANDLE hfile;
+  guint curpos;
+
+  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))
+    {
+      gint error = GetLastError ();
+
+      switch (error)
+       {
+       case ERROR_INVALID_HANDLE:
+         errno = EBADF;
+         break;
+       default:
+         errno = EIO;
+         break;
+       }
+
+      return -1;
+    }
+
+  return 0;
+}
+
+DIR*
+gwin_opendir (const char *dirname)
+{
+  DIR *result;
+  gchar *mask;
+  guint k;
+
+  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] == '\\')
+    {
+      result->dir_name[k - 1] = '\0';
+      k--;
+    }
+  mask = g_strdup_printf ("%s\\*", result->dir_name);
+
+  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;
+}
+
+struct dirent*
+gwin_readdir (DIR *dir)
+{
+  static struct dirent result;
+
+  g_return_val_if_fail (dir != NULL, NULL);
+
+  if (dir->just_opened)
+    dir->just_opened = FALSE;
+  else
+    {
+      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;
+}
+
+void
+gwin_rewinddir (DIR *dir)
+{
+  gchar *mask;
+
+  g_return_if_fail (dir != NULL);
+
+  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)
+    {
+      int error = GetLastError ();
+
+      switch (error)
+       {
+       default:
+         errno = EIO;
+         return;
+       }
+    }
+  dir->just_opened = TRUE;
+}  
+
+gint
+gwin_closedir (DIR *dir)
+{
+  g_return_val_if_fail (dir != NULL, -1);
+
+  if (!FindClose ((HANDLE) dir->find_file_handle))
+    {
+      int error = GetLastError ();
+
+      switch (error)
+       {
+       default:
+         errno = EIO; return -1;
+       }
+    }
+
+  g_free (dir->dir_name);
+  g_free (dir->find_file_data);
+  g_free (dir);
+
+  return 0;
+}
+
+#endif /* _MSC_VER */
+
+#endif /* NATIVE_WIN32 */