strnum.c revision ba54c370c4c1fee3d59a90cd4986bb7859a62c52
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "strnum.h"
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen
55a210942dc7da58b2fd0b11bed8da6b030af5c1Timo Sirainenbool str_is_numeric(const char *str, char end_char)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*str == '\0' || *str == end_char)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen while (*str != '\0' && *str != end_char) {
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen if (*str < '0' || *str > '9')
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen return TRUE;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen}
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainenint str_to_uint(const char *str, unsigned int *num_r)
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen{
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen uintmax_t l;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (str_to_uintmax(str, &l) < 0)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen if (l > (unsigned int)-1)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *num_r = (unsigned int)l;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainenint str_to_ulong(const char *str, unsigned long *num_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uintmax_t l;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (str_to_uintmax(str, &l) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (l > (unsigned long)-1)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *num_r = (unsigned long)l;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint str_to_ullong(const char *str, unsigned long long *num_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uintmax_t l;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (str_to_uintmax(str, &l) < 0)
d8b77aef97e89f1ccc5cbdaef77be9052279e35fTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d8b77aef97e89f1ccc5cbdaef77be9052279e35fTimo Sirainen if (l > (unsigned long long)-1)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *num_r = (unsigned long long)l;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen return 0;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen}
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainenint str_to_uint32(const char *str, uint32_t *num_r)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen{
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen uintmax_t l;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (str_to_uintmax(str, &l) < 0)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return -1;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (l > (uint32_t)-1)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return -1;
a928e7efabb1672b1476e597106d4b4b81ac6f3cTimo Sirainen *num_r = (uint32_t)l;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return 0;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen}
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainenint str_to_uint64(const char *str, uint64_t *num_r)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen uintmax_t l;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (str_to_uintmax(str, &l) < 0)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return -1;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen if (l > (uint64_t)-1)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen return -1;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen *num_r = (uint64_t)l;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen return 0;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen}
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainenint str_to_uintmax(const char *str, uintmax_t *num_r)
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen{
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen uintmax_t next, n = 0;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen if (*str < '0' || *str > '9')
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen return -1;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
a928e7efabb1672b1476e597106d4b4b81ac6f3cTimo Sirainen for (; *str >= '0' && *str <= '9'; str++) {
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen next = n*10;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen if (next < n) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* overflow */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen n = next + (*str - '0');
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (*str != '\0')
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *num_r = n;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint str_to_int(const char *str, int *num_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen intmax_t l;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (str_to_intmax(str, &l) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (l < INT_MIN || l > INT_MAX)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *num_r = (int)l;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint str_to_long(const char *str, long *num_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen intmax_t l;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (str_to_intmax(str, &l) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (l < LONG_MIN || l > LONG_MAX)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *num_r = (long)l;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainenint str_to_llong(const char *str, long long *num_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen intmax_t l;
8a3d609fdd84f5938c82e8e7eeb84a24ab41b317Timo Sirainen
8a3d609fdd84f5938c82e8e7eeb84a24ab41b317Timo Sirainen if (str_to_intmax(str, &l) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (l < LLONG_MIN || l > LLONG_MAX)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *num_r = (long long)l;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint str_to_intmax(const char *str, intmax_t *num_r)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen bool neg = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uintmax_t l;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen 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";
}
}