diff --git a/hawk/lib/fnc.c b/hawk/lib/fnc.c index 61989a0d..8da0f895 100644 --- a/hawk/lib/fnc.c +++ b/hawk/lib/fnc.c @@ -765,7 +765,7 @@ int hawk_fnc_substr (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) 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 (!r) return -1; + if (HAWK_UNLIKELY(!r)) return -1; } else { @@ -780,7 +780,7 @@ int hawk_fnc_substr (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) r = hawk_rtx_makestrvalwithoochars(rtx, &str[lindex], (hawk_oow_t)lcount); hawk_rtx_freevaloocstr (rtx, a0, str); - if (!r) return -1; + if (HAWK_UNLIKELY(!r)) return -1; } hawk_rtx_setretval (rtx, r); @@ -1014,30 +1014,46 @@ int hawk_fnc_tolower (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) hawk_val_t* a0, * r; a0 = hawk_rtx_getarg(rtx, 0); - if (HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_MBS) + switch (HAWK_RTX_GETVALTYPE(rtx, a0)) { - hawk_bcs_t str; - str.ptr = hawk_rtx_getvalbcstr(rtx, a0, &str.len); - if (!str.ptr) return -1; - r = hawk_rtx_makembsvalwithbcs(rtx, &str); - hawk_rtx_freevalbcstr (rtx, a0, str.ptr); - if (!r) return -1; - str.ptr = ((hawk_val_mbs_t*)r)->val.ptr; - str.len = ((hawk_val_mbs_t*)r)->val.len; - for (i = 0; i < str.len; i++) str.ptr[i] = hawk_to_bch_lower(str.ptr[i]); - } - else - { - hawk_oocs_t str; - str.ptr = hawk_rtx_getvaloocstr(rtx, a0, &str.len); - if (!str.ptr) return -1; - r = hawk_rtx_makestrvalwithoocs(rtx, &str); - hawk_rtx_freevaloocstr (rtx, a0, str.ptr); - if (!r) return -1; - str.ptr = ((hawk_val_str_t*)r)->val.ptr; - str.len = ((hawk_val_str_t*)r)->val.len; - for (i = 0; i < str.len; i++) str.ptr[i] = hawk_to_ooch_lower(str.ptr[i]); + case HAWK_VAL_MBS: + { + hawk_bcs_t str; + str.ptr = hawk_rtx_getvalbcstr(rtx, a0, &str.len); + if (!str.ptr) return -1; + r = hawk_rtx_makembsvalwithbcs(rtx, &str); + hawk_rtx_freevalbcstr (rtx, a0, str.ptr); + if (HAWK_UNLIKELY(!r)) return -1; + str.ptr = ((hawk_val_mbs_t*)r)->val.ptr; + str.len = ((hawk_val_mbs_t*)r)->val.len; + for (i = 0; i < str.len; i++) str.ptr[i] = hawk_to_bch_lower(str.ptr[i]); + break; + } + + case HAWK_VAL_CHAR: + { + hawk_ooch_t tmp = HAWK_RTX_GETCHARFROMVAL(rtx, a0); + tmp = hawk_to_bch_lower(tmp); + r = hawk_rtx_makecharval(rtx, tmp); + if (HAWK_UNLIKELY(!r)) return -1; + break; + } + + default: + { + hawk_oocs_t str; + str.ptr = hawk_rtx_getvaloocstr(rtx, a0, &str.len); + if (!str.ptr) return -1; + r = hawk_rtx_makestrvalwithoocs(rtx, &str); + hawk_rtx_freevaloocstr (rtx, a0, str.ptr); + if (HAWK_UNLIKELY(!r)) return -1; + str.ptr = ((hawk_val_str_t*)r)->val.ptr; + str.len = ((hawk_val_str_t*)r)->val.len; + for (i = 0; i < str.len; i++) str.ptr[i] = hawk_to_ooch_lower(str.ptr[i]); + break; + } } + hawk_rtx_setretval (rtx, r); return 0; } @@ -1048,30 +1064,46 @@ int hawk_fnc_toupper (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) hawk_val_t* a0, * r; a0 = hawk_rtx_getarg(rtx, 0); - if (HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_MBS) + switch (HAWK_RTX_GETVALTYPE(rtx, a0)) { - hawk_bcs_t str; - str.ptr = hawk_rtx_getvalbcstr(rtx, a0, &str.len); - if (!str.ptr) return -1; - r = hawk_rtx_makembsvalwithbcs(rtx, &str); - hawk_rtx_freevalbcstr (rtx, a0, str.ptr); - if (!r) return -1; - str.ptr = ((hawk_val_mbs_t*)r)->val.ptr; - str.len = ((hawk_val_mbs_t*)r)->val.len; - for (i = 0; i < str.len; i++) str.ptr[i] = hawk_to_bch_upper(str.ptr[i]); - } - else - { - hawk_oocs_t str; - str.ptr = hawk_rtx_getvaloocstr(rtx, a0, &str.len); - if (!str.ptr) return -1; - r = hawk_rtx_makestrvalwithoocs(rtx, &str); - hawk_rtx_freevaloocstr (rtx, a0, str.ptr); - if (!r) return -1; - str.ptr = ((hawk_val_str_t*)r)->val.ptr; - str.len = ((hawk_val_str_t*)r)->val.len; - for (i = 0; i < str.len; i++) str.ptr[i] = hawk_to_ooch_upper(str.ptr[i]); + case HAWK_VAL_MBS: + { + hawk_bcs_t str; + str.ptr = hawk_rtx_getvalbcstr(rtx, a0, &str.len); + if (!str.ptr) return -1; + r = hawk_rtx_makembsvalwithbcs(rtx, &str); + hawk_rtx_freevalbcstr (rtx, a0, str.ptr); + if (HAWK_UNLIKELY(!r)) return -1; + str.ptr = ((hawk_val_mbs_t*)r)->val.ptr; + str.len = ((hawk_val_mbs_t*)r)->val.len; + for (i = 0; i < str.len; i++) str.ptr[i] = hawk_to_bch_upper(str.ptr[i]); + break; + } + + case HAWK_VAL_CHAR: + { + hawk_ooch_t tmp = HAWK_RTX_GETCHARFROMVAL(rtx, a0); + tmp = hawk_to_bch_upper(tmp); + r = hawk_rtx_makecharval(rtx, tmp); + if (HAWK_UNLIKELY(!r)) return -1; + break; + } + + default: + { + hawk_oocs_t str; + str.ptr = hawk_rtx_getvaloocstr(rtx, a0, &str.len); + if (!str.ptr) return -1; + r = hawk_rtx_makestrvalwithoocs(rtx, &str); + hawk_rtx_freevaloocstr (rtx, a0, str.ptr); + if (HAWK_UNLIKELY(!r)) return -1; + str.ptr = ((hawk_val_str_t*)r)->val.ptr; + str.len = ((hawk_val_str_t*)r)->val.len; + for (i = 0; i < str.len; i++) str.ptr[i] = hawk_to_ooch_upper(str.ptr[i]); + break; + } } + hawk_rtx_setretval (rtx, r); return 0; } diff --git a/hawk/lib/mod-str.c b/hawk/lib/mod-str.c index 39115c7f..663caac6 100644 --- a/hawk/lib/mod-str.c +++ b/hawk/lib/mod-str.c @@ -450,7 +450,7 @@ static int fnc_tombs (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) { hawk_bcs_t str; str.ptr = hawk_rtx_getvalbcstrwithcmgr(rtx, a0, &str.len, cmgr); - if (!str.ptr) return -1; + if (HAWK_UNLIKELY(!str.ptr)) return -1; r = hawk_rtx_makembsvalwithbcs(rtx, &str); hawk_rtx_freevalbcstr (rtx, a0, str.ptr); if (!r) return -1; @@ -477,38 +477,67 @@ static int fnc_tonum (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) a0 = hawk_rtx_getarg(rtx, 0); - if (HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_MBS && hawk_rtx_getnargs(rtx) >= 2) + if (hawk_rtx_getnargs(rtx) >= 2) { - /* if the value is known to be a byte string, it supports the optional - * base parameter */ - hawk_val_t* a1 = hawk_rtx_getarg(rtx, 1); - hawk_int_t base; + switch (HAWK_RTX_GETVALTYPE(rtx, a0)) + { + case HAWK_VAL_MBS: + { + /* if the value is known to be a byte string, it supports the optional + * base parameter */ + hawk_val_t* a1 = hawk_rtx_getarg(rtx, 1); + hawk_int_t base; - 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), - ((hawk_val_mbs_t*)a0)->val.ptr, - ((hawk_val_mbs_t*)a0)->val.len, - &lv, &rv - ); - } - else if (HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_STR && hawk_rtx_getnargs(rtx) >= 2) - { - /* 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; + 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), + ((hawk_val_mbs_t*)a0)->val.ptr, + ((hawk_val_mbs_t*)a0)->val.len, + &lv, &rv + ); + break; + } - if (hawk_rtx_valtoint(rtx, a1, &base) <= -1) return -1; - rx = hawk_oochars_to_num( - HAWK_OOCHARS_TO_NUM_MAKE_OPTION(0, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), base), - ((hawk_val_str_t*)a0)->val.ptr, - ((hawk_val_str_t*)a0)->val.len, - &lv, &rv - ); + case HAWK_VAL_CHAR: + { + /* 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_ooch_t tmp = HAWK_RTX_GETCHARFROMVAL(rtx, a0); + + if (hawk_rtx_valtoint(rtx, a1, &base) <= -1) return -1; + rx = hawk_oochars_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_STR: + { + /* 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; + + if (hawk_rtx_valtoint(rtx, a1, &base) <= -1) return -1; + rx = hawk_oochars_to_num( + HAWK_OOCHARS_TO_NUM_MAKE_OPTION(0, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), base), + ((hawk_val_str_t*)a0)->val.ptr, + ((hawk_val_str_t*)a0)->val.len, + &lv, &rv + ); + break; + } + + default: + goto val_to_num; + } } else { + val_to_num: rx = hawk_rtx_valtonum(rtx, a0, &lv, &rv); } @@ -531,6 +560,60 @@ static int fnc_tonum (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) return 0; } +static int fnc_subchar (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) +{ + hawk_oow_t nargs; + hawk_val_t* a0, * a1, * r; + hawk_int_t lindex, lcount; + int n; + + nargs = hawk_rtx_getnargs(rtx); + HAWK_ASSERT (nargs >= 2 && nargs <= 3); + + a0 = hawk_rtx_getarg(rtx, 0); + a1 = hawk_rtx_getarg(rtx, 1); + + n = hawk_rtx_valtoint(rtx, a1, &lindex); + if (n <= -1) return -1; + + lindex = lindex - 1; + + if (HAWK_RTX_GETVALTYPE(rtx, a0) == 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; + + if (lindex >= 0 && lindex < (hawk_int_t)len) + r = hawk_rtx_makecharval(rtx, str[lindex]); + else + r = hawk_rtx_makenilval(rtx); + + if (HAWK_UNLIKELY(!r)) return -1; + } + else + { + hawk_ooch_t* str; + hawk_oow_t len; + + 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); + + hawk_rtx_freevaloocstr (rtx, a0, str); + if (HAWK_UNLIKELY(!r)) return -1; + } + + hawk_rtx_setretval (rtx, r); + return 0; +} + typedef struct fnctab_t fnctab_t; struct fnctab_t { @@ -576,6 +659,7 @@ static fnctab_t fnctab[] = { 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 } }, diff --git a/hawk/t/h-002.hawk b/hawk/t/h-002.hawk index 2e74c6cd..93984cd1 100644 --- a/hawk/t/h-002.hawk +++ b/hawk/t/h-002.hawk @@ -33,6 +33,12 @@ function main() ensure (x, "x\\y", @SCRIPTNAME, @SCRIPTLINE); ensure (y, "xAy", @SCRIPTNAME, @SCRIPTLINE); + x = y = "x\\y"; + gsub(/\\\\/, 'A', x); + gsub("\\\\", 'A', y); + ensure (x, "x\\y", @SCRIPTNAME, @SCRIPTLINE); + ensure (y, "xAy", @SCRIPTNAME, @SCRIPTLINE); + x = y = "x\\\\y"; gsub(/\\\\/, "A", x); gsub("\\\\", "A", y); @@ -275,6 +281,28 @@ function main() ensure (substr(1000+5000, 2) === "000", 1, @SCRIPTNAME, @SCRIPTLINE); 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, @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, @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, @SCRIPTNAME); + ensure (str::subchar(@b"abc", 0) === @nil, 1, @SCRIPTNAME, @SCRIPTNAME); + ensure (str::subchar(@b"abc", 1) === 'a', 1, @SCRIPTNAME, @SCRIPTNAME); + ensure (str::subchar(@b"abc", 2) === 'b', 1, @SCRIPTNAME, @SCRIPTNAME); + ensure (str::subchar(@b"abc", 3) === 'c', 1, @SCRIPTNAME, @SCRIPTNAME); + ensure (str::subchar(@b"abc", 4) === @nil, 1, @SCRIPTNAME, @SCRIPTNAME); } @@ -348,6 +376,49 @@ function main() } + { + ## character class functions in the str modules + ensure (str::isalnum('a'), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isalpha('a'), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isblank('a'), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::iscntrl('a'), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isdigit('a'), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isgraph('a'), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::islower('a'), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isprint('a'), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::ispunct('a'), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isspace('a'), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isupper('a'), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isxdigit('a'), 1, @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::toupper('a') === 'A', 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::tolower('A') === 'a', 1, @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::isalnum("a"), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isalpha("a"), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isblank("a"), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::iscntrl("a"), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isdigit("a"), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isgraph("a"), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::islower("a"), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isprint("a"), 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::ispunct("a"), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isspace("a"), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isupper("a"), 0, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::isxdigit("a"), 1, @SCRIPTNAME, @SCRIPTLINE); + + ensure (str::toupper("abc") === "ABC", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::tolower("ABC") === "abc", 1, @SCRIPTNAME, @SCRIPTLINE); + ensure (str::toupper(@b"abc") === @b"ABC", 1, @SCRIPTNAME, @SCRIPTLINE); + 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); + } + print "SUCCESS"; }