diff --git a/hawk/lib/mod-sys.c b/hawk/lib/mod-sys.c index 57ad8eb1..f9228a0f 100644 --- a/hawk/lib/mod-sys.c +++ b/hawk/lib/mod-sys.c @@ -4971,10 +4971,7 @@ static hawk_int_t pack_data (hawk_rtx_t* rtx, const hawk_oocs_t* fmt, const hawk break; case '>': /* big-endian */ - endian = ENDIAN_BIG; - break; - - case '!': /* network (= big-endian) */ + case '!': /* network */ endian = ENDIAN_BIG; break; @@ -5148,49 +5145,293 @@ oops_internal: return copy_error_to_sys_list (rtx, &rdp->sys_list); } +static hawk_uint16_t unpack_uint16 (const hawk_uint8_t* binp, int endian) +{ + hawk_uint16_t v; + + if (endian == ENDIAN_NATIVE) + { + v = *binp++; + v |= (hawk_uint16_t)(*binp++) << 8; + } + else + { + v = (hawk_uint16_t)(*binp++) << 8; + v |= *binp++; + } + return v; +} + +static hawk_int16_t unpack_int16 (const hawk_uint8_t* binp, int endian) +{ + hawk_uint16_t v = unpack_uint16 (binp, endian); + return (v <= HAWK_TYPE_MAX(hawk_int16_t))? (hawk_int16_t)v: ((hawk_int16_t)-1 - (hawk_int16_t)(HAWK_TYPE_MAX(hawk_uint16_t) - v)); +} + +static hawk_uint32_t unpack_uint32 (const hawk_uint8_t* binp, int endian) +{ + hawk_uint32_t v; + + if (endian == ENDIAN_NATIVE) + { + v = *binp++; + v |= (hawk_uint32_t)(*binp++) << 8; + v |= (hawk_uint32_t)(*binp++) << 16; + v |= (hawk_uint32_t)(*binp++) << 24; + } + else + { + v = (hawk_uint32_t)(*binp++) << 24; + v |= (hawk_uint32_t)(*binp++) << 16; + v |= (hawk_uint32_t)(*binp++) << 8; + v |= *binp++; + } + return v; +} + +static hawk_int32_t unpack_int32 (const hawk_uint8_t* binp, int endian) +{ + hawk_uint32_t v = unpack_uint32 (binp, endian); + return (v <= HAWK_TYPE_MAX(hawk_int32_t))? (hawk_int32_t)v: ((hawk_int32_t)-1 - (hawk_int32_t)(HAWK_TYPE_MAX(hawk_uint32_t) - v)); +} + +static hawk_uint64_t unpack_uint64 (const hawk_uint8_t* binp, int endian) +{ + hawk_uint64_t v; + + if (endian == ENDIAN_NATIVE) + { + v = *binp++; + v |= (hawk_uint64_t)(*binp++) << 8; + v |= (hawk_uint64_t)(*binp++) << 16; + v |= (hawk_uint64_t)(*binp++) << 24; + v |= (hawk_uint64_t)(*binp++) << 32; + v |= (hawk_uint64_t)(*binp++) << 40; + v |= (hawk_uint64_t)(*binp++) << 48; + v |= (hawk_uint64_t)(*binp++) << 56; + } + else + { + v = (hawk_uint64_t)(*binp++) << 56; + v |= (hawk_uint64_t)(*binp++) << 48; + v |= (hawk_uint64_t)(*binp++) << 40; + v |= (hawk_uint64_t)(*binp++) << 32; + v |= (hawk_uint64_t)(*binp++) << 24; + v |= (hawk_uint64_t)(*binp++) << 16; + v |= (hawk_uint64_t)(*binp++) << 8; + v |= *binp++; + } + return v; +} + +static hawk_int64_t unpack_int64 (const hawk_uint8_t* binp, int endian) +{ + hawk_uint64_t v = unpack_uint64 (binp, endian); + return (v <= HAWK_TYPE_MAX(hawk_int64_t))? (hawk_int64_t)v: ((hawk_int64_t)-1 - (hawk_int64_t)(HAWK_TYPE_MAX(hawk_uint64_t) - v)); +} + static hawk_int_t unpack_data (hawk_rtx_t* rtx, const hawk_bcs_t* bin, const hawk_oocs_t* fmt, const hawk_fnc_info_t* fi, rtx_data_t* rdp) { const hawk_ooch_t* fmtp, * fmte; - const hawk_bch_t* binp, * bine; + const hawk_uint8_t* binp, * bine; + hawk_oow_t rep_cnt, rep_set, rc; hawk_oow_t arg_idx, arg_cnt; + int endian = ENDIAN_NATIVE; hawk_val_t* v; +#define UNPACK_CHECK_ARG_AND_DATA(reqarg, reqsz) do { \ + if (arg_cnt - arg_idx < reqarg) return set_error_on_sys_list (rtx, &rdp->sys_list, HAWK_EARGTF, HAWK_NULL); \ + if (bine - binp < reqsz) goto oops_internal; \ +} while(0) /* TODO: */ arg_idx = 2; /* set past the format specifier */ arg_cnt = hawk_rtx_getnargs(rtx); - binp = bin->ptr; - bine = bin->ptr + bin->len; + rep_cnt = 1; + rep_set = 0; + + binp = (hawk_uint8_t*)bin->ptr; + bine = (hawk_uint8_t*)bin->ptr + bin->len; fmte = fmt->ptr + fmt->len; -#if 0 for (fmtp = fmt->ptr; fmtp < fmte; fmtp++) { switch (*fmtp) { + case '=': /* native */ + endian = ENDIAN_NATIVE; + break; + + case '<': /* little-endian */ + endian = ENDIAN_LITTLE; + break; + + case '>': /* big-endian */ + case '!': /* network */ + endian = ENDIAN_BIG; + break; + case 'b': { - v = hawk_rtx_makeintval(rtx, *binp++); - if (HAWK_UNLIKELY(!v)) goto oops_internal; - if (hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, arg_idx), v) <= -1) goto oops_internal; + UNPACK_CHECK_ARG_AND_DATA (rep_cnt, rep_cnt * HAWK_SIZEOF(hawk_int8_t)); + for (rc = 0; rc < rep_cnt; rc++) + { + v = hawk_rtx_makeintval(rtx, (hawk_int8_t)*binp++); + if (HAWK_UNLIKELY(!v)) goto oops_internal; + if (hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, arg_idx++), v) <= -1) goto oops_internal; + } + break; + } + + case 'B': + { + UNPACK_CHECK_ARG_AND_DATA (rep_cnt, rep_cnt * HAWK_SIZEOF(hawk_int8_t)); + for (rc = 0; rc < rep_cnt; rc++) + { + v = hawk_rtx_makeintval(rtx, *binp++); + if (HAWK_UNLIKELY(!v)) goto oops_internal; + if (hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, arg_idx++), v) <= -1) goto oops_internal; + } + break; } case 'h': { - v = hawk_rtx_makeintval(rtx, *binp++); - if (HAWK_UNLIKELY(!v)) goto oops_internal; - if (hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, arg_idx), v) <= -1) goto oops_internal; + UNPACK_CHECK_ARG_AND_DATA (rep_cnt, rep_cnt * HAWK_SIZEOF(hawk_int16_t)); + for (rc = 0; rc < rep_cnt; rc++) + { + v = hawk_rtx_makeintval(rtx, unpack_int16(binp, endian)); + binp += HAWK_SIZEOF(hawk_int16_t); + if (HAWK_UNLIKELY(!v)) goto oops_internal; + if (hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, arg_idx++), v) <= -1) goto oops_internal; + } + break; } + + case 'H': + { + UNPACK_CHECK_ARG_AND_DATA (rep_cnt, rep_cnt * HAWK_SIZEOF(hawk_uint16_t)); + for (rc = 0; rc < rep_cnt; rc++) + { + v = hawk_rtx_makeintval(rtx, unpack_uint16(binp, endian)); + binp += HAWK_SIZEOF(hawk_uint16_t); + if (HAWK_UNLIKELY(!v)) goto oops_internal; + if (hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, arg_idx++), v) <= -1) goto oops_internal; + } + break; + } + + + case 'i': + case 'l': + { + UNPACK_CHECK_ARG_AND_DATA (rep_cnt, rep_cnt * HAWK_SIZEOF(hawk_int32_t)); + for (rc = 0; rc < rep_cnt; rc++) + { + v = hawk_rtx_makeintval(rtx, unpack_int32(binp, endian)); + binp += HAWK_SIZEOF(hawk_int32_t); + if (HAWK_UNLIKELY(!v)) goto oops_internal; + if (hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, arg_idx++), v) <= -1) goto oops_internal; + } + break; + } + + case 'I': + case 'L': + { + UNPACK_CHECK_ARG_AND_DATA (rep_cnt, rep_cnt * HAWK_SIZEOF(hawk_uint32_t)); + for (rc = 0; rc < rep_cnt; rc++) + { + v = hawk_rtx_makeintval(rtx, unpack_uint32(binp, endian)); + binp += HAWK_SIZEOF(hawk_uint32_t); + if (HAWK_UNLIKELY(!v)) goto oops_internal; + if (hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, arg_idx++), v) <= -1) goto oops_internal; + } + break; + } + + case 'q': + { + UNPACK_CHECK_ARG_AND_DATA (rep_cnt, rep_cnt * HAWK_SIZEOF(hawk_int64_t)); + for (rc = 0; rc < rep_cnt; rc++) + { + v = hawk_rtx_makeintval(rtx, unpack_int64(binp, endian)); + binp += HAWK_SIZEOF(hawk_int64_t); + if (HAWK_UNLIKELY(!v)) goto oops_internal; + if (hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, arg_idx++), v) <= -1) goto oops_internal; + } + break; + } + + case 'Q': + { + UNPACK_CHECK_ARG_AND_DATA (rep_cnt, rep_cnt * HAWK_SIZEOF(hawk_uint64_t)); + for (rc = 0; rc < rep_cnt; rc++) + { + v = hawk_rtx_makeintval(rtx, unpack_uint64(binp, endian)); + binp += HAWK_SIZEOF(hawk_uint64_t); + if (HAWK_UNLIKELY(!v)) goto oops_internal; + if (hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, arg_idx++), v) <= -1) goto oops_internal; + } + break; + } + +#if 0 + case 'f': + case 'd': +#endif + + case 's': + case 'p': + { + UNPACK_CHECK_ARG_AND_DATA (1, rep_cnt); + v = hawk_rtx_makembsvalwithbchars(rtx, binp, rep_cnt); + binp += rep_cnt; + if (HAWK_UNLIKELY(!v)) goto oops_internal; + if (hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, arg_idx++), v) <= -1) goto oops_internal; + break; + } + + case 'x': + binp += rep_cnt; + break; + + default: + /* handle below outside 'switch' */ + if (hawk_is_ooch_digit(*fmtp)) + { + if (!rep_set) + { + rep_cnt = 0; + rep_set = 1; + } + rep_cnt = rep_cnt * 10 + (*fmtp - '0'); + } + else if (!hawk_is_ooch_space(*fmtp)) + { + return set_error_on_sys_list (rtx, &rdp->sys_list, HAWK_EINVAL, HAWK_T("invalid specifier - %jc"), *fmtp); + } + break; + } + + if (!hawk_is_ooch_digit(*fmtp) && !hawk_is_ooch_space(*fmtp)) + { + rep_cnt = 1; + rep_set = 0; } } -#endif + return 0; oops_internal: return copy_error_to_sys_list (rtx, &rdp->sys_list); } +/* + sys::pack(bin, "i 5s h", 10, "hello", -20); + printf ("%W\n", bin); +*/ static int fnc_pack (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) { rtx_data_t* rdp = rtx_to_data(rtx, fi); @@ -5229,6 +5470,9 @@ static int fnc_pack (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) return 0; } +/* sys::unpack(@b"\x00\x11\x12\x13\x14\x15", "h h h", a, b, c); + * print a, b, c; + */ static int fnc_unpack (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) { rtx_data_t* rdp = rtx_to_data(rtx, fi); @@ -5241,34 +5485,19 @@ static int fnc_unpack (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) bin.ptr = HAWK_NULL; a0 = hawk_rtx_getarg(rtx, 0); + a1 = hawk_rtx_getarg(rtx, 1); + bin.ptr = hawk_rtx_getvalbcstr(rtx, a0, &bin.len); if (HAWK_UNLIKELY(!bin.ptr)) goto fail; - a1 = hawk_rtx_getarg(rtx, 1); fmt.ptr = hawk_rtx_getvaloocstr(rtx, a1, &fmt.len); if (HAWK_UNLIKELY(!fmt.ptr)) goto fail; - - /* sys::unpack(@b"\x00\x11\x12\x13\x14\x15", "h h h", a, b, c); */ rx = unpack_data(rtx, &bin, &fmt, fi, rdp); hawk_rtx_freevaloocstr (rtx, a1, fmt.ptr); fmt.ptr = HAWK_NULL; hawk_rtx_freevalbcstr (rtx, a0, bin.ptr); bin.ptr = HAWK_NULL; - if (rx >= 0) - { - hawk_val_t* tmp; - int x; - - tmp = hawk_rtx_makembsvalwithbchars(rtx, rdp->pack.ptr, rdp->pack.len); - if (HAWK_UNLIKELY(!tmp)) goto fail; - - hawk_rtx_refupval (rtx, tmp); - x = hawk_rtx_setrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, 0), tmp); - hawk_rtx_refdownval (rtx, tmp); - if (x <= -1) goto fail; - } - done: hawk_rtx_setretval (rtx, hawk_rtx_makeintval(rtx, rx)); return 0;