diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2017-05-11 06:26:18 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2017-05-11 06:26:18 -0700 |
commit | f226f44490a31e88017b2c3e2032d6926ef1c336 (patch) | |
tree | a13c80ccf3354c03bbeeef29457e74a4e1990567 | |
parent | 39413e2d3568c3d18976d9b1c55af55af7905e4e (diff) | |
download | txr-f226f44490a31e88017b2c3e2032d6926ef1c336.tar.gz txr-f226f44490a31e88017b2c3e2032d6926ef1c336.tar.bz2 txr-f226f44490a31e88017b2c3e2032d6926ef1c336.zip |
ffi: encode-side character array specializations.
If the object being encoded is a string, and the array element
type is char, wchar or bchar, then encode a string, honoring
null termination flag. Unused space in the destination array
is filled with zeros.
* ffi.c (ffi_char_array_put, ffi_wchar_array_put,
ffi_bchar_array_put): New functions.
(ffi_array_put, ffi_array_out): Use new functions under
the right conditions.
-rw-r--r-- | ffi.c | 67 |
1 files changed, 65 insertions, 2 deletions
@@ -1012,6 +1012,24 @@ static val ffi_char_array_get(struct txr_ffi_type *tft, mem_t *src, } } +static void ffi_char_array_put(struct txr_ffi_type *tft, val str, mem_t *dst, + cnum nelem) +{ + int nt = tft->null_term; + const wchar_t *wstr = c_str(str); + size_t needed = utf8_to_buf(0, wstr, nt); + + if (needed <= nelem) { + utf8_to_buf(dst, wstr, nt); + memset(dst + needed, 0, nelem - needed); + } else { + char *u8str = utf8_dup_to(wstr); + memcpy(dst, u8str, nelem); + dst[nelem - 1] = 0; + free(u8str); + } +} + static val ffi_wchar_array_get(struct txr_ffi_type *tft, mem_t *src, cnum nelem) { @@ -1029,6 +1047,15 @@ static val ffi_wchar_array_get(struct txr_ffi_type *tft, mem_t *src, } } +static void ffi_wchar_array_put(struct txr_ffi_type *tft, val str, mem_t *dst, + cnum nelem) +{ + const wchar_t *wstr = c_str(str); + wcsncpy(coerce(wchar_t *, dst), wstr, nelem); + if (tft->null_term) + dst[nelem - 1] = 0; +} + static val ffi_bchar_array_get(struct txr_ffi_type *tft, mem_t *src, cnum nelem) { @@ -1043,6 +1070,28 @@ static val ffi_bchar_array_get(struct txr_ffi_type *tft, mem_t *src, } } +static void ffi_bchar_array_put(struct txr_ffi_type *tft, val str, mem_t *dst, + cnum nelem, val self) +{ + const wchar_t *wstr = c_str(str); + cnum i; + + for (i = 0; i < nelem && wstr[i]; i++) { + wchar_t wch = wstr[i]; + if (wch < 0 || wch > 255) + uw_throwf(error_s, lit("~a: character ~s out of unsigned 8 bit range"), + self, chr(wch), nao); + dst[i] = wch; + } + + if (i < nelem) { + for (; i < nelem; i++) + dst[i] = 0; + } else if (tft->null_term) { + dst[nelem - 1] = 0; + } +} + static val ffi_array_in_common(struct txr_ffi_type *tft, int copy, mem_t *src, val vec, val self, cnum nelem) { @@ -1112,7 +1161,14 @@ static void ffi_array_put_common(struct txr_ffi_type *tft, val vec, mem_t *dst, static void ffi_array_put(struct txr_ffi_type *tft, val vec, mem_t *dst, val self) { - ffi_array_put_common(tft, vec, dst, self, tft->nelem); + if (tft->char_conv && stringp(vec)) + ffi_char_array_put(tft, vec, dst, tft->nelem); + else if (tft->wchar_conv && stringp(vec)) + ffi_wchar_array_put(tft, vec, dst, tft->nelem); + else if (tft->bchar_conv && stringp(vec)) + ffi_bchar_array_put(tft, vec, dst, tft->nelem, self); + else + ffi_array_put_common(tft, vec, dst, self, tft->nelem); } static void ffi_array_out_common(struct txr_ffi_type *tft, int copy, val vec, @@ -1144,7 +1200,14 @@ static void ffi_array_out_common(struct txr_ffi_type *tft, int copy, val vec, static void ffi_array_out(struct txr_ffi_type *tft, int copy, val vec, mem_t *dst, val self) { - ffi_array_out_common(tft, copy, vec, dst, self, tft->nelem); + if (tft->char_conv && stringp(vec)) + ffi_char_array_put(tft, vec, dst, tft->nelem); + else if (tft->wchar_conv && stringp(vec)) + ffi_wchar_array_put(tft, vec, dst, tft->nelem); + else if (tft->bchar_conv && stringp(vec)) + ffi_bchar_array_put(tft, vec, dst, tft->nelem, self); + else + ffi_array_out_common(tft, copy, vec, dst, self, tft->nelem); } static val ffi_array_get_common(struct txr_ffi_type *tft, mem_t *src, val self, |