diff options
author | Denis Vlasenko | 2006-10-08 12:49:22 +0000 |
---|---|---|
committer | Denis Vlasenko | 2006-10-08 12:49:22 +0000 |
commit | 1385899416a4396385ad421ae1f532be7103738a (patch) | |
tree | fc4d14a910593d1235318bb36abe5e9f72d2039e /libbb/xatol.c | |
parent | 5625415085e68ac5e150f54e685417c866620d76 (diff) | |
download | busybox-1385899416a4396385ad421ae1f532be7103738a.zip busybox-1385899416a4396385ad421ae1f532be7103738a.tar.gz |
attempt to regularize atoi mess.
Diffstat (limited to 'libbb/xatol.c')
-rw-r--r-- | libbb/xatol.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/libbb/xatol.c b/libbb/xatol.c new file mode 100644 index 0000000..82250a7 --- /dev/null +++ b/libbb/xatol.c @@ -0,0 +1,210 @@ +/* vi: set sw=4 ts=4: */ +/* + * ascii-to-numbers implementations for busybox + * + * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org> + * + * Licensed under GPLv2, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" + +unsigned long long xatoull(const char *numstr) +{ + unsigned long long r; + int old_errno; + char *e; + if ((*numstr == '-') || (isspace)(*numstr)) + bb_error_msg_and_die("invalid number '%s'", numstr); + old_errno = errno; + errno = 0; + r = strtoull(numstr, &e, 10); + if (errno || (numstr == e) || *e) + /* Error / no digits / illegal trailing chars */ + bb_error_msg_and_die("invalid number '%s'", numstr); + /* No error. So restore errno. */ + errno = old_errno; + return r; +} + +unsigned long xstrtoul_range_sfx(const char *numstr, int base, + unsigned long lower, + unsigned long upper, + const struct suffix_mult *suffixes) +{ + unsigned long r; + int old_errno; + char *e; + + /* Disallow '-' and any leading whitespace. Speed isn't critical here + * since we're parsing commandline args. So make sure we get the + * actual isspace function rather than a lnumstrer macro implementaion. */ + if ((*numstr == '-') || (isspace)(*numstr)) + goto inval; + + /* Since this is a lib function, we're not allowed to reset errno to 0. + * Doing so could break an app that is deferring checking of errno. + * So, save the old value so that we can restore it if successful. */ + old_errno = errno; + errno = 0; + r = strtoul(numstr, &e, base); + /* Do the initial validity check. Note: The standards do not + * guarantee that errno is set if no digits were found. So we + * must test for this explicitly. */ + if (errno || (numstr == e)) + goto inval; /* error / no digits / illegal trailing chars */ + + errno = old_errno; /* Ok. So restore errno. */ + + /* Do optional suffix parsing. Allow 'empty' suffix tables. + * Note that we also allow nul suffixes with associated multipliers, + * to allow for scaling of the numstr by some default multiplier. */ + if (suffixes) { + while (suffixes->suffix) { + if (strcmp(suffixes->suffix, e) == 0) { + if (ULONG_MAX / suffixes->mult < r) + goto range; /* overflow! */ + ++e; + r *= suffixes->mult; + break; + } + ++suffixes; + } + } + + /* Note: trailing space is an error. + It would be easy enough to allow though if desired. */ + if (*e) + goto inval; + /* Finally, check for range limits. */ + if (r >= lower && r <= upper) + return r; + range: + bb_error_msg_and_die("number %s is not in %lu..%lu range", + numstr, lower, upper); + inval: + bb_error_msg_and_die("invalid number '%s'", numstr); +} + +unsigned long xstrtoul_range(const char *numstr, int base, + unsigned long lower, + unsigned long upper) +{ + return xstrtoul_range_sfx(numstr, base, lower, upper, NULL); +} + +unsigned long xstrtoul(const char *numstr, int base) +{ + return xstrtoul_range_sfx(numstr, base, 0, ULONG_MAX, NULL); +} + +unsigned long xatoul_range_sfx(const char *numstr, + unsigned long lower, + unsigned long upper, + const struct suffix_mult *suffixes) +{ + return xstrtoul_range_sfx(numstr, 10, lower, upper, suffixes); +} + +unsigned long xatoul_sfx(const char *numstr, + const struct suffix_mult *suffixes) +{ + return xstrtoul_range_sfx(numstr, 10, 0, ULONG_MAX, suffixes); +} + +unsigned long xatoul_range(const char *numstr, + unsigned long lower, + unsigned long upper) +{ + return xstrtol_range_sfx(numstr, 10, lower, upper, NULL); +} + +unsigned long xatoul(const char *numstr) +{ + return xatoul_sfx(numstr, NULL); +} + +/* Signed ones */ + +long xstrtol_range_sfx(const char *numstr, int base, + long lower, + long upper, + const struct suffix_mult *suffixes) +{ + unsigned long u = LONG_MAX; + long r; + const char *p = numstr; + + if ((p[0] == '-') && (p[1] != '+')) { + ++p; + ++u; /* two's complement */ + } + + r = xstrtoul_range_sfx(p, base, 0, u, suffixes); + + if (*numstr == '-') { + r = -r; + } + + if (r < lower || r > upper) { + bb_error_msg_and_die("number %s is not in %ld..%ld range", + numstr, lower, upper); + } + + return r; +} + +long xstrtol_range(const char *numstr, int base, long lower, long upper) +{ + return xstrtol_range_sfx(numstr, base, lower, upper, NULL); +} + +long xatol_range_sfx(const char *numstr, + long lower, + long upper, + const struct suffix_mult *suffixes) +{ + return xstrtol_range_sfx(numstr, 10, lower, upper, suffixes); +} + +long xatol_range(const char *numstr, long lower, long upper) +{ + return xstrtol_range_sfx(numstr, 10, lower, upper, NULL); +} + +long xatol_sfx(const char *numstr, const struct suffix_mult *suffixes) +{ + return xstrtol_range_sfx(numstr, 10, LONG_MIN, LONG_MAX, suffixes); +} + +long xatol(const char *numstr) +{ + return xstrtol_range_sfx(numstr, 10, LONG_MIN, LONG_MAX, NULL); +} + +/* Others */ + +unsigned xatou(const char *numstr) +{ + return xatoul_range(numstr, 0, UINT_MAX); +} + +int xatoi(const char *numstr) +{ + return xatol_range(numstr, INT_MIN, INT_MAX); +} + +int xatoi_u(const char *numstr) +{ + return xatoul_range(numstr, 0, INT_MAX); +} + +uint32_t xatou32(const char *numstr) +{ + return xatoul_range(numstr, 0, 0xffffffff); +} + +uint16_t xatou16(const char *numstr) +{ + return xatoul_range(numstr, 0, 0xffff); +} |