strnum.c revision 076f8c12cfa4c8d30695f94f389c670d89e200fa
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2010-2011 Dovecot authors, see the included COPYING file */
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen#include "lib.h"
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen#include "strnum.h"
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainenbool str_is_numeric(const char *str, char end_char)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen{
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (*str == '\0' || *str == end_char)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return FALSE;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen while (*str != '\0' && *str != end_char) {
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (*str < '0' || *str > '9')
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return FALSE;
decdff03c32cb5d0e99d71c5678fd008714de70bTimo Sirainen str++;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen }
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return TRUE;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen}
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainenint str_to_uint(const char *str, unsigned int *num_r)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen{
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen uintmax_t l;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (str_to_uintmax(str, &l) < 0)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return -1;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (l > (unsigned int)-1)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return -1;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen *num_r = (unsigned int)l;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return 0;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen}
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainenint str_to_ulong(const char *str, unsigned long *num_r)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen{
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen uintmax_t l;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (str_to_uintmax(str, &l) < 0)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return -1;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (l > (unsigned long)-1)
9766afd8dc3976d238e1c71712d6bafa316f2e06Timo Sirainen return -1;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen *num_r = (unsigned long)l;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return 0;
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen}
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainenint str_to_ullong(const char *str, unsigned long long *num_r)
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen{
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen uintmax_t l;
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen if (str_to_uintmax(str, &l) < 0)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return -1;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (l > (unsigned long long)-1)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return -1;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen *num_r = (unsigned long long)l;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return 0;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen}
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainenint str_to_uint32(const char *str, uint32_t *num_r)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen{
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen uintmax_t l;
9766afd8dc3976d238e1c71712d6bafa316f2e06Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (str_to_uintmax(str, &l) < 0)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return -1;
9766afd8dc3976d238e1c71712d6bafa316f2e06Timo Sirainen
9766afd8dc3976d238e1c71712d6bafa316f2e06Timo Sirainen if (l > (uint32_t)-1)
9766afd8dc3976d238e1c71712d6bafa316f2e06Timo Sirainen return -1;
9766afd8dc3976d238e1c71712d6bafa316f2e06Timo Sirainen *num_r = (uint32_t)l;
9766afd8dc3976d238e1c71712d6bafa316f2e06Timo Sirainen return 0;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen}
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainenint str_to_uint64(const char *str, uint64_t *num_r)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen{
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen uintmax_t l;
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen if (str_to_uintmax(str, &l) < 0)
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen return -1;
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen if (l > (uint64_t)-1)
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen return -1;
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen *num_r = (uint64_t)l;
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen return 0;
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen}
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainenint str_to_uintmax(const char *str, uintmax_t *num_r)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen{
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen uintmax_t next, n = 0;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (*str < '0' || *str > '9')
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return -1;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen for (; *str >= '0' && *str <= '9'; str++) {
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen next = n*10;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (next < n) {
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen /* overflow */
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return -1;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen }
decdff03c32cb5d0e99d71c5678fd008714de70bTimo Sirainen n = next + (*str - '0');
decdff03c32cb5d0e99d71c5678fd008714de70bTimo Sirainen }
decdff03c32cb5d0e99d71c5678fd008714de70bTimo Sirainen if (*str != '\0')
decdff03c32cb5d0e99d71c5678fd008714de70bTimo Sirainen return -1;
decdff03c32cb5d0e99d71c5678fd008714de70bTimo Sirainen *num_r = n;
decdff03c32cb5d0e99d71c5678fd008714de70bTimo Sirainen return 0;
decdff03c32cb5d0e99d71c5678fd008714de70bTimo Sirainen}
8e0eb6a0cfc2cb66385bdf05a70a38d753bc1e24Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainenint str_to_int(const char *str, int *num_r)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen{
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen intmax_t l;
8e0eb6a0cfc2cb66385bdf05a70a38d753bc1e24Timo Sirainen
8e0eb6a0cfc2cb66385bdf05a70a38d753bc1e24Timo Sirainen if (str_to_intmax(str, &l) < 0)
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen return -1;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (l < INT_MIN || l > INT_MAX)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return -1;
29cda2d6eb57b7fb65a55115ea8bcb6ab6938477Timo Sirainen *num_r = (int)l;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return 0;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen}
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainenint str_to_long(const char *str, long *num_r)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen{
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen intmax_t l;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (str_to_intmax(str, &l) < 0)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return -1;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (l < LONG_MIN || l > LONG_MAX)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return -1;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen *num_r = (long)l;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return 0;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen}
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
decdff03c32cb5d0e99d71c5678fd008714de70bTimo Sirainenint str_to_llong(const char *str, long long *num_r)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen{
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen intmax_t l;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (str_to_intmax(str, &l) < 0)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return -1;
25fb397382c6f7d39bfeee85774e7675f02bfb3cTimo Sirainen
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen if (l < LLONG_MIN || l > LLONG_MAX)
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return -1;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen *num_r = (long long)l;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen return 0;
854b4074ac77a138b3983d72510b4d8779d15040Timo Sirainen}
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;
/* 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;
}
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";
}
}