X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Fstrtonum-gen.h;h=6b1a6f8f3688b53d63e4ea22de02afda107bb088;hb=1b2faf7409371da71c440704e3a75c34f7a9d750;hp=079548ffe04e32dd8c941f5454b5d9df69896c59;hpb=9db82493c339b61cc587cad9e3dbbd5157a4f1d4;p=libucw.git diff --git a/ucw/strtonum-gen.h b/ucw/strtonum-gen.h index 079548ff..6b1a6f8f 100644 --- a/ucw/strtonum-gen.h +++ b/ucw/strtonum-gen.h @@ -22,91 +22,82 @@ #define STN_MAX ((STN_TYPE)(-1)) static const STN_TYPE S(tops)[STN_DBASES_MASK+1] = { [2] = STN_MAX/2, [8] = STN_MAX/8, [10] = STN_MAX/10, [16] = STN_MAX/16 }; +static const char *S(parse_string)(const char **pp, const uns flags, const uns sign, const uns base, STN_TYPE *num) +{ + const STN_TYPE max = STN_MAX; + const STN_TYPE top = S(tops)[base]; + if (!top) + return "Unknown base"; + + const STN_TYPE sign_max = ((flags & STN_SIGNED) || sign) ? max/2 + sign : max; + + STN_TYPE val = 0; + uns digits = 0; + int overflow = 0; + for (;; (*pp)++) + { + const uns c = (byte)**pp; + + if (c == '_') + { + if (flags & STN_UNDERSCORE) + continue; + else + break; + } + + const uns d = get_digit(c); + if (d >= base) + break; + + digits++; + + if (overflow) + continue; + + STN_TYPE v = val; + if ( (overflow = (v > top || (v *= base) > sign_max - d)) ) + continue; + val = v + d; + } + + if (!overflow) + { + if (!digits) + return "Number contains no digits"; + + if (sign) + val = -val; + } + else + { + if (flags & STN_TRUNC) + val = sign_max; + else + return "Numeric overflow"; + } + + if ((flags & STN_WHOLE) && **pp) + return "Invalid character"; + + if (num) + *num = val; + + return NULL; +} + STN_DECLARE(STN_TYPE, STN_SUFFIX) { - const char *p = str; const char *err = NULL; uns sign, base; - err = str_to_num_init(&p, flags, &sign, &base); - - const char *parse_string(void) - { - const STN_TYPE max = STN_MAX; - const STN_TYPE top = S(tops)[base]; - if (!top) - { - return err_unknown_base; - } - - const STN_TYPE sign_max = ((flags & STN_SIGNED) || sign) ? max/2 + sign : max; - - STN_TYPE val = 0; - uns digits = 0; - int overflow = 0; - for (;; p++) - { - const uns c = (byte)*p; - - if (c == '_') - { - if (flags & STN_UNDERSCORE) - continue; - else - break; - } - - const uns d = get_digit(c); - if (d >= base) - break; - digits++; - if (overflow) - continue; - - STN_TYPE v = val; - if ( (overflow = (v > top || (v *= base) > sign_max - d)) ) - continue; - val = v + d; - } - - if (!overflow) - { - if (!digits) - { - return err_no_digits; - } - - if (sign) - { - val = -val; - } - } - else - { - if (flags & STN_TRUNC) - val = sign_max; - else - { - return err_numeric_overflow; - } - } - - if ((flags & STN_ZCHAR) && *p) - { - return err_invalid_character; - } - - if (num) - *num = val; - - return NULL; - } + err = str_to_num_init(&str, flags, &sign, &base); if (!err) - err = parse_string(); + err = S(parse_string)(&str, flags, sign, base, num); if (next) - *next = p; + *next = str; return err; }