diff --git a/hawk/lib/err.c b/hawk/lib/err.c index 7ec05144..5ff3acab 100644 --- a/hawk/lib/err.c +++ b/hawk/lib/err.c @@ -166,7 +166,6 @@ const hawk_ooch_t* hawk_dfl_errstr (hawk_errnum_t errnum) HAWK_T("I/O name empty"), HAWK_T("I/O name containing '\\0'"), HAWK_T("not sufficient arguments to formatting sequence"), - HAWK_T("recursion detected in format conversion"), HAWK_T("invalid character in CONVFMT"), HAWK_T("invalid character in OFMT"), diff --git a/hawk/lib/fnc.c b/hawk/lib/fnc.c index 04f107a7..4a06f2de 100644 --- a/hawk/lib/fnc.c +++ b/hawk/lib/fnc.c @@ -566,94 +566,101 @@ static int index_or_rindex (hawk_rtx_t* rtx, int rindex) if (n <= -1) return -1; } - if (HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_MBS) + switch (HAWK_RTX_GETVALTYPE(rtx, a0)) { - hawk_bch_t* str0, * str1, * ptr; - hawk_oow_t len0, len1; - - str0 = ((hawk_val_mbs_t*)a0)->val.ptr; - len0 = ((hawk_val_mbs_t*)a0)->val.len; - - str1 = hawk_rtx_getvalbcstr(rtx, a1, &len1); - if (!str1) return -1; - - if (nargs < 3) + case HAWK_VAL_BCHR: + case HAWK_VAL_MBS: { - boundary = rindex? len0: 1; + hawk_bch_t* str0, * str1, * ptr; + hawk_oow_t len0, len1; + + str0 = ((hawk_val_mbs_t*)a0)->val.ptr; + len0 = ((hawk_val_mbs_t*)a0)->val.len; + + str1 = hawk_rtx_getvalbcstr(rtx, a1, &len1); + if (HAWK_UNLIKELY(!str0)) return -1; + + if (nargs < 3) + { + boundary = rindex? len0: 1; + } + else + { + if (boundary == 0) boundary = 1; + else if (boundary < 0) boundary = len0 + boundary + 1; + } + + if (boundary > len0 || boundary <= 0) + { + ptr = HAWK_NULL; + } + else if (rindex) + { + /* 'boundary' acts as an end position */ + ptr = hawk_rfind_bchars_in_bchars(&str0[0], boundary, str1, len1, rtx->gbl.ignorecase); + } + else + { + /* 'boundary' acts as an start position */ + ptr = hawk_find_bchars_in_bchars(&str0[boundary-1], len0 - boundary + 1, str1, len1, rtx->gbl.ignorecase); + } + + idx = (ptr == HAWK_NULL)? 0: ((hawk_int_t)(ptr - str0) + 1); + + hawk_rtx_freevalbcstr (rtx, a1, str1); + break; } - else + + default: { - if (boundary == 0) boundary = 1; - else if (boundary < 0) boundary = len0 + boundary + 1; - } + hawk_ooch_t* str0, * str1, * ptr; + hawk_oow_t len0, len1; - if (boundary > len0 || boundary <= 0) - { - ptr = HAWK_NULL; - } - else if (rindex) - { - /* 'boundary' acts as an end position */ - ptr = hawk_rfind_bchars_in_bchars(&str0[0], boundary, str1, len1, rtx->gbl.ignorecase); - } - else - { - /* 'boundary' acts as an start position */ - ptr = hawk_find_bchars_in_bchars(&str0[boundary-1], len0 - boundary + 1, str1, len1, rtx->gbl.ignorecase); - } + str0 = hawk_rtx_getvaloocstr(rtx, a0, &len0); + if (HAWK_UNLIKELY(!str0)) return -1; - idx = (ptr == HAWK_NULL)? 0: ((hawk_int_t)(ptr - str0) + 1); + str1 = hawk_rtx_getvaloocstr(rtx, a1, &len1); + if (!str1) + { + hawk_rtx_freevaloocstr (rtx, a0, str0); + return -1; + } - hawk_rtx_freevalbcstr (rtx, a1, str1); - } - else - { - hawk_ooch_t* str0, * str1, * ptr; - hawk_oow_t len0, len1; + if (nargs < 3) + { + boundary = rindex? len0: 1; + } + else + { + if (boundary == 0) boundary = 1; + else if (boundary < 0) boundary = len0 + boundary + 1; + } - str0 = hawk_rtx_getvaloocstr(rtx, a0, &len0); - if (!str0) return -1; + if (boundary > len0 || boundary <= 0) + { + ptr = HAWK_NULL; + } + else if (rindex) + { + /* 'boundary' acts as an end position */ + ptr = hawk_rfind_oochars_in_oochars(&str0[0], boundary, str1, len1, rtx->gbl.ignorecase); + } + else + { + /* 'boundary' acts as an start position */ + ptr = hawk_find_oochars_in_oochars(&str0[boundary-1], len0 - boundary + 1, str1, len1, rtx->gbl.ignorecase); + } - str1 = hawk_rtx_getvaloocstr(rtx, a1, &len1); - if (!str1) - { + idx = (ptr == HAWK_NULL)? 0: ((hawk_int_t)(ptr - str0) + 1); + + hawk_rtx_freevaloocstr (rtx, a1, str1); hawk_rtx_freevaloocstr (rtx, a0, str0); - return -1; } - - if (nargs < 3) - { - boundary = rindex? len0: 1; - } - else - { - if (boundary == 0) boundary = 1; - else if (boundary < 0) boundary = len0 + boundary + 1; - } - - if (boundary > len0 || boundary <= 0) - { - ptr = HAWK_NULL; - } - else if (rindex) - { - /* 'boundary' acts as an end position */ - ptr = hawk_rfind_oochars_in_oochars(&str0[0], boundary, str1, len1, rtx->gbl.ignorecase); - } - else - { - /* 'boundary' acts as an start position */ - ptr = hawk_find_oochars_in_oochars(&str0[boundary-1], len0 - boundary + 1, str1, len1, rtx->gbl.ignorecase); - } - - idx = (ptr == HAWK_NULL)? 0: ((hawk_int_t)(ptr - str0) + 1); - - hawk_rtx_freevaloocstr (rtx, a1, str1); - hawk_rtx_freevaloocstr (rtx, a0, str0); + break; } a0 = hawk_rtx_makeintval(rtx, idx); - if (a0 == HAWK_NULL) return -1; + if (HAWK_UNLIKELY(!a0)) return -1; hawk_rtx_setretval (rtx, a0); return 0; @@ -661,12 +668,12 @@ static int index_or_rindex (hawk_rtx_t* rtx, int rindex) int hawk_fnc_index (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) { - return index_or_rindex (rtx, 0); + return index_or_rindex(rtx, 0); } int hawk_fnc_rindex (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) { - return index_or_rindex (rtx, 1); + return index_or_rindex(rtx, 1); } int hawk_fnc_length (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) @@ -701,15 +708,23 @@ int hawk_fnc_length (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) len = HAWK_ARR_TALLY(((hawk_val_arr_t*)v)->arr); break; - case HAWK_VAL_STR: - /* string length */ - len = ((hawk_val_str_t*)v)->val.len; + case HAWK_VAL_BCHR: + len = 1; break; case HAWK_VAL_MBS: len = ((hawk_val_mbs_t*)v)->val.len; break; + case HAWK_VAL_CHAR: + len = 1; + break; + + case HAWK_VAL_STR: + /* string length */ + len = ((hawk_val_str_t*)v)->val.len; + break; + default: /* convert to string and get length */ str = hawk_rtx_valtooocstrdup(rtx, v, &len); @@ -753,34 +768,42 @@ int hawk_fnc_substr (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) lindex = lindex - 1; if (lindex < 0) lindex = 0; - if (HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_MBS) + switch (HAWK_RTX_GETVALTYPE(rtx, a0)) { - hawk_bch_t* str; - hawk_oow_t len; + case HAWK_VAL_BCHR: + case HAWK_VAL_MBS: + { + hawk_bch_t* str; + hawk_oow_t len; - str = ((hawk_val_mbs_t*)a0)->val.ptr; - len = ((hawk_val_mbs_t*)a0)->val.len; + str = hawk_rtx_getvalbcstr(rtx, a0, &len); + if (HAWK_UNLIKELY(!str)) return -1; - if (lindex >= (hawk_int_t)len) lindex = (hawk_int_t)len; - if (lcount > (hawk_int_t)len - lindex) lcount = (hawk_int_t)len - lindex; + if (lindex >= (hawk_int_t)len) lindex = (hawk_int_t)len; + if (lcount > (hawk_int_t)len - lindex) lcount = (hawk_int_t)len - lindex; - r = hawk_rtx_makembsvalwithbchars(rtx, &str[lindex], (hawk_oow_t)lcount); - if (HAWK_UNLIKELY(!r)) return -1; - } - else - { - hawk_ooch_t* str; - hawk_oow_t len; + r = hawk_rtx_makembsvalwithbchars(rtx, &str[lindex], (hawk_oow_t)lcount); + hawk_rtx_freevalbcstr (rtx, a0, str); + if (HAWK_UNLIKELY(!r)) return -1; + break; + } - str = hawk_rtx_getvaloocstr(rtx, a0, &len); - if (!str) return -1; + default: + { + hawk_ooch_t* str; + hawk_oow_t len; - if (lindex >= (hawk_int_t)len) lindex = (hawk_int_t)len; - if (lcount > (hawk_int_t)len - lindex) lcount = (hawk_int_t)len - lindex; + str = hawk_rtx_getvaloocstr(rtx, a0, &len); + if (HAWK_UNLIKELY(!str)) return -1; - r = hawk_rtx_makestrvalwithoochars(rtx, &str[lindex], (hawk_oow_t)lcount); - hawk_rtx_freevaloocstr (rtx, a0, str); - if (HAWK_UNLIKELY(!r)) return -1; + if (lindex >= (hawk_int_t)len) lindex = (hawk_int_t)len; + if (lcount > (hawk_int_t)len - lindex) lcount = (hawk_int_t)len - lindex; + + r = hawk_rtx_makestrvalwithoochars(rtx, &str[lindex], (hawk_oow_t)lcount); + hawk_rtx_freevaloocstr (rtx, a0, str); + if (HAWK_UNLIKELY(!r)) return -1; + break; + } } hawk_rtx_setretval (rtx, r); @@ -836,6 +859,9 @@ static int fnc_split (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi, int use_array) } else { + /* no distinction between byte-string and normal string for the lack of hawk_rtx_buildrex() with a byte string. + * TODO: distingish byte strings from normal strings once the regular expresson builder supports them */ + fs.ptr = hawk_rtx_getvaloocstr(rtx, t0, &fs.len); if (HAWK_UNLIKELY(!fs.ptr)) goto oops; @@ -864,17 +890,20 @@ static int fnc_split (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi, int use_array) } /* the first parameter - string to split */ - if (HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_MBS) + switch (HAWK_RTX_GETVALTYPE(rtx, a0)) { - byte_str = 1; - str.ptr = do_fld? hawk_rtx_valtobcstrdup(rtx, a0, &str.len): - hawk_rtx_getvalbcstr(rtx, a0, &str.len); - } - else - { - byte_str = 0; - str.ptr = do_fld? hawk_rtx_valtooocstrdup(rtx, a0, &str.len): - hawk_rtx_getvaloocstr(rtx, a0, &str.len); + case HAWK_VAL_BCHR: + case HAWK_VAL_MBS: + byte_str = 1; + str.ptr = do_fld? hawk_rtx_valtobcstrdup(rtx, a0, &str.len): + hawk_rtx_getvalbcstr(rtx, a0, &str.len); + break; + + default: + byte_str = 0; + str.ptr = do_fld? hawk_rtx_valtooocstrdup(rtx, a0, &str.len): + hawk_rtx_getvaloocstr(rtx, a0, &str.len); + break; } if (HAWK_UNLIKELY(!str.ptr)) goto oops; @@ -1016,6 +1045,15 @@ int hawk_fnc_tolower (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) a0 = hawk_rtx_getarg(rtx, 0); switch (HAWK_RTX_GETVALTYPE(rtx, a0)) { + case HAWK_VAL_BCHR: + { + hawk_bch_t tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, a0); + tmp = hawk_to_bch_lower(tmp); + r = hawk_rtx_makebchrval(rtx, tmp); + if (HAWK_UNLIKELY(!r)) return -1; + break; + } + case HAWK_VAL_MBS: { hawk_bcs_t str; @@ -1033,7 +1071,7 @@ int hawk_fnc_tolower (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) case HAWK_VAL_CHAR: { hawk_ooch_t tmp = HAWK_RTX_GETCHARFROMVAL(rtx, a0); - tmp = hawk_to_bch_lower(tmp); + tmp = hawk_to_ooch_lower(tmp); r = hawk_rtx_makecharval(rtx, tmp); if (HAWK_UNLIKELY(!r)) return -1; break; @@ -1066,6 +1104,15 @@ int hawk_fnc_toupper (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) a0 = hawk_rtx_getarg(rtx, 0); switch (HAWK_RTX_GETVALTYPE(rtx, a0)) { + case HAWK_VAL_BCHR: + { + hawk_bch_t tmp = HAWK_RTX_GETCHARFROMVAL(rtx, a0); + tmp = hawk_to_bch_upper(tmp); + r = hawk_rtx_makebchrval(rtx, tmp); + if (HAWK_UNLIKELY(!r)) return -1; + break; + } + case HAWK_VAL_MBS: { hawk_bcs_t str; @@ -1083,7 +1130,7 @@ int hawk_fnc_toupper (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) case HAWK_VAL_CHAR: { hawk_ooch_t tmp = HAWK_RTX_GETCHARFROMVAL(rtx, a0); - tmp = hawk_to_bch_upper(tmp); + tmp = hawk_to_ooch_upper(tmp); r = hawk_rtx_makecharval(rtx, tmp); if (HAWK_UNLIKELY(!r)) return -1; break; @@ -1373,23 +1420,26 @@ static int __substitute (hawk_rtx_t* rtx, hawk_oow_t max_count) { r2 = hawk_rtx_getrefval(rtx, (hawk_val_ref_t*)hawk_rtx_getarg(rtx, 2)); - if (HAWK_RTX_GETVALTYPE(rtx, r2) == HAWK_VAL_MBS) + switch (HAWK_RTX_GETVALTYPE(rtx, r2)) { - s2.ptr = hawk_rtx_getvalbcstr(rtx, r2, &s2.len); - s2_free = 2; + case HAWK_VAL_BCHR: + case HAWK_VAL_MBS: + s2.ptr = hawk_rtx_getvalbcstr(rtx, r2, &s2.len); + s2_free = 2; - /* the second argument - substitute */ - s1.ptr = hawk_rtx_getvalbcstr(rtx, a1, &s1.len); - s1_free = 2; - } - else - { - s2.ptr = hawk_rtx_getvaloocstr(rtx, r2, &s2.len); - s2_free = 1; + /* the second argument - substitute */ + s1.ptr = hawk_rtx_getvalbcstr(rtx, a1, &s1.len); + s1_free = 2; + break; - /* the second argument - substitute */ - s1.ptr = hawk_rtx_getvaloocstr(rtx, a1, &s1.len); - s1_free = 1; + default: + s2.ptr = hawk_rtx_getvaloocstr(rtx, r2, &s2.len); + s2_free = 1; + + /* the second argument - substitute */ + s1.ptr = hawk_rtx_getvaloocstr(rtx, a1, &s1.len); + s1_free = 1; + break; } } @@ -1738,61 +1788,66 @@ int hawk_fnc_sprintf (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) HAWK_ASSERT (nargs > 0); a0 = hawk_rtx_getarg(rtx, 0); - if (HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_MBS) + switch (HAWK_RTX_GETVALTYPE(rtx, a0)) { - hawk_becs_t fbu; - int fbu_inited = 0; - hawk_bcs_t cs0; - hawk_bcs_t x; + case HAWK_VAL_BCHR: + case HAWK_VAL_MBS: + { + hawk_becs_t fbu; + int fbu_inited = 0; + hawk_bcs_t cs0; + hawk_bcs_t x; - if (hawk_becs_init(&fbu, hawk_rtx_getgem(rtx), 256) <= -1) goto oops_mbs; - fbu_inited = 1; + if (hawk_becs_init(&fbu, hawk_rtx_getgem(rtx), 256) <= -1) goto oops_mbs; + fbu_inited = 1; - cs0.ptr = hawk_rtx_getvalbcstr(rtx, a0, &cs0.len); - if (HAWK_UNLIKELY(!cs0.ptr)) goto oops_mbs; + cs0.ptr = hawk_rtx_getvalbcstr(rtx, a0, &cs0.len); + if (HAWK_UNLIKELY(!cs0.ptr)) goto oops_mbs; - x.ptr = hawk_rtx_formatmbs(rtx, &rtx->fnc.bout, &fbu, cs0.ptr, cs0.len, nargs, HAWK_NULL, &x.len); - hawk_rtx_freevalbcstr (rtx, a0, cs0.ptr); - if (HAWK_UNLIKELY(!x.ptr)) goto oops_mbs; - - a0 = hawk_rtx_makembsvalwithbcs(rtx, &x); - if (HAWK_UNLIKELY(!a0)) goto oops_mbs; + x.ptr = hawk_rtx_formatmbs(rtx, &rtx->fnc.bout, &fbu, cs0.ptr, cs0.len, nargs, HAWK_NULL, &x.len); + hawk_rtx_freevalbcstr (rtx, a0, cs0.ptr); + if (HAWK_UNLIKELY(!x.ptr)) goto oops_mbs; + + a0 = hawk_rtx_makembsvalwithbcs(rtx, &x); + if (HAWK_UNLIKELY(!a0)) goto oops_mbs; - hawk_becs_fini (&fbu); - hawk_rtx_setretval (rtx, a0); - return 0; + hawk_becs_fini (&fbu); + hawk_rtx_setretval (rtx, a0); + return 0; - oops_mbs: - if (fbu_inited) hawk_becs_fini (&fbu); - return -1; - } - else - { - hawk_ooecs_t fbu; - int fbu_inited = 0; - hawk_oocs_t cs0; - hawk_oocs_t x; + oops_mbs: + if (fbu_inited) hawk_becs_fini (&fbu); + return -1; + } - if (hawk_ooecs_init(&fbu, hawk_rtx_getgem(rtx), 256) <= -1) goto oops; - fbu_inited = 1; + default: + { + hawk_ooecs_t fbu; + int fbu_inited = 0; + hawk_oocs_t cs0; + hawk_oocs_t x; - cs0.ptr = hawk_rtx_getvaloocstr(rtx, a0, &cs0.len); - if (HAWK_UNLIKELY(!cs0.ptr)) goto oops; + if (hawk_ooecs_init(&fbu, hawk_rtx_getgem(rtx), 256) <= -1) goto oops; + fbu_inited = 1; - x.ptr = hawk_rtx_format(rtx, &rtx->fnc.oout, &fbu, cs0.ptr, cs0.len, nargs, HAWK_NULL, &x.len); - hawk_rtx_freevaloocstr (rtx, a0, cs0.ptr); - if (HAWK_UNLIKELY(!x.ptr)) goto oops; + cs0.ptr = hawk_rtx_getvaloocstr(rtx, a0, &cs0.len); + if (HAWK_UNLIKELY(!cs0.ptr)) goto oops; - a0 = hawk_rtx_makestrvalwithoocs(rtx, &x); - if (HAWK_UNLIKELY(!a0)) goto oops; + x.ptr = hawk_rtx_format(rtx, &rtx->fnc.oout, &fbu, cs0.ptr, cs0.len, nargs, HAWK_NULL, &x.len); + hawk_rtx_freevaloocstr (rtx, a0, cs0.ptr); + if (HAWK_UNLIKELY(!x.ptr)) goto oops; - hawk_ooecs_fini (&fbu); - hawk_rtx_setretval (rtx, a0); - return 0; + a0 = hawk_rtx_makestrvalwithoocs(rtx, &x); + if (HAWK_UNLIKELY(!a0)) goto oops; - oops: - if (fbu_inited) hawk_ooecs_fini (&fbu); - return -1; + hawk_ooecs_fini (&fbu); + hawk_rtx_setretval (rtx, a0); + return 0; + + oops: + if (fbu_inited) hawk_ooecs_fini (&fbu); + return -1; + } } } diff --git a/hawk/lib/hawk-cmn.h b/hawk/lib/hawk-cmn.h index 9aff8f14..03ea57a0 100644 --- a/hawk/lib/hawk-cmn.h +++ b/hawk/lib/hawk-cmn.h @@ -1021,7 +1021,6 @@ enum hawk_errnum_t HAWK_EIONMEM, /**< I/O name empty */ HAWK_EIONMNL, /**< I/O name containing '\\0' */ HAWK_EFMTARG, /**< not sufficient arguments to formatting sequence */ - HAWK_EFMTCNV, /**< recursion detected in format conversion */ HAWK_ECONVFMTCHR, /**< invalid character in CONVFMT */ HAWK_EOFMTCHR, /**< invalid character in OFMT */ diff --git a/hawk/lib/hawk-prv.h b/hawk/lib/hawk-prv.h index 4edc66ba..f192d439 100644 --- a/hawk/lib/hawk-prv.h +++ b/hawk/lib/hawk-prv.h @@ -381,7 +381,13 @@ struct hawk_chain_t typedef struct hawk_ctos_b_t hawk_ctos_b_t; struct hawk_ctos_b_t { - hawk_ooch_t c[2]; + hawk_oochu_t c[2]; /* ensure the unsigned type to hold not only a character but also a free slot index */ +}; + +typedef struct hawk_bctos_b_t hawk_bctos_b_t; +struct hawk_bctos_b_t +{ + hawk_bchu_t c[2]; /* ensure the unsigned type to hold not only a byte character but also a free slot index */ }; struct hawk_rtx_t @@ -427,6 +433,12 @@ struct hawk_rtx_t hawk_oow_t fi; } ctos; /* char/nil to string conversion */ + struct + { + hawk_bctos_b_t b[256]; + hawk_oow_t fi; + } bctos; + struct { /* lists of values under gc management */ diff --git a/hawk/lib/mod-str.c b/hawk/lib/mod-str.c index fb099dd2..4a425023 100644 --- a/hawk/lib/mod-str.c +++ b/hawk/lib/mod-str.c @@ -37,30 +37,36 @@ static int fnc_normspace (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) hawk_val_t* a0; a0 = hawk_rtx_getarg(rtx, 0); - if (HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_MBS) + switch (HAWK_RTX_GETVALTYPE(rtx, a0)) { - hawk_bch_t* str0; - hawk_oow_t len0; + case HAWK_VAL_BCHR: + case HAWK_VAL_MBS: + { + hawk_bch_t* str0; + hawk_oow_t len0; - str0 = hawk_rtx_valtobcstrdup(rtx, a0, &len0); - if (HAWK_UNLIKELY(!str0)) return -1; - len0 = hawk_compact_bchars(str0, len0); - retv = hawk_rtx_makembsvalwithbchars(rtx, str0, len0); - hawk_rtx_freemem (rtx, str0); - } - else - { - hawk_ooch_t* str0; - hawk_oow_t len0; + str0 = hawk_rtx_valtobcstrdup(rtx, a0, &len0); + if (HAWK_UNLIKELY(!str0)) return -1; + len0 = hawk_compact_bchars(str0, len0); + retv = hawk_rtx_makembsvalwithbchars(rtx, str0, len0); + hawk_rtx_freemem (rtx, str0); + break; + } - str0 = hawk_rtx_valtooocstrdup(rtx, a0, &len0); - if (HAWK_UNLIKELY(!str0)) return -1; - len0 = hawk_compact_oochars(str0, len0); - retv = hawk_rtx_makestrvalwithoochars(rtx, str0, len0); - hawk_rtx_freemem (rtx, str0); + default: + { + hawk_ooch_t* str0; + hawk_oow_t len0; + + str0 = hawk_rtx_valtooocstrdup(rtx, a0, &len0); + if (HAWK_UNLIKELY(!str0)) return -1; + len0 = hawk_compact_oochars(str0, len0); + retv = hawk_rtx_makestrvalwithoochars(rtx, str0, len0); + hawk_rtx_freemem (rtx, str0); + } } - if (!retv) return -1; + if (HAWK_UNLIKELY(!retv)) return -1; hawk_rtx_setretval (rtx, retv); return 0; @@ -73,31 +79,39 @@ static int trim (hawk_rtx_t* rtx, int flags) a0 = hawk_rtx_getarg(rtx, 0); - if (HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_MBS) + switch (HAWK_RTX_GETVALTYPE(rtx, a0)) { - hawk_bcs_t path; - hawk_bch_t* npath; - path.ptr = ((hawk_val_mbs_t*)a0)->val.ptr; - path.len = ((hawk_val_mbs_t*)a0)->val.len; - npath = hawk_trim_bchars(path.ptr, &path.len, flags); - retv = hawk_rtx_makembsvalwithbchars(rtx, npath, path.len); - } - else - { - hawk_oocs_t path; - hawk_ooch_t* npath; - path.ptr = hawk_rtx_getvaloocstr(rtx, a0, &path.len); - if (!path.ptr) return -1; - /* because hawk_strxtrmx() returns the pointer and the length without - * affecting the string given, it's safe to pass the original value. - * hawk_rtx_getvaloocstr() doesn't duplicate the value if it's of - * the string type. */ - npath = hawk_trim_oochars(path.ptr, &path.len, flags); - retv = hawk_rtx_makestrvalwithoochars(rtx, npath, path.len); - hawk_rtx_freevaloocstr (rtx, a0, path.ptr); + case HAWK_VAL_BCHR: + case HAWK_VAL_MBS: + { + hawk_bcs_t path; + hawk_bch_t* npath; + path.ptr = hawk_rtx_getvalbcstr(rtx, a0, &path.len); + if (HAWK_UNLIKELY(!path.ptr)) return -1; + npath = hawk_trim_bchars(path.ptr, &path.len, flags); + retv = hawk_rtx_makembsvalwithbchars(rtx, npath, path.len); + hawk_rtx_freevalbcstr (rtx, a0, path.ptr); + break; + } + + default: + { + hawk_oocs_t path; + hawk_ooch_t* npath; + path.ptr = hawk_rtx_getvaloocstr(rtx, a0, &path.len); + if (HAWK_UNLIKELY(!path.ptr)) return -1; + /* because hawk_trim_oochars() returns the pointer and the length without + * affecting the string given, it's safe to pass the original value. + * hawk_rtx_getvaloocstr() doesn't duplicate the value if it's of + * the string type. */ + npath = hawk_trim_oochars(path.ptr, &path.len, flags); + retv = hawk_rtx_makestrvalwithoochars(rtx, npath, path.len); + hawk_rtx_freevaloocstr (rtx, a0, path.ptr); + break; + } } - if (!retv) return -1; + if (HAWK_UNLIKELY(!retv)) return -1; hawk_rtx_setretval (rtx, retv); return 0; } @@ -106,6 +120,8 @@ static int trim (hawk_rtx_t* rtx, int flags) static int fnc_trim (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) { + /* str::trim(" test string "); + str::trim(" test string ", str::TRIM_PAC_SPACES); */ if (hawk_rtx_getnargs(rtx) >= 2) { hawk_int_t iv; @@ -131,58 +147,67 @@ static int is_class (hawk_rtx_t* rtx, hawk_ooch_prop_t ctype) a0 = hawk_rtx_getarg(rtx, 0); - if (HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_MBS) + switch (HAWK_RTX_GETVALTYPE(rtx, a0)) { - hawk_bch_t* str0; - hawk_oow_t len0; - - str0 = ((hawk_val_mbs_t*)a0)->val.ptr; - len0 = ((hawk_val_mbs_t*)a0)->val.len; - - if (len0 <= 0) tmp = 0; - else + case HAWK_VAL_BCHR: + case HAWK_VAL_MBS: { - tmp = 1; - do + hawk_bch_t* str0; + hawk_oow_t len0; + + str0 = hawk_rtx_getvalbcstr(rtx, a0, &len0); + if (HAWK_UNLIKELY(!str0)) return -1; + + if (len0 <= 0) tmp = 0; + else { - len0--; - if (!hawk_is_bch_type(str0[len0], ctype)) + tmp = 1; + do { - tmp = 0; - break; + len0--; + if (!hawk_is_bch_type(str0[len0], ctype)) + { + tmp = 0; + break; + } } + while (len0 > 0); } - while (len0 > 0); + + hawk_rtx_freevalbcstr (rtx, a0, str0); + break; } - } - else - { - hawk_ooch_t* str0; - hawk_oow_t len0; - str0 = hawk_rtx_getvaloocstr(rtx, a0, &len0); - if (!str0) return -1; - - if (len0 <= 0) tmp = 0; - else + default: { - tmp = 1; - do + hawk_ooch_t* str0; + hawk_oow_t len0; + + str0 = hawk_rtx_getvaloocstr(rtx, a0, &len0); + if (HAWK_UNLIKELY(!str0)) return -1; + + if (len0 <= 0) tmp = 0; + else { - len0--; - if (!hawk_is_ooch_type(str0[len0], ctype)) + tmp = 1; + do { - tmp = 0; - break; + len0--; + if (!hawk_is_ooch_type(str0[len0], ctype)) + { + tmp = 0; + break; + } } + while (len0 > 0); } - while (len0 > 0); + hawk_rtx_freevaloocstr (rtx, a0, str0); + break; } - hawk_rtx_freevaloocstr (rtx, a0, str0); } a0 = hawk_rtx_makeintval (rtx, tmp); - if (!a0) return -1; + if (HAWK_UNLIKELY(!a0)) return -1; hawk_rtx_setretval (rtx, a0); return 0; @@ -248,6 +273,59 @@ static int fnc_isxdigit (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) return is_class(rtx, HAWK_OOCH_PROP_XDIGIT); } +static int fnc_frombcharcode (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) +{ + /* create a string from a series of character codes. + * create a character from a single character code. + * - str::fromcharcode(65) for 'A' + * - str::fromcharcode(65, 66, 67) for "ABC" */ + +/* TODO: how to support byte string? */ + + hawk_val_t* retv; + hawk_oow_t nargs, i; + hawk_bchu_t* ptr0; /* to guarantee the unsigned code conversion */ + + nargs = hawk_rtx_getnargs(rtx); + + if (nargs == 1) + { + hawk_val_t* a0; + hawk_int_t cc; + + a0 = hawk_rtx_getarg(rtx, 0); + if (hawk_rtx_valtoint(rtx, a0, &cc) <= -1) return -1; + + retv = hawk_rtx_makecharval(rtx, (hawk_ooch_t)cc); + if (HAWK_UNLIKELY(!retv)) return -1; + } + else + { + retv = hawk_rtx_makembsvalwithbchars(rtx, HAWK_NULL, nargs); + if (HAWK_UNLIKELY(!retv)) return -1; + + ptr0 = (hawk_bchu_t*)((hawk_val_mbs_t*)retv)->val.ptr; + + for (i = 0; i < nargs; i++) + { + hawk_val_t* a0; + hawk_int_t cc; + + a0 = hawk_rtx_getarg(rtx, i); + if (hawk_rtx_valtoint(rtx, a0, &cc) <= -1) + { + hawk_rtx_freeval (rtx, retv, 0); + return -1; + } + + ptr0[i] = cc; + } + } + + hawk_rtx_setretval (rtx, retv); + return 0; +} + static int fnc_fromcharcode (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) { /* create a string from a series of character codes. @@ -255,6 +333,8 @@ static int fnc_fromcharcode (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) * - str::fromcharcode(65) for 'A' * - str::fromcharcode(65, 66, 67) for "ABC" */ +/* TODO: how to support byte string? */ + hawk_val_t* retv; hawk_oow_t nargs, i; hawk_oochu_t* ptr0; /* to guarantee the unsigned code conversion */ @@ -318,49 +398,50 @@ static int fnc_tocharcode (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) pos--; /* 1 based indexing. range check to be done before accessing below */ } - if (HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_MBS) + switch (HAWK_RTX_GETVALTYPE(rtx, a0)) { - hawk_bch_t* str0; - hawk_oow_t len0; - - str0 = ((hawk_val_mbs_t*)a0)->val.ptr; - len0 = ((hawk_val_mbs_t*)a0)->val.len; - - if (pos >= 0 && pos < len0) + case HAWK_VAL_BCHR: + case HAWK_VAL_MBS: { - #if defined(HAWK_OOCH_IS_BCH) - /* typecasting in case hawk_bch_t is signed */ - iv = (unsigned char)str0[pos]; - #else - iv = str0[pos]; - #endif - } - } - else - { - hawk_ooch_t* str0; - hawk_oow_t len0; + hawk_bch_t* str0; + hawk_oow_t len0; - str0 = hawk_rtx_getvaloocstr(rtx, a0, &len0); - if (!str0) return -1; + str0 = hawk_rtx_getvalbcstr(rtx, a0, &len0); + if (HAWK_UNLIKELY(!str0)) return -1; - if (pos >= 0 && pos < len0) - { - #if defined(HAWK_OOCH_IS_BCH) - /* typecasting in case hawk_bch_t is signed */ - iv = (unsigned char)str0[pos]; - #else - iv = str0[pos]; - #endif + if (pos >= 0 && pos < len0) + { + /* typecasting in case hawk_bch_t is signed */ + iv = (hawk_bchu_t)str0[pos]; + } + + hawk_rtx_freevalbcstr(rtx, a0, str0); + break; } - hawk_rtx_freevaloocstr(rtx, a0, str0); + default: + { + hawk_ooch_t* str0; + hawk_oow_t len0; + + str0 = hawk_rtx_getvaloocstr(rtx, a0, &len0); + if (HAWK_UNLIKELY(!str0)) return -1; + + if (pos >= 0 && pos < len0) + { + /* typecasting in case hawk_bch_t is signed */ + iv = (hawk_oochu_t)str0[pos]; + } + + hawk_rtx_freevaloocstr(rtx, a0, str0); + break; + } } if (iv >= 0) { retv = hawk_rtx_makeintval(rtx, iv); - if (!retv) return -1; + if (HAWK_UNLIKELY(!retv)) return -1; hawk_rtx_setretval (rtx, retv); } @@ -498,6 +579,22 @@ static int fnc_tonum (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) { switch (HAWK_RTX_GETVALTYPE(rtx, a0)) { + case HAWK_VAL_BCHR: + { + /* if the value is known to be a string, it supports the optional + * base parameter */ + hawk_val_t* a1 = hawk_rtx_getarg(rtx, 1); + hawk_int_t base; + hawk_bch_t tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, a0); + + if (hawk_rtx_valtoint(rtx, a1, &base) <= -1) return -1; + rx = hawk_bchars_to_num( + HAWK_OOCHARS_TO_NUM_MAKE_OPTION(0, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), base), + &tmp, 1, &lv, &rv + ); + break; + } + case HAWK_VAL_MBS: { /* if the value is known to be a byte string, it supports the optional @@ -595,38 +692,45 @@ static int fnc_subchar (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) lindex = lindex - 1; - if (HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_MBS) + switch (HAWK_RTX_GETVALTYPE(rtx, a0)) { - hawk_bch_t* str; - hawk_oow_t len; + case HAWK_VAL_BCHR: + case HAWK_VAL_MBS: + { + hawk_bch_t* str; + hawk_oow_t len; - str = ((hawk_val_mbs_t*)a0)->val.ptr; - len = ((hawk_val_mbs_t*)a0)->val.len; + str = hawk_rtx_getvalbcstr(rtx, a0, &len); + if (!str) return -1; - if (lindex >= 0 && lindex < (hawk_int_t)len) - r = hawk_rtx_makebchrval(rtx, str[lindex]); - else - r = hawk_rtx_makenilval(rtx); + if (lindex >= 0 && lindex < (hawk_int_t)len) + r = hawk_rtx_makebchrval(rtx, str[lindex]); + else + r = hawk_rtx_makenilval(rtx); - if (HAWK_UNLIKELY(!r)) return -1; - } - else - { - hawk_ooch_t* str; - hawk_oow_t len; + hawk_rtx_freevalbcstr (rtx, a0, str); + break; + } + + default: + { + hawk_ooch_t* str; + hawk_oow_t len; - str = hawk_rtx_getvaloocstr(rtx, a0, &len); - if (!str) return -1; + str = hawk_rtx_getvaloocstr(rtx, a0, &len); + if (!str) return -1; - if (lindex >= 0 && lindex < (hawk_int_t)len) - r = hawk_rtx_makecharval(rtx, str[lindex]); - else - r = hawk_rtx_makenilval(rtx); + if (lindex >= 0 && lindex < (hawk_int_t)len) + r = hawk_rtx_makecharval(rtx, str[lindex]); + else + r = hawk_rtx_makenilval(rtx); - hawk_rtx_freevaloocstr (rtx, a0, str); - if (HAWK_UNLIKELY(!r)) return -1; + hawk_rtx_freevaloocstr (rtx, a0, str); + break; + } } + if (HAWK_UNLIKELY(!r)) return -1; hawk_rtx_setretval (rtx, r); return 0; } @@ -650,40 +754,41 @@ struct inttab_t static fnctab_t fnctab[] = { /* keep this table sorted for binary search in query(). */ - { HAWK_T("fromcharcode"), { { 0, A_MAX, HAWK_NULL }, fnc_fromcharcode, 0 } }, - { HAWK_T("frommbs"), { { 1, 2, HAWK_NULL }, fnc_frommbs, 0 } }, - { HAWK_T("gsub"), { { 2, 3, HAWK_T("xvr")}, hawk_fnc_gsub, 0 } }, - { HAWK_T("index"), { { 2, 3, HAWK_NULL }, hawk_fnc_index, 0 } }, - { HAWK_T("isalnum"), { { 1, 1, HAWK_NULL }, fnc_isalnum, 0 } }, - { HAWK_T("isalpha"), { { 1, 1, HAWK_NULL }, fnc_isalpha, 0 } }, - { HAWK_T("isblank"), { { 1, 1, HAWK_NULL }, fnc_isblank, 0 } }, - { HAWK_T("iscntrl"), { { 1, 1, HAWK_NULL }, fnc_iscntrl, 0 } }, - { HAWK_T("isdigit"), { { 1, 1, HAWK_NULL }, fnc_isdigit, 0 } }, - { HAWK_T("isgraph"), { { 1, 1, HAWK_NULL }, fnc_isgraph, 0 } }, - { HAWK_T("islower"), { { 1, 1, HAWK_NULL }, fnc_islower, 0 } }, - { HAWK_T("isprint"), { { 1, 1, HAWK_NULL }, fnc_isprint, 0 } }, - { HAWK_T("ispunct"), { { 1, 1, HAWK_NULL }, fnc_ispunct, 0 } }, - { HAWK_T("isspace"), { { 1, 1, HAWK_NULL }, fnc_isspace, 0 } }, - { HAWK_T("isupper"), { { 1, 1, HAWK_NULL }, fnc_isupper, 0 } }, - { HAWK_T("isxdigit"), { { 1, 1, HAWK_NULL }, fnc_isxdigit, 0 } }, - { HAWK_T("length"), { { 1, 1, HAWK_NULL }, hawk_fnc_length, 0 } }, - { HAWK_T("ltrim"), { { 1, 1, HAWK_NULL }, fnc_ltrim, 0 } }, - { HAWK_T("match"), { { 2, 4, HAWK_T("vxvr") }, hawk_fnc_match, 0 } }, - { HAWK_T("normspace"), { { 1, 1, HAWK_NULL }, fnc_normspace, 0 } }, /* deprecated, use trim("xxx", str::TRIM_PAC_SPACES) */ - { HAWK_T("printf"), { { 1, A_MAX, HAWK_NULL }, hawk_fnc_sprintf, 0 } }, - { HAWK_T("rindex"), { { 2, 3, HAWK_NULL }, hawk_fnc_rindex, 0 } }, - { HAWK_T("rtrim"), { { 1, 1, HAWK_NULL }, fnc_rtrim, 0 } }, - { HAWK_T("split"), { { 2, 3, HAWK_T("vrx") }, hawk_fnc_split, 0 } }, - { HAWK_T("splita"), { { 2, 3, HAWK_T("vrx") }, hawk_fnc_splita, 0 } }, /* split to array. asplit is not a good name for this */ - { HAWK_T("sub"), { { 2, 3, HAWK_T("xvr") }, hawk_fnc_sub, 0 } }, - { HAWK_T("subchar"), { { 2, 2, HAWK_NULL }, fnc_subchar, 0 } }, - { HAWK_T("substr"), { { 2, 3, HAWK_NULL }, hawk_fnc_substr, 0 } }, - { HAWK_T("tocharcode"), { { 1, 2, HAWK_NULL }, fnc_tocharcode, 0 } }, - { HAWK_T("tolower"), { { 1, 1, HAWK_NULL }, hawk_fnc_tolower, 0 } }, - { HAWK_T("tombs"), { { 1, 2, HAWK_NULL }, fnc_tombs, 0 } }, - { HAWK_T("tonum"), { { 1, 2, HAWK_NULL }, fnc_tonum, 0 } }, - { HAWK_T("toupper"), { { 1, 1, HAWK_NULL }, hawk_fnc_toupper, 0 } }, - { HAWK_T("trim"), { { 1, 2, HAWK_NULL }, fnc_trim, 0 } } + { HAWK_T("frombcharcode"), { { 0, A_MAX, HAWK_NULL }, fnc_frombcharcode, 0 } }, + { HAWK_T("fromcharcode"), { { 0, A_MAX, HAWK_NULL }, fnc_fromcharcode, 0 } }, + { HAWK_T("frommbs"), { { 1, 2, HAWK_NULL }, fnc_frommbs, 0 } }, + { HAWK_T("gsub"), { { 2, 3, HAWK_T("xvr")}, hawk_fnc_gsub, 0 } }, + { HAWK_T("index"), { { 2, 3, HAWK_NULL }, hawk_fnc_index, 0 } }, + { HAWK_T("isalnum"), { { 1, 1, HAWK_NULL }, fnc_isalnum, 0 } }, + { HAWK_T("isalpha"), { { 1, 1, HAWK_NULL }, fnc_isalpha, 0 } }, + { HAWK_T("isblank"), { { 1, 1, HAWK_NULL }, fnc_isblank, 0 } }, + { HAWK_T("iscntrl"), { { 1, 1, HAWK_NULL }, fnc_iscntrl, 0 } }, + { HAWK_T("isdigit"), { { 1, 1, HAWK_NULL }, fnc_isdigit, 0 } }, + { HAWK_T("isgraph"), { { 1, 1, HAWK_NULL }, fnc_isgraph, 0 } }, + { HAWK_T("islower"), { { 1, 1, HAWK_NULL }, fnc_islower, 0 } }, + { HAWK_T("isprint"), { { 1, 1, HAWK_NULL }, fnc_isprint, 0 } }, + { HAWK_T("ispunct"), { { 1, 1, HAWK_NULL }, fnc_ispunct, 0 } }, + { HAWK_T("isspace"), { { 1, 1, HAWK_NULL }, fnc_isspace, 0 } }, + { HAWK_T("isupper"), { { 1, 1, HAWK_NULL }, fnc_isupper, 0 } }, + { HAWK_T("isxdigit"), { { 1, 1, HAWK_NULL }, fnc_isxdigit, 0 } }, + { HAWK_T("length"), { { 1, 1, HAWK_NULL }, hawk_fnc_length, 0 } }, + { HAWK_T("ltrim"), { { 1, 1, HAWK_NULL }, fnc_ltrim, 0 } }, + { HAWK_T("match"), { { 2, 4, HAWK_T("vxvr") }, hawk_fnc_match, 0 } }, + { HAWK_T("normspace"), { { 1, 1, HAWK_NULL }, fnc_normspace, 0 } }, /* deprecated, use trim("xxx", str::TRIM_PAC_SPACES) */ + { HAWK_T("printf"), { { 1, A_MAX, HAWK_NULL }, hawk_fnc_sprintf, 0 } }, + { HAWK_T("rindex"), { { 2, 3, HAWK_NULL }, hawk_fnc_rindex, 0 } }, + { HAWK_T("rtrim"), { { 1, 1, HAWK_NULL }, fnc_rtrim, 0 } }, + { HAWK_T("split"), { { 2, 3, HAWK_T("vrx") }, hawk_fnc_split, 0 } }, + { HAWK_T("splita"), { { 2, 3, HAWK_T("vrx") }, hawk_fnc_splita, 0 } }, /* split to array. asplit is not a good name for this */ + { HAWK_T("sub"), { { 2, 3, HAWK_T("xvr") }, hawk_fnc_sub, 0 } }, + { HAWK_T("subchar"), { { 2, 2, HAWK_NULL }, fnc_subchar, 0 } }, + { HAWK_T("substr"), { { 2, 3, HAWK_NULL }, hawk_fnc_substr, 0 } }, + { HAWK_T("tocharcode"), { { 1, 2, HAWK_NULL }, fnc_tocharcode, 0 } }, + { HAWK_T("tolower"), { { 1, 1, HAWK_NULL }, hawk_fnc_tolower, 0 } }, + { HAWK_T("tombs"), { { 1, 2, HAWK_NULL }, fnc_tombs, 0 } }, + { HAWK_T("tonum"), { { 1, 2, HAWK_NULL }, fnc_tonum, 0 } }, + { HAWK_T("toupper"), { { 1, 1, HAWK_NULL }, hawk_fnc_toupper, 0 } }, + { HAWK_T("trim"), { { 1, 2, HAWK_NULL }, fnc_trim, 0 } } }; static inttab_t inttab[] = diff --git a/hawk/lib/parse.c b/hawk/lib/parse.c index 20992570..c452fed3 100644 --- a/hawk/lib/parse.c +++ b/hawk/lib/parse.c @@ -4666,7 +4666,7 @@ static hawk_nde_t* parse_primary_char (hawk_t* hawk, const hawk_loc_t* xloc) { hawk_nde_char_t* nde; - nde = (hawk_nde_char_t*)hawk_callocmem (hawk, HAWK_SIZEOF(*nde)); + nde = (hawk_nde_char_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*nde)); if (HAWK_UNLIKELY(!nde)) { ADJERR_LOC (hawk, xloc); @@ -4691,7 +4691,7 @@ static hawk_nde_t* parse_primary_bchr (hawk_t* hawk, const hawk_loc_t* xloc) { hawk_nde_bchr_t* nde; - nde = (hawk_nde_bchr_t*)hawk_callocmem (hawk, HAWK_SIZEOF(*nde)); + nde = (hawk_nde_bchr_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*nde)); if (HAWK_UNLIKELY(!nde)) { ADJERR_LOC (hawk, xloc); @@ -4717,7 +4717,7 @@ static hawk_nde_t* parse_primary_int (hawk_t* hawk, const hawk_loc_t* xloc) hawk_nde_int_t* nde; /* create the node for the literal */ - nde = (hawk_nde_int_t*)new_int_node ( + nde = (hawk_nde_int_t*)new_int_node( hawk, hawk_oochars_to_int (HAWK_OOECS_PTR(hawk->tok.name), HAWK_OOECS_LEN(hawk->tok.name), HAWK_OOCHARS_TO_INT_MAKE_OPTION(0, 0, 0), HAWK_NULL, HAWK_NULL), xloc @@ -4801,7 +4801,7 @@ static hawk_nde_t* parse_primary_mbs (hawk_t* hawk, const hawk_loc_t* xloc) hawk_nde_mbs_t* nde; nde = (hawk_nde_mbs_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*nde)); - if (nde == HAWK_NULL) + if (HAWK_UNLIKELY(!nde)) { ADJERR_LOC (hawk, xloc); return HAWK_NULL; @@ -5212,7 +5212,7 @@ static hawk_nde_t* parse_primary (hawk_t* hawk, const hawk_loc_t* xloc) hawk_loc_t ploc; left = parse_primary_nopipe(hawk, xloc); - if (left == HAWK_NULL) goto oops; + if (!left) goto oops; /* handle the piping part */ do @@ -5288,7 +5288,7 @@ static hawk_nde_t* parse_primary (hawk_t* hawk, const hawk_loc_t* xloc) novar: nde = (hawk_nde_getline_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*nde)); - if (nde == HAWK_NULL) + if (HAWK_UNLIKELY(!nde)) { ADJERR_LOC (hawk, xloc); goto oops; @@ -7243,7 +7243,7 @@ static int deparse (hawk_t* hawk) */ } - if (flush_out (hawk) <= -1) EXIT_DEPARSE (); + if (flush_out(hawk) <= -1) EXIT_DEPARSE (); exit_deparse: if (hawk->sio.outf(hawk, HAWK_SIO_CMD_CLOSE, &hawk->sio.arg, HAWK_NULL, 0) != 0 && n == 0) n = -1; diff --git a/hawk/lib/rio.c b/hawk/lib/rio.c index c405fce9..07855cc4 100644 --- a/hawk/lib/rio.c +++ b/hawk/lib/rio.c @@ -996,9 +996,21 @@ int hawk_rtx_writeioval (hawk_rtx_t* rtx, int out_type, const hawk_ooch_t* name, switch (vtype) { + case HAWK_VAL_CHAR: + { + hawk_ooch_t tmp = HAWK_RTX_GETCHARFROMVAL(rtx, v); + return hawk_rtx_writeiostr(rtx, out_type, name, &tmp, 1); + } + case HAWK_VAL_STR: return hawk_rtx_writeiostr(rtx, out_type, name, ((hawk_val_str_t*)v)->val.ptr, ((hawk_val_str_t*)v)->val.len); + case HAWK_VAL_BCHR: + { + hawk_bch_t tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v); + return hawk_rtx_writeiobytes(rtx, out_type, name, &tmp, 1); + } + case HAWK_VAL_MBS: return hawk_rtx_writeiobytes(rtx, out_type, name, ((hawk_val_mbs_t*)v)->val.ptr, ((hawk_val_mbs_t*)v)->val.len); @@ -1006,7 +1018,6 @@ int hawk_rtx_writeioval (hawk_rtx_t* rtx, int out_type, const hawk_ooch_t* name, { hawk_rtx_valtostr_out_t out; int n; - out.type = HAWK_RTX_VALTOSTR_CPLDUP | HAWK_RTX_VALTOSTR_PRINT; if (hawk_rtx_valtostr(rtx, v, &out) <= -1) return -1; n = hawk_rtx_writeiostr(rtx, out_type, name, out.u.cpldup.ptr, out.u.cpldup.len); diff --git a/hawk/lib/run.c b/hawk/lib/run.c index 0a68cfb5..a3f428c1 100644 --- a/hawk/lib/run.c +++ b/hawk/lib/run.c @@ -897,6 +897,16 @@ hawk_rtx_t* hawk_rtx_open (hawk_t* hawk, hawk_oow_t xtnsize, hawk_rio_cbs_t* rio /* rtx->ctos.b[0] is not used as the free index of 0 indicates the end of the list. * see hawk_rtx_getvaloocstr(). */ + /* chain the bctos slots */ + rtx->bctos.fi = HAWK_COUNTOF(rtx->bctos.b) - 1; + for (i = HAWK_COUNTOF(rtx->bctos.b); i > 1;) + { + --i; + rtx->bctos.b[i].c[0] = i - 1; + } + /* rtx->bctos.b[0] is not used as the free index of 0 indicates the end of the list. + * see hawk_rtx_getvaloocstr(). */ + return rtx; } @@ -5282,7 +5292,6 @@ static HAWK_INLINE int __cmp_mbs_bchr (hawk_rtx_t* rtx, hawk_val_t* left, hawk_v return -n; } - static HAWK_INLINE int __cmp_mbs_int (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right, cmp_op_t op_hint) { int n; @@ -5612,11 +5621,19 @@ static int teq_val (hawk_rtx_t* rtx, hawk_val_t* left, hawk_val_t* right) break; case HAWK_VAL_CHAR: - n = (HAWK_RTX_GETCHARFROMVAL (rtx, left) == HAWK_RTX_GETCHARFROMVAL (rtx, right)); + /* since a CHAR value is only reprensented in the value pointer, + * n is guaranteed to be 0 here. so the following check isn't needed */ + n = (HAWK_RTX_GETCHARFROMVAL(rtx, left) == HAWK_RTX_GETCHARFROMVAL(rtx, right)); + break; + + case HAWK_VAL_BCHR: + /* since a BCHR value is only reprensented in the value pointer, + * n is guaranteed to be 0 here. so the following check isn't needed */ + n = (HAWK_RTX_GETBCHRFROMVAL(rtx, left) == HAWK_RTX_GETBCHRFROMVAL(rtx, right)); break; case HAWK_VAL_INT: - n = (HAWK_RTX_GETINTFROMVAL (rtx, left) == HAWK_RTX_GETINTFROMVAL (rtx, right)); + n = (HAWK_RTX_GETINTFROMVAL(rtx, left) == HAWK_RTX_GETINTFROMVAL(rtx, right)); break; case HAWK_VAL_FLT: @@ -6054,44 +6071,50 @@ static hawk_val_t* eval_binop_concat (hawk_rtx_t* rtx, hawk_val_t* left, hawk_va { hawk_val_t* res; - if (HAWK_RTX_GETVALTYPE(rtx, left) == HAWK_VAL_MBS) + switch (HAWK_RTX_GETVALTYPE(rtx, left)) { - hawk_bcs_t l, r; - - l.ptr = hawk_rtx_getvalbcstr(rtx, left, &l.len); - if (HAWK_UNLIKELY(!l.ptr)) return HAWK_NULL; - - r.ptr = hawk_rtx_getvalbcstr(rtx, right, &r.len); - if (HAWK_UNLIKELY(!r.ptr)) + case HAWK_VAL_BCHR: + case HAWK_VAL_MBS: { + hawk_bcs_t l, r; + + l.ptr = hawk_rtx_getvalbcstr(rtx, left, &l.len); + if (HAWK_UNLIKELY(!l.ptr)) return HAWK_NULL; + + r.ptr = hawk_rtx_getvalbcstr(rtx, right, &r.len); + if (HAWK_UNLIKELY(!r.ptr)) + { + hawk_rtx_freevalbcstr (rtx, left, l.ptr); + return HAWK_NULL; + } + + res = (hawk_val_t*)hawk_rtx_makembsvalwithbchars2(rtx, l.ptr, l.len, r.ptr, r.len); + + hawk_rtx_freevalbcstr (rtx, right, r.ptr); hawk_rtx_freevalbcstr (rtx, left, l.ptr); - return HAWK_NULL; + break; } - res = (hawk_val_t*)hawk_rtx_makembsvalwithbchars2(rtx, l.ptr, l.len, r.ptr, r.len); - - hawk_rtx_freevalbcstr (rtx, right, r.ptr); - hawk_rtx_freevalbcstr (rtx, left, l.ptr); - } - else - { - - hawk_oocs_t l, r; - - l.ptr = hawk_rtx_getvaloocstr(rtx, left, &l.len); - if (HAWK_UNLIKELY(!l.ptr)) return HAWK_NULL; - - r.ptr = hawk_rtx_getvaloocstr(rtx, right, &r.len); - if (HAWK_UNLIKELY(!r.ptr)) + default: { + hawk_oocs_t l, r; + + l.ptr = hawk_rtx_getvaloocstr(rtx, left, &l.len); + if (HAWK_UNLIKELY(!l.ptr)) return HAWK_NULL; + + r.ptr = hawk_rtx_getvaloocstr(rtx, right, &r.len); + if (HAWK_UNLIKELY(!r.ptr)) + { + hawk_rtx_freevaloocstr (rtx, left, l.ptr); + return HAWK_NULL; + } + + res = (hawk_val_t*)hawk_rtx_makestrvalwithoochars2(rtx, l.ptr, l.len, r.ptr, r.len); + + hawk_rtx_freevaloocstr (rtx, right, r.ptr); hawk_rtx_freevaloocstr (rtx, left, l.ptr); - return HAWK_NULL; + break; } - - res = (hawk_val_t*)hawk_rtx_makestrvalwithoochars2(rtx, l.ptr, l.len, r.ptr, r.len); - - hawk_rtx_freevaloocstr (rtx, right, r.ptr); - hawk_rtx_freevaloocstr (rtx, left, l.ptr); } return res; @@ -8141,8 +8164,9 @@ hawk_ooch_t* hawk_rtx_format ( if (nargs_on_stack == (hawk_oow_t)-1) { + /* dirty hack to support a single value argument instead of a tree node */ val = (hawk_val_t*)args; - nargs_on_stack = 2; + nargs_on_stack = 2; /* indicate 2 arguments of a formatting specifier and the given value */ } else { @@ -8227,7 +8251,7 @@ wp_mod_main: hawk_val_t* v; int n; - if (args == HAWK_NULL) + if (!args) { if (stack_arg_idx >= nargs_on_stack) { @@ -8284,7 +8308,7 @@ wp_mod_main: FMT_STR(rtx->format.tmp.ptr, n); - if (args == HAWK_NULL || val != HAWK_NULL) stack_arg_idx++; + if (!args || val) stack_arg_idx++; else args = args->next; i++; } @@ -8334,7 +8358,7 @@ wp_mod_main: hawk_ooch_t fmt_fill = HAWK_T('\0'); const hawk_ooch_t* fmt_prefix = HAWK_NULL; - if (args == HAWK_NULL) + if (!args) { if (stack_arg_idx >= nargs_on_stack) { @@ -8345,7 +8369,7 @@ wp_mod_main: } else { - if (val != HAWK_NULL) + if (val) { if (stack_arg_idx >= nargs_on_stack) { @@ -8534,19 +8558,12 @@ wp_mod_main: fmt[i] == HAWK_T('g') || fmt[i] == HAWK_T('G') || fmt[i] == HAWK_T('f')) { + hawk_val_t* v; hawk_flt_t r; int n; - #if defined(HAWK_USE_FLTMAX) - /*FMT_CHAR (HAWK_T('j'));*/ - FMT_STR (HAWK_T("jj"), 2); /* see fmt.c for info on jj */ - #else - FMT_CHAR (HAWK_T('z')); - #endif - FMT_CHAR (fmt[i]); - - if (args == HAWK_NULL) + if (!args) { if (stack_arg_idx >= nargs_on_stack) { @@ -8557,7 +8574,7 @@ wp_mod_main: } else { - if (val != HAWK_NULL) + if (val) /* nargs_on_stack == (hawk_oow_t)-1 */ { if (stack_arg_idx >= nargs_on_stack) { @@ -8579,9 +8596,14 @@ wp_mod_main: if (n <= -1) return HAWK_NULL; #if defined(HAWK_USE_FLTMAX) + /*FMT_CHAR (HAWK_T('j'));*/ + FMT_STR (HAWK_T("jj"), 2); /* see fmt.c for info on jj */ + FMT_CHAR (fmt[i]); /*if (hawk_ooecs_fcat(out, HAWK_OOECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL;*/ if (hawk_ooecs_fcat(out, HAWK_OOECS_PTR(fbu), &r) == (hawk_oow_t)-1) return HAWK_NULL; #else + FMT_CHAR (HAWK_T('z')); + FMT_CHAR (fmt[i]); if (hawk_ooecs_fcat(out, HAWK_OOECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL; #endif } @@ -8592,18 +8614,18 @@ wp_mod_main: hawk_val_t* v; hawk_val_type_t vtype; - if (args == HAWK_NULL) + if (!args) { if (stack_arg_idx >= nargs_on_stack) { hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EFMTARG); return HAWK_NULL; } - v = hawk_rtx_getarg (rtx, stack_arg_idx); + v = hawk_rtx_getarg(rtx, stack_arg_idx); } else { - if (val != HAWK_NULL) + if (val) { if (stack_arg_idx >= nargs_on_stack) { @@ -8633,6 +8655,11 @@ wp_mod_main: ch_len = 1; break; + case HAWK_VAL_BCHR: + ch = (hawk_ooch_t)HAWK_RTX_GETBCHRFROMVAL(rtx, v); + ch_len = 1; + break; + case HAWK_VAL_INT: ch = (hawk_ooch_t)HAWK_RTX_GETINTFROMVAL(rtx, v); ch_len = 1; @@ -8708,14 +8735,9 @@ wp_mod_main: } else if (fmt[i] == HAWK_T('s') || fmt[i] == HAWK_T('k') || fmt[i] == HAWK_T('K')) { - hawk_ooch_t* str_ptr, * str_free = HAWK_NULL; - hawk_oow_t str_len; - hawk_int_t k; hawk_val_t* v; - hawk_val_type_t vtype; - int bytetostr_flagged_radix = 16; - if (args == HAWK_NULL) + if (!args) { if (stack_arg_idx >= nargs_on_stack) { @@ -8742,153 +8764,207 @@ wp_mod_main: } } - hawk_rtx_refupval (rtx, v); - - vtype = HAWK_RTX_GETVALTYPE(rtx, v); - switch (vtype) + if (val) { - case HAWK_VAL_NIL: - str_ptr = HAWK_T(""); - str_len = 0; - break; + /* val_flt_to_str() in val.c calls hawk_rtx_format() with nargs_on_stack of (hawk_oow_t)-1 and the actual value. + * the actual value is assigned to 'val' at the beginning of this function. + * + * the following code can drive here. + * BEGIN { CONVFMT="%s"; a=98.76 ""; } + * + * when the first attempt to convert 98.76 to a textual form invokes this function with %s and 98.76. + * it comes to this part because the format specifier is 's'. since the floating-point type is not + * specially handled, hawk_rtx_valtooocstrdup() is called below. it calls val_flt_to_str() again, + * which eventually creates recursion and stack depletion. + * + * assuming only val_flt_to_str() calls it this way, i must convert the floating point number + * to text in a rather crude way without calling hawk_rtx_valtooocstrdup(). + */ + hawk_flt_t r; + int n; - case HAWK_VAL_STR: - str_ptr = ((hawk_val_str_t*)v)->val.ptr; - str_len = ((hawk_val_str_t*)v)->val.len; - break; + HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, val) == HAWK_VAL_FLT); - case HAWK_VAL_MBS: - #if defined(HAWK_OOCH_IS_BCH) - str_ptr = ((hawk_val_mbs_t*)v)->val.ptr; - str_len = ((hawk_val_mbs_t*)v)->val.len; - break; - #else - if (fmt[i] != HAWK_T('s')) - { + hawk_rtx_refupval (rtx, v); + n = hawk_rtx_valtoflt(rtx, v, &r); + hawk_rtx_refdownval (rtx, v); + if (n <= -1) return HAWK_NULL; + + /* format the value as if '%g' is given */ + #if defined(HAWK_USE_FLTMAX) + FMT_STR (HAWK_T("jjg"), 3); /* see fmt.c for info on jj */ + if (hawk_ooecs_fcat(out, HAWK_OOECS_PTR(fbu), &r) == (hawk_oow_t)-1) return HAWK_NULL; + #else + FMT_STR (HAWK_T("zg"), 2); + if (hawk_ooecs_fcat(out, HAWK_OOECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL; + #endif + } + else + { + hawk_ooch_t* str_ptr, * str_free = HAWK_NULL, ooch_tmp; + hawk_bch_t bch_tmp; + hawk_oow_t str_len; + hawk_int_t k; + hawk_val_type_t vtype; + int bytetostr_flagged_radix = 16; + + hawk_rtx_refupval (rtx, v); + + vtype = HAWK_RTX_GETVALTYPE(rtx, v); + switch (vtype) + { + case HAWK_VAL_NIL: + str_ptr = HAWK_T(""); + str_len = 0; + break; + + case HAWK_VAL_CHAR: + ooch_tmp = HAWK_RTX_GETCHARFROMVAL(rtx, v); + str_ptr = &ooch_tmp; + str_len = 1; + break; + + case HAWK_VAL_STR: + str_ptr = ((hawk_val_str_t*)v)->val.ptr; + str_len = ((hawk_val_str_t*)v)->val.len; + break; + + case HAWK_VAL_BCHR: + #if defined(HAWK_OOCH_IS_BCH) + ooch_tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v); + str_ptr = &ooch_tmp; + str_len = 1; + #else + if (fmt[i] == HAWK_T('s')) goto duplicate; + bch_tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v); + str_ptr = (hawk_ooch_t*)&bch_tmp; + str_len = 1; + #endif + break; + + case HAWK_VAL_MBS: + #if defined(HAWK_OOCH_IS_BCH) + str_ptr = ((hawk_val_mbs_t*)v)->val.ptr; + str_len = ((hawk_val_mbs_t*)v)->val.len; + #else + if (fmt[i] == HAWK_T('s')) goto duplicate; str_ptr = (hawk_ooch_t*)((hawk_val_mbs_t*)v)->val.ptr; str_len = ((hawk_val_mbs_t*)v)->val.len; + #endif break; + + default: + duplicate: + str_ptr = hawk_rtx_valtooocstrdup(rtx, v, &str_len); + if (!str_ptr) + { + hawk_rtx_refdownval (rtx, v); + return HAWK_NULL; + } + + str_free = str_ptr; + break; + + } + + if (wp_idx != WP_PRECISION || wp[WP_PRECISION] <= -1 || wp[WP_PRECISION] > (hawk_int_t)str_len) + { + /* precision not specified, or specified to a negative value or greater than the actual length */ + wp[WP_PRECISION] = (hawk_int_t)str_len; + } + if (wp[WP_PRECISION] > wp[WP_WIDTH]) wp[WP_WIDTH] = wp[WP_PRECISION]; + + if (!(flags & FLAG_MINUS)) + { + /* right align */ + while (wp[WP_WIDTH] > wp[WP_PRECISION]) + { + if (hawk_ooecs_ccat(out, HAWK_T(' ')) == (hawk_oow_t)-1) + { + if (str_free) hawk_rtx_freemem (rtx, str_free); + hawk_rtx_refdownval (rtx, v); + return HAWK_NULL; + } + wp[WP_WIDTH]--; } + } + + if (fmt[i] == HAWK_T('k')) bytetostr_flagged_radix |= HAWK_BYTE_TO_BCSTR_LOWERCASE; + + for (k = 0; k < wp[WP_PRECISION]; k++) + { + hawk_ooch_t curc; + + #if defined(HAWK_OOCH_IS_BCH) + curc = str_ptr[k]; + #else + if ((vtype == HAWK_VAL_MBS || vtype == HAWK_VAL_BCHR) && fmt[i] != HAWK_T('s')) + curc = (hawk_uint8_t)((hawk_bch_t*)str_ptr)[k]; + else curc = str_ptr[k]; #endif - default: - { - if (v == val) + if (fmt[i] != HAWK_T('s') && !HAWK_BYTE_PRINTABLE(curc)) { - hawk_rtx_refdownval (rtx, v); - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EFMTCNV); - return HAWK_NULL; - } - - str_ptr = hawk_rtx_valtooocstrdup(rtx, v, &str_len); - if (!str_ptr) - { - hawk_rtx_refdownval (rtx, v); - return HAWK_NULL; - } - - str_free = str_ptr; - break; - } - } - - if (wp_idx != WP_PRECISION || wp[WP_PRECISION] <= -1 || wp[WP_PRECISION] > (hawk_int_t)str_len) - { - /* precision not specified, or specified to a negative value or greater than the actual length */ - wp[WP_PRECISION] = (hawk_int_t)str_len; - } - if (wp[WP_PRECISION] > wp[WP_WIDTH]) wp[WP_WIDTH] = wp[WP_PRECISION]; - - if (!(flags & FLAG_MINUS)) - { - /* right align */ - while (wp[WP_WIDTH] > wp[WP_PRECISION]) - { - if (hawk_ooecs_ccat(out, HAWK_T(' ')) == (hawk_oow_t)-1) - { - if (str_free) hawk_rtx_freemem (rtx, str_free); - hawk_rtx_refdownval (rtx, v); - return HAWK_NULL; - } - wp[WP_WIDTH]--; - } - } - - if (fmt[i] == HAWK_T('k')) bytetostr_flagged_radix |= HAWK_BYTE_TO_BCSTR_LOWERCASE; - - for (k = 0; k < wp[WP_PRECISION]; k++) - { - hawk_ooch_t curc; - - #if defined(HAWK_OOCH_IS_BCH) - curc = str_ptr[k]; - #else - if (vtype == HAWK_VAL_MBS && fmt[i] != HAWK_T('s')) - curc = (hawk_uint8_t)((hawk_bch_t*)str_ptr)[k]; - else curc = str_ptr[k]; - #endif - - if (fmt[i] != HAWK_T('s') && !HAWK_BYTE_PRINTABLE(curc)) - { - hawk_ooch_t xbuf[3]; - if (curc <= 0xFF) - { - if (hawk_ooecs_ncat(out, HAWK_T("\\x"), 2) == (hawk_oow_t)-1) goto s_fail; - hawk_byte_to_oocstr(curc, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0')); - if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; - } - else if (curc <= 0xFFFF) - { - hawk_uint16_t u16 = curc; - if (hawk_ooecs_ncat(out, HAWK_T("\\u"), 2) == (hawk_oow_t)-1) goto s_fail; - hawk_byte_to_oocstr((u16 >> 8) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0')); - if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; - hawk_byte_to_oocstr(u16 & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0')); - if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + hawk_ooch_t xbuf[3]; + if (curc <= 0xFF) + { + if (hawk_ooecs_ncat(out, HAWK_T("\\x"), 2) == (hawk_oow_t)-1) goto s_fail; + hawk_byte_to_oocstr(curc, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0')); + if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + } + else if (curc <= 0xFFFF) + { + hawk_uint16_t u16 = curc; + if (hawk_ooecs_ncat(out, HAWK_T("\\u"), 2) == (hawk_oow_t)-1) goto s_fail; + hawk_byte_to_oocstr((u16 >> 8) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0')); + if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + hawk_byte_to_oocstr(u16 & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0')); + if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + } + else + { + hawk_uint32_t u32 = curc; + if (hawk_ooecs_ncat(out, HAWK_T("\\U"), 2) == (hawk_oow_t)-1) goto s_fail; + hawk_byte_to_oocstr((u32 >> 24) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0')); + if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + hawk_byte_to_oocstr((u32 >> 16) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0')); + if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + hawk_byte_to_oocstr((u32 >> 8) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0')); + if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + hawk_byte_to_oocstr(u32 & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0')); + if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + } } else { - hawk_uint32_t u32 = curc; - if (hawk_ooecs_ncat(out, HAWK_T("\\U"), 2) == (hawk_oow_t)-1) goto s_fail; - hawk_byte_to_oocstr((u32 >> 24) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0')); - if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; - hawk_byte_to_oocstr((u32 >> 16) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0')); - if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; - hawk_byte_to_oocstr((u32 >> 8) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0')); - if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; - hawk_byte_to_oocstr(u32 & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetostr_flagged_radix, HAWK_T('0')); - if (hawk_ooecs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + if (hawk_ooecs_ccat(out, curc) == (hawk_oow_t)-1) + { + s_fail: + if (str_free) hawk_rtx_freemem (rtx, str_free); + hawk_rtx_refdownval (rtx, v); + return HAWK_NULL; + } } } - else + + if (str_free) hawk_rtx_freemem (rtx, str_free); + + if (flags & FLAG_MINUS) { - if (hawk_ooecs_ccat(out, curc) == (hawk_oow_t)-1) + /* left align */ + while (wp[WP_WIDTH] > wp[WP_PRECISION]) { - s_fail: - if (str_free) hawk_rtx_freemem (rtx, str_free); - hawk_rtx_refdownval (rtx, v); - return HAWK_NULL; + if (hawk_ooecs_ccat(out, HAWK_T(' ')) == (hawk_oow_t)-1) + { + hawk_rtx_refdownval (rtx, v); + return HAWK_NULL; + } + wp[WP_WIDTH]--; } } + + hawk_rtx_refdownval (rtx, v); } - - if (str_free) hawk_rtx_freemem (rtx, str_free); - - if (flags & FLAG_MINUS) - { - /* left align */ - while (wp[WP_WIDTH] > wp[WP_PRECISION]) - { - if (hawk_ooecs_ccat(out, HAWK_T(' ')) == (hawk_oow_t)-1) - { - hawk_rtx_refdownval (rtx, v); - return HAWK_NULL; - } - wp[WP_WIDTH]--; - } - } - - hawk_rtx_refdownval (rtx, v); } else { @@ -8897,7 +8973,7 @@ wp_mod_main: goto skip_taking_arg; } - if (args == HAWK_NULL || val != HAWK_NULL) stack_arg_idx++; + if (!args || val) stack_arg_idx++; else args = args->next; skip_taking_arg: hawk_ooecs_clear (fbu); @@ -8937,7 +9013,7 @@ hawk_bch_t* hawk_rtx_formatmbs ( } \ (buf)->len += (buf)->inc; \ (buf)->ptr = (hawk_bch_t*)hawk_rtx_allocmem(rtx, (buf)->len * HAWK_SIZEOF(hawk_bch_t)); \ - if ((buf)->ptr == HAWK_NULL) \ + if (HAWK_UNLIKELY(!(buf)->ptr)) \ { \ (buf)->len = 0; \ return HAWK_NULL; \ @@ -8952,7 +9028,7 @@ hawk_bch_t* hawk_rtx_formatmbs ( } \ (buf)->len += ((incv) > (buf)->inc)? (incv): (buf)->inc; \ (buf)->ptr = (hawk_bch_t*)hawk_rtx_allocmem(rtx, (buf)->len * HAWK_SIZEOF(hawk_bch_t)); \ - if ((buf)->ptr == HAWK_NULL) \ + if (HAWK_UNLIKELY(!(buf)->ptr)) \ { \ (buf)->len = 0; \ return HAWK_NULL; \ @@ -8964,6 +9040,7 @@ hawk_bch_t* hawk_rtx_formatmbs ( if (nargs_on_stack == (hawk_oow_t)-1) { + /* dirty hack to support a single value argument instead of a tree node */ val = (hawk_val_t*)args; nargs_on_stack = 2; } @@ -9050,7 +9127,7 @@ wp_mod_main: hawk_val_t* v; int n; - if (args == HAWK_NULL) + if (!args) { if (stack_arg_idx >= nargs_on_stack) { @@ -9107,7 +9184,7 @@ wp_mod_main: FMT_MBS(rtx->formatmbs.tmp.ptr, n); - if (args == HAWK_NULL || val != HAWK_NULL) stack_arg_idx++; + if (!args || val) stack_arg_idx++; else args = args->next; i++; } @@ -9158,7 +9235,7 @@ wp_mod_main: hawk_bch_t fmt_fill = HAWK_BT('\0'); const hawk_bch_t* fmt_prefix = HAWK_NULL; - if (args == HAWK_NULL) + if (!args) { if (stack_arg_idx >= nargs_on_stack) { @@ -9169,7 +9246,7 @@ wp_mod_main: } else { - if (val != HAWK_NULL) + if (val) { if (stack_arg_idx >= nargs_on_stack) { @@ -9360,15 +9437,7 @@ wp_mod_main: hawk_flt_t r; int n; - #if defined(HAWK_USE_FLTMAX) - /*FMT_MCHAR (HAWK_BT('j'));*/ - FMT_MBS (HAWK_BT("jj"), 2); /* see fmt.c for info on jj */ - #else - FMT_MCHAR (HAWK_BT('z')); - #endif - FMT_MCHAR (fmt[i]); - - if (args == HAWK_NULL) + if (!args) { if (stack_arg_idx >= nargs_on_stack) { @@ -9379,7 +9448,7 @@ wp_mod_main: } else { - if (val != HAWK_NULL) + if (val) { if (stack_arg_idx >= nargs_on_stack) { @@ -9401,9 +9470,14 @@ wp_mod_main: if (n <= -1) return HAWK_NULL; #if defined(HAWK_USE_FLTMAX) + /*FMT_MCHAR (HAWK_BT('j'));*/ + FMT_MBS (HAWK_BT("jj"), 2); /* see fmt.c for info on jj */ + FMT_MCHAR (fmt[i]); /*if (hawk_becs_fcat(out, HAWK_BECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL;*/ if (hawk_becs_fcat(out, HAWK_BECS_PTR(fbu), &r) == (hawk_oow_t)-1) return HAWK_NULL; #else + FMT_MCHAR (HAWK_BT('z')); + FMT_MCHAR (fmt[i]); if (hawk_becs_fcat(out, HAWK_BECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL; #endif } @@ -9414,7 +9488,7 @@ wp_mod_main: hawk_val_t* v; hawk_val_type_t vtype; - if (args == HAWK_NULL) + if (!args) { if (stack_arg_idx >= nargs_on_stack) { @@ -9425,7 +9499,7 @@ wp_mod_main: } else { - if (val != HAWK_NULL) + if (val) { if (stack_arg_idx >= nargs_on_stack) { @@ -9455,6 +9529,11 @@ wp_mod_main: ch_len = 1; break; + case HAWK_VAL_BCHR: + ch = HAWK_RTX_GETBCHRFROMVAL(rtx, v); + ch_len = 1; + break; + case HAWK_VAL_INT: ch = (hawk_bch_t)HAWK_RTX_GETINTFROMVAL(rtx, v); ch_len = 1; @@ -9527,7 +9606,7 @@ wp_mod_main: /* left align */ while (wp[WP_WIDTH] > wp[WP_PRECISION]) { - if (hawk_becs_ccat (out, HAWK_BT(' ')) == (hawk_oow_t)-1) + if (hawk_becs_ccat(out, HAWK_BT(' ')) == (hawk_oow_t)-1) { hawk_rtx_refdownval (rtx, v); return HAWK_NULL; @@ -9540,14 +9619,9 @@ wp_mod_main: } else if (fmt[i] == HAWK_BT('s') || fmt[i] == HAWK_BT('k') || fmt[i] == HAWK_BT('K')) { - hawk_bch_t* str_ptr, * str_free = HAWK_NULL; - hawk_oow_t str_len; - hawk_int_t k; hawk_val_t* v; - hawk_val_type_t vtype; - int bytetombs_flagged_radix = 16; - if (args == HAWK_NULL) + if (!args) { if (stack_arg_idx >= nargs_on_stack) { @@ -9574,149 +9648,201 @@ wp_mod_main: } } - hawk_rtx_refupval (rtx, v); - - vtype = HAWK_RTX_GETVALTYPE(rtx, v); - switch (vtype) + if (val) { - case HAWK_VAL_NIL: - str_ptr = HAWK_BT(""); - str_len = 0; - break; + /* val_flt_to_str() in val.c calls hawk_rtx_format() with nargs_on_stack of (hawk_oow_t)-1 and the actual value. + * the actual value is assigned to 'val' at the beginning of this function. + * + * the following code can drive here. + * BEGIN { CONVFMT="%s"; a=98.76 ""; } + * + * when the first attempt to convert 98.76 to a textual form invokes this function with %s and 98.76. + * it comes to this part because the format specifier is 's'. since the floating-point type is not + * specially handled, hawk_rtx_valtooocstrdup() is called below. it calls val_flt_to_str() again, + * which eventually creates recursion and stack depletion. + * + * assuming only val_flt_to_str() calls it this way, i must convert the floating point number + * to text in a rather crude way without calling hawk_rtx_valtooocstrdup(). + */ + hawk_flt_t r; + int n; - case HAWK_VAL_MBS: - str_ptr = ((hawk_val_mbs_t*)v)->val.ptr; - str_len = ((hawk_val_mbs_t*)v)->val.len; - break; + HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, val) == HAWK_VAL_FLT); - case HAWK_VAL_STR: - #if defined(HAWK_OOCH_IS_BCH) - str_ptr = ((hawk_val_str_t*)v)->val.ptr; - str_len = ((hawk_val_str_t*)v)->val.len; - break; - #else - if (fmt[i] != HAWK_BT('s')) - { + hawk_rtx_refupval (rtx, v); + n = hawk_rtx_valtoflt(rtx, v, &r); + hawk_rtx_refdownval (rtx, v); + if (n <= -1) return HAWK_NULL; + + /* format the value as if '%g' is given */ + #if defined(HAWK_USE_FLTMAX) + FMT_MBS (HAWK_BT("jjg"), 3); /* see fmt.c for info on jj */ + if (hawk_becs_fcat(out, HAWK_BECS_PTR(fbu), &r) == (hawk_oow_t)-1) return HAWK_NULL; + #else + FMT_MBS (HAWK_BT("zg"), 2); + if (hawk_becs_fcat(out, HAWK_BECS_PTR(fbu), r) == (hawk_oow_t)-1) return HAWK_NULL; + #endif + } + else + { + hawk_bch_t* str_ptr, * str_free = HAWK_NULL, bchr_tmp; + hawk_ooch_t ooch_tmp; + hawk_oow_t str_len; + hawk_int_t k; + hawk_val_type_t vtype; + int bytetombs_flagged_radix = 16; + + hawk_rtx_refupval (rtx, v); + + vtype = HAWK_RTX_GETVALTYPE(rtx, v); + switch (vtype) + { + case HAWK_VAL_NIL: + str_ptr = HAWK_BT(""); + str_len = 0; + break; + + case HAWK_VAL_BCHR: + bchr_tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v); + str_ptr = &bchr_tmp; + str_len = 1; + break; + + case HAWK_VAL_MBS: + str_ptr = ((hawk_val_mbs_t*)v)->val.ptr; + str_len = ((hawk_val_mbs_t*)v)->val.len; + break; + + case HAWK_VAL_CHAR: + #if defined(HAWK_OOCH_IS_BCH) + bchr_tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v); + str_ptr = &bchr_tmp; + str_len = 1; + #else + if (fmt[i] == HAWK_BT('s')) goto duplicate; + ooch_tmp = HAWK_RTX_GETCHARFROMVAL(rtx, v); + str_ptr = (hawk_bch_t*)&ooch_tmp; + str_len = 1 * (HAWK_SIZEOF_OOCH_T / HAWK_SIZEOF_BCH_T); + #endif + break; + + case HAWK_VAL_STR: + #if defined(HAWK_OOCH_IS_BCH) + str_ptr = ((hawk_val_str_t*)v)->val.ptr; + str_len = ((hawk_val_str_t*)v)->val.len; + #else + if (fmt[i] == HAWK_BT('s')) goto duplicate; /* arrange to print the wide character string byte by byte regardless of byte order */ str_ptr = (hawk_bch_t*)((hawk_val_str_t*)v)->val.ptr; str_len = ((hawk_val_str_t*)v)->val.len * (HAWK_SIZEOF_OOCH_T / HAWK_SIZEOF_BCH_T); + #endif break; - } - /* fall thru */ - #endif - default: - { - if (v == val) - { - hawk_rtx_refdownval (rtx, v); - hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EFMTCNV); - return HAWK_NULL; - } + default: + duplicate: + str_ptr = hawk_rtx_valtobcstrdup(rtx, v, &str_len); + if (!str_ptr) + { + hawk_rtx_refdownval (rtx, v); + return HAWK_NULL; + } - str_ptr = hawk_rtx_valtobcstrdup(rtx, v, &str_len); - if (!str_ptr) - { - hawk_rtx_refdownval (rtx, v); - return HAWK_NULL; - } - - str_free = str_ptr; - break; + str_free = str_ptr; + break; } - } - if (wp_idx != WP_PRECISION || wp[WP_PRECISION] <= -1 || wp[WP_PRECISION] > (hawk_int_t)str_len) - { - /* precision not specified, or specified to a negative value or greater than the actual length */ - wp[WP_PRECISION] = (hawk_int_t)str_len; - } - if (wp[WP_PRECISION] > wp[WP_WIDTH]) wp[WP_WIDTH] = wp[WP_PRECISION]; - - if (!(flags & FLAG_MINUS)) - { - /* right align */ - while (wp[WP_WIDTH] > wp[WP_PRECISION]) + if (wp_idx != WP_PRECISION || wp[WP_PRECISION] <= -1 || wp[WP_PRECISION] > (hawk_int_t)str_len) { - if (hawk_becs_ccat(out, HAWK_BT(' ')) == (hawk_oow_t)-1) - { - if (str_free) hawk_rtx_freemem (rtx, str_free); - hawk_rtx_refdownval (rtx, v); - return HAWK_NULL; - } - wp[WP_WIDTH]--; + /* precision not specified, or specified to a negative value or greater than the actual length */ + wp[WP_PRECISION] = (hawk_int_t)str_len; } - } + if (wp[WP_PRECISION] > wp[WP_WIDTH]) wp[WP_WIDTH] = wp[WP_PRECISION]; - if (fmt[i] == HAWK_BT('k')) bytetombs_flagged_radix |= HAWK_BYTE_TO_BCSTR_LOWERCASE; - - for (k = 0; k < wp[WP_PRECISION]; k++) - { - hawk_bch_t curc; - - curc = str_ptr[k]; - - if (fmt[i] != HAWK_BT('s') && !HAWK_BYTE_PRINTABLE(curc)) + if (!(flags & FLAG_MINUS)) { - hawk_bch_t xbuf[3]; - if (curc <= 0xFF) + /* right align */ + while (wp[WP_WIDTH] > wp[WP_PRECISION]) { - if (hawk_becs_ncat(out, HAWK_BT("\\x"), 2) == (hawk_oow_t)-1) goto s_fail; - hawk_byte_to_bcstr(curc, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0')); - if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + if (hawk_becs_ccat(out, HAWK_BT(' ')) == (hawk_oow_t)-1) + { + if (str_free) hawk_rtx_freemem (rtx, str_free); + hawk_rtx_refdownval (rtx, v); + return HAWK_NULL; + } + wp[WP_WIDTH]--; } - else if (curc <= 0xFFFF) + } + + if (fmt[i] == HAWK_BT('k')) bytetombs_flagged_radix |= HAWK_BYTE_TO_BCSTR_LOWERCASE; + + for (k = 0; k < wp[WP_PRECISION]; k++) + { + hawk_bch_t curc; + + curc = str_ptr[k]; + + if (fmt[i] != HAWK_BT('s') && !HAWK_BYTE_PRINTABLE(curc)) { - hawk_uint16_t u16 = curc; - if (hawk_becs_ncat(out, HAWK_BT("\\u"), 2) == (hawk_oow_t)-1) goto s_fail; - hawk_byte_to_bcstr((u16 >> 8) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0')); - if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; - hawk_byte_to_bcstr(u16 & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0')); - if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + hawk_bch_t xbuf[3]; + if (curc <= 0xFF) + { + if (hawk_becs_ncat(out, HAWK_BT("\\x"), 2) == (hawk_oow_t)-1) goto s_fail; + hawk_byte_to_bcstr(curc, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0')); + if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + } + else if (curc <= 0xFFFF) + { + hawk_uint16_t u16 = curc; + if (hawk_becs_ncat(out, HAWK_BT("\\u"), 2) == (hawk_oow_t)-1) goto s_fail; + hawk_byte_to_bcstr((u16 >> 8) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0')); + if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + hawk_byte_to_bcstr(u16 & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0')); + if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + } + else + { + hawk_uint32_t u32 = curc; + if (hawk_becs_ncat(out, HAWK_BT("\\U"), 2) == (hawk_oow_t)-1) goto s_fail; + hawk_byte_to_bcstr((u32 >> 24) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0')); + if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + hawk_byte_to_bcstr((u32 >> 16) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0')); + if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + hawk_byte_to_bcstr((u32 >> 8) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0')); + if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + hawk_byte_to_bcstr(u32 & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0')); + if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + } } else { - hawk_uint32_t u32 = curc; - if (hawk_becs_ncat(out, HAWK_BT("\\U"), 2) == (hawk_oow_t)-1) goto s_fail; - hawk_byte_to_bcstr((u32 >> 24) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0')); - if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; - hawk_byte_to_bcstr((u32 >> 16) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0')); - if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; - hawk_byte_to_bcstr((u32 >> 8) & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0')); - if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; - hawk_byte_to_bcstr(u32 & 0xFF, xbuf, HAWK_COUNTOF(xbuf), bytetombs_flagged_radix, HAWK_BT('0')); - if (hawk_becs_ncat(out, xbuf, 2) == (hawk_oow_t)-1) goto s_fail; + if (hawk_becs_ccat(out, curc) == (hawk_oow_t)-1) + { + s_fail: + if (str_free) hawk_rtx_freemem (rtx, str_free); + hawk_rtx_refdownval (rtx, v); + return HAWK_NULL; + } } } - else + + if (str_free) hawk_rtx_freemem (rtx, str_free); + + if (flags & FLAG_MINUS) { - if (hawk_becs_ccat(out, curc) == (hawk_oow_t)-1) + /* left align */ + while (wp[WP_WIDTH] > wp[WP_PRECISION]) { - s_fail: - if (str_free) hawk_rtx_freemem (rtx, str_free); - hawk_rtx_refdownval (rtx, v); - return HAWK_NULL; + if (hawk_becs_ccat(out, HAWK_BT(' ')) == (hawk_oow_t)-1) + { + hawk_rtx_refdownval (rtx, v); + return HAWK_NULL; + } + wp[WP_WIDTH]--; } } + + hawk_rtx_refdownval (rtx, v); } - - if (str_free) hawk_rtx_freemem (rtx, str_free); - - if (flags & FLAG_MINUS) - { - /* left align */ - while (wp[WP_WIDTH] > wp[WP_PRECISION]) - { - if (hawk_becs_ccat(out, HAWK_BT(' ')) == (hawk_oow_t)-1) - { - hawk_rtx_refdownval (rtx, v); - return HAWK_NULL; - } - wp[WP_WIDTH]--; - } - } - - hawk_rtx_refdownval (rtx, v); } else { @@ -9725,7 +9851,7 @@ wp_mod_main: goto skip_taking_arg; } - if (args == HAWK_NULL || val != HAWK_NULL) stack_arg_idx++; + if (!args || val) stack_arg_idx++; else args = args->next; skip_taking_arg: hawk_becs_clear (fbu); diff --git a/hawk/lib/tree.c b/hawk/lib/tree.c index 751d7cd9..5ee1d899 100644 --- a/hawk/lib/tree.c +++ b/hawk/lib/tree.c @@ -318,18 +318,18 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde) #if defined(HAWK_OOCH_IS_UCH) else if (tmp <= 0xFFFF) { - hawk_fmttooocstr (hawk, buf, HAWK_COUNTOF(buf), HAWK_T("\\u%04x"), tmp); + hawk_fmttooocstr (hawk, buf, HAWK_COUNTOF(buf), HAWK_T("\\u%04x"), (hawk_oochu_t)tmp); PUT_SRCSTR (hawk, buf); } else { - hawk_fmttooocstr (hawk, buf, HAWK_COUNTOF(buf), HAWK_T("\\U%08x"), tmp); + hawk_fmttooocstr (hawk, buf, HAWK_COUNTOF(buf), HAWK_T("\\U%08x"), (hawk_oochu_t)tmp); PUT_SRCSTR (hawk, buf); } #else else { - hawk_fmttooocstr (hawk, buf, HAWK_COUNTOF(buf), HAWK_T("\\x%02x"), tmp); + hawk_fmttooocstr (hawk, buf, HAWK_COUNTOF(buf), HAWK_T("\\x%02x"), (hawk_oochu_t)tmp); PUT_SRCSTR (hawk, buf); } #endif @@ -349,10 +349,13 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde) else if (tmp == '\'') PUT_SRCSTR (hawk, HAWK_T("\\'")); else if (hawk_is_bch_print(tmp)) - PUT_SRCSTRN (hawk, &tmp, 1); + { + hawk_ooch_t oc = (hawk_bchu_t)tmp; + PUT_SRCSTRN (hawk, &oc, 1); + } else { - hawk_fmttooocstr (hawk, buf, HAWK_COUNTOF(buf), HAWK_T("\\x%02x"), tmp); + hawk_fmttooocstr (hawk, buf, HAWK_COUNTOF(buf), HAWK_T("\\x%02x"), (hawk_bchu_t)tmp); PUT_SRCSTR (hawk, buf); } @@ -364,9 +367,7 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde) { if (((hawk_nde_int_t*)nde)->str) { - PUT_SRCSTRN (hawk, - ((hawk_nde_int_t*)nde)->str, - ((hawk_nde_int_t*)nde)->len); + PUT_SRCSTRN (hawk, ((hawk_nde_int_t*)nde)->str, ((hawk_nde_int_t*)nde)->len); } else { @@ -399,9 +400,7 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde) { if (((hawk_nde_flt_t*)nde)->str) { - PUT_SRCSTRN (hawk, - ((hawk_nde_flt_t*)nde)->str, - ((hawk_nde_flt_t*)nde)->len); + PUT_SRCSTRN (hawk, ((hawk_nde_flt_t*)nde)->str, ((hawk_nde_flt_t*)nde)->len); } else { @@ -519,18 +518,18 @@ static int print_expr (hawk_t* hawk, hawk_nde_t* nde) #if defined(HAWK_OOCH_IS_BCH) PUT_SRCSTRN (hawk, &ptr[i], 1); #else - hawk_ooch_t wc = ptr[i]; - if (HAWK_BYTE_PRINTABLE(wc)) + hawk_ooch_t oc = (hawk_bchu_t)ptr[i]; + if (HAWK_BYTE_PRINTABLE(oc)) { - PUT_SRCSTRN (hawk, &wc, 1); + PUT_SRCSTRN (hawk, &oc, 1); } else { hawk_bch_t xbuf[3]; - hawk_byte_to_bcstr (wc, xbuf, HAWK_COUNTOF(xbuf), 16, '0'); + hawk_byte_to_bcstr (oc, xbuf, HAWK_COUNTOF(xbuf), 16, '0'); PUT_SRCSTR (hawk, HAWK_T("\\x")); - wc = xbuf[0]; PUT_SRCSTRN (hawk, &wc, 1); - wc = xbuf[1]; PUT_SRCSTRN (hawk, &wc, 1); + oc = (hawk_bchu_t)xbuf[0]; PUT_SRCSTRN (hawk, &oc, 1); + oc = (hawk_bchu_t)xbuf[1]; PUT_SRCSTRN (hawk, &oc, 1); } #endif break; diff --git a/hawk/lib/utf8.c b/hawk/lib/utf8.c index eecc54fa..0e172c18 100644 --- a/hawk/lib/utf8.c +++ b/hawk/lib/utf8.c @@ -81,7 +81,7 @@ static HAWK_INLINE __utf8_t* get_utf8_slot (hawk_uch_t uc) hawk_oow_t hawk_uc_to_utf8 (hawk_uch_t uc, hawk_bch_t* utf8, hawk_oow_t size) { - __utf8_t* cur = get_utf8_slot (uc); + __utf8_t* cur = get_utf8_slot(uc); if (cur == HAWK_NULL) return 0; /* illegal character */ diff --git a/hawk/lib/utl-str.c b/hawk/lib/utl-str.c index c9af7471..ed849192 100644 --- a/hawk/lib/utl-str.c +++ b/hawk/lib/utl-str.c @@ -3495,9 +3495,7 @@ int hawk_conv_bcstr_to_ucstr_with_cmgr ( return n; } -int hawk_conv_uchars_to_bchars_with_cmgr ( - const hawk_uch_t* ucs, hawk_oow_t* ucslen, - hawk_bch_t* bcs, hawk_oow_t* bcslen, hawk_cmgr_t* cmgr) +int hawk_conv_uchars_to_bchars_with_cmgr (const hawk_uch_t* ucs, hawk_oow_t* ucslen, hawk_bch_t* bcs, hawk_oow_t* bcslen, hawk_cmgr_t* cmgr) { const hawk_uch_t* p = ucs; const hawk_uch_t* end = ucs + *ucslen; diff --git a/hawk/lib/val-prv.h b/hawk/lib/val-prv.h index 21dc9d74..fd3371c5 100644 --- a/hawk/lib/val-prv.h +++ b/hawk/lib/val-prv.h @@ -66,7 +66,7 @@ struct hawk_val_rchunk_t * add a field to indicate if a value is static. * -#define HAWK_IS_STATICVAL(val) ((val) == HAWK_NULL || (val) == hawk_val_nil || (val) == hawk_val_zls || (val) == hawk_val_zlm) +#define HAWK_IS_STATICVAL(val) ((val) == HAWK_NULL || (val) == hawk_val_nil || (val) == hawk_val_zls || (val) == hawk_val_zlbs) */ #define HAWK_IS_STATICVAL(val) ((val)->v_static) @@ -169,11 +169,14 @@ extern hawk_val_t* hawk_val_nil; /* represents an empty string */ extern hawk_val_t* hawk_val_zls; +/* represents an empty byte string */ +extern hawk_val_t* hawk_val_zlbs; + void hawk_rtx_freeval ( - hawk_rtx_t* rtx, - hawk_val_t* val, - int flags + hawk_rtx_t* rtx, + hawk_val_t* val, + int flags ); void hawk_rtx_freevalchunk ( diff --git a/hawk/lib/val.c b/hawk/lib/val.c index afa0dea5..19e41f83 100644 --- a/hawk/lib/val.c +++ b/hawk/lib/val.c @@ -30,11 +30,11 @@ static hawk_val_nil_t hawk_nil = { HAWK_VAL_NIL, 0, 1, 0, 0 }; static hawk_val_str_t hawk_zls = { HAWK_VAL_STR, 0, 1, 0, 0, { HAWK_T(""), 0 } }; -static hawk_val_mbs_t hawk_zlm = { HAWK_VAL_MBS, 0, 1, 0, 0, { HAWK_BT(""), 0 } }; +static hawk_val_mbs_t hawk_zlbs = { HAWK_VAL_MBS, 0, 1, 0, 0, { HAWK_BT(""), 0 } }; hawk_val_t* hawk_val_nil = (hawk_val_t*)&hawk_nil; hawk_val_t* hawk_val_zls = (hawk_val_t*)&hawk_zls; -hawk_val_t* hawk_val_zlm = (hawk_val_t*)&hawk_zlm; +hawk_val_t* hawk_val_zlbs = (hawk_val_t*)&hawk_zlbs; /* --------------------------------------------------------------------- */ @@ -734,7 +734,7 @@ hawk_val_t* hawk_rtx_makenumorstrvalwithuchars (hawk_rtx_t* rtx, const hawk_uch_ hawk_int_t l; hawk_flt_t r; - if (ptr[0] == '.' && len == 1) goto make_str; + if (len == 1 && ptr[0] == '.') goto make_str; x = hawk_uchars_to_num(HAWK_OOCHARS_TO_NUM_MAKE_OPTION(1, 1, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0), ptr, len, &l, &r); if (x == 0) return hawk_rtx_makeintval(rtx, l); @@ -750,7 +750,7 @@ hawk_val_t* hawk_rtx_makenumorstrvalwithbchars (hawk_rtx_t* rtx, const hawk_bch_ hawk_int_t l; hawk_flt_t r; - if (ptr[0] == '.' && len == 1) goto make_str; + if (len == 1 && ptr[0] == '.') goto make_str; x = hawk_bchars_to_num(HAWK_OOCHARS_TO_NUM_MAKE_OPTION(1, 1, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0), ptr, len, &l, &r); if (x == 0) return hawk_rtx_makeintval(rtx, l); @@ -838,7 +838,7 @@ static HAWK_INLINE hawk_val_t* make_mbs_val (hawk_rtx_t* rtx, const hawk_bch_t* hawk_oow_t i; #endif - if (HAWK_UNLIKELY(len1 <= 0 && len2 <= 0)) return hawk_val_zls; + if (HAWK_UNLIKELY(len1 <= 0 && len2 <= 0)) return hawk_val_zlbs; aligned_len = HAWK_ALIGN_POW2((len1 + len2 + 1), HAWK_MBS_CACHE_BLOCK_UNIT); #if defined(HAWK_ENABLE_MBS_CACHE) @@ -887,7 +887,7 @@ hawk_val_t* hawk_rtx_makembsvalwithuchars (hawk_rtx_t* rtx, const hawk_uch_t* uc hawk_bch_t* bcs; hawk_oow_t bcslen; - if (HAWK_UNLIKELY(len <= 0)) return hawk_val_zlm; + if (HAWK_UNLIKELY(len <= 0)) return hawk_val_zlbs; bcs = hawk_rtx_duputobchars(rtx, ucs, len, &bcslen); if (HAWK_UNLIKELY(!bcs)) return HAWK_NULL; @@ -954,10 +954,13 @@ hawk_val_t* hawk_rtx_makenumormbsvalwithuchars (hawk_rtx_t* rtx, const hawk_uch_ hawk_int_t l; hawk_flt_t r; + if (len == 1 && ptr[0] == '.') goto make_str; + x = hawk_uchars_to_num(HAWK_OOCHARS_TO_NUM_MAKE_OPTION(1, 1, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0), ptr, len, &l, &r); if (x == 0) return hawk_rtx_makeintval(rtx, l); else if (x >= 1) return hawk_rtx_makefltval(rtx, r); +make_str: return hawk_rtx_makembsvalwithuchars(rtx, ptr, len); } @@ -967,10 +970,13 @@ hawk_val_t* hawk_rtx_makenumormbsvalwithbchars (hawk_rtx_t* rtx, const hawk_bch_ hawk_int_t l; hawk_flt_t r; + if (len == 1 && ptr[0] == '.') goto make_str; + x = hawk_bchars_to_num(HAWK_OOCHARS_TO_NUM_MAKE_OPTION(1, 1, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0), ptr, len, &l, &r); if (x == 0) return hawk_rtx_makeintval(rtx, l); else if (x >= 1) return hawk_rtx_makefltval(rtx, r); +make_str: return hawk_rtx_makembsvalwithbchars(rtx, ptr, len); } @@ -1465,6 +1471,7 @@ void hawk_rtx_freeval (hawk_rtx_t* rtx, hawk_val_t* val, int flags) break; } + case HAWK_VAL_BCHR: case HAWK_VAL_CHAR: { /* this never happens */ @@ -1713,9 +1720,12 @@ int hawk_rtx_valtobool (hawk_rtx_t* rtx, const hawk_val_t* val) { case HAWK_VAL_NIL: return 0; + + case HAWK_VAL_BCHR: case HAWK_VAL_CHAR: /* return always true - treat it like a 1-letter string */ return 1; + case HAWK_VAL_INT: return HAWK_RTX_GETINTFROMVAL(rtx, val) != 0; case HAWK_VAL_FLT: @@ -2134,6 +2144,16 @@ int hawk_rtx_valtostr (hawk_rtx_t* rtx, const hawk_val_t* v, hawk_rtx_valtostr_o case HAWK_VAL_NIL: return str_to_str(rtx, HAWK_T(""), 0, out); + case HAWK_VAL_BCHR: + { + hawk_bch_t tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v); + #if defined(HAWK_OOCH_IS_BCH) + return str_to_str(rtx, &tmp, 1, out); + #else + return mbs_to_str(rtx, &tmp, 1, out); + #endif + } + case HAWK_VAL_CHAR: { hawk_ooch_t tmp = HAWK_RTX_GETCHARFROMVAL(rtx, v); @@ -2416,8 +2436,33 @@ void hawk_rtx_freevaloocstr (hawk_rtx_t* rtx, hawk_val_t* v, hawk_ooch_t* str) hawk_bch_t* hawk_rtx_getvalbcstrwithcmgr (hawk_rtx_t* rtx, hawk_val_t* v, hawk_oow_t* len, hawk_cmgr_t* cmgr) { + hawk_bch_t c; + hawk_oow_t l; + switch (HAWK_RTX_GETVALTYPE(rtx, v)) { + case HAWK_VAL_NIL: + c = '\0'; + l = 0; + goto bctos; + case HAWK_VAL_BCHR: + c = HAWK_RTX_GETBCHRFROMVAL(rtx, v); + l = 1; + bctos: + if (rtx->bctos.fi) /* free slot available */ + { + /* use a bctos slot to avoid duplication */ + hawk_oow_t fi; + fi = rtx->bctos.fi; + rtx->bctos.fi = rtx->bctos.b[rtx->bctos.fi].c[0]; + rtx->bctos.b[fi].c[0] = c; + rtx->bctos.b[fi].c[1] = '\0'; + if (len) *len = l; + HAWK_ASSERT ((void*)&rtx->bctos.b[fi] == (void*)rtx->bctos.b[fi].c); + return rtx->bctos.b[fi].c; + } + goto duplicate; + case HAWK_VAL_MBS: #if 0 plain_mbs: @@ -2436,19 +2481,8 @@ hawk_bch_t* hawk_rtx_getvalbcstrwithcmgr (hawk_rtx_t* rtx, hawk_val_t* v, hawk_o /* fall through */ #endif - -#if 0 - case HAWK_VAL_CHAR: - i can treat a character value between 0 and 255 as a byte. - but doing so can cause inconsitency between the two ranges: - * 128 - 255 (kept as a single byte) - * 255 - max character value (encoded to multiple bytes) - - it looks more consistent that 255 becomes \xc3\xbf (assuming utf8). - so no special handling for HAWK_VAL_CHAR here. -#endif - default: + duplicate: return hawk_rtx_valtobcstrdupwithcmgr(rtx, v, len, cmgr); } } @@ -2457,6 +2491,22 @@ void hawk_rtx_freevalbcstr (hawk_rtx_t* rtx, hawk_val_t* v, hawk_bch_t* str) { switch (HAWK_RTX_GETVALTYPE(rtx, v)) { + case HAWK_VAL_NIL: + case HAWK_VAL_BCHR: + { + hawk_bctos_b_t* b = (hawk_bctos_b_t*)str; + if (b >= &rtx->bctos.b[0] && b < &rtx->bctos.b[HAWK_COUNTOF(rtx->bctos.b)]) + { + hawk_oow_t fi; + fi = b - &rtx->bctos.b[0]; + rtx->bctos.b[fi].c[0] = rtx->bctos.fi; + rtx->bctos.fi = fi; + break; + } + + goto freemem; + } + case HAWK_VAL_MBS: #if 0 plain_mbs: @@ -2472,6 +2522,7 @@ void hawk_rtx_freevalbcstr (hawk_rtx_t* rtx, hawk_val_t* v, hawk_bch_t* str) #endif default: + freemem: hawk_rtx_freemem (rtx, str); break; } @@ -2542,6 +2593,15 @@ int hawk_rtx_valtonum (hawk_rtx_t* rtx, const hawk_val_t* v, hawk_int_t* l, hawk *l = 0; return 0; + case HAWK_VAL_BCHR: + { + hawk_bch_t tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v); + return hawk_bchars_to_num( + HAWK_OOCHARS_TO_NUM_MAKE_OPTION(0, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0), + &tmp, 1, l, r + ); + } + case HAWK_VAL_CHAR: { /* treat it as if it is a 1-letter string */ @@ -2651,17 +2711,39 @@ hawk_fun_t* hawk_rtx_valtofun (hawk_rtx_t* rtx, hawk_val_t* v) fun = ((hawk_val_fun_t*)v)->fun; break; - case HAWK_VAL_STR: - if (hawk_count_oocstr(((hawk_val_str_t*)v)->val.ptr) != ((hawk_val_str_t*)v)->val.len) goto error_inval; - fun = hawk_rtx_findfunwithoocstr(rtx, ((hawk_val_str_t*)v)->val.ptr); - if (!fun) return HAWK_NULL; - break; - + case HAWK_VAL_BCHR: case HAWK_VAL_MBS: - if (hawk_count_bcstr(((hawk_val_mbs_t*)v)->val.ptr) != ((hawk_val_mbs_t*)v)->val.len) goto error_inval; - fun = hawk_rtx_findfunwithbcstr(rtx, ((hawk_val_mbs_t*)v)->val.ptr); + { + hawk_bcs_t x; + x.ptr = hawk_rtx_getvalbcstr(rtx, v, &x.len); + if (HAWK_UNLIKELY(!x.ptr)) return HAWK_NULL; + if (hawk_count_bcstr(x.ptr) != x.len) + { + hawk_rtx_freevalbcstr (rtx, v, x.ptr); + goto error_inval; + } + fun = hawk_rtx_findfunwithbcstr(rtx, x.ptr); + hawk_rtx_freevalbcstr (rtx, v, x.ptr); if (!fun) return HAWK_NULL; break; + } + + case HAWK_VAL_CHAR: + case HAWK_VAL_STR: + { + hawk_oocs_t x; + x.ptr = hawk_rtx_getvaloocstr(rtx, v, &x.len); + if (HAWK_UNLIKELY(!x.ptr)) return HAWK_NULL; + if (hawk_count_oocstr(x.ptr) != x.len) + { + hawk_rtx_freevaloocstr (rtx, v, x.ptr); + goto error_inval; + } + fun = hawk_rtx_findfunwithoocstr(rtx, x.ptr); + hawk_rtx_freevaloocstr (rtx, v, x.ptr); + if (!fun) return HAWK_NULL; + break; + } default: error_inval: @@ -2693,6 +2775,13 @@ hawk_int_t hawk_rtx_hashval (hawk_rtx_t* rtx, hawk_val_t* v) hv = 0; break; + case HAWK_VAL_BCHR: + { + hawk_bch_t tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v); + hv = (hawk_int_t)hash((hawk_uint8_t*)&tmp, HAWK_SIZEOF(tmp)); + break; + } + case HAWK_VAL_CHAR: { hawk_ooch_t tmp = HAWK_RTX_GETCHARFROMVAL(rtx, v); @@ -3008,8 +3097,16 @@ void hawk_dprintval (hawk_rtx_t* run, hawk_val_t* val) break; } + case HAWK_VAL_BCHR: + hawk_errputstrf (HAWK_T("%hc"), HAWK_GETBCHRFROMVAL(val)); + break; + + case HAWK_VAL_CHAR: + hawk_errputstrf (HAWK_T("%jc"), HAWK_GETCHARFROMVAL(val)); + break; + case HAWK_VAL_INT: - hawk_errputstrf (HAWK_T("%jd"), (hawk_intmax_t)((hawk_val_int_t*)val)->val); + hawk_errputstrf (HAWK_T("%jd"), (hawk_intmax_t)HAWK_GETINTFROMVAL(val)); break; case HAWK_VAL_FLT: diff --git a/hawk/t/h-001.hawk b/hawk/t/h-001.hawk index b61c3833..49e05fd2 100644 --- a/hawk/t/h-001.hawk +++ b/hawk/t/h-001.hawk @@ -3,6 +3,11 @@ @include "ensure.inc"; +function f(a, b, c) +{ + return a + b + c; +} + function call_by_ref_1(&a, b, &c) { c = "hello, world"; @@ -23,8 +28,17 @@ function call_by_ref_3(&x) function main() { - { + ensure (@b"" !== "", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (@b"" === "", 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (@b"" != "", 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (@b"" == "", 1, @SCRIPTNAME, @SCRIPTLINE); + + ensure (@b' ' !== ' ', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (@b' ' === ' ', 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (@b' ' != ' ', 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (@b' ' == ' ', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure ((@nil == 'A'), 0, @SCRIPTNAME, @SCRIPTLINE); ensure ((@nil != 'A'), 1, @SCRIPTNAME, @SCRIPTLINE); ensure ((@nil > 'A'), 0, @SCRIPTNAME, @SCRIPTLINE); @@ -41,6 +55,14 @@ function main() ensure (('A' == @b'A'), 1, @SCRIPTNAME, @SCRIPTLINE); ensure (('\u00FF' == @b'\xFF'), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (('A' < @b'\xFF'), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure ((@b'A' < @b'\xFF'), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (('A' > @b'\xFF'), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure ((@b'A' > @b'\xFF'), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (('A' < @b'B'), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure ((@b'A' < @b'B'), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (('A' > @b'B'), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure ((@b'A' > @b'B'), 0, @SCRIPTNAME, @SCRIPTLINE); ensure (("10" == 10), 1, @SCRIPTNAME, @SCRIPTLINE); ensure (("10" == 10.00), 1, @SCRIPTNAME, @SCRIPTLINE); @@ -146,6 +168,11 @@ function main() ensure (length(b), 2, @SCRIPTNAME, @SCRIPTLINE); ensure (b[1], 99, @SCRIPTNAME, @SCRIPTLINE); ensure (b[2], "perfect", @SCRIPTNAME, @SCRIPTLINE); + + ensure (hawk::call('f', 1, 2, 3), 6, @SCRIPTNAME, @SCRIPTLINE); + ensure (hawk::call("f", 1, 2, 3), 6, @SCRIPTNAME, @SCRIPTLINE); + ensure (hawk::call(@b'f', 1, 2, 3), 6, @SCRIPTNAME, @SCRIPTLINE); + ensure (hawk::call(@b"f", 1, 2, 3), 6, @SCRIPTNAME, @SCRIPTLINE); } @@ -262,6 +289,8 @@ function main() ensure ((@b"hawk" str::fromcharcode(0x26be)) === @b"hawk\xe2\x9a\xbe", 1, @SCRIPTNAME, @SCRIPTLINE); ensure (("hawk" str::fromcharcode(0x26be)) === "hawk⚾", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure ((@b"hawk" @b'\xFF') === @b"hawk\xFF", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure ((str::subchar(@b"\xFF\xFE", 1) str::subchar(@b"\xFF\xFE", 2)) === @b"\xFF\xFE", 1, @SCRIPTNAME, @SCRIPTLINE); ensure ((@b"hawk" %% 10) === @b"hawk10", 1, @SCRIPTNAME, @SCRIPTLINE); ensure (("hawk" %% 10) === "hawk10", 1, @SCRIPTNAME, @SCRIPTLINE); diff --git a/hawk/t/h-002.hawk b/hawk/t/h-002.hawk index dca5992e..375f3d92 100644 --- a/hawk/t/h-002.hawk +++ b/hawk/t/h-002.hawk @@ -44,6 +44,54 @@ function main() gsub("\\\\", "A", y); ensure (x, "xAy", @SCRIPTNAME, @SCRIPTLINE); ensure (y, "xAAy", @SCRIPTNAME, @SCRIPTLINE); + + + x = y = @b"x\\\\y"; + gsub(/\\\\/, "A", x); + gsub("\\\\", "A", y); + ensure (x === @b"xAy", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (y === @b"xAAy", 1, @SCRIPTNAME, @SCRIPTLINE); + + x = y = @b"x\\\\y"; + gsub(/\\\\/, 'A', x); + gsub("\\\\", 'A', y); + ensure (x === @b"xAy", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (y === @b"xAAy", 1, @SCRIPTNAME, @SCRIPTLINE); + + x = y = "x\\\\y"; + gsub(/\\\\/, @b'A', x); + gsub("\\\\", @b'A', y); + ensure (x === "xAy", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (y === "xAAy", 1, @SCRIPTNAME, @SCRIPTLINE); + + x = y = "x\\\\y"; + gsub(/\\\\/, @b"A", x); + gsub("\\\\", @b"A", y); + ensure (x === "xAy", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (y === "xAAy", 1, @SCRIPTNAME, @SCRIPTLINE); + + x = y = '\\'; + gsub(/\\/, @b"A", x); + gsub("\\\\", @b"A", y); + ensure (x === "A", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (y === "A", 1, @SCRIPTNAME, @SCRIPTLINE); + + x = y = '\\'; + gsub(/\\/, @b'A', x); + gsub("\\\\", @b'A', y); + ensure (x === "A", 1, @SCRIPTNAME, @SCRIPTLINE); + + x = y = @b'\\'; + gsub(/\\/, @b"A", x); + gsub("\\\\", @b"A", y); + ensure (x === @b"A", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (y === @b"A", 1, @SCRIPTNAME, @SCRIPTLINE); + + x = y = @b'\\'; + gsub(/\\/, @b'A', x); + gsub("\\\\", @b'A', y); + ensure (x === @b"A", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (y === @b"A", 1, @SCRIPTNAME, @SCRIPTLINE); } ## gsub - POSIX rule for &, \&, \\&, \\\& @@ -248,6 +296,10 @@ function main() ensure (sprintf("%+d %d", 3, 4), "+3 4", @SCRIPTNAME, @SCRIPTLINE); ensure (sprintf(@b"%+d %d", 3, 4), @b"+3 4", @SCRIPTNAME, @SCRIPTLINE); + + + ensure (sprintf(@b'A') === @b"A", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (sprintf('A') === "A", 1, @SCRIPTNAME, @SCRIPTLINE); } { @@ -282,29 +334,74 @@ function main() ensure (substr(1000+10000, 2) === "1000", 1, @SCRIPTNAME, @SCRIPTLINE); ensure (substr(1000+5000, 2) === "000", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar("abc", -1) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar("abc", 0) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar("abc", 1) === 'a', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar("abc", 2) === 'b', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar("abc", 3) === 'c', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar("abc", 4) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); - ensure (str::subchar("abc", -1) === @nil, 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar("abc", 0) === @nil, 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar("abc", 1) === 'a', 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar("abc", 2) === 'b', 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar("abc", 3) === 'c', 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar("abc", 4) === @nil, 1, @SCRIPTNAME, @SCRIPTNAME); + ensure (str::subchar("☕⛄", -1) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar("☕⛄", 0) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar("☕⛄", 1) === '☕', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar("☕⛄", 2) === '⛄', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar("☕⛄", 3) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar("☕⛄", 4) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); - ensure (str::subchar("☕⛄", -1) === @nil, 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar("☕⛄", 0) === @nil, 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar("☕⛄", 1) === '☕', 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar("☕⛄", 2) === '⛄', 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar("☕⛄", 3) === @nil, 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar("☕⛄", 4) === @nil, 1, @SCRIPTNAME, @SCRIPTNAME); + ensure (str::subchar(@b"abc", -1) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar(@b"abc", 0) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar(@b"abc", 1) === @b'a', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar(@b"abc", 2) === @b'b', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar(@b"abc", 3) === @b'c', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar(@b"abc", 4) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); - ensure (str::subchar(@b"abc", -1) === @nil, 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar(@b"abc", 0) === @nil, 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar(@b"abc", 1) === @b'a', 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar(@b"abc", 2) === @b'b', 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar(@b"abc", 3) === @b'c', 1, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::subchar(@b"abc", 4) === @nil, 1, @SCRIPTNAME, @SCRIPTNAME); + ensure (str::subchar('a', 0) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar('a', 1) === 'a', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar('a', 2) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::subchar(@b'a', 0) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar(@b'a', 1) === @b'a', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar(@b'a', 2) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::subchar(123, 0) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar(123, 1) === '1', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar(123, 2) === '2', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar(123, 3) === '3', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::subchar(123, 4) === @nil, 1, @SCRIPTNAME, @SCRIPTLINE); } + { + ensure (str::substr("☕Q⛄", 0) === "☕Q⛄", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::substr("☕Q⛄", 1) === "☕Q⛄", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::substr("☕Q⛄", 2) === "Q⛄", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::substr("☕Q⛄", 3) === "⛄", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::substr("☕Q⛄", 4) === "", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::substr("☕Q⛄", 1, 2) === "☕Q", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::substr("☕Q⛄", 1, 4) === "☕Q⛄", 1, @SCRIPTNAME, @SCRIPTLINE); + ###ensure (str::substr("☕Q⛄", -1, 1) === "⛄", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::substr('☕', 1, 4) === "☕", 1, @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::substr(@b"\xAD\xAA\xBB\CC", 2, 2) === @b"\xAA\xBB", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::substr(@b'\xAD', 1, 1) === @b"\xAD", 1, @SCRIPTNAME, @SCRIPTLINE); + } + + { + ensure (str::index("☕Q⛄X⛄Z", '⛄'), 3, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::index("☕Q⛄X⛄Z", "⛄"), 3, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::index("☕Q⛄X⛄Z", "Q⛄"), 2, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::rindex("☕Q⛄X⛄Z", '⛄'), 5, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::rindex("☕Q⛄X⛄Z", "⛄"), 5, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::rindex("☕Q⛄X⛄Z", "Q⛄"), 2, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::rindex("☕Q⛄X⛄Z", "Q⛄Q"), 0, @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::index(@b"\xFFQ\xABX\xABZ", @b'\xAB'), 3, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::index(@b"\xFFQ\xABX\xABZ", @b"\xAB"), 3, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::index(@b"\xFFQ\xABX\xABZ", @b"Q\xAB"), 2, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::rindex(@b"\xFFQ\xABX\xABZ", @b'\xAB'), 5, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::rindex(@b"\xFFQ\xABX\xABZ", @b"\xAB"), 5, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::rindex(@b"\xFFQ\xABX\xABZ", @b"Q\xAB"), 2, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::rindex(@b"\xFFQ\xABX\xABZ", @b"Q\xABQ"), 0, @SCRIPTNAME, @SCRIPTLINE); + } { # split, str::split, str::splita @@ -365,6 +462,26 @@ function main() ensure (a[3], "", @SCRIPTNAME, @SCRIPTLINE); ensure (a[4], "b\t\tc", @SCRIPTNAME, @SCRIPTLINE); ensure (a[5], "d", @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::split('a', a, /a/), 2, @SCRIPTNAME, @SCRIPTLINE); + ensure (a[1] === "", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (a[2] === "", 1, @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::split('a', a, 'a'), 2, @SCRIPTNAME, @SCRIPTLINE); + ensure (a[1] === "", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (a[2] === "", 1, @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::split('a', a, @b'a'), 2, @SCRIPTNAME, @SCRIPTLINE); + ensure (a[1] === "", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (a[2] === "", 1, @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::split(@b'a', a, /a/), 2, @SCRIPTNAME, @SCRIPTLINE); + ensure (a[1] === @b"", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (a[2] === @b"", 1, @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::split(@b'a', a, @b'a'), 2, @SCRIPTNAME, @SCRIPTLINE); + ensure (a[1] === @b"", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (a[2] === @b"", 1, @SCRIPTNAME, @SCRIPTLINE); } @@ -413,10 +530,26 @@ function main() ensure (str::tolower(@b"ABC") === @b"abc", 1, @SCRIPTNAME, @SCRIPTLINE); } - { - ensure (str::tocharcode(str::fromcharcode('2')), 2, @SCRIPTNAME, @SCRIPTNAME); - ensure (str::tonum('a', 16), 10, @SCRIPTNAME, @SCRIPTNAME); + ensure (str::tocharcode(@b'\xFF'), 0xFF, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::tocharcode('\u3321'), 0x3321, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::tocharcode(@b'\xFF', 0), @nil, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::tocharcode('\u3321', 0), @nil, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::tocharcode(@b'\xFF', 1), 0xFF, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::tocharcode('\u3321', 1), 0x3321, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::tocharcode(@b'\xFF', 2), @nil, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::tocharcode('\u3321', 2), @nil, @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::tocharcode(str::fromcharcode('2')), 2, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::tonum('a', 16), 10, @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::fromcharcode(65, 66, 67) === "ABC", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::frombcharcode(65, 66, 67) === @b"ABC", 1, @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::trim(" hello world ") === "hello world", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::trim(" hello world ", str::TRIM_PAC_SPACES) === "hello world", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::trim(@b" hello world ") === @b"hello world", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::trim(@b" hello world ", str::TRIM_PAC_SPACES) === @b"hello world", 1, @SCRIPTNAME, @SCRIPTLINE); } print "SUCCESS";