#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);
-
- auto const char *parse_string(void);
- 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;
- }
+ 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;
}