strnum.c revision 7b58c089a0711e5e874fbf24c03d890ed2eebd62
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2010-2015 Dovecot authors, see the included COPYING file */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#include "lib.h"
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#include "strnum.h"
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenbool str_is_numeric(const char *str, char end_char)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (*str == '\0' || *str == end_char)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return FALSE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen while (*str != '\0' && *str != end_char) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (*str < '0' || *str > '9')
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return FALSE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen str++;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return TRUE;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen/*
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen * Unsigned decimal
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#define STR_PARSE_U__TEMPLATE(name, type) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenint name(const char *str, type *num_r, const char **endp_r) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{ \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uintmax_t l; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (str_parse_uintmax(str, &l, endp_r) < 0 || l > (type)-1) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1; \
fe779565bda49a0ed0476724819c6e3c1340c94bTimo Sirainen *num_r = (type)l; \
fe779565bda49a0ed0476724819c6e3c1340c94bTimo Sirainen return 0; \
fe779565bda49a0ed0476724819c6e3c1340c94bTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_PARSE_U__TEMPLATE(str_parse_uint, unsigned int)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_PARSE_U__TEMPLATE(str_parse_ulong, unsigned long)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan BoschSTR_PARSE_U__TEMPLATE(str_parse_ullong, unsigned long long)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan BoschSTR_PARSE_U__TEMPLATE(str_parse_uint32, uint32_t)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_PARSE_U__TEMPLATE(str_parse_uint64, uint64_t)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#define STR_TO_U__TEMPLATE(name, type) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenint name(const char *str, type *num_r) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{ \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uintmax_t l; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (str_to_uintmax(str, &l) < 0 || l > (type)-1) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen *num_r = (type)l; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_U__TEMPLATE(str_to_uint, unsigned int)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_U__TEMPLATE(str_to_ulong, unsigned long)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_U__TEMPLATE(str_to_ullong, unsigned long long)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_U__TEMPLATE(str_to_uint32, uint32_t)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_U__TEMPLATE(str_to_uint64, uint64_t)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenint str_parse_uintmax(const char *str, uintmax_t *num_r,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen const char **endp_r)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uintmax_t n = 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (*str < '0' || *str > '9')
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen for (; *str >= '0' && *str <= '9'; str++) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (n >= ((uintmax_t)-1 / 10)) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (n > (uintmax_t)-1 / 10)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if ((uintmax_t)(*str - '0') > ((uintmax_t)-1 % 10))
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen n = n * 10 + (*str - '0');
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (endp_r != NULL)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen *endp_r = str;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen *num_r = n;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenint str_to_uintmax(const char *str, uintmax_t *num_r)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen const char *endp;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uintmax_t n;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen int ret = str_parse_uintmax(str, &n, &endp);
1c75bf24894a3fc0631caa4954e5130e9bb01d8dTimo Sirainen if ((ret != 0) || (*endp != '\0'))
1c75bf24894a3fc0631caa4954e5130e9bb01d8dTimo Sirainen return -1;
1c75bf24894a3fc0631caa4954e5130e9bb01d8dTimo Sirainen *num_r = n;
1c75bf24894a3fc0631caa4954e5130e9bb01d8dTimo Sirainen return 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenbool str_uint_equals(const char *str, uintmax_t num)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch uintmax_t l;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (str_to_uintmax(str, &l) < 0)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return FALSE;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return l == num;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen/*
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen * Unsigned hexadecimal
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#define STR_PARSE_UHEX__TEMPLATE(name, type) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenint name(const char *str, type *num_r, const char **endp_r) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{ \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uintmax_t l; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (str_parse_uintmax_hex(str, &l, endp_r) < 0 || l > (type)-1) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen *num_r = (type)l; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_PARSE_UHEX__TEMPLATE(str_parse_uint_hex, unsigned int)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_PARSE_UHEX__TEMPLATE(str_parse_ulong_hex, unsigned long)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_PARSE_UHEX__TEMPLATE(str_parse_ullong_hex, unsigned long long)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_PARSE_UHEX__TEMPLATE(str_parse_uint32_hex, uint32_t)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_PARSE_UHEX__TEMPLATE(str_parse_uint64_hex, uint64_t)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#define STR_TO_UHEX__TEMPLATE(name, type) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenint name(const char *str, type *num_r) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{ \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uintmax_t l; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (str_to_uintmax_hex(str, &l) < 0 || l > (type)-1) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1; \
3858a7a5da361c35f1e6e50c8e3214dc0cf379d6Phil Carmody *num_r = (type)l; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_UHEX__TEMPLATE(str_to_uint_hex, unsigned int)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_UHEX__TEMPLATE(str_to_ulong_hex, unsigned long)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_UHEX__TEMPLATE(str_to_ullong_hex, unsigned long long)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_UHEX__TEMPLATE(str_to_uint32_hex, uint32_t)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_UHEX__TEMPLATE(str_to_uint64_hex, uint64_t)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic inline int _str_parse_hex(const char ch,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen unsigned int *hex_r)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch switch (ch) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen *hex_r = (unsigned int)(ch - 'a' + 10);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen *hex_r = (unsigned int)(ch - 'A' + 10);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen case '0': case '1': case '2': case '3': case '4':
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen case '5': case '6': case '7': case '8': case '9':
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen *hex_r = (unsigned int)(ch - '0');
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen default:
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen break;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenint str_parse_uintmax_hex(const char *str, uintmax_t *num_r,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen const char **endp_r)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen unsigned int hex;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uintmax_t n = 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (_str_parse_hex(*str, &hex) < 0)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen do {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (n >= ((uintmax_t)-1 >> 4)) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (n > (uintmax_t)-1 >> 4)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if ((uintmax_t)hex > ((uintmax_t)-1 & 0x0f))
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen n = (n << 4) + hex;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen str++;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen } while (_str_parse_hex(*str, &hex) >= 0);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (endp_r != NULL)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen *endp_r = str;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen *num_r = n;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenint str_to_uintmax_hex(const char *str, uintmax_t *num_r)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen const char *endp;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uintmax_t n;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen int ret = str_parse_uintmax_hex(str, &n, &endp);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if ((ret != 0) || (*endp != '\0'))
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen *num_r = n;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen/*
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen * Unsigned octal
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#define STR_PARSE_UOCT__TEMPLATE(name, type) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenint name(const char *str, type *num_r, const char **endp_r) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{ \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uintmax_t l; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (str_parse_uintmax_oct(str, &l, endp_r) < 0 || l > (type)-1) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen *num_r = (type)l; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_PARSE_UOCT__TEMPLATE(str_parse_uint_oct, unsigned int)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_PARSE_UOCT__TEMPLATE(str_parse_ulong_oct, unsigned long)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_PARSE_UOCT__TEMPLATE(str_parse_ullong_oct, unsigned long long)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_PARSE_UOCT__TEMPLATE(str_parse_uint32_oct, uint32_t)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_PARSE_UOCT__TEMPLATE(str_parse_uint64_oct, uint64_t)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#define STR_TO_UOCT__TEMPLATE(name, type) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenint name(const char *str, type *num_r) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{ \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uintmax_t l; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (str_to_uintmax_oct(str, &l) < 0 || l > (type)-1) \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return -1; \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch *num_r = (type)l; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0; \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_UOCT__TEMPLATE(str_to_uint_oct, unsigned int)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_UOCT__TEMPLATE(str_to_ulong_oct, unsigned long)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_UOCT__TEMPLATE(str_to_ullong_oct, unsigned long long)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_UOCT__TEMPLATE(str_to_uint32_oct, uint32_t)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo SirainenSTR_TO_UOCT__TEMPLATE(str_to_uint64_oct, uint64_t)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenint str_parse_uintmax_oct(const char *str, uintmax_t *num_r,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen const char **endp_r)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uintmax_t n = 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (*str < '0' || *str > '7')
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen for (; *str >= '0' && *str <= '7'; str++) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (n >= ((uintmax_t)-1 >> 3)) {
8855b8b57050fe3b6dc3f19283488512fae98648Timo Sirainen if (n > (uintmax_t)-1 >> 3)
8855b8b57050fe3b6dc3f19283488512fae98648Timo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if ((uintmax_t)(*str - '0') > ((uintmax_t)-1 & 0x03))
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen n = (n << 3) + (*str - '0');
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (endp_r != NULL)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen *endp_r = str;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch *num_r = n;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch}
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschint str_to_uintmax_oct(const char *str, uintmax_t *num_r)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch{
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch const char *endp;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch uintmax_t n;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch int ret = str_parse_uintmax_oct(str, &n, &endp);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if ((ret != 0) || (*endp != '\0'))
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return -1;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch *num_r = n;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return 0;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch}
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch/*
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch * Signed
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen */
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#define STR_PARSE_S__TEMPLATE(name, type, int_min, int_max) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenint name(const char *str, type *num_r, const char **endp_r) \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{ \
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen intmax_t l; \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (str_parse_intmax(str, &l, endp_r) < 0) \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return -1; \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (l < int_min || l > int_max) \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return -1; \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch *num_r = (type)l; \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return 0; \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch}
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan BoschSTR_PARSE_S__TEMPLATE(str_parse_int, int, INT_MIN, INT_MAX)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan BoschSTR_PARSE_S__TEMPLATE(str_parse_long, long, LONG_MIN, LONG_MAX)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan BoschSTR_PARSE_S__TEMPLATE(str_parse_llong, long long, LLONG_MIN, LLONG_MAX)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan BoschSTR_PARSE_S__TEMPLATE(str_parse_int32, int32_t, INT32_MIN, INT32_MAX)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan BoschSTR_PARSE_S__TEMPLATE(str_parse_int64, int64_t, INT64_MIN, INT64_MAX)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch#define STR_TO_S__TEMPLATE(name, type, int_min, int_max) \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschint name(const char *str, type *num_r) \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch{ \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch intmax_t l; \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (str_to_intmax(str, &l) < 0) \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return -1; \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (l < int_min || l > int_max) \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return -1; \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch *num_r = (type)l; \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return 0; \
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch}
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan BoschSTR_TO_S__TEMPLATE(str_to_int, int, INT_MIN, INT_MAX)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan BoschSTR_TO_S__TEMPLATE(str_to_long, long, LONG_MIN, LONG_MAX)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan BoschSTR_TO_S__TEMPLATE(str_to_llong, long long, LLONG_MIN, LLONG_MAX)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan BoschSTR_TO_S__TEMPLATE(str_to_int32, int32_t, INT32_MIN, INT32_MAX)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan BoschSTR_TO_S__TEMPLATE(str_to_int64, int64_t, INT64_MIN, INT64_MAX)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschint str_parse_intmax(const char *str, intmax_t *num_r,
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch const char **endp_r)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch{
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch bool neg = FALSE;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch uintmax_t l;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (*str == '-') {
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch neg = TRUE;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch str++;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch }
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (str_parse_uintmax(str, &l, endp_r) < 0)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return -1;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (!neg) {
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (l > INTMAX_MAX)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return -1;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch *num_r = (intmax_t)l;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch } else {
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (l > UINTMAX_MAX - (UINTMAX_MAX + INTMAX_MIN))
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen *num_r = (intmax_t)-l;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenint str_to_intmax(const char *str, intmax_t *num_r)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen const char *endp;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen intmax_t n;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen int ret = str_parse_intmax(str, &n, &endp);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if ((ret != 0) || (*endp != '\0'))
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen *num_r = n;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen/*
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen * Special numeric types
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic int verify_xid(uintmax_t l, unsigned int result_size)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen unsigned int result_bits;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* we assume that result is a signed type,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen but that it can never be negative */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen result_bits = result_size*CHAR_BIT - 1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if ((l >> result_bits) != 0)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenint str_to_uid(const char *str, uid_t *num_r)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch{
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uintmax_t l;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (str_to_uintmax(str, &l) < 0)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen 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;
/* OS X uses negative GIDs */
#ifndef __APPLE__
if (verify_xid(l, sizeof(*num_r)) < 0)
return -1;
#endif
*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;
}
int str_to_time(const char *str, time_t *num_r)
{
intmax_t l;
if (str_to_intmax(str, &l) < 0)
return -1;
*num_r = (time_t)l;
return 0;
}
STR_PARSE_U__TEMPLATE(str_parse_uoff, uoff_t)
/*
* Error handling
*/
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";
}
}