]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
strnum: Implemented many more numeric string parsing functions.
authorStephan Bosch <stephan@rename-it.nl>
Sat, 29 Aug 2015 11:31:51 +0000 (14:31 +0300)
committerStephan Bosch <stephan@rename-it.nl>
Sat, 29 Aug 2015 11:31:51 +0000 (14:31 +0300)
Created macros for most of the implementation to avoid further code
duplication.

src/lib/strnum.c
src/lib/strnum.h

index a782174c3b9a0714f1d0e0390990e755a19a9fcf..a79ce1cbcace50e86ffbf9ed84f20acd7cb9ac49 100644 (file)
@@ -17,155 +17,285 @@ bool str_is_numeric(const char *str, char end_char)
        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;
+/* 
+ * Unsigned decimal
+ */
+
+#define STR_PARSE_U__TEMPLATE(name, type)                     \
+int name(const char *str, type *num_r, const char **endp_r)   \
+{                                                             \
+       uintmax_t l;                                                \
+       if (str_parse_uintmax(str, &l, endp_r) < 0 || l > (type)-1) \
+               return -1;                                                \
+       *num_r = (type)l;                                           \
+       return 0;                                                   \
+}
 
-       if (l > UINT_MAX)
-               return -1;
-       *num_r = (unsigned int)l;
-       return 0;
+STR_PARSE_U__TEMPLATE(str_parse_uint, unsigned int)
+STR_PARSE_U__TEMPLATE(str_parse_ulong, unsigned long)
+STR_PARSE_U__TEMPLATE(str_parse_ullong, unsigned long long)
+STR_PARSE_U__TEMPLATE(str_parse_uint32, uint32_t)
+STR_PARSE_U__TEMPLATE(str_parse_uint64, uint64_t)
+
+#define STR_TO_U__TEMPLATE(name, type)                        \
+int name(const char *str, type *num_r)                        \
+{                                                             \
+       uintmax_t l;                                                \
+       if (str_to_uintmax(str, &l) < 0 || l > (type)-1)            \
+               return -1;                                                \
+       *num_r = (type)l;                                           \
+       return 0;                                                   \
 }
 
-int str_to_ulong(const char *str, unsigned long *num_r)
+STR_TO_U__TEMPLATE(str_to_uint, unsigned int)
+STR_TO_U__TEMPLATE(str_to_ulong, unsigned long)
+STR_TO_U__TEMPLATE(str_to_ullong, unsigned long long)
+STR_TO_U__TEMPLATE(str_to_uint32, uint32_t)
+STR_TO_U__TEMPLATE(str_to_uint64, uint64_t)
+
+int str_parse_uintmax(const char *str, uintmax_t *num_r,
+       const char **endp_r)
 {
-       uintmax_t l;
+       uintmax_t n = 0;
 
-       if (str_to_uintmax(str, &l) < 0)
+       if (*str < '0' || *str > '9')
                return -1;
 
-       if (l > (unsigned long)-1)
-               return -1;
-       *num_r = (unsigned long)l;
+       for (; *str >= '0' && *str <= '9'; str++) {
+               if (n >= ((uintmax_t)-1 / 10)) {
+                       if (n > (uintmax_t)-1 / 10)
+                               return -1;
+                       if ((uintmax_t)(*str - '0') > ((uintmax_t)-1 % 10))
+                               return -1;
+               }
+               n = n * 10 + (*str - '0');
+       }
+       if (endp_r != NULL)
+               *endp_r = str;
+       *num_r = n;
        return 0;
 }
-
-int str_to_ullong(const char *str, unsigned long long *num_r)
+int str_to_uintmax(const char *str, uintmax_t *num_r)
 {
-       uintmax_t l;
-
-       if (str_to_uintmax(str, &l) < 0)
-               return -1;
-
-       if (l > (unsigned long long)-1)
+       const char *endp;
+       uintmax_t n;
+       int ret = str_parse_uintmax(str, &n, &endp);
+       if ((ret != 0) || (*endp != '\0'))
                return -1;
-       *num_r = (unsigned long long)l;
+       *num_r = n;
        return 0;
 }
 
