summaryrefslogtreecommitdiffstats
path: root/ffi.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-05-01 20:54:12 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-05-01 20:54:12 -0700
commit1689bfa3d7f348f8c0fa7a010ba1c18b032e8906 (patch)
tree2fdd4bd877dd93cc28a34cf8296d9bd0c9f51b64 /ffi.c
parent15888fc36f23ff33ec7b780670ef374b5f517c54 (diff)
downloadtxr-1689bfa3d7f348f8c0fa7a010ba1c18b032e8906.tar.gz
txr-1689bfa3d7f348f8c0fa7a010ba1c18b032e8906.tar.bz2
txr-1689bfa3d7f348f8c0fa7a010ba1c18b032e8906.zip
ffi: more complete string semantics for char arrays.
* ffi.c (ffi_array_in): Support the char_conv and wchar_conv flags similarly in ffi_array_get. This allows (ptr (array n char)) to receive data from the C buffer as a string, storing it into the string object.
Diffstat (limited to 'ffi.c')
-rw-r--r--ffi.c62
1 files changed, 50 insertions, 12 deletions
diff --git a/ffi.c b/ffi.c
index 077751aa..e1fedf7c 100644
--- a/ffi.c
+++ b/ffi.c
@@ -1067,21 +1067,59 @@ static void ffi_array_in(struct txr_ffi_type *tft, mem_t *src, val vec,
mem_t *rtvec[], val self)
{
val eltypes = tft->mtypes;
- cnum nelem = tft->nelem, i;
- 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;
- if (etft->in != 0) {
- val elval = ref(vec, num_fast(i));
- etft->in(etft, src + offs, elval, rtvec, self);
+ if (tft->char_conv) {
+ val str;
+
+ if (!eltypes) {
+ str = null_string;
} else {
- val elval = etft->get(etft, src + offs, self);
- refset(vec, num_fast(i), elval);
+ const char *chptr = coerce(const char *, src);
+ if (chptr[tft->size - 1] == 0) {
+ str = string_utf8(chptr);
+ } else {
+ wchar_t *wch = utf8_dup_from_buf(chptr, tft->size);
+ str = string_own(wch);
+ }
+ }
+ replace(vec, str, zero, t);
+ } else if (tft->wchar_conv) {
+ val str;
+
+ if (!eltypes) {
+ str = null_string;
+ } else {
+ cnum nchar = tft->size / sizeof (wchar_t);
+ const wchar_t *wchptr = coerce(const wchar_t *, src);
+
+ if (wchptr[nchar - 1] == 0) {
+ str = string(wchptr);
+ } else {
+ val ustr = mkustring(num_fast(nchar));
+ str = init_str(ustr, wchptr);
+ }
+ }
+ replace(vec, str, zero, t);
+ } else {
+ if (eltypes) {
+ cnum nelem = tft->nelem, i;
+ 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;
+
+ if (etft->in != 0) {
+ val elval = ref(vec, num_fast(i));
+ etft->in(etft, src + offs, elval, rtvec, self);
+ } else {
+ val elval = etft->get(etft, src + offs, self);
+ refset(vec, num_fast(i), elval);
+ }
+ offs += elsize;
+ }
}
- offs += elsize;
}
}