From: Timo Sirainen Date: Tue, 6 Apr 2010 22:48:03 +0000 (+0300) Subject: Added str_to_*() for converting strings to numbers, plus a few helper functions. X-Git-Tag: 2.0.beta5~189 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3ed749924ed5215d84e0a095bc7d74ce3100e242;p=thirdparty%2Fdovecot%2Fcore.git Added str_to_*() for converting strings to numbers, plus a few helper functions. The str_to_*() return failure also if integer is too large or too small to fit into destination. --HG-- branch : HEAD --- diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index b916ad805b..cec20cd8a7 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -104,6 +104,7 @@ liblib_la_SOURCES = \ str-sanitize.c \ strescape.c \ strfuncs.c \ + strnum.c \ time-util.c \ unix-socket-create.c \ unlink-directory.c \ @@ -198,6 +199,7 @@ headers = \ str-sanitize.h \ strescape.h \ strfuncs.h \ + strnum.h \ time-util.h \ unix-socket-create.h \ unlink-directory.h \ diff --git a/src/lib/lib.h b/src/lib/lib.h index f33d35af85..0305c891a4 100644 --- a/src/lib/lib.h +++ b/src/lib/lib.h @@ -37,6 +37,7 @@ struct ostream; #include "array-decl.h" /* ARRAY_DEFINE()s may exist in any header */ #include "strfuncs.h" +#include "strnum.h" size_t nearest_power(size_t num) ATTR_CONST; diff --git a/src/lib/strnum.c b/src/lib/strnum.c new file mode 100644 index 0000000000..e50316deb6 --- /dev/null +++ b/src/lib/strnum.c @@ -0,0 +1,253 @@ +/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "strnum.h" + +bool str_is_numeric(const char *str, char end_char) +{ + if (*str == '\0' || *str == end_char) + return FALSE; + + while (*str != '\0' && *str != end_char) { + if (*str < '0' || *str > '9') + return FALSE; + str++; + } + + return TRUE; +} + +int str_to_uint(const char *str, unsigned int *num_r) +{ + uintmax_t l; + + if (str_to_uintmax(str, &l) < 0) + return -1; + + if (l > (unsigned int)-1) + return -1; + *num_r = (unsigned int)l; + return 0; +} + +int str_to_ulong(const char *str, unsigned long *num_r) +{ + uintmax_t l; + + if (str_to_uintmax(str, &l) < 0) + return -1; + + if (l > (unsigned long)-1) + return -1; + *num_r = (unsigned long)l; + return 0; +} + +int str_to_ullong(const char *str, unsigned long long *num_r) +{ + uintmax_t l; + + if (str_to_uintmax(str, &l) < 0) + return -1; + + if (l > (unsigned long long)-1) + return -1; + *num_r = (unsigned long long)l; + return 0; +} + +int str_to_uint32(const char *str, uint32_t *num_r) +{ + uintmax_t l; + + if (str_to_uintmax(str, &l) < 0) + return -1; + + if (l > (uint32_t)-1) + return -1; + *num_r = (uint32_t)l; + return 0; +} + +int str_to_uint64(const char *str, uint64_t *num_r) +{ + uintmax_t l; + + if (str_to_uintmax(str, &l) < 0) + return -1; + + if (l > (uint64_t)-1) + return -1; + *num_r = (uint64_t)l; + return 0; +} + +int str_to_uintmax(const char *str, uintmax_t *num_r) +{ + uintmax_t next, n = 0; + + if (*str < '0' || *str > '9') + return -1; + + for (; *str >= '0' && *str <= '9'; str++) { + next = n*10; + if (next < n) { + /* overflow */ + return -1; + } + n = next + (*str - '0'); + } + if (str != '\0') + return -1; + *num_r = n; + return 0; +} + +int str_to_int(const char *str, int *num_r) +{ + intmax_t l; + + if (str_to_intmax(str, &l) < 0) + return -1; + + if (l < INT_MIN || l > INT_MAX) + return -1; + *num_r = (int)l; + return 0; +} + +int str_to_long(const char *str, long *num_r) +{ + intmax_t l; + + if (str_to_intmax(str, &l) < 0) + return -1; + + if (l < LONG_MIN || l > LONG_MAX) + return -1; + *num_r = (long)l; + return 0; +} + +int str_to_llong(const char *str, long long *num_r) +{ + intmax_t l; + + if (str_to_intmax(str, &l) < 0) + return -1; + + if (l < LLONG_MIN || l > LLONG_MAX) + return -1; + *num_r = (long long)l; + return 0; +} + +int str_to_intmax(const char *str, intmax_t *num_r) +{ + bool neg = FALSE; + uintmax_t l; + + if (*str == '-') { + neg = TRUE; + str++; + } + if (str_to_uintmax(str, &l) < 0) + return -1; + + if (!neg) { + if (l > INTMAX_MAX) + return -1; + *num_r = (intmax_t)l; + } else { + if (l > UINTMAX_MAX - (UINTMAX_MAX + INTMAX_MIN)) + return -1; + *num_r = (intmax_t)-l; + } + return 0; +} + +static int verify_xid(uintmax_t l, unsigned int result_size) +{ + unsigned int result_bits; + + /* we assume that result is a signed type, + but that it can never be negative */ + result_bits = result_size*CHAR_BIT - 1; + if ((l >> result_bits) != 0) + return -1; + return 0; +} + +int str_to_uid(const char *str, uid_t *num_r) +{ + uintmax_t l; + + if (str_to_uintmax(str, &l) < 0) + return -1; + + if (verify_xid(l, sizeof(*num_r)) < 0) + return -1; + *num_r = (uid_t)l; + return 0; +} + +int str_to_gid(const char *str, gid_t *num_r) +{ + uintmax_t l; + + if (str_to_uintmax(str, &l) < 0) + return -1; + + if (verify_xid(l, sizeof(*num_r)) < 0) + return -1; + *num_r = (gid_t)l; + return 0; +} + +int str_to_pid(const char *str, pid_t *num_r) +{ + uintmax_t l; + + if (str_to_uintmax(str, &l) < 0) + return -1; + + if (verify_xid(l, sizeof(*num_r)) < 0) + return -1; + *num_r = (pid_t)l; + return 0; +} + +int str_to_uoff(const char *str, uoff_t *num_r) +{ + uintmax_t l; + + if (str_to_uintmax(str, &l) < 0) + return -1; + + if (l > (uoff_t)-1) + return -1; + *num_r = (uoff_t)l; + return 0; +} + +bool str_uint_equals(const char *str, uintmax_t num) +{ + uintmax_t l; + + if (str_to_uintmax(str, &l) < 0) + return FALSE; + return l == num; +} + +const char *str_num_error(const char *str) +{ + if (*str == '-') { + if (!str_is_numeric(str + 1, '\0')) + return "Not a valid number"; + return "Number too small"; + } else { + if (!str_is_numeric(str, '\0')) + return "Not a valid number"; + return "Number too large"; + } +} diff --git a/src/lib/strnum.h b/src/lib/strnum.h new file mode 100644 index 0000000000..cd56de03f9 --- /dev/null +++ b/src/lib/strnum.h @@ -0,0 +1,36 @@ +#ifndef STRNUM_H +#define STRNUM_H + +/* Return TRUE if all characters in string are numbers. + Stop when `end_char' is found from string. */ +bool str_is_numeric(const char *str, char end_char) ATTR_PURE; + +/* str_to_*() functions return 0 if string is valid number in valid range. + Otherwise -1 is returned and num_r is left untouched */ + +int str_to_uint(const char *str, unsigned int *num_r) ATTR_WARN_UNUSED_RESULT; +int str_to_ulong(const char *str, unsigned long *num_r) ATTR_WARN_UNUSED_RESULT; +int str_to_ullong(const char *str, unsigned long long *num_r) ATTR_WARN_UNUSED_RESULT; +int str_to_uint32(const char *str, uint32_t *num_r) ATTR_WARN_UNUSED_RESULT; +int str_to_uint64(const char *str, uint64_t *num_r) ATTR_WARN_UNUSED_RESULT; +int str_to_uintmax(const char *str, uintmax_t *num_r) ATTR_WARN_UNUSED_RESULT; + +int str_to_int(const char *str, int *num_r) ATTR_WARN_UNUSED_RESULT; +int str_to_long(const char *str, long *num_r) ATTR_WARN_UNUSED_RESULT; +int str_to_llong(const char *str, long long *num_r) ATTR_WARN_UNUSED_RESULT; +int str_to_intmax(const char *str, intmax_t *num_r) ATTR_WARN_UNUSED_RESULT; + +int str_to_uid(const char *str, uid_t *num_r) ATTR_WARN_UNUSED_RESULT; +int str_to_gid(const char *str, gid_t *num_r) ATTR_WARN_UNUSED_RESULT; +int str_to_pid(const char *str, pid_t *num_r) ATTR_WARN_UNUSED_RESULT; +int str_to_uoff(const char *str, uoff_t *num_r) ATTR_WARN_UNUSED_RESULT; + +/* Returns TRUE if str is a valid unsigned number that equals to num. */ +bool str_uint_equals(const char *str, uintmax_t num); + +/* Returns human readable string about what is wrong with the string. + This function assumes that str_to_*() had already returned -1 for the + string. */ +const char *str_num_error(const char *str); + +#endif