Blame src/compat/compat.c

Packit c32a2d
/*
Packit c32a2d
	compat: Some compatibility functions (basic memory & string stuff in separate file)
Packit c32a2d
Packit c32a2d
	The mpg123 code is determined to keep it's legacy. A legacy of old, old UNIX.
Packit c32a2d
	So anything possibly somewhat advanced should be considered to be put here, with proper #ifdef;-)
Packit c32a2d
Packit c32a2d
	copyright 2007-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
Packit c32a2d
	see COPYING and AUTHORS files in distribution or http://mpg123.org
Packit c32a2d
	initially written by Thomas Orgis, Windows Unicode stuff by JonY.
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
#include "config.h"
Packit c32a2d
/* This source file does need _POSIX_SOURCE to get some sigaction. */
Packit c32a2d
#define _POSIX_SOURCE
Packit c32a2d
#include "compat.h"
Packit c32a2d
Packit c32a2d
#ifdef _MSC_VER
Packit c32a2d
#include <io.h>
Packit c32a2d
Packit c32a2d
#if(defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP))
Packit c32a2d
#define WINDOWS_UWP
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
#endif
Packit c32a2d
#ifdef HAVE_SYS_STAT_H
Packit c32a2d
#  include <sys/stat.h>
Packit c32a2d
#endif
Packit c32a2d
#ifdef HAVE_DIRENT_H
Packit c32a2d
#  include <dirent.h>
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
/* Win32 is only supported with unicode now. These headers also cover
Packit c32a2d
   module stuff. The WANT_WIN32_UNICODE macro is synonymous with
Packit c32a2d
   "want windows-specific API, and only the unicode variants of which". */
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
#include <wchar.h>
Packit c32a2d
#include <windows.h>
Packit c32a2d
#include <winnls.h>
Packit c32a2d
#include <shlwapi.h>
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
#ifdef USE_MODULES
Packit c32a2d
#  ifdef HAVE_DLFCN_H
Packit c32a2d
#    include <dlfcn.h>
Packit c32a2d
#  endif
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
#include "debug.h"
Packit c32a2d
Packit c32a2d
#ifndef WINDOWS_UWP
Packit c32a2d
Packit c32a2d
char *compat_getenv(const char* name)
Packit c32a2d
{
Packit c32a2d
	char *ret = NULL;
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
	wchar_t *env;
Packit c32a2d
	wchar_t *wname = NULL;
Packit c32a2d
	if(win32_utf8_wide(name, &wname, NULL) > 0)
Packit c32a2d
	{
Packit c32a2d
		env = _wgetenv(wname);
Packit c32a2d
		free(wname);
Packit c32a2d
		if(env)
Packit c32a2d
			win32_wide_utf8(env, &ret, NULL);
Packit c32a2d
	}
Packit c32a2d
#else
Packit c32a2d
	ret = getenv(name);
Packit c32a2d
	if(ret)
Packit c32a2d
		ret = compat_strdup(ret);
Packit c32a2d
#endif
Packit c32a2d
	return ret;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
Packit c32a2d
/* Convert unix UTF-8 (or ASCII) paths to Windows wide character paths. */
Packit c32a2d
static wchar_t* u2wpath(const char *upath)
Packit c32a2d
{
Packit c32a2d
	wchar_t* wpath, *p;
Packit c32a2d
	if(!upath || win32_utf8_wide(upath, &wpath, NULL) < 1)
Packit c32a2d
		return NULL;
Packit c32a2d
	for(p=wpath; *p; ++p)
Packit c32a2d
		if(*p == L'/')
Packit c32a2d
			*p = L'\\';
Packit c32a2d
	return wpath;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Convert Windows wide character paths to unix UTF-8. */
Packit c32a2d
static char* w2upath(const wchar_t *wpath)
Packit c32a2d
{
Packit c32a2d
	char* upath, *p;
Packit c32a2d
	if(!wpath || win32_wide_utf8(wpath, &upath, NULL) < 1)
Packit c32a2d
		return NULL;
Packit c32a2d
	for(p=upath; *p; ++p)
Packit c32a2d
		if(*p == '\\')
Packit c32a2d
			*p = '/';
Packit c32a2d
	return upath;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* An absolute path that is too long and not already marked with
Packit c32a2d
   \\?\ can be marked as a long one and still work. */
Packit c32a2d
static int wpath_need_elongation(wchar_t *wpath)
Packit c32a2d
{
Packit c32a2d
	if( wpath && !PathIsRelativeW(wpath)
Packit c32a2d
	&&	wcslen(wpath) > MAX_PATH-1
Packit c32a2d
	&&	wcsncmp(L"\\\\?\\", wpath, 4) )
Packit c32a2d
		return 1;
Packit c32a2d
	else
Packit c32a2d
		return 0;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Take any wide windows path and turn it into a path that is allowed
Packit c32a2d
   to be longer than MAX_PATH, if it is not already. */
Packit c32a2d
static wchar_t* wlongpath(wchar_t *wpath)
Packit c32a2d
{
Packit c32a2d
	size_t len, plen;
Packit c32a2d
	const wchar_t *prefix = L"";
Packit c32a2d
	wchar_t *wlpath = NULL;
Packit c32a2d
	if(!wpath)
Packit c32a2d
		return NULL;
Packit c32a2d
Packit c32a2d
	/* Absolute paths that do not start with \\?\ get that prepended
Packit c32a2d
	   to allow them being long. */
Packit c32a2d
	if(!PathIsRelativeW(wpath) && wcsncmp(L"\\\\?\\", wpath, 4))
Packit c32a2d
	{
Packit c32a2d
		if(wcslen(wpath) >= 2 && PathIsUNCW(wpath))
Packit c32a2d
		{
Packit c32a2d
			/* \\server\path -> \\?\UNC\server\path */
Packit c32a2d
			prefix = L"\\\\?\\UNC";
Packit c32a2d
			++wpath; /* Skip the first \. */
Packit c32a2d
		}
Packit c32a2d
		else /* c:\some/path -> \\?\c:\some\path */
Packit c32a2d
			prefix = L"\\\\?\\";
Packit c32a2d
	}
Packit c32a2d
	plen = wcslen(prefix);
Packit c32a2d
	len = plen + wcslen(wpath);
Packit c32a2d
	wlpath = malloc(len+1*sizeof(wchar_t));
Packit c32a2d
	if(wlpath)
Packit c32a2d
	{
Packit c32a2d
		/* Brute force memory copying, swprintf is too dandy. */
Packit c32a2d
		memcpy(wlpath, prefix, sizeof(wchar_t)*plen);
Packit c32a2d
		memcpy(wlpath+plen, wpath, sizeof(wchar_t)*(len-plen));
Packit c32a2d
		wlpath[len] = 0;
Packit c32a2d
	}
Packit c32a2d
	return wlpath;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Convert unix path to wide windows path, optionally marking
Packit c32a2d
   it as long path if necessary. */
Packit c32a2d
static wchar_t* u2wlongpath(const char *upath)
Packit c32a2d
{
Packit c32a2d
	wchar_t *wpath  = NULL;
Packit c32a2d
	wchar_t *wlpath = NULL;
Packit c32a2d
	wpath = u2wpath(upath);
Packit c32a2d
	if(wpath_need_elongation(wpath))
Packit c32a2d
	{
Packit c32a2d
		wlpath = wlongpath(wpath);
Packit c32a2d
		free(wpath);
Packit c32a2d
		wpath = wlpath;
Packit c32a2d
	}
Packit c32a2d
	return wpath;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
#else
Packit c32a2d
Packit c32a2d
static wchar_t* u2wlongpath(const char *upath)
Packit c32a2d
{
Packit c32a2d
	wchar_t* wpath, *p;
Packit c32a2d
	if (!upath || win32_utf8_wide(upath, &wpath, NULL) < 1)
Packit c32a2d
		return NULL;
Packit c32a2d
	for (p = wpath; *p; ++p)
Packit c32a2d
		if (*p == L'/')
Packit c32a2d
			*p = L'\\';
Packit c32a2d
	return wpath;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
/* Always add a default permission mask in case of flags|O_CREAT. */
Packit c32a2d
int compat_open(const char *filename, int flags)
Packit c32a2d
{
Packit c32a2d
	int ret;
Packit c32a2d
#if defined (WANT_WIN32_UNICODE)
Packit c32a2d
	wchar_t *frag = NULL;
Packit c32a2d
Packit c32a2d
	frag = u2wlongpath(filename);
Packit c32a2d
	/* Fallback to plain open when ucs-2 conversion fails */
Packit c32a2d
	if(!frag)
Packit c32a2d
		goto open_fallback;
Packit c32a2d
Packit c32a2d
	/*Try _wopen */
Packit c32a2d
	ret = _wopen(frag, flags|_O_BINARY, _S_IREAD | _S_IWRITE);
Packit c32a2d
	if(ret != -1 )
Packit c32a2d
		goto open_ok; /* msdn says -1 means failure */
Packit c32a2d
Packit c32a2d
open_fallback:
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
#if (defined(WIN32) && !defined (__CYGWIN__))
Packit c32a2d
	/* MSDN says POSIX function is deprecated beginning in Visual C++ 2005 */
Packit c32a2d
	/* Try plain old _open(), if it fails, do nothing */
Packit c32a2d
	ret = _open(filename, flags|_O_BINARY, _S_IREAD | _S_IWRITE);
Packit c32a2d
#else
Packit c32a2d
	ret = open(filename, flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
#if defined (WANT_WIN32_UNICODE)
Packit c32a2d
open_ok:
Packit c32a2d
	free(frag);
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
	return ret;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Moved over from wav.c, logic with fallbacks added from the
Packit c32a2d
   example of compat_open(). */
Packit c32a2d
FILE* compat_fopen(const char *filename, const char *mode)
Packit c32a2d
{
Packit c32a2d
	FILE* stream = NULL;
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
	int cnt = 0;
Packit c32a2d
	wchar_t *wname = NULL;
Packit c32a2d
	wchar_t *wmode = NULL;
Packit c32a2d
Packit c32a2d
	wname = u2wlongpath(filename);
Packit c32a2d
	if(!wname)
Packit c32a2d
		goto fopen_fallback;
Packit c32a2d
	cnt = win32_utf8_wide(mode, &wmode, NULL);
Packit c32a2d
	if( (wmode == NULL) || (cnt == 0))
Packit c32a2d
		goto fopen_fallback;
Packit c32a2d
Packit c32a2d
	stream = _wfopen(wname, wmode);
Packit c32a2d
	if(stream) goto fopen_ok;
Packit c32a2d
Packit c32a2d
fopen_fallback:
Packit c32a2d
#endif
Packit c32a2d
	stream = fopen(filename, mode);
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
Packit c32a2d
fopen_ok:
Packit c32a2d
	free(wmode);
Packit c32a2d
	free(wname);
Packit c32a2d
#endif
Packit c32a2d
	return stream;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
FILE* compat_fdopen(int fd, const char *mode)
Packit c32a2d
{
Packit c32a2d
	return fdopen(fd, mode);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int compat_close(int infd)
Packit c32a2d
{
Packit c32a2d
#if (defined(WIN32) && !defined (__CYGWIN__)) /* MSDN says POSIX function is deprecated beginning in Visual C++ 2005 */
Packit c32a2d
	return _close(infd);
Packit c32a2d
#else
Packit c32a2d
	return close(infd);
Packit c32a2d
#endif
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int compat_fclose(FILE *stream)
Packit c32a2d
{
Packit c32a2d
	return fclose(stream);
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Windows Unicode stuff */
Packit c32a2d
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
int win32_wide_utf8(const wchar_t * const wptr, char **mbptr, size_t * buflen)
Packit c32a2d
{
Packit c32a2d
  size_t len;
Packit c32a2d
  char *buf;
Packit c32a2d
  int ret = 0;
Packit c32a2d
Packit c32a2d
  len = WideCharToMultiByte(CP_UTF8, 0, wptr, -1, NULL, 0, NULL, NULL); /* Get utf-8 string length */
Packit c32a2d
  buf = calloc(len + 1, sizeof (char)); /* Can we assume sizeof char always = 1? */
Packit c32a2d
Packit c32a2d
  if(!buf) len = 0;
Packit c32a2d
  else {
Packit c32a2d
    if (len != 0) ret = WideCharToMultiByte(CP_UTF8, 0, wptr, -1, buf, len, NULL, NULL); /*Do actual conversion*/
Packit c32a2d
    buf[len] = '0'; /* Must terminate */
Packit c32a2d
  }
Packit c32a2d
  *mbptr = buf; /* Set string pointer to allocated buffer */
Packit c32a2d
  if(buflen != NULL) *buflen = (len) * sizeof (char); /* Give length of allocated memory if needed. */
Packit c32a2d
  return ret;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int win32_utf8_wide(const char *const mbptr, wchar_t **wptr, size_t *buflen)
Packit c32a2d
{
Packit c32a2d
  size_t len;
Packit c32a2d
  wchar_t *buf;
Packit c32a2d
  int ret = 0;
Packit c32a2d
Packit c32a2d
  len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, mbptr, -1, NULL, 0); /* Get converted size */
Packit c32a2d
  buf = calloc(len + 1, sizeof (wchar_t)); /* Allocate memory accordingly */
Packit c32a2d
Packit c32a2d
  if(!buf) len = 0;
Packit c32a2d
  else {
Packit c32a2d
    if (len != 0) ret = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, mbptr, -1, buf, len); /* Do conversion */
Packit c32a2d
    buf[len] = L'0'; /* Must terminate */
Packit c32a2d
  }
Packit c32a2d
  *wptr = buf; /* Set string pointer to allocated buffer */
Packit c32a2d
  if (buflen != NULL) *buflen = len * sizeof (wchar_t); /* Give length of allocated memory if needed. */
Packit c32a2d
  return ret; /* Number of characters written */
Packit c32a2d
}
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
#ifndef WINDOWS_UWP
Packit c32a2d
Packit c32a2d
/*
Packit c32a2d
	The Windows file and path stuff is an extract of jon_y's win32 loader
Packit c32a2d
	prototype from the loader_rework branch. It's been divided in to
Packit c32a2d
	reusable functons by ThOr in the hope to work out some generic-looking
Packit c32a2d
	loader code for both POSIX and Windows. The routines might be
Packit c32a2d
	helpful for consistent path work in other parts of mpg123, too.
Packit c32a2d
Packit c32a2d
	This all is about getting some working code on a wide range of
Packit c32a2d
	systems while staying somewhat sane. If it does ridiculously inefficient
Packit c32a2d
	things with extraneous copies and grabbing of functions that made
Packit c32a2d
	it late to some official APIs, that's still fine with us.
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
char* compat_catpath(const char *prefix, const char* path)
Packit c32a2d
{
Packit c32a2d
	char *ret = NULL;
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
	wchar_t *wprefix = NULL; /* Wide windows versions of */
Packit c32a2d
	wchar_t *wpath   = NULL; /* input arguments. */
Packit c32a2d
	wchar_t *locwret = NULL; /* Tmp return value from LocalAlloc */
Packit c32a2d
	/*
Packit c32a2d
		This variation of combinepath can work with long and UNC paths, but
Packit c32a2d
		is not officially exposed in any DLLs, It also allocates all its buffers
Packit c32a2d
		internally via LocalAlloc, avoiding buffer overflow problems.
Packit c32a2d
		ThOr: I presume this hack is for supporting pre-8 Windows, as
Packit c32a2d
		from Windows 8 on, this is documented in the API.
Packit c32a2d
	*/
Packit c32a2d
	HRESULT (__stdcall *mypac)( const wchar_t *in, const wchar_t* more
Packit c32a2d
	,	unsigned long flags, wchar_t **out ) = NULL;
Packit c32a2d
	HMODULE pathcch = NULL;
Packit c32a2d
Packit c32a2d
	if(!prefix && !path)
Packit c32a2d
		goto catpath_end;
Packit c32a2d
	wprefix = u2wpath(prefix);
Packit c32a2d
	wpath   = u2wpath(path);
Packit c32a2d
	if((prefix && !wprefix) || (path && !wpath))
Packit c32a2d
		goto catpath_end;
Packit c32a2d
Packit c32a2d
	/* Again: I presume this whole fun is to get at PathAllocCombine
Packit c32a2d
	   even when pathcch.h is not available (like in MinGW32). */
Packit c32a2d
	if( (pathcch = GetModuleHandleA("kernelbase")) )
Packit c32a2d
		mypac = (void *)GetProcAddress(pathcch, "PathAllocCombine");
Packit c32a2d
	if(mypac) /* PATHCCH_ALLOW_LONG_PATH = 1 per API docs */
Packit c32a2d
	{
Packit c32a2d
		debug("Actually calling PathAllocCombine!");
Packit c32a2d
		mypac(wprefix, wpath, 1, &locwret);
Packit c32a2d
	}
Packit c32a2d
	else
Packit c32a2d
	{
Packit c32a2d
		/* Playing safe, if we'd care much about performance, this would be on
Packit c32a2d
		   the stack. */
Packit c32a2d
		locwret = LocalAlloc(LPTR, sizeof(wchar_t)*MAX_PATH);
Packit c32a2d
		if(locwret)
Packit c32a2d
			PathCombineW(locwret, wprefix, wpath);
Packit c32a2d
	}
Packit c32a2d
	ret = w2upath(locwret);
Packit c32a2d
Packit c32a2d
catpath_end:
Packit c32a2d
	LocalFree(locwret);
Packit c32a2d
	free(wprefix);
Packit c32a2d
	free(wpath);
Packit c32a2d
#else
Packit c32a2d
	size_t len, prelen, patlen;
Packit c32a2d
Packit c32a2d
	if(path && path[0] == '/')
Packit c32a2d
		prefix = NULL; /* Absolute path stays as it is. */
Packit c32a2d
	prelen = prefix ? strlen(prefix) : 0;
Packit c32a2d
	patlen = path   ? strlen(path)   : 0;
Packit c32a2d
	/* Concatenate the two, put a / in between if both present. */
Packit c32a2d
	len = ((prefix && path) ? 1 : 0) + prelen + patlen;
Packit c32a2d
	ret = malloc(len+1);
Packit c32a2d
	if(ret)
Packit c32a2d
	{
Packit c32a2d
		size_t off=0;
Packit c32a2d
		memcpy(ret, prefix, prelen);
Packit c32a2d
		if(prefix && path)
Packit c32a2d
			ret[prelen+(off++)] = '/';
Packit c32a2d
		memcpy(ret+prelen+off, path, patlen);
Packit c32a2d
		ret[len] = 0;
Packit c32a2d
	}
Packit c32a2d
#endif
Packit c32a2d
	return ret;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
int compat_isdir(const char *path)
Packit c32a2d
{
Packit c32a2d
	int ret = 0;
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
	wchar_t *wpath;
Packit c32a2d
	wpath = u2wlongpath(path);
Packit c32a2d
	if(wpath)
Packit c32a2d
	{
Packit c32a2d
		DWORD attr = GetFileAttributesW(wpath);
Packit c32a2d
		if(attr != INVALID_FILE_ATTRIBUTES && attr & FILE_ATTRIBUTE_DIRECTORY)
Packit c32a2d
			ret=1;
Packit c32a2d
		free(wpath);
Packit c32a2d
	}
Packit c32a2d
#else
Packit c32a2d
	struct stat sb;
Packit c32a2d
	if(path && !stat(path, &sb))
Packit c32a2d
	{
Packit c32a2d
		if(S_ISDIR(sb.st_mode))
Packit c32a2d
			ret=1;
Packit c32a2d
	}
Packit c32a2d
#endif
Packit c32a2d
	return ret;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
struct compat_dir
Packit c32a2d
{
Packit c32a2d
	char *path;
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
	int gotone; /* Got a result stored from FindFirstFileW. */
Packit c32a2d
	WIN32_FIND_DATAW d;
Packit c32a2d
	HANDLE ffn;
Packit c32a2d
#else
Packit c32a2d
	DIR* dir;
Packit c32a2d
#endif
Packit c32a2d
};
Packit c32a2d
Packit c32a2d
struct compat_dir* compat_diropen(char *path)
Packit c32a2d
{
Packit c32a2d
	struct compat_dir *cd;
Packit c32a2d
	if(!path)
Packit c32a2d
		return NULL;
Packit c32a2d
	cd = malloc(sizeof(*cd));
Packit c32a2d
	if(!cd)
Packit c32a2d
		return NULL;
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
	cd->gotone = 0;
Packit c32a2d
	{
Packit c32a2d
		char *pattern;
Packit c32a2d
		wchar_t *wpattern;
Packit c32a2d
		pattern = compat_catpath(path, "*");
Packit c32a2d
		wpattern = u2wlongpath(pattern);
Packit c32a2d
		if(wpattern)
Packit c32a2d
		{
Packit c32a2d
			cd->ffn = FindFirstFileW(wpattern, &(cd->d));
Packit c32a2d
			if(cd->ffn == INVALID_HANDLE_VALUE)
Packit c32a2d
			{
Packit c32a2d
				/* FindClose() only needed after successful first find, right? */
Packit c32a2d
				free(cd);
Packit c32a2d
				cd = NULL;
Packit c32a2d
			}
Packit c32a2d
			else
Packit c32a2d
				cd->gotone = 1;
Packit c32a2d
		}
Packit c32a2d
		free(wpattern);
Packit c32a2d
		free(pattern);
Packit c32a2d
	}
Packit c32a2d
#else
Packit c32a2d
	cd->dir = opendir(path);
Packit c32a2d
	if(!cd->dir)
Packit c32a2d
	{
Packit c32a2d
		free(cd);
Packit c32a2d
		cd = NULL;
Packit c32a2d
	}
Packit c32a2d
#endif
Packit c32a2d
	if(cd)
Packit c32a2d
	{
Packit c32a2d
		cd->path = compat_strdup(path);
Packit c32a2d
		if(!cd->path)
Packit c32a2d
		{
Packit c32a2d
			compat_dirclose(cd);
Packit c32a2d
			cd = NULL;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
	return cd;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void compat_dirclose(struct compat_dir *cd)
Packit c32a2d
{
Packit c32a2d
	if(cd)
Packit c32a2d
	{
Packit c32a2d
		free(cd->path);
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
		FindClose(cd->ffn);
Packit c32a2d
#else
Packit c32a2d
		closedir(cd->dir);
Packit c32a2d
#endif
Packit c32a2d
		free(cd);
Packit c32a2d
	}
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
char* compat_nextfile(struct compat_dir *cd)
Packit c32a2d
{
Packit c32a2d
	if(!cd)
Packit c32a2d
		return NULL;
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
	while(cd->gotone || FindNextFileW(cd->ffn, &(cd->d)))
Packit c32a2d
	{
Packit c32a2d
		cd->gotone = 0;
Packit c32a2d
		if(!(cd->d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
Packit c32a2d
		{
Packit c32a2d
			char *ret;
Packit c32a2d
			win32_wide_utf8(cd->d.cFileName, &ret, NULL);
Packit c32a2d
			return ret;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
#else
Packit c32a2d
	{
Packit c32a2d
		struct dirent *dp;
Packit c32a2d
		while((dp = readdir(cd->dir)))
Packit c32a2d
		{
Packit c32a2d
			struct stat fst;
Packit c32a2d
			char *fullpath = compat_catpath(cd->path, dp->d_name);
Packit c32a2d
			if(fullpath && !stat(fullpath, &fst) && S_ISREG(fst.st_mode))
Packit c32a2d
			{
Packit c32a2d
				free(fullpath);
Packit c32a2d
				return compat_strdup(dp->d_name);
Packit c32a2d
			}
Packit c32a2d
			free(fullpath);
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
#endif
Packit c32a2d
	return NULL;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
char* compat_nextdir(struct compat_dir *cd)
Packit c32a2d
{
Packit c32a2d
	if(!cd)
Packit c32a2d
		return NULL;
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
	while(cd->gotone || FindNextFileW(cd->ffn, &(cd->d)))
Packit c32a2d
	{
Packit c32a2d
		cd->gotone = 0;
Packit c32a2d
		if(cd->d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
Packit c32a2d
		{
Packit c32a2d
			char *ret;
Packit c32a2d
			win32_wide_utf8(cd->d.cFileName, &ret, NULL);
Packit c32a2d
			return ret;
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
#else
Packit c32a2d
	{
Packit c32a2d
		struct dirent *dp;
Packit c32a2d
		while((dp = readdir(cd->dir)))
Packit c32a2d
		{
Packit c32a2d
			struct stat fst;
Packit c32a2d
			char *fullpath = compat_catpath(cd->path, dp->d_name);
Packit c32a2d
			if(fullpath && !stat(fullpath, &fst) && S_ISDIR(fst.st_mode))
Packit c32a2d
			{
Packit c32a2d
				free(fullpath);
Packit c32a2d
				return compat_strdup(dp->d_name);
Packit c32a2d
			}
Packit c32a2d
			free(fullpath);
Packit c32a2d
		}
Packit c32a2d
	}
Packit c32a2d
#endif
Packit c32a2d
	return NULL;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
#ifdef USE_MODULES
Packit c32a2d
/*
Packit c32a2d
	This is what I expected the platform-specific dance for dynamic module
Packit c32a2d
	support to be. Little did I know about the peculiarities of (long)
Packit c32a2d
	paths and directory/file search on Windows.
Packit c32a2d
*/
Packit c32a2d
Packit c32a2d
void *compat_dlopen(const char *path)
Packit c32a2d
{
Packit c32a2d
	void *handle = NULL;
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
	wchar_t *wpath;
Packit c32a2d
	wpath = u2wlongpath(path);
Packit c32a2d
	if(wpath)
Packit c32a2d
		handle = LoadLibraryW(wpath);
Packit c32a2d
	free(wpath);
Packit c32a2d
#else
Packit c32a2d
	handle = dlopen(path, RTLD_NOW);
Packit c32a2d
#endif
Packit c32a2d
	return handle;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void *compat_dlsym(void *handle, const char *name)
Packit c32a2d
{
Packit c32a2d
	void *sym = NULL;
Packit c32a2d
	if(!handle)
Packit c32a2d
		return NULL;
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
	sym = GetProcAddress(handle, name);
Packit c32a2d
#else
Packit c32a2d
	sym = dlsym(handle, name);
Packit c32a2d
#endif
Packit c32a2d
	return sym;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
void compat_dlclose(void *handle)
Packit c32a2d
{
Packit c32a2d
	if(!handle)
Packit c32a2d
		return;
Packit c32a2d
#ifdef WANT_WIN32_UNICODE
Packit c32a2d
	FreeLibrary(handle);
Packit c32a2d
#else
Packit c32a2d
	dlclose(handle);
Packit c32a2d
#endif
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#endif /* USE_MODULES */
Packit c32a2d
Packit c32a2d
Packit c32a2d
/* This shall survive signals and any return value less than given byte count
Packit c32a2d
   is an error */
Packit c32a2d
size_t unintr_write(int fd, void const *buffer, size_t bytes)
Packit c32a2d
{
Packit c32a2d
	size_t written = 0;
Packit c32a2d
	while(bytes)
Packit c32a2d
	{
Packit c32a2d
		ssize_t part = write(fd, (char*)buffer+written, bytes);
Packit c32a2d
		if(part < 0 && errno != EINTR)
Packit c32a2d
			break;
Packit c32a2d
		bytes   -= part;
Packit c32a2d
		written += part;
Packit c32a2d
	}
Packit c32a2d
	return written;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
/* Same for reading the data. */
Packit c32a2d
size_t unintr_read(int fd, void *buffer, size_t bytes)
Packit c32a2d
{
Packit c32a2d
	size_t got = 0;
Packit c32a2d
	while(bytes)
Packit c32a2d
	{
Packit c32a2d
		ssize_t part = read(fd, (char*)buffer+got, bytes);
Packit c32a2d
		if(part < 0 && errno != EINTR)
Packit c32a2d
			break;
Packit c32a2d
		bytes -= part;
Packit c32a2d
		got   += part;
Packit c32a2d
	}
Packit c32a2d
	return got;
Packit c32a2d
}
Packit c32a2d
Packit c32a2d
#ifndef NO_CATCHSIGNAL
Packit c32a2d
#if (!defined(WIN32) || defined (__CYGWIN__)) && defined(HAVE_SIGNAL_H)
Packit c32a2d
void (*catchsignal(int signum, void(*handler)()))()
Packit c32a2d
{
Packit c32a2d
	struct sigaction new_sa;
Packit c32a2d
	struct sigaction old_sa;
Packit c32a2d
Packit c32a2d
#ifdef DONT_CATCH_SIGNALS
Packit c32a2d
	fprintf (stderr, "Not catching any signals.\n");
Packit c32a2d
	return ((void (*)()) -1);
Packit c32a2d
#endif
Packit c32a2d
Packit c32a2d
	new_sa.sa_handler = handler;
Packit c32a2d
	sigemptyset(&new_sa.sa_mask);
Packit c32a2d
	new_sa.sa_flags = 0;
Packit c32a2d
	if(sigaction(signum, &new_sa, &old_sa) == -1)
Packit c32a2d
		return ((void (*)()) -1);
Packit c32a2d
	return (old_sa.sa_handler);
Packit c32a2d
}
Packit c32a2d
#endif
Packit c32a2d
#endif