forked from ElektraInitiative/libelektra
-
Notifications
You must be signed in to change notification settings - Fork 0
/
integer.c
120 lines (113 loc) · 2.35 KB
/
integer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <kdbhelper.h>
#include <limits.h>
#include "integer.h"
static bool getValue (const char * start, const char * str, unsigned long long base, unsigned long long factor, unsigned long long * value);
static unsigned long long getDigitValue (char digit);
bool isValidIntegerAnyBase (const char * str)
{
return isValidInteger (str, 2) || isValidInteger (str, 8) || isValidInteger (str, 10) || isValidInteger (str, 16);
}
bool isValidInteger (const char * str, unsigned long long base)
{
if (str[0] == '0' || base == 10)
{
if ((base == 2 && str[1] == 'b') || (base == 8 && str[1] == 'o') || base == 10 || (base == 16 && str[1] == 'x'))
{
const char * start = str;
if (base != 10)
{
start += 2;
}
else if (*str == '-' || *str == '+')
{
start++;
}
if (*start == '_' || *start == 0)
{
return false;
}
unsigned long long value = 0;
bool success = getValue (start, start + elektraStrLen (start) - 2, base, 1, &value);
if (!success)
{
return false;
}
else if (base == 10)
{
if (*str == '-')
{
return value <= (unsigned long long) LLONG_MIN;
}
else
{
return value <= (unsigned long long) LLONG_MAX;
}
}
else
{
return success;
}
}
}
return false;
}
static unsigned long long getDigitValue (char digit)
{
if (digit >= '0' && digit <= '9')
{
return digit - '0';
}
else if (digit >= 'a' && digit <= 'f')
{
return 10 + digit - 'a';
}
else if (digit >= 'A' && digit <= 'F')
{
return 10 + digit - 'A';
}
else
{
return (unsigned long long) -1;
}
}
static bool getValue (const char * start, const char * str, unsigned long long base, unsigned long long factor, unsigned long long * value)
{
if (str < start)
{
return true;
}
else if (*str == '_')
{
return getValue (start, str - 1, base, factor, value);
}
else
{
unsigned long long digitValue = getDigitValue (*str);
if (digitValue >= base)
{
return false;
}
else if (digitValue > 0 && digitValue > ULLONG_MAX / factor)
{
return false;
}
unsigned long long factoredValue = factor * digitValue;
if (factoredValue > ULLONG_MAX - *value)
{
return false;
}
else
{
*value += factoredValue;
if (factor > ULLONG_MAX / base)
{
return str - 1 < start;
}
else
{
return getValue (start, str - 1, base, factor * base, value);
}
}
}
return false;
}