rktio: add iconv

This commit is contained in:
Matthew Flatt 2017-06-21 10:10:35 -06:00
parent db7c242983
commit 6a543f4783
19 changed files with 1071 additions and 671 deletions

67
racket/src/configure vendored
View File

@ -5103,32 +5103,8 @@ fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $using_gnu_cpp" >&5
$as_echo "$using_gnu_cpp" >&6; }
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_langinfo (CODESET)" >&5
$as_echo_n "checking for nl_langinfo (CODESET)... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <langinfo.h>
int
main ()
{
char *codeset = nl_langinfo (CODESET);
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
$as_echo "#define HAVE_CODESET 1" >>confdefs.h
have_codeset=yes
else
have_codeset=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_codeset" >&5
$as_echo "$have_codeset" >&6; }
# Although rktio takes care of iconv, we need to know whether
# to link to it
iconv_lib_flag=""
if test "${skip_iconv_check}" = "no" ; then
if test "${enable_iconv}" = "yes" ; then
@ -5463,40 +5439,8 @@ $as_echo_n "checking $msg... " >&6; }
iconv_usage_result="$enable_iconv$iconv_lib_flag"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $iconv_usage_result" >&5
$as_echo "$iconv_usage_result" >&6; }
if test "${enable_iconv}" = "no" ; then
MZOPTIONS="$MZOPTIONS -DMZ_NO_ICONV"
fi
fi
msg="for mbsrtowcs"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $msg" >&5
$as_echo_n "checking $msg... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <wchar.h>
#include <strings.h>
int main() {
mbstate_t state;
char *src = "X";
bzero(&state, sizeof(mbstate_t));
mbsrtowcs(0, &src, 0, &state);
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
mbsrtowcs=yes
else
mbsrtowcs=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
if test "$mbsrtowcs" = "no" ; then
MZOPTIONS="$MZOPTIONS -DNO_MBTOWC_FUNCTIONS"
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $mbsrtowcs" >&5
$as_echo "$mbsrtowcs" >&6; }
if test "${check_for_mprotect}" = "yes" ; then
msg="for mmap and mprotect"
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $msg" >&5
@ -6892,6 +6836,13 @@ else
SUB_CONFIGURE_EXTRAS="$SUB_CONFIGURE_EXTRAS --disable-pthread"
fi
# Make sure the --enable-iconv result is propagated:
if test "${enable_iconv}" = "yes" ; then
SUB_CONFIGURE_EXTRAS="$SUB_CONFIGURE_EXTRAS --enable-iconv"
else
SUB_CONFIGURE_EXTRAS="$SUB_CONFIGURE_EXTRAS --disable-iconv"
fi
FOREIGNTARGET=
FOREIGN_IF_USED="FOREIGN_NOT_USED"
if test -d "${srcdir}/foreign" && test "${enable_foreign}" = "yes" ; then

View File

