From df3442b0eb1ec4c6f8f4547cc20e5ad0824e7cd5 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 5 Jul 2017 16:08:59 +0200 Subject: erts: Refactor erts_unicode_list_to_buf to get bytes written when truncated. --- erts/emulator/beam/bif.c | 17 +++++++------ erts/emulator/beam/global.h | 2 +- erts/emulator/beam/utils.c | 60 +++++++++++++++++++++++++-------------------- 3 files changed, 44 insertions(+), 35 deletions(-) (limited to 'erts') diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 40dd4129d2..8380efaf13 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -3021,17 +3021,17 @@ BIF_RETTYPE list_to_atom_1(BIF_ALIST_1) { Eterm res; byte *buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, MAX_ATOM_SZ_LIMIT); - Sint i = erts_unicode_list_to_buf(BIF_ARG_1, buf, MAX_ATOM_CHARACTERS); - + Sint written; + int i = erts_unicode_list_to_buf(BIF_ARG_1, buf, MAX_ATOM_CHARACTERS, + &written); if (i < 0) { erts_free(ERTS_ALC_T_TMP, (void *) buf); - i = erts_list_length(BIF_ARG_1); - if (i > MAX_ATOM_CHARACTERS) { + if (i == -2) { BIF_ERROR(BIF_P, SYSTEM_LIMIT); } BIF_ERROR(BIF_P, BADARG); } - res = erts_atom_put(buf, i, ERTS_ATOM_ENC_UTF8, 1); + res = erts_atom_put(buf, written, ERTS_ATOM_ENC_UTF8, 1); ASSERT(is_atom(res)); erts_free(ERTS_ALC_T_TMP, (void *) buf); BIF_RET(res); @@ -3042,8 +3042,9 @@ BIF_RETTYPE list_to_atom_1(BIF_ALIST_1) BIF_RETTYPE list_to_existing_atom_1(BIF_ALIST_1) { byte *buf = (byte *) erts_alloc(ERTS_ALC_T_TMP, MAX_ATOM_SZ_LIMIT); - Sint i = erts_unicode_list_to_buf(BIF_ARG_1, buf, MAX_ATOM_CHARACTERS); - + Sint written; + int i = erts_unicode_list_to_buf(BIF_ARG_1, buf, MAX_ATOM_CHARACTERS, + &written); if (i < 0) { error: erts_free(ERTS_ALC_T_TMP, (void *) buf); @@ -3051,7 +3052,7 @@ BIF_RETTYPE list_to_existing_atom_1(BIF_ALIST_1) } else { Eterm a; - if (erts_atom_get((char *) buf, i, &a, ERTS_ATOM_ENC_UTF8)) { + if (erts_atom_get((char *) buf, written, &a, ERTS_ATOM_ENC_UTF8)) { erts_free(ERTS_ALC_T_TMP, (void *) buf); BIF_RET(a); } else { diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index fc95535ec3..fcb88712e9 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -1287,7 +1287,7 @@ int erts_utf8_to_latin1(byte* dest, const byte* source, int slen); void bin_write(fmtfn_t, void*, byte*, size_t); Sint intlist_to_buf(Eterm, char*, Sint); /* most callers pass plain char*'s */ -Sint erts_unicode_list_to_buf(Eterm list, byte *buf, Sint len); +int erts_unicode_list_to_buf(Eterm list, byte *buf, Sint len, Sint* written); struct Sint_buf { #if defined(ARCH_64) diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index 457cada745..ba7596cde4 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -3634,30 +3634,40 @@ intlist_to_buf(Eterm list, char *buf, Sint len) return -2; /* not enough space */ } -/* Fill buf with the contents of the unicode list. - * Return the number of bytes in the buffer, - * or -1 for type error, - * or -2 for not enough buffer space (buffer contains truncated result). +/** @brief Fill buf with the UTF8 contents of the unicode list + * @param len Max number of characters to write. + * @param written NULL or bytes written. + * @return 0 ok, + * -1 type error, + * -2 list too long, only \c len characters written */ -Sint -erts_unicode_list_to_buf(Eterm list, byte *buf, Sint len) +int +erts_unicode_list_to_buf(Eterm list, byte *buf, Sint len, Sint* written) { Eterm* listptr; Sint sz = 0; + Sint val; + int res; - if (is_nil(list)) { - return 0; - } - if (is_not_list(list)) { - return -1; - } - listptr = list_val(list); + while (1) { + if (is_nil(list)) { + res = 0; + break; + } + if (is_not_list(list)) { + res = -1; + break; + } + listptr = list_val(list); - while (len-- > 0) { - Sint val; + if (len-- <= 0) { + res = -2; + break; + } if (is_not_small(CAR(listptr))) { - return -1; + res = -1; + break; } val = signed_val(CAR(listptr)); if (0 <= val && val < 0x80) { @@ -3669,7 +3679,8 @@ erts_unicode_list_to_buf(Eterm list, byte *buf, Sint len) sz += 2; } else if (val < 0x10000UL) { if (0xD800 <= val && val <= 0xDFFF) { - return -1; + res = -1; + break; } buf[sz+0] = 0xE0 | (val >> 12); buf[sz+1] = 0x80 | ((val >> 6) & 0x3F); @@ -3682,18 +3693,15 @@ erts_unicode_list_to_buf(Eterm list, byte *buf, Sint len) buf[sz+3] = 0x80 | (val & 0x3F); sz += 4; } else { - return -1; + res = -1; + break; } list = CDR(listptr); - if (is_nil(list)) { - return sz; - } - if (is_not_list(list)) { - return -1; - } - listptr = list_val(list); } - return -2; /* not enough space */ + + if (written) + *written = sz; + return res; } /* -- cgit v1.2.3