rktio: wide-string handling for Windows
This commit is contained in:
parent
4ffb01c6fa
commit
9bfaaf3ab3
|
@ -24,6 +24,7 @@ OBJS = rktio_fs.@LTO@ \
|
|||
rktio_envvars.@LTO@ \
|
||||
rktio_fs_change.@LTO@ \
|
||||
rktio_error.@LTO@ \
|
||||
rktio_wide.@LTO@ \
|
||||
rktio_main.@LTO@
|
||||
|
||||
librktio.@LIBSFX@: $(OBJS)
|
||||
|
@ -69,6 +70,9 @@ rktio_fs_change.@LTO@: $(srcdir)/rktio_fs_change.c $(RKTIO_HEADERS)
|
|||
rktio_error.@LTO@: $(srcdir)/rktio_error.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_error.@LTO@ -c $(srcdir)/rktio_error.c
|
||||
|
||||
rktio_wide.@LTO@: $(srcdir)/rktio_wide.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_wide.@LTO@ -c $(srcdir)/rktio_wide.c
|
||||
|
||||
rktio_main.@LTO@: $(srcdir)/rktio_main.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_main.@LTO@ -c $(srcdir)/rktio_main.c
|
||||
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
# include <poll.h>
|
||||
#endif
|
||||
|
||||
/*========================================================================*/
|
||||
/* fd struct */
|
||||
/*========================================================================*/
|
||||
|
||||
struct rktio_fd_t {
|
||||
int modes;
|
||||
|
||||
|
@ -31,16 +35,64 @@ struct rktio_fd_t {
|
|||
HANDLE fd;
|
||||
int sock; /* when `modes & RKTIO_OPEN_SOCKET` */
|
||||
};
|
||||
Win_FD_Input_Thread *th; /* input mode */
|
||||
Win_FD_Output_Thread *oth; /* output mode */
|
||||
struct Win_FD_Input_Thread *th; /* input mode */
|
||||
struct Win_FD_Output_Thread *oth; /* output mode */
|
||||
char *buffer;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*************************************************************/
|
||||
/* creating an fd */
|
||||
/*************************************************************/
|
||||
/*========================================================================*/
|
||||
/* Windows I/O helper structs */
|
||||
/*========================================================================*/
|
||||
|
||||
static void init_read_fd(rktio_fd_t *rfd)
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
|
||||
typedef struct Win_FD_Input_Thread {
|
||||
/* This is malloced for use in a Win32 thread */
|
||||
HANDLE fd;
|
||||
volatile int avail, err, checking;
|
||||
int *refcount;
|
||||
HANDLE eof;
|
||||
unsigned char *buffer;
|
||||
HANDLE checking_sema, ready_sema, you_clean_up_sema;
|
||||
HANDLE thread;
|
||||
} Win_FD_Input_Thread;
|
||||
|
||||
typedef struct Win_FD_Output_Thread {
|
||||
/* This is malloced for use in a Win32 thread */
|
||||
HANDLE fd;
|
||||
int nonblocking; /* non-zero => an NT pipe where non-blocking WriteFile
|
||||
works. We still use a thread to detect when the
|
||||
write has ben flushed, which in turn is needed to
|
||||
know whether future writes will immediately succeed. */
|
||||
volatile flushed, needflush; /* Used for non-blocking, only. The flushed
|
||||
flag communicates from the flush-testing thread
|
||||
to the main thread. For efficiency, we request
|
||||
flush checking only when needed (instead of
|
||||
after every write); needflush indicates that
|
||||
a flush check is currently needed, but hasn't
|
||||
been started. */
|
||||
volatile int done, err_no;
|
||||
volatile unsigned int buflen, bufstart, bufend; /* used for blocking, only */
|
||||
unsigned char *buffer; /* used for blocking, only */
|
||||
int *refcount;
|
||||
HANDLE lock_sema, work_sema, ready_sema, you_clean_up_sema;
|
||||
/* lock_sema protects the fields, work_sema starts the flush or
|
||||
flush-checking thread to work, ready_sema indicates that a flush
|
||||
finished, and you_clean_up_sema is essentially a reference
|
||||
count */
|
||||
HANDLE thread;
|
||||
} Win_FD_Output_Thread;
|
||||
|
||||
# define RKTIO_FD_BUFFSIZE 4096
|
||||
|
||||
#endif
|
||||
|
||||
/*========================================================================*/
|
||||
/* creating an fd */
|
||||
/*========================================================================*/
|
||||
|
||||
static void init_read_fd(rktio_t *rktio, rktio_fd_t *rfd)
|
||||
{
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
# ifdef SOME_FDS_ARE_NOT_SELECTABLE
|
||||
|
@ -60,17 +112,18 @@ static void init_read_fd(rktio_fd_t *rfd)
|
|||
Win_FD_Input_Thread *th;
|
||||
DWORD id;
|
||||
HANDLE h;
|
||||
OS_SEMAPHORE_TYPE sm;
|
||||
HANDLE sm;
|
||||
char *bfr;
|
||||
|
||||
th = malloc(sizeof(Win_FD_Input_Thread));
|
||||
rfd->th = th;
|
||||
|
||||
/* Replace buffer with a malloced one: */
|
||||
bfr = malloc(MZPORT_FD_BUFFSIZE);
|
||||
fip->buffer = bfr;
|
||||
bfr = malloc(RKTIO_FD_BUFFSIZE);
|
||||
rfd->buffer = bfr;
|
||||
th->buffer = bfr;
|
||||
|
||||
th->fd = (HANDLE)fd;
|
||||
th->fd = rfd->fd;
|
||||
th->avail = 0;
|
||||
th->err = 0;
|
||||
th->eof = NULL;
|
||||
|
@ -123,7 +176,7 @@ rktio_fd_t *rktio_system_fd(rktio_t *rktio, intptr_t system_fd, int modes)
|
|||
#endif
|
||||
|
||||
if (modes & RKTIO_OPEN_READ)
|
||||
init_read_fd(rfd);
|
||||
init_read_fd(rktio, rfd);
|
||||
|
||||
return rfd;
|
||||
}
|
||||
|
@ -192,9 +245,9 @@ rktio_fd_t *rktio_dup(rktio_t *rktio, rktio_fd_t *rfd)
|
|||
#endif
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
/* closing */
|
||||
/*************************************************************/
|
||||
/*========================================================================*/
|
||||
/* closing */
|
||||
/*========================================================================*/
|
||||
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
void rktio_reliably_close(intptr_t s) {
|
||||
|
@ -288,9 +341,9 @@ void rktio_forget(rktio_t *rktio, rktio_fd_t *rfd)
|
|||
free(rfd);
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
/* polling */
|
||||
/*************************************************************/
|
||||
/*========================================================================*/
|
||||
/* polling */
|
||||
/*========================================================================*/
|
||||
|
||||
#ifdef SOME_FDS_ARE_NOT_SELECTABLE
|
||||
static int try_get_fd_char(int fd, int *ready)
|
||||
|
@ -477,7 +530,7 @@ int poll_write_ready_or_flushed(rktio_t *rktio, rktio_fd_t *rfd, int check_flush
|
|||
} else
|
||||
retval = (oth->err_no || (check_flushed
|
||||
? !oth->buflen
|
||||
: (oth->buflen < MZPORT_FD_BUFFSIZE)));
|
||||
: (oth->buflen < RKTIO_FD_BUFFSIZE)));
|
||||
if (!retval && !check_flushed)
|
||||
WaitForSingleObject(oth->ready_sema, 0); /* clear any leftover state */
|
||||
ReleaseSemaphore(oth->lock_sema, 1, NULL);
|
||||
|
@ -562,9 +615,9 @@ void rktio_poll_add(rktio_t *rktio, rktio_fd_t *rfd, rktio_poll_set_t *fds, int
|
|||
#endif
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
/* reading */
|
||||
/*************************************************************/
|
||||
/*========================================================================*/
|
||||
/* reading */
|
||||
/*========================================================================*/
|
||||
|
||||
intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
|
||||
{
|
||||
|
@ -671,7 +724,7 @@ static long WINAPI WindowsFDReader(Win_FD_Input_Thread *th)
|
|||
|
||||
if (GetFileType((HANDLE)th->fd) == FILE_TYPE_PIPE) {
|
||||
/* Reading from a pipe will return early when data is available. */
|
||||
toget = MZPORT_FD_BUFFSIZE;
|
||||
toget = RKTIO_FD_BUFFSIZE;
|
||||
} else {
|
||||
/* Non-pipe: get one char at a time: */
|
||||
toget = 1;
|
||||
|
@ -735,9 +788,9 @@ static void WindowsFDICleanup(Win_FD_Input_Thread *th)
|
|||
|
||||
#endif
|
||||
|
||||
/*************************************************************/
|
||||
/* writing */
|
||||
/*************************************************************/
|
||||
/*========================================================================*/
|
||||
/* writing */
|
||||
/*========================================================================*/
|
||||
|
||||
intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
|
||||
{
|
||||
|
@ -914,7 +967,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
|
|||
HANDLE h;
|
||||
DWORD id;
|
||||
unsigned char *bfr;
|
||||
OS_SEMAPHORE_TYPE sm;
|
||||
HANDLE sm;
|
||||
|
||||
oth = malloc(sizeof(Win_FD_Output_Thread));
|
||||
rfd->oth = oth;
|
||||
|
@ -922,7 +975,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
|
|||
oth->nonblocking = nonblocking;
|
||||
|
||||
if (!nonblocking) {
|
||||
bfr = malloc(MZPORT_FD_BUFFSIZE);
|
||||
bfr = malloc(RKTIO_FD_BUFFSIZE);
|
||||
oth->buffer = bfr;
|
||||
oth->flushed = 0;
|
||||
oth->needflush = 0;
|
||||
|
@ -975,7 +1028,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
|
|||
if (oth->err_no) {
|
||||
errsaved = oth->err_no;
|
||||
ok = 0;
|
||||
} else if (oth->buflen == MZPORT_FD_BUFFSIZE) {
|
||||
} else if (oth->buflen == RKTIO_FD_BUFFSIZE) {
|
||||
WaitForSingleObject(oth->ready_sema, 0); /* clear any leftover state */
|
||||
ok = 1;
|
||||
} else {
|
||||
|
@ -993,7 +1046,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
|
|||
|
||||
if (oth->bufstart <= oth->bufend) {
|
||||
was_pre = 1;
|
||||
topp = MZPORT_FD_BUFFSIZE;
|
||||
topp = RKTIO_FD_BUFFSIZE;
|
||||
} else {
|
||||
was_pre = 0;
|
||||
topp = oth->bufstart;
|
||||
|
@ -1008,7 +1061,7 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
|
|||
out_len = winwrote;
|
||||
|
||||
oth->bufend += winwrote;
|
||||
if (oth->bufend == MZPORT_FD_BUFFSIZE)
|
||||
if (oth->bufend == RKTIO_FD_BUFFSIZE)
|
||||
oth->bufend = 0;
|
||||
|
||||
if (was_pre) {
|
||||
|
@ -1046,3 +1099,56 @@ intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len
|
|||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* refcounts for Windows fd threads */
|
||||
/*========================================================================*/
|
||||
|
||||
#if defined(WINDOWS_FILE_HANDLES) || defined(MZ_USE_PLACES)
|
||||
# define MZ_LOCK_REFCOUNTS
|
||||
static mzrt_mutex *refcount_mutex;
|
||||
#endif
|
||||
|
||||
static int *malloc_refcount(int val, int free_on_zero)
|
||||
{
|
||||
int *rc;
|
||||
|
||||
#ifdef MZ_LOCK_REFCOUNTS
|
||||
if (!refcount_mutex)
|
||||
mzrt_mutex_create(&refcount_mutex);
|
||||
#endif
|
||||
|
||||
rc = (int *)malloc(2 * sizeof(int));
|
||||
*rc = val;
|
||||
rc[1] = free_on_zero;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int adj_refcount(int *refcount, int amt)
|
||||
XFORM_SKIP_PROC
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!refcount)
|
||||
return 0;
|
||||
|
||||
#ifdef MZ_LOCK_REFCOUNTS
|
||||
mzrt_mutex_lock(refcount_mutex);
|
||||
#endif
|
||||
if (amt > 0) {
|
||||
/* don't increment up from 0 */
|
||||
if (*refcount)
|
||||
*refcount += amt;
|
||||
} else
|
||||
*refcount += amt;
|
||||
rc = *refcount;
|
||||
#ifdef MZ_LOCK_REFCOUNTS
|
||||
mzrt_mutex_unlock(refcount_mutex);
|
||||
#endif
|
||||
|
||||
if (!rc && refcount[1])
|
||||
free(refcount);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
#include <grp.h>
|
||||
#include <dirent.h>
|
||||
#endif
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
# include <shlobj.h>
|
||||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
# define A_PATH_SEP '/'
|
||||
|
@ -52,7 +55,7 @@ typedef struct group_member_cache_entry_t {
|
|||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
static int procs_initied = 0;
|
||||
static int procs_inited = 0;
|
||||
typedef BOOLEAN (WINAPI*CreateSymbolicLinkProc_t)(wchar_t *dest, wchar_t *src, DWORD flags);
|
||||
static CreateSymbolicLinkProc_t CreateSymbolicLinkProc = NULL;
|
||||
|
||||
|
@ -60,6 +63,12 @@ typedef BOOL (WINAPI*DeviceIoControlProc_t)(HANDLE hDevice, DWORD dwIoControlCod
|
|||
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
|
||||
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped);
|
||||
static DeviceIoControlProc_t DeviceIoControlProc;
|
||||
|
||||
typedef DWORD (WINAPI*GetFinalPathNameByHandle_t)(HANDLE hFile, wchar_t *lpszFilePath,
|
||||
DWORD cchFilePath, DWORD dwFlags);
|
||||
GetFinalPathNameByHandle_t GetFinalPathNameByHandleProc;
|
||||
|
||||
# define rktioFILE_NAME_NORMALIZED 0x0
|
||||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
|
@ -74,6 +83,7 @@ static void init_procs()
|
|||
|
||||
CreateSymbolicLinkProc = (CreateSymbolicLinkProc_t)GetProcAddress(hm, "CreateSymbolicLinkW");
|
||||
DeviceIoControlProc = (DeviceIoControlProc_t)GetProcAddress(hm, "DeviceIoControl");
|
||||
GetFinalPathNameByHandleProc = (GetFinalPathNameByHandle_t)GetProcAddress(hm, "GetFinalPathNameByHandleW");
|
||||
|
||||
FreeLibrary(hm);
|
||||
}
|
||||
|
@ -81,9 +91,9 @@ static void init_procs()
|
|||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
# define MZ_UNC_READ RKTIO_PERMISSION_READ
|
||||
# define MZ_UNC_WRITE RKTIO_PERMISSION_WRITE
|
||||
# define MZ_UNC_EXEC RKTIO_PERMISSION_EXEC
|
||||
# define RKTIO_UNC_READ RKTIO_PERMISSION_READ
|
||||
# define RKTIO_UNC_WRITE RKTIO_PERMISSION_WRITE
|
||||
# define RKTIO_UNC_EXEC RKTIO_PERMISSION_EXEC
|
||||
|
||||
# define FIND_FIRST FindFirstFileW
|
||||
# define FIND_NEXT FindNextFileW
|
||||
|
@ -199,7 +209,7 @@ typedef struct mz_REPARSE_DATA_BUFFER {
|
|||
#define mzFILE_FLAG_OPEN_REPARSE_POINT 0x200000
|
||||
#define mzFSCTL_GET_REPARSE_POINT 0x900A8
|
||||
|
||||
static char *UNC_readlink(const char *fn)
|
||||
static char *UNC_readlink(rktio_t *rktio, const char *fn)
|
||||
{
|
||||
HANDLE h;
|
||||
DWORD got;
|
||||
|
@ -307,7 +317,7 @@ static char *UNC_readlink(const char *fn)
|
|||
}
|
||||
|
||||
static int UNC_stat(rktio_t *rktio, const char *dirname, int *flags, int *isdir, int *islink,
|
||||
rktio_timestamp_t **date, rktio_file_size_t *filesize,
|
||||
rktio_timestamp_t **date, rktio_size_t *filesize,
|
||||
const char **resolved_path, int set_flags)
|
||||
/* dirname must be absolute */
|
||||
{
|
||||
|
@ -390,7 +400,7 @@ static int UNC_stat(rktio_t *rktio, const char *dirname, int *flags, int *isdir,
|
|||
the path from the handle. */
|
||||
HANDLE h;
|
||||
wchar_t *dest = NULL;
|
||||
DWORD len = 255;
|
||||
DWORD len = 255, dest_len;
|
||||
|
||||
h = CreateFileW(WIDE_PATH_temp(copy), FILE_READ_ATTRIBUTES,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
||||
|
@ -408,7 +418,7 @@ static int UNC_stat(rktio_t *rktio, const char *dirname, int *flags, int *isdir,
|
|||
if (dest) free(dest);
|
||||
dest_len = len + 1;
|
||||
dest = malloc(dest_len);
|
||||
len = GetFinalPathNameByHandleW(h, dest, dest_len, FILE_NAME_NORMALIZED);
|
||||
len = GetFinalPathNameByHandleProcW(h, dest, dest_len, rktioFILE_NAME_NORMALIZED);
|
||||
} while (len > dest_len);
|
||||
|
||||
if (!len) {
|
||||
|
@ -435,7 +445,7 @@ static int UNC_stat(rktio_t *rktio, const char *dirname, int *flags, int *isdir,
|
|||
if (set_flags != -1) {
|
||||
DWORD attrs = GET_FF_ATTRIBS(fad);
|
||||
|
||||
if (!(set_flags & MZ_UNC_WRITE))
|
||||
if (!(set_flags & RKTIO_UNC_WRITE))
|
||||
attrs |= FF_A_RDONLY;
|
||||
else if (attrs & FF_A_RDONLY)
|
||||
attrs -= FF_A_RDONLY;
|
||||
|
@ -452,7 +462,7 @@ static int UNC_stat(rktio_t *rktio, const char *dirname, int *flags, int *isdir,
|
|||
return 0;
|
||||
}
|
||||
if (flags)
|
||||
*flags = MZ_UNC_READ | MZ_UNC_EXEC | ((GET_FF_ATTRIBS(fad) & FF_A_RDONLY) ? 0 : MZ_UNC_WRITE);
|
||||
*flags = RKTIO_UNC_READ | RKTIO_UNC_EXEC | ((GET_FF_ATTRIBS(fad) & FF_A_RDONLY) ? 0 : RKTIO_UNC_WRITE);
|
||||
if (date) {
|
||||
rktio_timestamp_t *dt;
|
||||
time_t mdt;
|
||||
|
@ -736,11 +746,11 @@ rktio_identity_t *rktio_path_identity(rktio_t *rktio, char *path, int follow_lin
|
|||
}
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
static int enable_write_permission(const char *fn)
|
||||
static int enable_write_permission(rktio_t *rktio, const char *fn)
|
||||
{
|
||||
int flags;
|
||||
|
||||
return UNC_stat(rktio, fn, &flags, NULL, NULL, NULL, NULL, NULL, MZ_UNC_WRITE);
|
||||
return UNC_stat(rktio, fn, &flags, NULL, NULL, NULL, NULL, NULL, RKTIO_UNC_WRITE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -755,7 +765,7 @@ int rktio_delete_file(rktio_t *rktio, char *fn, int enable_write_on_fail)
|
|||
if ((errid == ERROR_ACCESS_DENIED) && enable_write_on_fail) {
|
||||
/* Maybe it's just that the file has no write permission. Provide a more
|
||||
Unix-like experience by attempting to change the file's permission. */
|
||||
if (enable_write_permission(fn)) {
|
||||
if (enable_write_permission(rktio, fn)) {
|
||||
if (DeleteFileW(WIDE_PATH_temp(fn)))
|
||||
return 1;
|
||||
}
|
||||
|
@ -830,9 +840,10 @@ int rktio_rename_file(rktio_t *rktio, char *dest, char *src, int exists_ok)
|
|||
char *rktio_readlink(rktio_t *rktio, char *fullfilename)
|
||||
{
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
int is_link;
|
||||
if (UNC_stat(rktio, fullfilename, NULL, NULL, &is_link, NULL, NULL, NULL, -1)
|
||||
&& is_link) {
|
||||
return UNC_readlink(fullfilename);
|
||||
return UNC_readlink(rktio, fullfilename);
|
||||
} else {
|
||||
set_racket_error(RKTIO_ERROR_NOT_A_LINK);
|
||||
return NULL;
|
||||
|
@ -918,7 +929,7 @@ int rktio_delete_directory(rktio_t *rktio, char *filename, char *current_directo
|
|||
tried_cwd = 1;
|
||||
} else if ((errno == EACCES) && !tried_perm && enable_write_on_fail) {
|
||||
/* Maybe the directory doesn't have write permission. */
|
||||
(void)enable_write_permission(filename);
|
||||
(void)enable_write_permission(rktio, filename);
|
||||
tried_perm = 1;
|
||||
}
|
||||
# endif
|
||||
|
@ -940,7 +951,7 @@ int rktio_make_link(rktio_t *rktio, char *src, char *dest, int dest_is_directory
|
|||
|
||||
if (CreateSymbolicLinkProc) {
|
||||
int flags;
|
||||
wchar_t *src_w = WIDE_PATH_COPY(src);
|
||||
wchar_t *src_w = WIDE_PATH_copy(src);
|
||||
|
||||
if (dest_is_directory)
|
||||
flags = 0x1; /* directory */
|
||||
|
@ -1181,13 +1192,10 @@ int rktio_get_file_or_directory_permissions(rktio_t *rktio, char *filename, int
|
|||
int flags;
|
||||
|
||||
if (UNC_stat(rktio, filename, &flags, NULL, NULL, NULL, NULL, NULL, -1)) {
|
||||
if (as_bits)
|
||||
if (all_bits)
|
||||
return (flags | (flags << 3) | (flags << 6));
|
||||
else {
|
||||
return ((read ? MZ_UNC_READ : 0)
|
||||
| (write ? MZ_UNC_WRITE : 0)
|
||||
| (execute ? MZ_UNC_EXEC : 0));
|
||||
}
|
||||
else
|
||||
return flags;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
@ -1219,12 +1227,12 @@ int rktio_set_file_or_directory_permissions(rktio_t *rktio, char *filename, int
|
|||
# ifdef RKTIO_SYSTEM_WINDOWS
|
||||
{
|
||||
int len = strlen(filename);
|
||||
int ALWAYS_SET_BITS = ((MZ_UNC_READ | MZ_UNC_EXEC)
|
||||
| ((MZ_UNC_READ | MZ_UNC_EXEC) << 3)
|
||||
| ((MZ_UNC_READ | MZ_UNC_EXEC) << 6));
|
||||
int ALWAYS_SET_BITS = ((RKTIO_UNC_READ | RKTIO_UNC_EXEC)
|
||||
| ((RKTIO_UNC_READ | RKTIO_UNC_EXEC) << 3)
|
||||
| ((RKTIO_UNC_READ | RKTIO_UNC_EXEC) << 6));
|
||||
if (((new_bits & ALWAYS_SET_BITS) != ALWAYS_SET_BITS)
|
||||
|| ((new_bits & MZ_UNC_WRITE) != ((new_bits & (MZ_UNC_WRITE << 3)) >> 3))
|
||||
|| ((new_bits & MZ_UNC_WRITE) != ((new_bits & (MZ_UNC_WRITE << 6)) >> 6))
|
||||
|| ((new_bits & RKTIO_UNC_WRITE) != ((new_bits & (RKTIO_UNC_WRITE << 3)) >> 3))
|
||||
|| ((new_bits & RKTIO_UNC_WRITE) != ((new_bits & (RKTIO_UNC_WRITE << 6)) >> 6))
|
||||
|| (new_bits >= (1 << 9))) {
|
||||
set_racket_error(RKTIO_ERROR_BAD_PERMISSION);
|
||||
return 0;
|
||||
|
@ -1244,7 +1252,10 @@ rktio_size_t *rktio_file_size(rktio_t *rktio, char *filename)
|
|||
rktio_size_t *sz = NULL;
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
{
|
||||
if (UNC_stat(rktio, filename, NULL, NULL, NULL, NULL, &sz, NULL, -1)) {
|
||||
rktio_size_t sz_v;
|
||||
if (UNC_stat(rktio, filename, NULL, NULL, NULL, NULL, &sz_v, NULL, -1)) {
|
||||
sz = malloc(sizeof(rktio_size_t));
|
||||
*sz = sz_v;
|
||||
return sz;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -1283,9 +1294,10 @@ rktio_size_t *rktio_file_size(rktio_t *rktio, char *filename)
|
|||
/* directory list */
|
||||
/*========================================================================*/
|
||||
|
||||
#ifdef USE_FINDFIRST
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
|
||||
struct rktio_directory_list_t {
|
||||
int first_ready;
|
||||
FF_HANDLE_TYPE hfile;
|
||||
FF_TYPE info;
|
||||
};
|
||||
|
@ -1361,7 +1373,7 @@ rktio_directory_list_t *rktio_directory_list_start(rktio_t *rktio, char *filenam
|
|||
}
|
||||
|
||||
dl = malloc(sizeof(rktio_directory_list_t));
|
||||
memcpy(&dl->info, &info);
|
||||
memcpy(&dl->info, &info, sizeof(info));
|
||||
dl->hfile = hfile;
|
||||
|
||||
return dl;
|
||||
|
@ -1377,7 +1389,7 @@ char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl)
|
|||
&& !GET_FF_NAME(dl->info)[2]))) {
|
||||
/* skip . and .. */
|
||||
} else {
|
||||
return NARROW_PATH_copy(info.cFileName);
|
||||
return NARROW_PATH_copy(dl->info.cFileName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1600,7 +1612,7 @@ char **rktio_filesystem_root_list(rktio_t *rktio)
|
|||
char drives[DRIVE_BUF_SIZE], *s;
|
||||
intptr_t len, ds, ss_len, ss_count = 0;
|
||||
UINT oldmode;
|
||||
char **ss, *new_ss;
|
||||
char **ss, **new_ss;
|
||||
|
||||
len = GetLogicalDriveStrings(DRIVE_BUF_SIZE, drives);
|
||||
if (len <= DRIVE_BUF_SIZE)
|
||||
|
@ -1618,7 +1630,7 @@ char **rktio_filesystem_root_list(rktio_t *rktio)
|
|||
while (s[ds]) {
|
||||
DWORD a, b, c, d;
|
||||
/* GetDiskFreeSpace effectively checks whether we can read the disk: */
|
||||
if (GetDiskFreeSpace(s XFORM_OK_PLUS ds, &a, &b, &c, &d)) {
|
||||
if (GetDiskFreeSpace(s + ds, &a, &b, &c, &d)) {
|
||||
if ((ss_count + 1) == ss_len) {
|
||||
new_ss = malloc(sizeof(char*) * ss_len * 2);
|
||||
mempcy(ss, new_ss, ss_count * sizeof(char*));
|
||||
|
@ -1628,11 +1640,11 @@ char **rktio_filesystem_root_list(rktio_t *rktio)
|
|||
|
||||
ss[ss_count++] = strdup(s + ds);
|
||||
}
|
||||
ds += strlen(s XFORM_OK_PLUS ds) + 1;
|
||||
ds += strlen(s + ds) + 1;
|
||||
}
|
||||
SetErrorMode(oldmode);
|
||||
|
||||
if (s != drived)
|
||||
if (s != drives)
|
||||
free(s);
|
||||
|
||||
ss[ss_count] = 0;
|
||||
|
@ -1681,14 +1693,16 @@ char *rktio_expand_user_tilde(rktio_t *rktio, char *filename) {
|
|||
user[u] = 0;
|
||||
|
||||
if (!user[0]) {
|
||||
if (!(home = getenv("HOME"))) {
|
||||
if (!(home = rktio_getenv(rktio, "HOME"))) {
|
||||
char *ptr;
|
||||
|
||||
ptr = getenv("USER");
|
||||
ptr = rktio_getenv(rktio, "USER");
|
||||
if (!ptr)
|
||||
ptr = getenv("LOGNAME");
|
||||
ptr = rktio_getenv(rktio, "LOGNAME");
|
||||
|
||||
who = ptr ? getpwnam(ptr) : NULL;
|
||||
|
||||
if (ptr) free(ptr);
|
||||
|
||||
if (!who)
|
||||
who = getpwuid(getuid());
|
||||
|
@ -1696,8 +1710,8 @@ char *rktio_expand_user_tilde(rktio_t *rktio, char *filename) {
|
|||
} else
|
||||
who = getpwnam(user);
|
||||
|
||||
if (!home && who)
|
||||
home = who->pw_dir;
|
||||
if (!home && who && who->pw_dir)
|
||||
home = strdup(who->pw_dir);
|
||||
|
||||
if (!home) {
|
||||
set_racket_error(RKTIO_ERROR_UNKNOWN_USER);
|
||||
|
@ -1716,6 +1730,8 @@ char *rktio_expand_user_tilde(rktio_t *rktio, char *filename) {
|
|||
memcpy(naya + len + 1, filename + f + 1, flen);
|
||||
naya[len + flen + 1] = 0;
|
||||
|
||||
free(home);
|
||||
|
||||
filename = naya;
|
||||
|
||||
return filename;
|
||||
|
@ -1756,9 +1772,11 @@ char *rktio_system_path(rktio_t *rktio, int which)
|
|||
if (which == RKTIO_PATH_TEMP_DIR) {
|
||||
char *p;
|
||||
|
||||
if ((p = getenv("TMPDIR"))) {
|
||||
if ((p = rktio_getenv(rktio, "TMPDIR"))) {
|
||||
if (rktio_directory_exists(rktio, p))
|
||||
return strdup(p);
|
||||
return p;
|
||||
else
|
||||
free(p);
|
||||
}
|
||||
|
||||
if (rktio_directory_exists(rktio, "/var/tmp"))
|
||||
|
@ -1777,9 +1795,6 @@ char *rktio_system_path(rktio_t *rktio, int which)
|
|||
/* Everything else is in ~: */
|
||||
char *home_str, *ex_home, *alt_home, *home;
|
||||
|
||||
/* cast here avoids a clang warning: */
|
||||
# define mz_STR_OFFSET(s, d) ((const char *)s XFORM_OK_PLUS d)
|
||||
|
||||
if ((which == RKTIO_PATH_PREF_DIR)
|
||||
|| (which == RKTIO_PATH_PREF_FILE)
|
||||
|| (which == RKTIO_PATH_ADDON_DIR)) {
|
||||
|
@ -1802,9 +1817,9 @@ char *rktio_system_path(rktio_t *rktio, int which)
|
|||
home_str = "~/";
|
||||
}
|
||||
|
||||
alt_home = getenv("PLTUSERHOME");
|
||||
alt_home = rktio_getenv(rktio, "PLTUSERHOME");
|
||||
if (alt_home)
|
||||
home = append_paths(alt_home, home_str + 2, 0, 0);
|
||||
home = append_paths(alt_home, home_str + 2, 1, 0);
|
||||
else {
|
||||
home = rktio_expand_user_tilde(rktio, home_str);
|
||||
|
||||
|
@ -1846,22 +1861,25 @@ char *rktio_system_path(rktio_t *rktio, int which)
|
|||
|
||||
{
|
||||
char *d, *p;
|
||||
Scheme_Object *home;
|
||||
char *home;
|
||||
|
||||
if (which == RKTIO_PATH_TEMP_DIR) {
|
||||
if ((p = getenv("TMP")) || (p = getenv("TEMP"))) {
|
||||
if (p && rktio_directory_exists(p))
|
||||
return strdup(p);
|
||||
if ((p = rktio_getenv(rktio, "TMP")) || (p = rktio_getenv(rktio, "TEMP"))) {
|
||||
if (p) {
|
||||
if (rktio_directory_exists(rktio, p))
|
||||
return p;
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
return rktio_current_drectory();
|
||||
return rktio_get_current_directory(rktio);
|
||||
}
|
||||
|
||||
home = NULL;
|
||||
|
||||
p = getenv("PLTUSERHOME");
|
||||
p = rktio_getenv(rktio, "PLTUSERHOME");
|
||||
if (p)
|
||||
home = strdup(p);
|
||||
home = p;
|
||||
|
||||
if (!home) {
|
||||
/* Try to get Application Data directory: */
|
||||
|
@ -1904,20 +1922,23 @@ char *rktio_system_path(rktio_t *rktio, int which)
|
|||
|
||||
if (!home) {
|
||||
/* Back-up: try USERPROFILE environment variable */
|
||||
d = getenv("USERPROFILE");
|
||||
if (d && rktio_directory_exists(d))
|
||||
return strdup(d);
|
||||
d = rktio_getenv(rktio, "USERPROFILE");
|
||||
if (d) {
|
||||
if (rktio_directory_exists(rktio, d))
|
||||
return d;
|
||||
free(d);
|
||||
}
|
||||
}
|
||||
|
||||
if (!home) {
|
||||
/* Last-ditch effort: try HOMEDRIVE+HOMEPATH */
|
||||
d = getenv("HOMEDRIVE");
|
||||
p = getenv("HOMEPATH");
|
||||
d = rktio_getenv(rktio, "HOMEDRIVE");
|
||||
p = rktio_getenv(rktio, "HOMEPATH");
|
||||
|
||||
if (d && p) {
|
||||
home = append_paths(d, p);
|
||||
home = append_paths(d, p, 1, 1);
|
||||
|
||||
if (rktio_directory_exists(home))
|
||||
if (rktio_directory_exists(rktio, home))
|
||||
return home;
|
||||
else {
|
||||
free(home);
|
||||
|
@ -1931,7 +1952,7 @@ char *rktio_system_path(rktio_t *rktio, int which)
|
|||
|
||||
if (!GetModuleFileNameW(NULL, name, 1024)) {
|
||||
/* Disaster. Use CWD. */
|
||||
home = rktio_current_drectory();
|
||||
home = rktio_get_current_directory(rktio);
|
||||
if (!home)
|
||||
return NULL;
|
||||
} else {
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
# define USE_DYNAMIC_FDSET_SIZE
|
||||
#endif
|
||||
|
||||
#if RKTIO_SYSTEM_WINDOWS
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
# define USE_FAR_RKTIO_FDCALLS
|
||||
#endif
|
||||
#ifdef USE_DYNAMIC_FDSET_SIZE
|
||||
|
@ -50,7 +50,7 @@ struct rktio_t {
|
|||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
int windows_nt_or_later;
|
||||
HANDLE break_semaphore;
|
||||
int wsr_size = 0;
|
||||
int wsr_size;
|
||||
struct rktio_socket_t *wsr_array;
|
||||
#endif
|
||||
#ifdef USE_FAR_RKTIO_FDCALLS
|
||||
|
@ -86,6 +86,11 @@ struct rktio_t {
|
|||
#ifdef HAVE_INOTIFY_SYSCALL
|
||||
struct rin_inotify_state_t *inotify_server;
|
||||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
intptr_t wide_buffer_size;
|
||||
wchar_t *wide_buffer;
|
||||
#endif
|
||||
};
|
||||
|
||||
/*========================================================================*/
|
||||
|
@ -188,7 +193,7 @@ int rktio_process_init(rktio_t *rktio);
|
|||
void rktio_process_deinit(rktio_t *rktio);
|
||||
|
||||
/*========================================================================*/
|
||||
/* Misc */
|
||||
/* Strings */
|
||||
/*========================================================================*/
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
|
@ -201,6 +206,23 @@ void rktio_process_deinit(rktio_t *rktio);
|
|||
# define MSC_WIDE_PATH_temp(n) n
|
||||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
|
||||
wchar_t *rktio_convert_to_wchar(rktio_t *rktio, const char *s, int do_copy);
|
||||
char *rktio_convert_from_wchar(const wchar_t *ws, int free_given);
|
||||
|
||||
# define WIDE_PATH_temp(s) rktio_convert_to_wchar(rktio, s, 0)
|
||||
# define WIDE_PATH_copy(s) rktio_convert_to_wchar(rktio, s, 1)
|
||||
|
||||
# define NARROW_PATH_copy(ws) rktio_convert_from_wchar(ws, 0)
|
||||
# define NARROW_PATH_copy_then_free(ws) rktio_convert_from_wchar(ws, 1)
|
||||
|
||||
#endif
|
||||
|
||||
/*========================================================================*/
|
||||
/* Misc */
|
||||
/*========================================================================*/
|
||||
|
||||
void rktio_get_posix_error(rktio_t *rktio);
|
||||
#define get_posix_error() rktio_get_posix_error(rktio)
|
||||
|
||||
|
|
324
racket/src/rktio/rktio_wide.c
Normal file
324
racket/src/rktio/rktio_wide.c
Normal file
|
@ -0,0 +1,324 @@
|
|||
#include "rktio.h"
|
||||
#include "rktio_private.h"
|
||||
|
||||
/* For converting byte strings to and from "wide" strings on Windows. */
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* A UTF-8 to UTF-16 conversion, but accepts an extended variant of
|
||||
UTF-16 that accommodates unpaired surrogates, so that all 16-byte
|
||||
sequences are accessible. */
|
||||
static intptr_t utf8ish_to_utf16ish(const unsigned char *s, intptr_t end, unsigned short *us, int replacement)
|
||||
{
|
||||
intptr_t i, j, oki;
|
||||
int state;
|
||||
int init_doki;
|
||||
int nextbits, v;
|
||||
unsigned int sc;
|
||||
int pending_surrogate = 0;
|
||||
|
||||
state = 0;
|
||||
init_doki = 0;
|
||||
nextbits = 0;
|
||||
v = 0;
|
||||
|
||||
oki = 0;
|
||||
j = 0;
|
||||
i = 0;
|
||||
while (i < end) {
|
||||
sc = s[i];
|
||||
if (sc < 0x80) {
|
||||
if (state) {
|
||||
/* In a sequence, but didn't continue */
|
||||
state = 0;
|
||||
nextbits = 0;
|
||||
v = replacement;
|
||||
i = oki;
|
||||
j += init_doki;
|
||||
} else {
|
||||
v = sc;
|
||||
}
|
||||
} else if ((sc & 0xC0) == 0x80) {
|
||||
/* Continues a sequence ... */
|
||||
if (state) {
|
||||
/* ... and we're in one ... */
|
||||
if (!nextbits || (sc & nextbits)) {
|
||||
/* and we have required bits. */
|
||||
v = (v << 6) + (sc & 0x3F);
|
||||
nextbits = 0;
|
||||
--state;
|
||||
if (state) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
/* We finished. One last check: */
|
||||
if (v > 0x10FFFF) {
|
||||
/* illegal code units */
|
||||
v = replacement;
|
||||
j += init_doki;
|
||||
i = oki;
|
||||
}
|
||||
} else {
|
||||
/* ... but we're missing required bits. */
|
||||
state = 0;
|
||||
nextbits = 0;
|
||||
v = replacement;
|
||||
j += init_doki;
|
||||
i = oki;
|
||||
}
|
||||
} else {
|
||||
/* ... but we're not in one */
|
||||
v = replacement;
|
||||
}
|
||||
} else if (state) {
|
||||
/* bad: already in a sequence */
|
||||
state = 0;
|
||||
v = replacement;
|
||||
i = oki;
|
||||
j += init_doki;
|
||||
} else {
|
||||
if ((sc & 0xE0) == 0xC0) {
|
||||
if (sc & 0x1E) {
|
||||
state = 1;
|
||||
v = (sc & 0x1F);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
/* else too small */
|
||||
} else if ((sc & 0xF0) == 0xE0) {
|
||||
state = 2;
|
||||
v = (sc & 0xF);
|
||||
if (!v)
|
||||
nextbits = 0x20;
|
||||
i++;
|
||||
continue;
|
||||
} else if ((sc & 0xF8) == 0xF0) {
|
||||
v = (sc & 0x7);
|
||||
if (v <= 4) {
|
||||
state = 3;
|
||||
if (!v)
|
||||
nextbits = 0x30;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
/* Else will be larger than 0x10FFFF, so fail */
|
||||
}
|
||||
/* Too small, or 0xFF or 0xFe, or start of a 5- or 6-byte sequence */
|
||||
v = replacement;
|
||||
}
|
||||
|
||||
/* If we get here, we're supposed to output v */
|
||||
|
||||
if (v > 0xFFFF) {
|
||||
if (pending_surrogate) {
|
||||
/* Accept previously written unpaired surrogate */
|
||||
if (us)
|
||||
us[j] = pending_surrogate;
|
||||
j++;
|
||||
pending_surrogate = 0;
|
||||
}
|
||||
|
||||
if (us) {
|
||||
v -= 0x10000;
|
||||
us[j] = 0xD800 | ((v >> 10) & 0x3FF);
|
||||
us[j+1] = 0xDC00 | (v & 0x3FF);
|
||||
}
|
||||
j++;
|
||||
} else {
|
||||
/* We allow a surrogate by itself, but don't allow a UTF-8ish a
|
||||
0xDC00 after a UTF-8ish 0xD800, otherwise multiple encodings
|
||||
can map to the same thing. */
|
||||
if ((v >= 0xD800) && (v <= 0xDFFF)) {
|
||||
if (pending_surrogate && ((v & 0xDC00) == 0xDC00)) {
|
||||
/* This would look like a surrogate pair... */
|
||||
/* We need to fill in 6 replacement substitutions,
|
||||
one for each input byte. If we can't put all 6,
|
||||
then don't use any input. */
|
||||
int p;
|
||||
if (us) {
|
||||
for (p = 0; p < 5; p++) {
|
||||
us[j+p] = replacement;
|
||||
}
|
||||
}
|
||||
j += 5;
|
||||
v = replacement;
|
||||
pending_surrogate = 0;
|
||||
} else {
|
||||
if (pending_surrogate) {
|
||||
if (us)
|
||||
us[j] = pending_surrogate;
|
||||
j++; /* Accept previousy written unpaired surrogate */
|
||||
pending_surrogate = 0;
|
||||
}
|
||||
if ((v & 0xDC00) == 0xD800)
|
||||
pending_surrogate = v;
|
||||
else
|
||||
pending_surrogate = 0;
|
||||
}
|
||||
} else {
|
||||
if (pending_surrogate) {
|
||||
if (us)
|
||||
us[j] = pending_surrogate;
|
||||
j++; /* Accept previousy written unpaired surrogate */
|
||||
pending_surrogate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (pending_surrogate)
|
||||
--j; /* don't accept unpaired surrogate, yet */
|
||||
else if (us)
|
||||
us[j] = v;
|
||||
}
|
||||
j++;
|
||||
i++;
|
||||
oki = i;
|
||||
init_doki = 0;
|
||||
}
|
||||
|
||||
if (pending_surrogate) {
|
||||
if (us)
|
||||
us[j] = pending_surrogate;
|
||||
j++;
|
||||
}
|
||||
|
||||
if (state) {
|
||||
for (i = oki; i < end; i++) {
|
||||
if (us)
|
||||
us[j] = replacement;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
/* A UTF-16 to UTF-8 conversion, but unpaired surrogates map to an
|
||||
extended variant of UTF-18, so all 16-byte sequences are
|
||||
encodable. */
|
||||
static intptr_t utf16ish_to_utf8ish(const unsigned short *us, intptr_t end, unsigned char *s)
|
||||
{
|
||||
intptr_t i, j;
|
||||
unsigned int wc;
|
||||
|
||||
j = 0;
|
||||
for (i = 0; i < end; i++) {
|
||||
wc = us[i];
|
||||
if ((wc & 0xF800) == 0xD800) {
|
||||
/* Unparse surrogates. */
|
||||
if ((wc & 0xFC00) != 0xD800) {
|
||||
/* Count as one */
|
||||
} else if ((i + 1 >= end)
|
||||
|| (((us[i+1]) & 0xFC00) != 0xDC00)) {
|
||||
/* Let the misplaced surrogate through */
|
||||
} else {
|
||||
i++;
|
||||
wc = ((wc & 0x3FF) << 10) + ((us[i]) & 0x3FF);
|
||||
wc += 0x10000;
|
||||
}
|
||||
}
|
||||
if (!s) {
|
||||
if (wc < 0x80) {
|
||||
j += 1;
|
||||
} else if (wc < 0x800) {
|
||||
j += 2;
|
||||
} else if (wc < 0x10000) {
|
||||
j += 3;
|
||||
} else if (wc < 0x200000) {
|
||||
j += 4;
|
||||
} else if (wc < 0x4000000) {
|
||||
j += 5;
|
||||
} else {
|
||||
j += 6;
|
||||
}
|
||||
} else {
|
||||
if (wc < 0x80) {
|
||||
s[j++] = wc;
|
||||
} else if (wc < 0x800) {
|
||||
s[j++] = 0xC0 | ((wc & 0x7C0) >> 6);
|
||||
s[j++] = 0x80 | (wc & 0x3F);
|
||||
} else if (wc < 0x10000) {
|
||||
s[j++] = 0xE0 | ((wc & 0xF000) >> 12);
|
||||
s[j++] = 0x80 | ((wc & 0x0FC0) >> 6);
|
||||
s[j++] = 0x80 | (wc & 0x3F);
|
||||
} else if (wc < 0x200000) {
|
||||
s[j++] = 0xF0 | ((wc & 0x1C0000) >> 18);
|
||||
s[j++] = 0x80 | ((wc & 0x03F000) >> 12);
|
||||
s[j++] = 0x80 | ((wc & 0x000FC0) >> 6);
|
||||
s[j++] = 0x80 | (wc & 0x3F);
|
||||
} else if (wc < 0x4000000) {
|
||||
s[j++] = 0xF8 | ((wc & 0x3000000) >> 24);
|
||||
s[j++] = 0x80 | ((wc & 0x0FC0000) >> 18);
|
||||
s[j++] = 0x80 | ((wc & 0x003F000) >> 12);
|
||||
s[j++] = 0x80 | ((wc & 0x0000FC0) >> 6);
|
||||
s[j++] = 0x80 | (wc & 0x3F);
|
||||
} else {
|
||||
s[j++] = 0xFC | ((wc & 0x40000000) >> 30);
|
||||
s[j++] = 0x80 | ((wc & 0x3F000000) >> 24);
|
||||
s[j++] = 0x80 | ((wc & 0x00FC0000) >> 18);
|
||||
s[j++] = 0x80 | ((wc & 0x0003F000) >> 12);
|
||||
s[j++] = 0x80 | ((wc & 0x00000FC0) >> 6);
|
||||
s[j++] = 0x80 | (wc & 0x3F);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
#define RKTIO_MAX_IDEAL_BUFFER_SIZE 4096
|
||||
|
||||
wchar_t *rktio_convert_to_wchar(rktio_t *rktio, const char *s, int do_copy)
|
||||
/* This function uses '\t' in place of invalid UTF-8 encoding
|
||||
bytes, because '\t' is not a legal filename under Windows. */
|
||||
{
|
||||
intptr_t len, l;
|
||||
wchar_t *ws;
|
||||
|
||||
l = strlen(s)+1; /* add nul terminator */
|
||||
|
||||
len = utf8ish_to_utf16ish((unsigned char *)s, l, NULL, '\t');
|
||||
|
||||
if (do_copy)
|
||||
ws = malloc(sizeof(wchar_t) * len);
|
||||
else if (len > rktio->wide_buffer_size) {
|
||||
free(rktio->wide_buffer);
|
||||
rktio->wide_buffer_size = len;
|
||||
ws = malloc(sizeof(wchar_t) * len);
|
||||
rktio->wide_buffer = ws;
|
||||
} else if ((len < RKTIO_MAX_IDEAL_BUFFER_SIZE)
|
||||
&& (rktio->wide_buffer_size > RKTIO_MAX_IDEAL_BUFFER_SIZE)) {
|
||||
free(rktio->wide_buffer);
|
||||
rktio->wide_buffer_size = RKTIO_MAX_IDEAL_BUFFER_SIZE;
|
||||
ws = malloc(sizeof(wchar_t) * RKTIO_MAX_IDEAL_BUFFER_SIZE);
|
||||
rktio->wide_buffer = ws;
|
||||
}
|
||||
|
||||
(void)utf8ish_to_utf16ish((unsigned char *)s, l, (unsigned short*)ws, '\t');
|
||||
|
||||
return ws;
|
||||
}
|
||||
|
||||
char *rktio_convert_from_wchar(const wchar_t *ws, int free_given)
|
||||
{
|
||||
intptr_t len, l;
|
||||
char *s;
|
||||
|
||||
l = wc_slen(ws) + 1; /* add nul terminator */
|
||||
|
||||
len = utf16ish_to_utf8ish((unsigned short *)ws, l, NULL);
|
||||
|
||||
s = (char *)scheme_malloc_atomic(len);
|
||||
|
||||
len = utf16ish_to_utf8ish((unsigned short *)ws, l, s);
|
||||
|
||||
if (free_given)
|
||||
free((void *)ws);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user