@ -1068,14 +1068,8 @@ if test "$using_gnu_cpp" = "yes" ; then
fi
AC_MSG_RESULT($using_gnu_cpp)
AC_MSG_CHECKING([for nl_langinfo (CODESET)])
AC_TRY_LINK([#include <langinfo.h>],
[char *codeset = nl_langinfo (CODESET);],
AC_DEFINE(HAVE_CODESET,1,[Have nl_langinfo (CODESET)])
have_codeset=yes,
have_codeset=no)
AC_MSG_RESULT($have_codeset)
# Although rktio takes care of iconv, we need to know whether
# to link to it
iconv_lib_flag=""
if test "${skip_iconv_check}" = "no" ; then
if test "${enable_iconv}" = "yes" ; then
@ -1113,28 +1107,8 @@ if test "${skip_iconv_check}" = "no" ; then
AC_MSG_CHECKING($msg)
iconv_usage_result="$enable_iconv$iconv_lib_flag"
AC_MSG_RESULT($iconv_usage_result)
if test "${enable_iconv}" = "no" ; then
MZOPTIONS="$MZOPTIONS -DMZ_NO_ICONV"
fi
fi
[ msg="for mbsrtowcs" ]
AC_MSG_CHECKING($msg)
AC_LINK_IFELSE([AC_LANG_SOURCE([
#include <wchar.h>
#include <strings.h>
int main() {
mbstate_t state;
char *src = "X";
bzero(&state, sizeof(mbstate_t));
mbsrtowcs(0, &src, 0, &state);
return 0;
}])], mbsrtowcs=yes, mbsrtowcs=no)
if test "$mbsrtowcs" = "no" ; then
MZOPTIONS="$MZOPTIONS -DNO_MBTOWC_FUNCTIONS"
fi
AC_MSG_RESULT($mbsrtowcs)
if test "${check_for_mprotect}" = "yes" ; then
[ msg="for mmap and mprotect" ]
AC_MSG_CHECKING($msg)
@ -1825,6 +1799,13 @@ else
SUB_CONFIGURE_EXTRAS="$SUB_CONFIGURE_EXTRAS --disable-pthread"
fi
# Make sure the --enable-iconv result is propagated:
if test "${enable_iconv}" = "yes" ; then
SUB_CONFIGURE_EXTRAS="$SUB_CONFIGURE_EXTRAS --enable-iconv"
else
SUB_CONFIGURE_EXTRAS="$SUB_CONFIGURE_EXTRAS --disable-iconv"
fi
FOREIGNTARGET=
FOREIGN_IF_USED="FOREIGN_NOT_USED"
if test -d "${srcdir}/foreign" && test "${enable_foreign}" = "yes" ; then

View File

@ -44,9 +44,6 @@ typedef unsigned long uintptr_t;
/* Direction of stack growth: 1 = up, -1 = down, 0 = unknown. */
#undef STACK_DIRECTION
/* Whether nl_langinfo works. */
#undef HAVE_CODESET
/* Whether __attribute__ ((noinline)) works. */
#undef MZ_USE_NOINLINE

View File

@ -5392,29 +5392,23 @@ void scheme_set_addon_dir(Scheme_Object *p)
#ifdef DOS_FILE_SYSTEM
static wchar_t *dlldir;
wchar_t *scheme_get_dll_path(wchar_t *s)
{
if (dlldir) {
int len1, len2;
wchar_t *p;
len1 = wc_strlen(dlldir);
len2 = wc_strlen(s);
p = (wchar_t *)scheme_malloc_atomic((len1 + len2 + 2) * sizeof(wchar_t));
memcpy(p, dlldir, len1 * sizeof(wchar_t));
if (p[len1 - 1] != '\\') {
p[len1++] = '\\';
}
memcpy(p + len1, s, (len2 + 1) * sizeof(wchar_t));
return p;
} else
return s;
}
void scheme_set_dll_path(wchar_t *p)
{
dlldir = p;
rktio_set_dll_path(p);
}
wchar_t *scheme_get_dll_path(wchar_t *p)
{
wchar_t *r, *r2;
intptr_t len;
r = rktio_get_dll_path(p);
if (!r)
return p;
len = wcslen(r) + 1;
r2 = scheme_malloc_atomic(sizeof(wchar_t) * len);
memcpy(r2, r, sizeof(wchar_t) * len);
free(r);
return r2;
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,7 @@ OBJS = rktio_fs.@LTO@ \
rktio_shellex.@LTO@ \
rktio_time.@LTO@ \
rktio_syslog.@LTO@ \
rktio_convert.@LTO@ \
rktio_error.@LTO@ \
rktio_hash.@LTO@ \
rktio_wide.@LTO@ \
@ -85,6 +86,9 @@ rktio_time.@LTO@: $(srcdir)/rktio_time.c $(RKTIO_HEADERS)
rktio_syslog.@LTO@: $(srcdir)/rktio_syslog.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_syslog.@LTO@ -c $(srcdir)/rktio_syslog.c
rktio_convert.@LTO@: $(srcdir)/rktio_convert.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_convert.@LTO@ -c $(srcdir)/rktio_convert.c
rktio_error.@LTO@: $(srcdir)/rktio_error.c $(RKTIO_HEADERS)
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_error.@LTO@ -c $(srcdir)/rktio_error.c

View File

@ -694,6 +694,8 @@ ac_subst_files=''
ac_user_opts='
enable_option_checking
enable_shared
enable_pthread
enable_iconv
'
ac_precious_vars='build_alias
host_alias
@ -1317,6 +1319,8 @@ Optional Features:
--disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
--enable-FEATURE[=ARG] include FEATURE [ARG=yes]
--enable-shared create shared libraries (ok, but not recommended)
--enable-pthread link with pthreads (usually auto-enabled if needed)
--enable-iconv use iconv (usually auto-enabled)
Some influential environment variables:
CC C compiler command
@ -2243,6 +2247,20 @@ if test "${enable_shared+set}" = set; then :
enableval=$enable_shared;
fi
# Check whether --enable-pthread was given.
if test "${enable_pthread+set}" = set; then :
enableval=$enable_pthread;
fi
# Check whether --enable-iconv was given.
if test "${enable_iconv+set}" = set; then :
enableval=$enable_iconv;
fi
if test "${enable_iconv}" = "" ; then
enable_iconv=yes
fi
###### Autoconfigure #######
@ -3921,9 +3939,39 @@ $as_echo_n "checking $msg... " >&6; }
iconv_usage_result="$enable_iconv$iconv_lib_flag"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $iconv_usage_result" >&5
$as_echo "$iconv_usage_result" >&6; }
if test "${enable_iconv}" = "no" ; then
CFLAGS="$CFLAGS -DRKTIO_NO_ICONV"
fi
fi
if test "${enable_iconv}" = "no" ; then
$as_echo "#define RKTIO_NO_ICON 1" >>confdefs.h
fi
if test "${enable_iconv}" = "yes" ; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nl_langinfo (CODESET)" >&5
$as_echo_n "checking for nl_langinfo (CODESET)... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <langinfo.h>
int
main ()
{
char *codeset = nl_langinfo (CODESET);
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
$as_echo "#define RKTIO_HAVE_CODESET 1" >>confdefs.h
have_codeset=yes
else
have_codeset=no
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_codeset" >&5
$as_echo "$have_codeset" >&6; }
fi
msg="for mbsrtowcs"

View File

