diff --git a/qse/include/qse/awk/awk.h b/qse/include/qse/awk/awk.h index ddd2c5f0..03aab016 100644 --- a/qse/include/qse/awk/awk.h +++ b/qse/include/qse/awk/awk.h @@ -2777,13 +2777,17 @@ QSE_EXPORT int qse_awk_rtx_valtoflt ( * memory pointed to by \a l; A string containng '.', 'E', or 'e' is * converted to a floating-pointer number and it is stored into memory * pointed to by \a r. If \a strict is 0, the function takes up to the last - * valid character and never fails. If \a strict is non-zero, an invalid + * valid character and never fails. If \a strict is 1, an invalid * character causes the function to return an error. * * \return 0 if converted to an integer, * 1 if converted to a floating-point number * -1 on error. */ +#define QSE_AWK_RTX_STRTONUM_MAKE_OPTION(strict,base) (((strict) & 1) | ((base) << 8)) +#define QSE_AWK_RTX_STRTONUM_GET_OPTION_STRICT(option) ((option) & 1) +#define QSE_AWK_RTX_STRTONUN_GET_OPTION_BASE(option) ((option) >> 8) + QSE_EXPORT int qse_awk_rtx_strtonum ( qse_awk_rtx_t* rtx, /**< runtime context */ int strict, /**< determines to perform strict check */ diff --git a/qse/lib/awk/mod-str.c b/qse/lib/awk/mod-str.c index a074600d..8255cca8 100644 --- a/qse/lib/awk/mod-str.c +++ b/qse/lib/awk/mod-str.c @@ -29,6 +29,7 @@ #include #include "../cmn/mem-prv.h" #include "fnc.h" +#include "val.h" static int fnc_normspace (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) { @@ -215,6 +216,7 @@ static int fnc_value (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) static int fnc_tonum (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) { /* str::tonum (value) */ + /* str::tonum (string, base) */ qse_awk_val_t* retv; qse_awk_val_t* a0; @@ -224,18 +226,38 @@ static int fnc_tonum (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) a0 = qse_awk_rtx_getarg(rtx, 0); - rx = qse_awk_rtx_valtonum (rtx, a0, &lv, &rv); - if (rx == 0) + if (QSE_AWK_RTX_GETVALTYPE(rtx, a0) == QSE_AWK_VAL_STR && qse_awk_rtx_getnargs(rtx) >= 2) { - retv = qse_awk_rtx_makeintval (rtx, lv); - } - else if (rx >= 1) - { - retv = qse_awk_rtx_makefltval (rtx, rv); + /* if the value is known to be a string, it supports the optional + * base parameter */ + qse_awk_val_t* a1 = qse_awk_rtx_getarg(rtx, 1); + qse_awk_int_t base; + + if (qse_awk_rtx_valtoint(rtx, a1, &base) <= -1) return -1; + rx = qse_awk_rtx_strtonum ( + rtx, + QSE_AWK_RTX_STRTONUM_MAKE_OPTION(0, base), + ((qse_awk_val_str_t*)a0)->val.ptr, + ((qse_awk_val_str_t*)a0)->val.len, + &lv, &rv + ); } else { - retv = qse_awk_rtx_makeintval (rtx, 0); + rx = qse_awk_rtx_valtonum(rtx, a0, &lv, &rv); + } + + if (rx == 0) + { + retv = qse_awk_rtx_makeintval(rtx, lv); + } + else if (rx >= 1) + { + retv = qse_awk_rtx_makefltval(rtx, rv); + } + else + { + retv = qse_awk_rtx_makeintval(rtx, 0); } if (!retv) return -1; @@ -281,7 +303,7 @@ static fnctab_t fnctab[] = { QSE_T("sub"), { { 2, 3, QSE_T("xvr") }, qse_awk_fnc_sub, 0 } }, { QSE_T("substr"), { { 2, 3, QSE_NULL }, qse_awk_fnc_substr, 0 } }, { QSE_T("tolower"), { { 1, 1, QSE_NULL }, qse_awk_fnc_tolower, 0 } }, - { QSE_T("tonum"), { { 1, 1, QSE_NULL }, fnc_tonum, 0 } }, + { QSE_T("tonum"), { { 1, 2, QSE_NULL }, fnc_tonum, 0 } }, { QSE_T("toupper"), { { 1, 1, QSE_NULL }, qse_awk_fnc_toupper, 0 } }, { QSE_T("trim"), { { 1, 1, QSE_NULL }, fnc_trim, 0 } }, { QSE_T("value"), { { 1, 1, QSE_NULL }, fnc_value, 0 } } diff --git a/qse/lib/awk/run.c b/qse/lib/awk/run.c index cbab4045..c74ff3df 100644 --- a/qse/lib/awk/run.c +++ b/qse/lib/awk/run.c @@ -4204,7 +4204,8 @@ static QSE_INLINE int __cmp_int_str ( qse_awk_flt_t rr; n = qse_awk_rtx_strtonum ( - rtx, 1, + rtx, + QSE_AWK_RTX_STRTONUM_MAKE_OPTION(1, 0), ((qse_awk_val_str_t*)right)->val.ptr, ((qse_awk_val_str_t*)right)->val.len, &ll, &rr diff --git a/qse/lib/awk/std.c b/qse/lib/awk/std.c index 0ccdc566..aae6cf5c 100644 --- a/qse/lib/awk/std.c +++ b/qse/lib/awk/std.c @@ -2185,9 +2185,9 @@ static int fnc_setioattr (qse_awk_rtx_t* rtx, const qse_awk_fnc_info_t* fi) qse_awk_flt_t r; int x; - /* no error is returned by qse_awk_rtx_strnum() if the second - * parameter is 0. so i don't check for an error */ - x = qse_awk_rtx_strtonum (rtx, 0, ptr[2], len[2], &l, &r); + /* no error is returned by qse_awk_rtx_strnum() if the strict option + * of the second parameter is 0. so i don't check for an error */ + x = qse_awk_rtx_strtonum(rtx, QSE_AWK_RTX_STRTONUM_MAKE_OPTION(0, 0), ptr[2], len[2], &l, &r); if (x == 0) r = (qse_awk_flt_t)l; ioattr = find_or_make_ioattr (rtx, &rxtn->cmgrtab, ptr[0], len[0]); diff --git a/qse/lib/awk/val.c b/qse/lib/awk/val.c index 65a2fe0d..82c3bea0 100644 --- a/qse/lib/awk/val.c +++ b/qse/lib/awk/val.c @@ -443,8 +443,8 @@ qse_awk_val_t* qse_awk_rtx_makenstrvalwithxstr (qse_awk_rtx_t* rtx, const qse_cs qse_awk_int_t l; qse_awk_flt_t r; - x = qse_awk_rtx_strtonum (rtx, 1, str->ptr, str->len, &l, &r); - v = qse_awk_rtx_makestrvalwithxstr (rtx, str); + x = qse_awk_rtx_strtonum(rtx, QSE_AWK_RTX_STRTONUM_MAKE_OPTION(1, 0), str->ptr, str->len, &l, &r); + v = qse_awk_rtx_makestrvalwithxstr(rtx, str); if (v == QSE_NULL) return QSE_NULL; @@ -1555,7 +1555,8 @@ static int val_ref_to_num ( if (idx == 0) { return qse_awk_rtx_strtonum ( - rtx, 0, + rtx, + QSE_AWK_RTX_STRTONUM_MAKE_OPTION(0, 0), QSE_STR_PTR(&rtx->inrec.line), QSE_STR_LEN(&rtx->inrec.line), l, r @@ -1564,7 +1565,8 @@ static int val_ref_to_num ( else if (idx <= rtx->inrec.nflds) { return qse_awk_rtx_strtonum ( - rtx, 0, + rtx, + QSE_AWK_RTX_STRTONUM_MAKE_OPTION(0, 0), rtx->inrec.flds[idx-1].ptr, rtx->inrec.flds[idx-1].len, l, r @@ -1573,7 +1575,7 @@ static int val_ref_to_num ( else { return qse_awk_rtx_strtonum ( - rtx, 0, QSE_T(""), 0, l, r + rtx, QSE_AWK_RTX_STRTONUM_MAKE_OPTION(0, 0), QSE_T(""), 0, l, r ); } } @@ -1628,7 +1630,8 @@ int qse_awk_rtx_valtonum ( case QSE_AWK_VAL_STR: { return qse_awk_rtx_strtonum ( - rtx, 0, + rtx, + QSE_AWK_RTX_STRTONUM_MAKE_OPTION(0, 0), ((qse_awk_val_str_t*)v)->val.ptr, ((qse_awk_val_str_t*)v)->val.len, l, r @@ -1691,15 +1694,18 @@ int qse_awk_rtx_valtoflt ( } int qse_awk_rtx_strtonum ( - qse_awk_rtx_t* rtx, int strict, + qse_awk_rtx_t* rtx, int option, const qse_char_t* ptr, qse_size_t len, qse_awk_int_t* l, qse_awk_flt_t* r) { const qse_char_t* endptr; const qse_char_t* end; + int strict = QSE_AWK_RTX_STRTONUM_GET_OPTION_STRICT(option); + int base = QSE_AWK_RTX_STRTONUN_GET_OPTION_BASE(option); + end = ptr + len; - *l = qse_awk_strxtoint (rtx->awk, ptr, len, 0, &endptr); + *l = qse_awk_strxtoint(rtx->awk, ptr, len, base, &endptr); if (endptr < end) { if (*endptr == QSE_T('.') || *endptr == QSE_T('E') || *endptr == QSE_T('e'))