summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-04-29 14:32:32 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-04-29 14:32:32 -0700
commit1ca136f653d66cd271a33c37ea17cf836f7197b4 (patch)
tree0477fb7c9e5604a52baea117cb2b1b2a1810e9a3
parent17d4160a2e6dcb07d2d7d09f8682ec120034a084 (diff)
downloadtxr-1ca136f653d66cd271a33c37ea17cf836f7197b4.tar.gz
txr-1ca136f653d66cd271a33c37ea17cf836f7197b4.tar.bz2
txr-1ca136f653d66cd271a33c37ea17cf836f7197b4.zip
ffi: conv between strings and char/wchar_t arrays.
* ffi.c (struct txr_ffi_type): New bitfield members char_conv, wchar_conv. (ffi_array_put): Check char_conv and wchar_conv flags and perform conversion to string, watching out for the presence or absence of null termination. (ffi_type_compile): When compiling array, check for the str and wstr element type, and set the flags. * utf8.c (ut8f_dup_from_buf): New function. * utf8.c (ut8f_dup_from_buf): Declared.
-rw-r--r--ffi.c59
-rw-r--r--utf8.c8
-rw-r--r--utf8.h1
3 files changed, 56 insertions, 12 deletions
diff --git a/ffi.c b/ffi.c
index d1a23359..8dc9bb3a 100644
--- a/ffi.c
+++ b/ffi.c
@@ -88,6 +88,8 @@ struct txr_ffi_type {
cnum nelem;
int rtidx, rtsize;
unsigned null_term : 1;
+ unsigned char_conv : 1;
+ unsigned wchar_conv : 1;
void (*walk)(struct txr_ffi_type *, mem_t *ctx,
void (*visit)(struct txr_ffi_type *, mem_t *ctx));
void (*put)(struct txr_ffi_type *, val obj, mem_t *dst,
@@ -958,20 +960,49 @@ static void ffi_array_put(struct txr_ffi_type *tft, val vec, mem_t *dst,
static val ffi_array_get(struct txr_ffi_type *tft, mem_t *src, val self)
{
val eltypes = tft->mtypes;
- cnum nelem = tft->nelem, i;
- val vec = vector(num_fast(nelem), nil);
- ucnum offs = 0;
- for (i = 0; i < nelem; i++) {
- val eltype = pop(&eltypes);
- struct txr_ffi_type *etft = ffi_type_struct(eltype);
- cnum elsize = etft->size;
- val elval = etft->get(etft, src + offs, self);
- refset(vec, num_fast(i), elval);
- offs += elsize;
- }
+ if (tft->char_conv) {
+ if (!eltypes) {
+ return null_string;
+ } else {
+ const char *chptr = coerce(const char *, src);
+ if (chptr[tft->size - 1] == 0) {
+ return string_utf8(chptr);
+ } else {
+ wchar_t *wch = utf8_dup_from_buf(chptr, tft->size);
+ return string_own(wch);
+ }
+ }
+ } else if (tft->wchar_conv) {
+ if (!eltypes) {
+ return null_string;
+ } else {
+ cnum nchar = tft->size / sizeof (wchar_t);
+ const wchar_t *wchptr = coerce(const wchar_t *, src);
+
+ if (wchptr[nchar - 1] == 0) {
+ return string(wchptr);
+ } else {
+ val ustr = mkustring(num_fast(nchar));
+ return init_str(ustr, wchptr);
+ }
+ }
+ } else {
+ cnum nelem = tft->nelem;
+ val vec = vector(num_fast(nelem), nil);
+ cnum offs, i;
+
+ for (i = 0, offs = 0; i < nelem; i++) {
+ val eltype = pop(&eltypes);
+ struct txr_ffi_type *etft = ffi_type_struct(eltype);
+ cnum elsize = etft->size;
+ val elval = etft->get(etft, src + offs, self);
+ refset(vec, num_fast(i), elval);
+ offs += elsize;
+ }
- return vec;
+ return vec;
+ }
}
static void ffi_array_fill(struct txr_ffi_type *tft, mem_t *src,
@@ -1220,6 +1251,10 @@ val ffi_type_compile(val syntax)
struct txr_ffi_type *tft = ffi_type_struct(type);
if (sym == zarray_s)
tft->null_term = 1;
+ if (eltype_syntax == char_s)
+ tft->char_conv = 1;
+ else if (eltype_syntax == wchar_s)
+ tft->wchar_conv = 1;
return type;
}
} else if (sym == ptr_in_s) {
diff --git a/utf8.c b/utf8.c
index f0084230..206a7e70 100644
--- a/utf8.c
+++ b/utf8.c
@@ -207,6 +207,14 @@ wchar_t *utf8_dup_from(const char *str)
return wstr;
}
+wchar_t *utf8_dup_from_buf(const char *str, size_t size)
+{
+ size_t nchar = utf8_from_buf(0, coerce(const unsigned char *, str), size);
+ wchar_t *wstr = chk_wmalloc(nchar);
+ utf8_from_buf(wstr, coerce(const unsigned char *, str), size);
+ return wstr;
+}
+
unsigned char *utf8_dup_to_buf(const wchar_t *wstr, size_t *pnbytes,
int null_term)
{
diff --git a/utf8.h b/utf8.h
index 3be8ee5f..2d253fae 100644
--- a/utf8.h
+++ b/utf8.h
@@ -30,6 +30,7 @@ size_t utf8_from(wchar_t *, const char *);
size_t utf8_to_buf(unsigned char *dst, const wchar_t *wsrc, int null_term);
size_t utf8_to(char *, const wchar_t *);
wchar_t *utf8_dup_from(const char *);
+wchar_t *utf8_dup_from_buf(const char *str, size_t size);
char *utf8_dup_to(const wchar_t *);
unsigned char *utf8_dup_to_buf(const wchar_t *, size_t *pnbytes,
int null_term);