@ -11,6 +11,12 @@ AC_CONFIG_AUX_DIR(../lt)
AC_CANONICAL_SYSTEM
AC_ARG_ENABLE(shared, [ --enable-shared create shared libraries (ok, but not recommended)])
AC_ARG_ENABLE(pthread, [ --enable-pthread link with pthreads (usually auto-enabled if needed)])
AC_ARG_ENABLE(iconv, [ --enable-iconv use iconv (usually auto-enabled)])
if test "${enable_iconv}" = "" ; then
enable_iconv=yes
fi
###### Autoconfigure #######
@ -156,9 +162,19 @@ if test "${skip_iconv_check}" = "no" ; then
AC_MSG_CHECKING($msg)
iconv_usage_result="$enable_iconv$iconv_lib_flag"
AC_MSG_RESULT($iconv_usage_result)
if test "${enable_iconv}" = "no" ; then
CFLAGS="$CFLAGS -DRKTIO_NO_ICONV"
fi
fi
if test "${enable_iconv}" = "no" ; then
AC_DEFINE(RKTIO_NO_ICON,1,[Do not use iconv])
fi
if test "${enable_iconv}" = "yes" ; then
AC_MSG_CHECKING([for nl_langinfo (CODESET)])
AC_TRY_LINK([#include <langinfo.h>],
[char *codeset = nl_langinfo (CODESET);],
AC_DEFINE(RKTIO_HAVE_CODESET,1,[Have nl_langinfo (CODESET)])
have_codeset=yes,
have_codeset=no)
AC_MSG_RESULT($have_codeset)
fi
[ msg="for mbsrtowcs" ]

View File

@ -72,6 +72,9 @@ Thread and signal conventions:
# define RKTIO_EXTERN extern
#endif
/*************************************************/
/* Initialization and general datatypes */
typedef struct rktio_t rktio_t;
/* A rktio_t value represents an instance of the Racket I/O system.
Almost every `rktio_...` function takes it as the first argument. */
@ -101,6 +104,24 @@ typedef int rktio_tri_t;
typedef int rktio_bool_t;
/* 0 or 1. */
typedef unsigned short rktio_char16_t;
/* A UTF-16 code unit. A `rktio_char16_t *` is meant to be the same as
`wchar_t *` on Windows. */
/*************************************************/
/* DLL paths */
RKTIO_EXTERN void rktio_set_dll_path(rktio_char16_t *p);
/* Sets a path to search for loading DLLs, such as `iconv` on Windows.
This function departs from all the usual conventions: the given
path is in wide-character format, it's not copied, and it's not
specific to a `rktio_t` instance. */
RKTIO_EXTERN rktio_char16_t *rktio_get_dll_path(rktio_char16_t *p);
/* Combines a path prevously registered with `rktio_set_dll_path` with
the given filename. The result is allocated (as should be
deallocated) as usual. */
/*************************************************/
/* Reading and writing files */
@ -878,11 +899,10 @@ rktio_ok_t rktio_shell_execute(rktio_t *rktio,
/*************************************************/
/* Path conversion */
void *rktio_path_to_wide_path(rktio_t *rktio, const char *p);
char *rktio_wide_path_to_path(rktio_t *rktio, const void *wp);
rktio_char16_t *rktio_path_to_wide_path(rktio_t *rktio, const char *p);
char *rktio_wide_path_to_path(rktio_t *rktio, const rktio_char16_t *wp);
/* Convert to/from the OS's native path representation. These
functions are useful only on Windows, where each `void *`
is actually a `wchar_t*`. The `rktio_path_to_wide_path`
functions are useful only on Windows. The `rktio_path_to_wide_path`
function can fail and report `RKTIO_ERROR_INVALID_PATH`. */
/*************************************************/
@ -904,6 +924,91 @@ enum {
RKTIO_LOG_DEBUG
};
/*************************************************/
/* Encoding conversion */
int rktio_convert_properties(rktio_t *rktio);
/* Returns a combination of the following flags. */
#define RKTIO_CONVERTER_SUPPORTED (1 << 0)
#define RKTIO_CONVERT_STRCOLL_UTF16 (1 << 1)
#define RKTIO_CONVERT_RECASE_UTF16 (1 << 2)
typedef struct rktio_converter_t rktio_converter_t;
rktio_converter_t *rktio_converter_open(rktio_t *rktio, const char *to_enc, const char *from_enc);
/* Creates an encoding converter. */
void rktio_converter_close(rktio_t *rktio, rktio_converter_t *cvt);
/* Destroys an encoding converter. */
intptr_t rktio_convert(rktio_t *rktio,
rktio_converter_t *cvt,
char **in, intptr_t *in_left,
char **out, intptr_t *out_left);
/* Converts some bytes, following the icon protocol: each consumed by
increments `*in` and decrements `*in_left`, and each produced by
increments `*out` and decrements `*out_left`. In case of an error,
the result is `RKTIO_CONVERT_ERROR` and the last error is set to
one of `RKTIO_ERROR_CONVERT_NOT_ENOUGH_SPACE`,
`RKTIO_ERROR_CONVERT_BAD_SEQUENCE`, or `RKTIO_ERROR_CONVERT_OTHER`
--- but an error indicates something within `in` or `out`,
and some bytes may have been successfully converted even if an
error is reported. */
#define RKTIO_CONVERT_ERROR (-1)
char *rktio_locale_recase(rktio_t *rktio,
rktio_bool_t to_up,
char *in);
/* Upcases (of `to_up`) or downcases (if `!to_up`) the content of `in`
using the current locale's encoding and case conversion. */
rktio_char16_t *rktio_recase_utf16(rktio_t *rktio,
rktio_bool_t to_up, rktio_char16_t *s1,
intptr_t len, intptr_t *olen);
/* Converts the case of a string encoded in UTF-16 for the system's
default locale if the OS provided direct support for it. The
`RKTIO_CONVERT_RECASE_UTF16 property from
`rktio_convert_properties` reports whether this functon will work.
Takes and optionally returns a length (`olen` can be NULL), but the
UTF-16 sequence is expected to have no nuls. */
int rktio_locale_strcoll(rktio_t *rktio, char *s1, char *s2);
/* Returns -1 if `s1` is less than `s2` by the current locale's
comparison, positive is `s1` is greater, and 0 if the strings
are equal. */
int rktio_strcoll_utf16(rktio_t *rktio,
rktio_char16_t *s1, intptr_t l1,
rktio_char16_t *s2, intptr_t l2,
rktio_bool_t cvt_case);
/* Compares two strings encoded in UTF-16 for the system's default
locale if the OS provided direct support for it. The
`RKTIO_CONVERT_STRCOLL_UTF16 property from
`rktio_convert_properties` reports whether this functon will work.
Takes lengths, but the UTF-16 sequences are expected to have
no include nuls. */
char *rktio_locale_encoding(rktio_t *rktio);
/* Returns the name of the current locale's encoding. */
void rktio_set_locale(rktio_t *rktio, char *name);
/* Sets the current locale, which affects string comparisons and
conversions. It can also affect the C library's character-property
predicates and number printing/parsing. The empty string
corresponds to the OS's native locale. */
char *rktio_push_c_numeric_locale(rktio_t *rktio);
void rktio_pop_c_numeric_locale(rktio_t *rktio, char *prev);
/* Use this pair of funtions to temporarily switch the locale to the C
locale for number parsing and printing. The result of the first
function is deallocated when passed to second function. */
char *rktio_system_language_country(rktio_t *rktio);
/* Returns the current system's language in country in a 5-character
format such as "en_US". */
/*************************************************/
/* Errors */
@ -948,6 +1053,10 @@ enum {
RKTIO_ERROR_TIME_OUT_OF_RANGE,
RKTIO_ERROR_NO_SUCH_ENVVAR,
RKTIO_ERROR_SHELL_EXECUTE_FAILED,
RKTIO_ERROR_CONVERT_NOT_ENOUGH_SPACE,
RKTIO_ERROR_CONVERT_BAD_SEQUENCE,
RKTIO_ERROR_CONVERT_PREMATURE_END,
RKTIO_ERROR_CONVERT_OTHER,
};
RKTIO_EXTERN void rktio_set_last_error(rktio_t *rktio, int kind, int errid);

View File

@ -46,8 +46,14 @@ typedef unsigned long long rktio_uint64_t;
/* Whether getaddrinfo() is available: */
#undef HAVE_GETADDRINFO
/* Whether nl_langinfo works. */
#undef RKTIO_HAVE_CODESET
/* In case you want to avoid dynamic sizing of `fd_set` arrays: */
#undef RKTIO_STATIC_FDSET_SIZE
/* In case you want to use fcntl for file locks */
#undef RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
/* In case iconv is not available: */
#undef RKTIO_NO_ICONV

View File

@ -0,0 +1,670 @@
#include "rktio.h"
#include "rktio_private.h"
#include <string.h>
#include <stdlib.h>
#ifdef OS_X
# define MACOS_UNICODE_SUPPORT
#endif
#include <locale.h>
#include <errno.h>
#if !defined(RKTIO_SYSTEM_WINDOWS) && !defined(RKTIO_NO_ICONV)
# include <iconv.h>
# include <langinfo.h>
#endif
#include <wchar.h>
#include <wctype.h>
#ifdef MACOS_UNICODE_SUPPORT
# include <CoreFoundation/CFString.h>
# include <CoreFoundation/CFLocale.h>
#endif
/*============================================================*/
/* Using iconv via a DLL */
/*============================================================*/
#ifdef RKTIO_NO_ICONV
# define HAVE_CODESET 0
# define ICONV_errno 0
# define RKTIO_CHK_PROC(x) 0
# define iconv_ready 1
typedef intptr_t iconv_t;
static size_t iconv(iconv_t cd, char **in, size_t *in_left, char **out, size_t *out_left) { return (size_t)-1; }
static iconv_t iconv_open(const char *to, const char *from) { return -1; }
static void iconv_close(iconv_t cd) { }
static void init_iconv() { }
#elif defined(RKTIO_SYSTEM_WINDOWS)
static wchar_t *dlldir;
typedef intptr_t iconv_t;
typedef int *(*errno_proc_t)();
typedef size_t (*iconv_proc_t)(iconv_t cd,
char **inbuf, size_t *inbytesleft,
char **outbuf, size_t *outbytesleft);
typedef iconv_t (*iconv_open_proc_t)(const char *tocode, const char *fromcode);
typedef void (*iconv_close_proc_t)(iconv_t cd);
typedef char *(*locale_charset_proc_t)();
static errno_proc_t iconv_errno;
static iconv_proc_t iconv;
static iconv_open_proc_t iconv_open;
static iconv_close_proc_t iconv_close;
static locale_charset_proc_t locale_charset; /* Not used, currently */
static int get_iconv_errno(void)
{
int *a;
a = iconv_errno();
return *a;
}
# define HAVE_CODESET 1
# define CODESET 0
# define ICONV_errno get_iconv_errno()
# define RKTIO_CHK_PROC(x) x
static int iconv_ready = 0;
static void init_iconv()
{
HMODULE m;
wchar_t *p;
p = rktio_get_dll_path(L"iconv.dll");
if (p) {
m = LoadLibraryW(p);
free(p);
} else
m = NULL;
if (!m) {
p = rktio_get_dll_path(L"libiconv.dll");
if (p) {
m = LoadLibraryW(p);
free(p);
} else
m = NULL;
}
if (!m) {
p = rktio_get_dll_path(L"libiconv-2.dll");
if (p) {
m = LoadLibraryW(p);
free(p);
} else
m = NULL;
}
if (!m)
m = LoadLibraryW(L"iconv.dll");
if (!m)
m = LoadLibraryW(L"libiconv.dll");
if (!m)
m = LoadLibraryW(L"libiconv-2.dll");
if (m) {
iconv = (iconv_proc_t)GetProcAddress(m, "libiconv");
iconv_open = (iconv_open_proc_t)GetProcAddress(m, "libiconv_open");
iconv_close = (iconv_close_proc_t)GetProcAddress(m, "libiconv_close");
locale_charset = (locale_charset_proc_t)GetProcAddress(m, "locale_charset");
/* Make sure we have all of them or none: */
if (!iconv || !iconv_open || !iconv_close) {
iconv = NULL;
iconv_open = NULL;
iconv_close = NULL;
}
}
if (iconv) {
iconv_errno = (errno_proc_t)GetProcAddress(m, "_errno");
if (!iconv_errno) {
/* The iconv.dll distributed with Racket links to msvcrt.dll.
It's a slighly dangerous assumption that whatever iconv we
found also uses msvcrt.dll. */
m = LoadLibraryW(L"msvcrt.dll");
if (m) {
iconv_errno = (errno_proc_t)GetProcAddress(m, "_errno");
if (!iconv_errno) {
iconv = NULL;
iconv_open = NULL;
iconv_close = NULL;
}
}
}
}
iconv_ready = 1;
}
rktio_char16_t *rktio_get_dll_path(rktio_char16_t *s)
{
if (dlldir) {
int len1, len2;
wchar_t *p;
len1 = wcslen(dlldir);
len2 = wcslen(s);
p = malloc((len1 + len2 + 2) * sizeof(wchar_t));
memcpy(p, dlldir, len1 * sizeof(wchar_t));
if (p[len1 - 1] != '\\') {
p[len1++] = '\\';
}
memcpy(p + len1, s, (len2 + 1) * sizeof(wchar_t));
return p;
} else
return NULL;
}
void rktio_set_dll_path(rktio_char16_t *p)
{
dlldir = p;
}
#else
# ifdef RKTIO_HAVE_CODESET
# define HAVE_CODESET 1
# else
# define HAVE_CODESET 0
# endif
# include <errno.h>
# define ICONV_errno errno
# define iconv_ready 1
# define RKTIO_CHK_PROC(x) 1
static void init_iconv() { }
void rktio_set_dll_path(rktio_char16_t *p) { }
rktio_char16_t *rktio_get_dll_path(rktio_char16_t *s) { return NULL; }
#endif
/*============================================================*/
/* Properties */
/*============================================================*/
int rktio_convert_properties(rktio_t *rktio)
{
int flags = 0;
if (!iconv_ready) init_iconv();
if (RKTIO_CHK_PROC(iconv_errno))
flags = RKTIO_CONVERTER_SUPPORTED;
#if defined(MACOS_UNICODE_SUPPORT) || defined(RKTIO_SYSTEM_WINDOWS)
flags |= (RKTIO_CONVERT_STRCOLL_UTF16 | RKTIO_CONVERT_RECASE_UTF16);
#endif
return flags;
}
/*============================================================*/
/* Current locale */
/*============================================================*/
void rktio_set_locale(rktio_t *rktio, char *name)
{
/* We only need CTYPE and COLLATE; two calls seem to be much
faster than one call with ALL */
if (name) {
if (!setlocale(LC_CTYPE, name))
setlocale(LC_CTYPE, "C");
if (!setlocale(LC_COLLATE, name))
setlocale(LC_COLLATE, "C");
} else {
setlocale(LC_CTYPE, "C");
setlocale(LC_COLLATE, "C");
}
}
char *rktio_push_c_numeric_locale(rktio_t *rktio)
{
char *prev;
prev = setlocale(LC_NUMERIC, NULL);
if (!prev || !strcmp(prev, "C"))
return NULL;
else
return setlocale(LC_NUMERIC, "C");
}
void rktio_pop_c_numeric_locale(rktio_t *rktio, char *prev)
{
if (prev)
setlocale(LC_NUMERIC, prev);
}
/*============================================================*/
/* Current locale's encoding */
/*============================================================*/
#ifdef RKTIO_SYSTEM_WINDOWS
static char *nl_langinfo_dup()
{
int i;
char *current_locale_name;
current_locale_name = setlocale(LC_NUMERIC, NULL);
if (!current_locale_name)
current_locale_name = "";
if ((current_locale_name[0] == 'C')
&& !current_locale_name[1])
return MSC_IZE(strdup)("US-ASCII");
for (i = 0; current_locale_name[i]; i++) {
if (current_locale_name[i] == '.') {
if (current_locale_name[i + 1]) {
int len, j;
char *enc;
i++;
len = scheme_char_strlen(current_locale_name) - i;
enc = malloc(2 + len + 1);
/* Check whether the encoding is numeric, in which case
we add "CP" in front to make it an encoding name */
for (j = i; current_locale_name[j]; j++) {
if (current_locale_name[j] > 127)
break;
if (!isdigit(current_locale_name[j]))
break;
}
if (!current_locale_name[j]) {
j = 2;
memcpy(enc, "CP", j);
} else {
j = 0;
}
while (current_locale_name[i]) {
if (current_locale_name[i] > 127) {
free(enc);
return MSC_IZE(strdup)("UTF-8");
}
enc[j++] = current_locale_name[i++];
}
enc[j] = 0;
return enc;
}
}
}
return MSC_IZE(strdup)("UTF-8");
}
#else
static char *nl_langinfo_dup()
{
char *s;
# if HAVE_CODESET
s = nl_langinfo(CODESET);
# else
/* nl_langinfo doesn't work, so just make up something */
s = "UTF-8";
# endif
return MSC_IZE(strdup)(s);
}
#endif
char *rktio_locale_encoding(rktio_t *rktio)
{
return nl_langinfo_dup();
}
/*============================================================*/
char *rktio_system_language_country(rktio_t *rktio)
{
#ifdef MACOS_UNICODE_SUPPORT
/* Mac OS */
CFLocaleRef l;
CFStringRef s;
int len;
char *r;
l = CFLocaleCopyCurrent();
s = CFLocaleGetIdentifier(l);
len = CFStringGetLength(s);
r = malloc(len * 6 + 1);
CFStringGetCString(s, r, len * 6 + 1, kCFStringEncodingUTF8);
CFRelease(l);
r[5] = 0;
return r;
#elif defined(RKTIO_SYSTEM_WINDOWS)
/* Windows */
LCID l;
int llen, clen;
char *lang, *country, *s;
l = GetUserDefaultLCID();
llen = GetLocaleInfo(l, LOCALE_SENGLANGUAGE, NULL, 0);
lang = malloc(llen);
GetLocaleInfo(l, LOCALE_SENGLANGUAGE, lang, llen);
if (llen)
llen -= 1; /* drop nul terminator */
clen = GetLocaleInfo(l, LOCALE_SENGCOUNTRY, NULL, 0);
country = malloc(clen);
GetLocaleInfo(l, LOCALE_SENGCOUNTRY, country, clen);
if (clen)
clen -= 1; /* drop nul terminator */
s = malloc(clen + llen + 2);
memcpy(s, lang, llen);
memcpy(s + 1 + llen, country, clen);
s[llen] = '_';
s[clen + llen + 1] = 0;
free(lang);
free(country);
return s;
#else
/* Unix */
char *s;
s = getenv("LC_ALL");
if (!s)
s = getenv("LC_CTYPE");
if (!s)
s = getenv("LANG");
if (s) {
/* Check that the environment variable has the form
xx_XX[.ENC] */
if ((s[0] >= 'a') && (s[0] <= 'z')
&& (s[1] >= 'a') && (s[1] <= 'z')
&& (s[2] == '_')
&& (s[3] >= 'A') && (s[3] <= 'Z')
&& (s[4] >= 'A') && (s[4] <= 'Z')
&& (!s[5] || s[5] == '.')) {
/* Good */
} else
s = NULL;
}
if (!s)
s = "en_US";
return MSC_IZE(strdup)(s);
#endif
}
/*============================================================*/
/* Converters */
/*============================================================*/
struct rktio_converter_t {
iconv_t cd;
};
rktio_converter_t *rktio_converter_open(rktio_t *rktio, const char *to_enc, const char *from_enc)
{
iconv_t cd;
rktio_converter_t *cvt;
if (!iconv_ready) init_iconv();
cd = iconv_open(to_enc, from_enc);
if (cd == (iconv_t)-1) {
errno = ICONV_errno;
get_posix_error();
return NULL;
}
cvt = malloc(sizeof(rktio_converter_t));
cvt->cd = cd;
return cvt;
}
void rktio_converter_close(rktio_t *rktio, rktio_converter_t *cvt)
{
iconv_close(cvt->cd);
free(cvt);
}
intptr_t rktio_convert(rktio_t *rktio,
rktio_converter_t *cvt,
char **in, intptr_t *in_left,
char **out, intptr_t *out_left)
{
size_t il = *in_left, ol = *out_left, r;
int icerr;
r = iconv(cvt->cd, in, &il, out, &ol);
*in_left = il;
*out_left = ol;
if (r == (size_t)-1) {
icerr = ICONV_errno;
if (icerr == E2BIG)
set_racket_error(RKTIO_ERROR_CONVERT_NOT_ENOUGH_SPACE);
else if (icerr == EILSEQ)
set_racket_error(RKTIO_ERROR_CONVERT_BAD_SEQUENCE);
else if (icerr == EINVAL)
set_racket_error(RKTIO_ERROR_CONVERT_PREMATURE_END);
else
set_racket_error(RKTIO_ERROR_CONVERT_OTHER);
return RKTIO_CONVERT_ERROR;
}
return (intptr_t)r;
}
/*============================================================*/
/* Case conversion */
/*============================================================*/
char *rktio_locale_recase(rktio_t *rktio,
rktio_bool_t to_up,
char *in)
{
char *out;
#ifdef NO_MBTOWC_FUNCTIONS
/* No wide-char functions...
The C library's toupper and tolower is supposed to be
locale-sensitive. It can't be right for characters that are
encoded in multiple bytes, but probably it will do the right
thing in common cases. */
intptr_t iilen = strlen(in);
int i;
/* First, copy "in" to "out" */
out = malloc(iilen + 1);
memcpy(out, in, iilen);
out[iilen] = 0;
/* Re-case chars in "out" */
for (i = 0; i < iilen; i++) {
char t;
t = (to_up) ? toupper(out[i]) : tolower(out[i]);
out[i] = t;
}
return out;
#else
/* To change the case, convert the string to multibyte, re-case the
multibyte, then convert back. */
# define RKTIO_WC_BUF_SIZE 32
mbstate_t state;
size_t wl, ml;
wchar_t *wc, *ws, wcbuf[RKTIO_WC_BUF_SIZE], cwc;
const char *s;
unsigned int j;
/* The "n" versions are apparently not too standard: */
# define mz_mbsnrtowcs(t, f, fl, tl, s) mbsrtowcs(t, f, tl, s)
# define mz_wcsnrtombs(t, f, fl, tl, s) wcsrtombs(t, f, tl, s)
/* ----- to wide char ---- */
/* Get length */
memset(&state, 0, sizeof(mbstate_t));
s = in;
wl = mz_mbsnrtowcs(NULL, &s, iilen, 0, &state);
s = NULL;
/* Allocate space */
if (wl < RKTIO_WC_BUF_SIZE) {
wc = wcbuf;
} else {
wc = malloc(sizeof(wchar_t) * (wl + 1));
}
/* Convert */
memset(&state, 0, sizeof(mbstate_t));
s = in;
(void)mz_mbsnrtowcs(wc, &s, iilen, wl + 1, &state);
s = NULL;
wc[wl] = 0; /* just in case */
/* ---- re-case ---- */
if (to_up) {
for (j = 0; j < wl; j++) {
cwc = towupper(wc[j]);
wc[j] = cwc;
}
} else {
for (j = 0; j < wl; j++) {
cwc = towlower(wc[j]);
wc[j] = cwc;
}
}
/* ---- back to multibyte ---- */
/* Measure */
memset(&state, 0, sizeof(mbstate_t));
ws = wc;
ml = mz_wcsnrtombs(NULL, (const wchar_t **)&ws, wl, 0, &state);
ws = NULL;
/* Allocate space */
out = malloc(ml + 1);
/* Convert */
memset(&state, 0, sizeof(mbstate_t));
ws = wc;
(void)mz_wcsnrtombs(out, (const wchar_t **)&ws, wl, ml + 1, &state);
ws = NULL;
out[ml] = 0;
if (wc != wcbuf) free(wc);
return out;
#endif
}
rktio_char16_t *rktio_recase_utf16(rktio_t *rktio, rktio_bool_t to_up, rktio_char16_t *s1, intptr_t l1, intptr_t *olen)
{
#ifdef MACOS_UNICODE_SUPPORT
CFMutableStringRef mstr;
CFStringRef str;
CFRange rng;
rktio_char16_t *result;
intptr_t len;
str = CFStringCreateWithBytes(NULL, (unsigned char *)s1, (l1 * sizeof(rktio_char16_t)), kCFStringEncodingUnicode, FALSE);
mstr = CFStringCreateMutableCopy(NULL, 0, str);
CFRelease(str);
if (to_up)
CFStringUppercase(mstr, NULL);
else
CFStringLowercase(mstr, NULL);
len = CFStringGetLength(mstr);
result = malloc((len + 1) * sizeof(rktio_char16_t));
rng = CFRangeMake(0, len);
CFStringGetCharacters(mstr, rng, (UniChar *)result);
CFRelease(mstr);
result[len] = 0;
if (olen)
*olen = len;
return result;
#elif defined(RKTIO_SYSTEM_WINDOWS)
rktio_char16_t *result;
result = malloc((l1 + 1) * sizeof(rktio_char16_t));
memcpy(result, s1, l1 * sizeof(rktio_char16_t));
result[l1] = 0;
if (to_up)
CharUpperBuffW((wchar_t *)result, l1);
else
CharLowerBuffW((wchar_t *)result, l1);
if (olen)
*olen = l1;
return result;
#else
return NULL;
#endif
}
/*============================================================*/
/* Native string comparison */
/*============================================================*/
int rktio_locale_strcoll(rktio_t *rktio, char *s1, char *s2)
{
return strcoll(s1, s2);
}
int rktio_strcoll_utf16(rktio_t *rktio,
rktio_char16_t *s1, intptr_t l1,
rktio_char16_t *s2, intptr_t l2,
rktio_bool_t cvt_case)
{
#ifdef MACOS_UNICODE_SUPPORT
CFStringRef str1, str2;
CFComparisonResult r;
str1 = CFStringCreateWithBytes(NULL, (unsigned char *)s1, (l1 * sizeof(rktio_char16_t)),
kCFStringEncodingUnicode, FALSE);
str2 = CFStringCreateWithBytes(NULL, (unsigned char *)s2, (l2 * sizeof(rktio_char16_t)),
kCFStringEncodingUnicode, FALSE);
r = CFStringCompare(str1, str2, (kCFCompareLocalized
| (cvt_case ? kCFCompareCaseInsensitive : 0)));
CFRelease(str1);
CFRelease(str2);
return (int)r;
#elif defined(RKTIO_SYSTEM_WINDOWS)
int r;
r = CompareStringW(LOCALE_USER_DEFAULT,
((cvt_case ? NORM_IGNORECASE : 0)
| NORM_IGNOREKANATYPE
| NORM_IGNOREWIDTH),
(wchar_t *)s1, l1, (wchar_t *)s2, l2);
return r - 2;
#else
return 0;
#endif
}

View File

@ -217,7 +217,7 @@ rktio_envvars_t *rktio_envvars(rktio_t *rktio)
p = ea[i];
for (j = 0; p[j] && p[j] != '='; j++) {
}
envvars->names[i] = MSC_IZE(strndup)(p, j);
envvars->names[i] = rktio_strndup(p, j);
envvars->vals[i] = MSC_IZE(strdup)(p+j+1);
}

View File

@ -1,8 +1,5 @@
#include "rktio.h"
#include "rktio_private.h"
#ifdef RKTIO_SYSTEM_WINDOWS
# include <windows.h>
#endif
#include <errno.h>
#include <string.h>
@ -38,6 +35,10 @@ err_str_t err_strs[] = {
{ RKTIO_ERROR_TIME_OUT_OF_RANGE, "time value out-of-range for date conversion" },
{ RKTIO_ERROR_NO_SUCH_ENVVAR, "no value as an environment variable" },
{ RKTIO_ERROR_SHELL_EXECUTE_FAILED, "ShellExecute failed" },
{ RKTIO_ERROR_CONVERT_NOT_ENOUGH_SPACE, "encoding conversion needs more output space" },
{ RKTIO_ERROR_CONVERT_BAD_SEQUENCE, "ill-formed input encountered in encoding conversion" },
{ RKTIO_ERROR_CONVERT_PREMATURE_END, "input encoding ended prematurely" },
{ RKTIO_ERROR_CONVERT_OTHER, "encoding conversion encountered an error" },
{ 0, NULL }
};

View File

@ -1533,7 +1533,7 @@ char *rktio_directory_list_step(rktio_t *rktio, rktio_directory_list_t *dl)
continue;
# endif
return strndup(e->d_name, nlen);
return rktio_strndup(e->d_name, nlen);
}
rktio_directory_list_stop(rktio, dl);

