X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Fstrtonum-gen.h;h=621162d41582fabce8dcaf17d0ae02308ce5f760;hb=bc2bbfcbe76e78db9cde27455ddbcfe1ddcc61d6;hp=60dcca7b5a357be2d19ce4ec1c3fd62f836e0d6c;hpb=2c7483b13f06f97b8a3d98f27ebe5ebf003be1c2;p=libucw.git diff --git a/ucw/strtonum-gen.h b/ucw/strtonum-gen.h index 60dcca7b..621162d4 100644 --- a/ucw/strtonum-gen.h +++ b/ucw/strtonum-gen.h @@ -7,8 +7,10 @@ * of the GNU Lesser General Public License. */ -/* This is not a normall header file, it is generator of a function for converting strings to integers - * of a certain type. This file should be used only by ucw/stronum.c . +/* + * This is not a normal header file, it is a generator of a function for + * converting strings to integers of a certain type. This file should be used + * by ucw/stronum.c only. */ #define STN_DECLARE(type, suffix) STN_DECLARE_CONVERTOR(type, suffix) @@ -20,89 +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 uint flags, const uint sign, const uint 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; + uint digits = 0; + int overflow = 0; + for (;; (*pp)++) + { + const uint c = (byte)**pp; + + if (c == '_') + { + if (flags & STN_UNDERSCORE) + continue; + else + break; + } + + const uint 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 ((flags & STN_ZCHAR) && *p) - { - return err_invalid_character; - } - - if (!digits) - { - return err_no_digits; - } - - if (sign) - { - val = -val; - } - } - else - { - if (flags & STN_TRUNC) - val = sign_max; - else - { - return err_numeric_overflow; - } - } - - if (num) - *num = val; - - return NULL; - } + uint sign, base; + 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; }