mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-13 04:46:15 +01:00
f477518c3a
* README.win32: More text. * config.h.win32 glibconfig.h.win32: Update to match the corresponding generated files on Unix. * makefile.msc: Update with new source files, and gthread library. Use the compiler flag -MD instead of using -D_DLL and "/nodefaultlib:libc msvcrt.lib" in the link phase. * glib.def: Include new functions, drop removed ones. * glib.h: Add comments about main loop and polling on Win32. (In general, it's only for the GIMP's use.) Add Win32 IO Channel functions. Remove the obsoleted old IO Channel stuff (which was in #if 0 already). * giowin32.c: New file. * gmain.c: Include config.h, conditionalize <sys/time.h> inclusion. Add g_poll implementation for Win32 (only for the GIMP's needs for now, it's hard or even impossible to be as clean and generic as on Unix). Implement g_get_current_time on Win32. If threads aren't supported, don't try to wake up main thread's loop. On Win32, use a semaphore and not a pipe to wake up the main loop. * gmessages.c: On Win32, allocate a console window if the standard output handle is invalid before writing to stdout, and reopen stdout to that console window. * giochannel.c: Conditionalize unistd.h inclusion. Some indentation cleanup. * gstrfuncs.c: Include <signal.h>. * gutils.c: On Win32, also check the HOMEDRIVE and HOMEPATH environment variables. * gmodule-dl.c gmodule-dld.c: In _g_module_build_path, don't add the "lib" prefix and ".so" or ".sl" suffix if already there. * gmodule-win32.c: Likewise for the ".dll" suffix. * gthread-posix.c: Conditionalize <sys/time.h> inclusion.
829 lines
16 KiB
C
829 lines
16 KiB
C
/* GLIB - Library of useful routines for C programming
|
|
* 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
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/*
|
|
* MT safe for the unix part, FIXME: make the win32 part MT safe as well.
|
|
*/
|
|
|
|
#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;
|
|
|
|
#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,
|
|
gulong n,
|
|
gchar const *fmt,
|
|
...)
|
|
{
|
|
#ifdef HAVE_VSNPRINTF
|
|
va_list args;
|
|
gint retval;
|
|
|
|
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);
|
|
|
|
strncpy (str, printed, n);
|
|
str[n-1] = '\0';
|
|
|
|
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;
|
|
|
|
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
|
|
g_parse_debug_string (const gchar *string,
|
|
GDebugKey *keys,
|
|
guint nkeys)
|
|
{
|
|
guint i;
|
|
guint result = 0;
|
|
|
|
g_return_val_if_fail (string != NULL, 0);
|
|
|
|
if (!g_strcasecmp (string, "all"))
|
|
{
|
|
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);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
gchar*
|
|
g_basename (const gchar *file_name)
|
|
{
|
|
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;
|
|
}
|
|
|
|
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_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;
|
|
|
|
#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 (buffer);
|
|
#else /* !sun */
|
|
dir = getcwd (buffer, G_PATH_LENGTH - 1);
|
|
#endif /* !sun */
|
|
|
|
if (!dir || !*buffer)
|
|
{
|
|
/* hm, should we g_error() out here?
|
|
* this can happen if e.g. "./" has mode \0000
|
|
*/
|
|
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;
|
|
|
|
/* 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
|
|
}
|
|
|
|
G_LOCK_DECLARE_STATIC (g_utils_global);
|
|
|
|
static gchar *g_tmp_dir = NULL;
|
|
static gchar *g_user_name = NULL;
|
|
static gchar *g_real_name = NULL;
|
|
static gchar *g_home_dir = NULL;
|
|
|
|
/* HOLDS: g_utils_global_lock */
|
|
static void
|
|
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"));
|
|
|
|
#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 */
|
|
}
|
|
|
|
#ifdef NATIVE_WIN32
|
|
/* The official way to specify a home directory on NT is
|
|
* the HOMEDRIVE and HOMEPATH environment variables.
|
|
*
|
|
* This is inside #ifdef NATIVE_WIN32 because with the cygwin dll,
|
|
* HOME should be a POSIX style pathname.
|
|
*/
|
|
|
|
if (getenv ("HOMEDRIVE") != NULL && getenv ("HOMEPATH") != NULL)
|
|
{
|
|
gchar *homedrive, *homepath;
|
|
|
|
homedrive = g_strdup (g_getenv ("HOMEDRIVE"));
|
|
homepath = g_strdup (g_getenv ("HOMEPATH"));
|
|
|
|
g_home_dir = g_strconcat (homedrive, homepath, NULL);
|
|
g_free (homedrive);
|
|
g_free (homepath);
|
|
}
|
|
if (!g_home_dir)
|
|
g_home_dir = g_strdup (g_getenv ("HOME"));
|
|
#else
|
|
g_home_dir = g_strdup (g_getenv ("HOME"));
|
|
#endif
|
|
|
|
#ifdef HAVE_PWD_H
|
|
/* FIXME: we must actually use the getpwuid_r function here, as
|
|
getpwuid is not MT-safe, but the prototype doesn't seem to be
|
|
agreed upon on the different systems, i.e. it is
|
|
|
|
struct passwd *getpwuid_r(uid_t uid, struct passwd * pwd,
|
|
char *buffer, int buflen);
|
|
|
|
on solaris, but
|
|
|
|
int getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer,
|
|
size_t bufsize struct passwd **result);
|
|
|
|
on posix. weird. */
|
|
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 */
|
|
}
|
|
}
|
|
|
|
gchar*
|
|
g_get_user_name (void)
|
|
{
|
|
G_LOCK (g_utils_global);
|
|
if (!g_tmp_dir)
|
|
g_get_any_init ();
|
|
G_UNLOCK (g_utils_global);
|
|
|
|
return g_user_name;
|
|
}
|
|
|
|
gchar*
|
|
g_get_real_name (void)
|
|
{
|
|
G_LOCK (g_utils_global);
|
|
if (!g_tmp_dir)
|
|
g_get_any_init ();
|
|
G_UNLOCK (g_utils_global);
|
|
|
|
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)
|
|
{
|
|
G_LOCK (g_utils_global);
|
|
if (!g_tmp_dir)
|
|
g_get_any_init ();
|
|
G_UNLOCK (g_utils_global);
|
|
|
|
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)
|
|
{
|
|
G_LOCK (g_utils_global);
|
|
if (!g_tmp_dir)
|
|
g_get_any_init ();
|
|
G_UNLOCK (g_utils_global);
|
|
|
|
return g_tmp_dir;
|
|
}
|
|
|
|
static gchar *g_prgname = NULL;
|
|
|
|
gchar*
|
|
g_get_prgname (void)
|
|
{
|
|
gchar* retval;
|
|
|
|
G_LOCK (g_utils_global);
|
|
retval = g_prgname;
|
|
G_UNLOCK (g_utils_global);
|
|
|
|
return retval;
|
|
}
|
|
|
|
void
|
|
g_set_prgname (const gchar *prgname)
|
|
{
|
|
gchar *c;
|
|
|
|
G_LOCK (g_utils_global);
|
|
c = g_prgname;
|
|
g_prgname = g_strdup (prgname);
|
|
g_free (c);
|
|
G_UNLOCK (g_utils_global);
|
|
}
|
|
|
|
guint
|
|
g_direct_hash (gconstpointer v)
|
|
{
|
|
return GPOINTER_TO_UINT (v);
|
|
}
|
|
|
|
gint
|
|
g_direct_equal (gconstpointer v1,
|
|
gconstpointer v2)
|
|
{
|
|
return GPOINTER_TO_UINT (v1) == GPOINTER_TO_UINT (v2);
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
#if 0 /* Old IO Channels */
|
|
|
|
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 */
|
|
}
|
|
|
|
#endif /* Old IO Channels */
|
|
|
|
#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 */
|