View File

@ -51,7 +51,7 @@ void rktio_destroy(rktio_t *rktio)
}
/* Useful on Windows to make sure everyone is using the same malloc()
and fre(): */
and free(): */
void rktio_free(void *p)
{
free(p);

View File

@ -91,13 +91,13 @@ struct rktio_t {
wchar_t *wide_buffer;
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
HANDLE hEventLog;
#endif
#ifdef RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
struct rktio_hash_t *locked_fd_process_map;
#endif
#ifdef RKTIO_SYSTEM_WINDOWS
HANDLE hEventLog;
#endif
};
/*========================================================================*/
@ -323,3 +323,5 @@ void rktio_syslog_clean(rktio_t* rktio);
#else
# define BIG_OFF_T_IZE(n) n
#endif
char *rktio_strndup(char *s, intptr_t len);

View File

@ -1,5 +1,6 @@
#include "rktio.h"
#include "rktio_private.h"
#include <stdlib.h>
#include <string.h>
/* For converting byte strings to and from "wide" strings on Windows. */
@ -7,14 +8,16 @@
#ifdef RKTIO_SYSTEM_UNIX
void rktio_init_wide(rktio_t *rktio) { }
void *rktio_path_to_wide_path(rktio_t *rktio, const char *p)
rktio_char16_t *rktio_path_to_wide_path(rktio_t *rktio, const char *p)
{
return strdup(p);
set_racket_error(RKTIO_ERROR_UNSUPPORTED);
return NULL;
}
char *rktio_wide_path_to_path(rktio_t *rktio, const void *wp)
char *rktio_wide_path_to_path(rktio_t *rktio, const rktio_char16_t *wp)
{
return strdup((char *)wp);
set_racket_error(RKTIO_ERROR_UNSUPPORTED);
return NULL;
}
#endif
@ -320,14 +323,26 @@ char *rktio_convert_from_wchar(const wchar_t *ws, int free_given)
return s;
}
void *rktio_path_to_wide_path(rktio_t *rktio, const char *p)
rktio_char16_t *rktio_path_to_wide_path(rktio_t *rktio, const char *p)
{
return WIDE_PATH_copy(p);
}
char *rktio_wide_path_to_path(rktio_t *rktio, const void *wp)
char *rktio_wide_path_to_path(rktio_t *rktio, const rktio_char16_t *wp)
{
return NARROW_PATH_copy(wp);
}
#endif
/*============================================================*/
/* The same as strndup(), but sometimes strndup() is missing */
char *rktio_strndup(char *s, intptr_t len)
{
char *s2;
s2 = malloc(len + 1);
memcpy(s2, s, len);
s2[len] = 0;
return s2;
}

View File

@ -166,6 +166,10 @@
RelativePath="..\..\rktio\rktio_syslog.c"
>
</File>
<File
RelativePath="..\..\rktio\rktio_convert.c"
>
</File>
<File
RelativePath="..\..\rktio\rktio_error.c"
>

View File

@ -130,6 +130,7 @@
<ClCompile Include="..\..\rktio\rktio_shellex.c" />
<ClCompile Include="..\..\rktio\rktio_time.c" />
<ClCompile Include="..\..\rktio\rktio_syslog.c" />
<ClCompile Include="..\..\rktio\rktio_convert.c" />
<ClCompile Include="..\..\rktio\rktio_error.c" />
<ClCompile Include="..\..\rktio\rktio_hash.c" />
<ClCompile Include="..\..\rktio\rktio_wide.c" />