-int str_to_uint32(const char *str, uint32_t *num_r)
+bool str_uint_equals(const char *str, uintmax_t num)
 {
        uintmax_t l;
 
        if (str_to_uintmax(str, &l) < 0)
-               return -1;
+               return FALSE;
+       return l == num;
+}
 
-       if (l > (uint32_t)-1)
-               return -1;
-       *num_r = (uint32_t)l;
-       return 0;
+/* 
+ * Unsigned hexadecimal
+ */
+
+#define STR_PARSE_UHEX__TEMPLATE(name, type)                       \
+int name(const char *str, type *num_r, const char **endp_r)        \
+{                                                                  \
+       uintmax_t l;                                                     \
+       if (str_parse_uintmax_hex(str, &l, endp_r) < 0 || l > (type)-1)  \
+               return -1;                                                     \
+       *num_r = (type)l;                                                \
+       return 0;                                                        \
 }
 
-int str_to_uint64(const char *str, uint64_t *num_r)
-{
-       uintmax_t l;
+STR_PARSE_UHEX__TEMPLATE(str_parse_uint_hex, unsigned int)
+STR_PARSE_UHEX__TEMPLATE(str_parse_ulong_hex, unsigned long)
+STR_PARSE_UHEX__TEMPLATE(str_parse_ullong_hex, unsigned long long)
+STR_PARSE_UHEX__TEMPLATE(str_parse_uint32_hex, uint32_t)
+STR_PARSE_UHEX__TEMPLATE(str_parse_uint64_hex, uint64_t)
+
+#define STR_TO_UHEX__TEMPLATE(name, type)                          \
+int name(const char *str, type *num_r)                             \
+{                                                                  \
+       uintmax_t l;                                                     \
+       if (str_to_uintmax_hex(str, &l) < 0 || l > (type)-1)             \
+               return -1;                                                     \
+       *num_r = (type)l;                                                \
+       return 0;                                                        \
+}
 
-       if (str_to_uintmax(str, &l) < 0)
-               return -1;
+STR_TO_UHEX__TEMPLATE(str_to_uint_hex, unsigned int)
+STR_TO_UHEX__TEMPLATE(str_to_ulong_hex, unsigned long)
+STR_TO_UHEX__TEMPLATE(str_to_ullong_hex, unsigned long long)
+STR_TO_UHEX__TEMPLATE(str_to_uint32_hex, uint32_t)
+STR_TO_UHEX__TEMPLATE(str_to_uint64_hex, uint64_t)
 
-       if (l > (uint64_t)-1)
-               return -1;
-       *num_r = (uint64_t)l;
-       return 0;
+static inline int _str_parse_hex(const char ch,
+       unsigned int *hex_r)
+{
+       switch (ch) {
+       case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+               *hex_r = (unsigned int)(ch - 'a' + 10);
+               return 0;
+       case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+               *hex_r = (unsigned int)(ch - 'A' + 10);
+               return 0;
+       case '0': case '1': case '2': case '3': case '4':
+       case '5': case '6': case '7': case '8': case '9':
+               *hex_r = (unsigned int)(ch - '0');
+               return 0;
+       default:
+               break;
+       }
+       return -1;
 }
-
-int str_parse_uintmax(const char *str, uintmax_t *num_r, const char **endp_r)
+int str_parse_uintmax_hex(const char *str, uintmax_t *num_r,
+       const char **endp_r)
 {
+       unsigned int hex;
        uintmax_t n = 0;
 
-       if (*str < '0' || *str > '9')
+       if (_str_parse_hex(*str, &hex) < 0)
                return -1;
 
-       for (; *str >= '0' && *str <= '9'; str++) {
-               if (n >= ((uintmax_t)-1 / 10)) {
-                       if (n > (uintmax_t)-1 / 10)
+       do {
+               if (n >= ((uintmax_t)-1 >> 4)) {
+                       if (n > (uintmax_t)-1 >> 4)
                                return -1;
-                       if ((uintmax_t)(*str - '0') > ((uintmax_t)-1 % 10))
+                       if ((uintmax_t)hex > ((uintmax_t)-1 & 0x0f))
                                return -1;
                }
-               n = n * 10 + (*str - '0');
-       }
+               n = (n << 4) + hex;
+               str++;
+       } while (_str_parse_hex(*str, &hex) >= 0);
        if (endp_r != NULL)
                *endp_r = str;
        *num_r = n;
        return 0;
 }
-int str_to_uintmax(const char *str, uintmax_t *num_r)
+int str_to_uintmax_hex(const char *str, uintmax_t *num_r)
 {
        const char *endp;
        uintmax_t n;
-       int ret = str_parse_uintmax(str, &n, &endp);
+       int ret = str_parse_uintmax_hex(str, &n, &endp);
        if ((ret != 0) || (*endp != '\0'))
                return -1;
        *num_r = n;
        return 0;
 }
 
-#define STR_TO_U__TEMPLATE(name, type)                         \
-int name(const char *str, type *num_r, const char **endp_r)    \
-{                                                              \
-       uintmax_t l;                                            \
-       if (str_parse_uintmax(str, &l, endp_r) < 0 || l > (type)-1)\
-               return -1;                                      \
-       *num_r = l;                                             \
-       return 0;                                               \
+/* 
+ * Unsigned octal
+ */
+
+#define STR_PARSE_UOCT__TEMPLATE(name, type)                       \
+int name(const char *str, type *num_r, const char **endp_r)        \
+{                                                                  \
+       uintmax_t l;                                                     \
+       if (str_parse_uintmax_oct(str, &l, endp_r) < 0 || l > (type)-1)  \
+               return -1;                                                     \
+       *num_r = (type)l;                                                \
+       return 0;                                                        \
 }
-STR_TO_U__TEMPLATE(str_parse_uoff, uoff_t)
-STR_TO_U__TEMPLATE(str_parse_uint, unsigned int)
 
-int str_to_int(const char *str, int *num_r)
+STR_PARSE_UOCT__TEMPLATE(str_parse_uint_oct, unsigned int)
+STR_PARSE_UOCT__TEMPLATE(str_parse_ulong_oct, unsigned long)
+STR_PARSE_UOCT__TEMPLATE(str_parse_ullong_oct, unsigned long long)
+STR_PARSE_UOCT__TEMPLATE(str_parse_uint32_oct, uint32_t)
+STR_PARSE_UOCT__TEMPLATE(str_parse_uint64_oct, uint64_t)
+
+#define STR_TO_UOCT__TEMPLATE(name, type)                          \
+int name(const char *str, type *num_r)                             \
+{                                                                  \
+       uintmax_t l;                                                     \
+       if (str_to_uintmax_oct(str, &l) < 0 || l > (type)-1)             \
+               return -1;                                                     \
+       *num_r = (type)l;                                                \
+       return 0;                                                        \
+}
+
+STR_TO_UOCT__TEMPLATE(str_to_uint_oct, unsigned int)
+STR_TO_UOCT__TEMPLATE(str_to_ulong_oct, unsigned long)
+STR_TO_UOCT__TEMPLATE(str_to_ullong_oct, unsigned long long)
+STR_TO_UOCT__TEMPLATE(str_to_uint32_oct, uint32_t)
+STR_TO_UOCT__TEMPLATE(str_to_uint64_oct, uint64_t)
+
+int str_parse_uintmax_oct(const char *str, uintmax_t *num_r,
+       const char **endp_r)
 {
-       intmax_t l;
+       uintmax_t n = 0;
 
-       if (str_to_intmax(str, &l) < 0)
+       if (*str < '0' || *str > '7')
                return -1;
 
-       if (l < INT_MIN || l > INT_MAX)
-               return -1;
-       *num_r = (int)l;
+       for (; *str >= '0' && *str <= '7'; str++) {
+               if (n >= ((uintmax_t)-1 >> 3)) {
+                       if (n > (uintmax_t)-1 >> 3)
+                               return -1;
+                       if ((uintmax_t)(*str - '0') > ((uintmax_t)-1 & 0x03))
+                               return -1;
+               }
+               n = (n << 3) + (*str - '0');
+       }
+       if (endp_r != NULL)
+               *endp_r = str;
+       *num_r = n;
        return 0;
 }
-
-int str_to_long(const char *str, long *num_r)
+int str_to_uintmax_oct(const char *str, uintmax_t *num_r)
 {
-       intmax_t l;
-
-       if (str_to_intmax(str, &l) < 0)
-               return -1;
-
-       if (l < LONG_MIN || l > LONG_MAX)
+       const char *endp;
+       uintmax_t n;
+       int ret = str_parse_uintmax_oct(str, &n, &endp);
+       if ((ret != 0) || (*endp != '\0'))
                return -1;
-       *num_r = (long)l;
+       *num_r = n;
        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;
+/* 
+ * Signed
+ */
+
+#define STR_PARSE_S__TEMPLATE(name, type, int_min, int_max)   \
+int name(const char *str, type *num_r, const char **endp_r)      \
+{                                                             \
+       intmax_t l;                                                 \
+       if (str_parse_intmax(str, &l, endp_r) < 0)                  \
+               return -1;                                                \
+       if (l < int_min || l > int_max)                             \
+               return -1;                                                \
+       *num_r = (type)l;                                           \
+       return 0;                                                   \
+}
 
-       if (l < LLONG_MIN || l > LLONG_MAX)
-               return -1;
-       *num_r = (long long)l;
-       return 0;
+STR_PARSE_S__TEMPLATE(str_parse_int, int, INT_MIN, INT_MAX)
+STR_PARSE_S__TEMPLATE(str_parse_long, long, LONG_MIN, LONG_MAX)
+STR_PARSE_S__TEMPLATE(str_parse_llong, long long, LLONG_MIN, LLONG_MAX)
+STR_PARSE_S__TEMPLATE(str_parse_int32, int32_t, INT32_MIN, INT32_MAX)
+STR_PARSE_S__TEMPLATE(str_parse_int64, int64_t, INT64_MIN, INT64_MAX)
+
+#define STR_TO_S__TEMPLATE(name, type, int_min, int_max)      \
+int name(const char *str, type *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 = (type)l;                                           \
+       return 0;                                                   \
 }
 
-int str_to_intmax(const char *str, intmax_t *num_r)
+STR_TO_S__TEMPLATE(str_to_int, int, INT_MIN, INT_MAX)
+STR_TO_S__TEMPLATE(str_to_long, long, LONG_MIN, LONG_MAX)
+STR_TO_S__TEMPLATE(str_to_llong, long long, LLONG_MIN, LLONG_MAX)
+STR_TO_S__TEMPLATE(str_to_int32, int32_t, INT32_MIN, INT32_MAX)
+STR_TO_S__TEMPLATE(str_to_int64, int64_t, INT64_MIN, INT64_MAX)
+
+int str_parse_intmax(const char *str, intmax_t *num_r,
+       const char **endp_r)
 {
        bool neg = FALSE;
        uintmax_t l;
@@ -174,7 +304,7 @@ int str_to_intmax(const char *str, intmax_t *num_r)
                neg = TRUE;
                str++;
        }
-       if (str_to_uintmax(str, &l) < 0)
+       if (str_parse_uintmax(str, &l, endp_r) < 0)
                return -1;
 
        if (!neg) {
@@ -188,6 +318,20 @@ int str_to_intmax(const char *str, intmax_t *num_r)
        }
        return 0;
 }
+int str_to_intmax(const char *str, intmax_t *num_r)
+{
+       const char *endp;
+       intmax_t n;
+       int ret = str_parse_intmax(str, &n, &endp);
+       if ((ret != 0) || (*endp != '\0'))
+               return -1;
+       *num_r = n;
+       return 0;
+}
+
+/* 
+ * Special numeric types
+ */
 
 static int verify_xid(uintmax_t l, unsigned int result_size)
 {
@@ -267,14 +411,11 @@ int str_to_time(const char *str, time_t *num_r)
        return 0;
 }
 
-bool str_uint_equals(const char *str, uintmax_t num)
-{
-       uintmax_t l;
+STR_PARSE_U__TEMPLATE(str_parse_uoff, uoff_t)
 
-       if (str_to_uintmax(str, &l) < 0)
-               return FALSE;
-       return l == num;
-}
+/*
+ * Error handling
+ */
 
 const char *str_num_error(const char *str)
 {
index 48c5efc7a6c83bf7c9d6b4fdde19bd1415a232c3..3cd5cdc1bf78da40879781db7b00894b276c53bc 100644 (file)
@@ -1,10 +1,6 @@
 #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 nothing more than a valid number
    in valid range. Otherwise -1 is returned and num_r is left untouched
 
@@ -13,30 +9,174 @@ bool str_is_numeric(const char *str, char end_char) ATTR_PURE;
    it is non-NULL. What is written to endp_r in error cases is undefined.
 */
 
-int str_to_uint(const char *str, unsigned int *num_r) ATTR_WARN_UNUSED_RESULT;
-int str_parse_uint(const char *str, unsigned int *num_r, const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
-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_parse_uintmax(const char *str, uintmax_t *num_r, const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
-
-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;
-int str_parse_uoff(const char *str, uoff_t *num_r, const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
-int str_to_time(const char *str, time_t *num_r) ATTR_WARN_UNUSED_RESULT;
+/*
+ * Unsigned decimal
+ */
+
+int str_to_uint(const char *str, unsigned int *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_uint(const char *str, unsigned int *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_ulong(const char *str, unsigned long *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_ulong(const char *str, unsigned long *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_ullong(const char *str, unsigned long long *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_ullong(const char *str, unsigned long long *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_uint32(const char *str, uint32_t *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_uint32(const char *str, uint32_t *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_uint64(const char *str, uint64_t *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_uint64(const char *str, uint64_t *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_uintmax(const char *str, uintmax_t *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_uintmax(const char *str, uintmax_t *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
 
 /* Returns TRUE if str is a valid unsigned number that equals to num. */
 bool str_uint_equals(const char *str, uintmax_t num);
 
+/*
+ * Unsigned hexadecimal
+ */
+
+int str_to_uint_hex(const char *str, unsigned int *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_uint_hex(const char *str, unsigned int *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_ulong_hex(const char *str, unsigned long *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_ulong_hex(const char *str, unsigned long *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_ullong_hex(const char *str, unsigned long long *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_ullong_hex(const char *str, unsigned long long *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_uint32_hex(const char *str, uint32_t *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_uint32_hex(const char *str, uint32_t *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_uint64_hex(const char *str, uint64_t *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_uint64_hex(const char *str, uint64_t *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_uintmax_hex(const char *str, uintmax_t *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_uintmax_hex(const char *str, uintmax_t *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+/*
+ * Unsigned octal
+ */
+
+int str_to_uint_oct(const char *str, unsigned int *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_uint_oct(const char *str, unsigned int *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_ulong_oct(const char *str, unsigned long *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_ulong_oct(const char *str, unsigned long *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_ullong_oct(const char *str, unsigned long long *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_ullong_oct(const char *str, unsigned long long *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_uint32_oct(const char *str, uint32_t *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_uint32_oct(const char *str, uint32_t *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_uint64_oct(const char *str, uint64_t *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_uint64_oct(const char *str, uint64_t *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_uintmax_oct(const char *str, uintmax_t *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_uintmax_oct(const char *str, uintmax_t *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+/*
+ * Signed
+ */
+
+int str_to_int(const char *str, int *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_int(const char *str, int *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_long(const char *str, long *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_long(const char *str, long *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_llong(const char *str, long long *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_llong(const char *str, long long *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_int32(const char *str, int32_t *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_int32(const char *str, int32_t *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_int64(const char *str, int64_t *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_int64(const char *str, int64_t *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_intmax(const char *str, intmax_t *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+int str_parse_intmax(const char *str, intmax_t *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+/*
+ * Special numeric types
+ */
+
+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;
+int str_parse_uoff(const char *str, uoff_t *num_r,
+       const char **endp_r) ATTR_WARN_UNUSED_RESULT ATTR_NULL(3);
+
+int str_to_time(const char *str, time_t *num_r)
+       ATTR_WARN_UNUSED_RESULT;
+
+/*
+ * Utility
+ */
+
+/* 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;
+
 /* Returns human readable string about what is wrong with the string.
    This function assumes that str_to_*() had already returned -1 for the
    string. */