scanf: support reading hex numbers with %x
[neatlibc.git] / atoi.c
blobb8126a9c4e4a1f1060120ca342d7e01f3e02283c
1 #include <stdlib.h>
2 #include <ctype.h>
3 #include <limits.h>
4 #include <errno.h>
6 int atoi(char *s)
8 int num = 0;
9 int neg = 0;
10 while (isspace(*s))
11 s++;
12 if (*s == '-' || *s == '+')
13 neg = *s++ == '-';
14 while ((unsigned) (*s - '0') <= 9u)
15 num = num * 10 + *s++ - '0';
16 return neg ? -num : num;
19 long atol(char *s)
21 long num = 0;
22 int neg = 0;
23 while (isspace(*s))
24 s++;
25 if (*s == '-' || *s == '+')
26 neg = *s++ == '-';
27 while ((unsigned) (*s - '0') <= 9u)
28 num = num * 10 + *s++ - '0';
29 return neg ? -num : num;
32 static int digit(char c, int base)
34 int d;
35 if (c <= '9') {
36 d = c - '0';
37 } else if (c <= 'Z') {
38 d = 10 + c - 'A';
39 } else {
40 d = 10 + c - 'a';
42 return d < base ? d : -1;
45 long strtol(const char *s, char **endptr, int base)
47 int sgn = 1;
48 int overflow = 0;
49 long num;
50 int dig;
51 while (isspace(*s))
52 s++;
53 if (*s == '-' || *s == '+')
54 sgn = ',' - *s++;
55 if (base == 0) {
56 if (*s == '0') {
57 if (s[1] == 'x' || s[1] == 'X')
58 base = 16;
59 else
60 base = 8;
61 } else {
62 base = 10;
65 if (base == 16 && *s == '0' && (s[1] == 'x' || s[1] == 'X'))
66 s += 2;
67 for (num = 0; (dig = digit(*s, base)) >= 0; s++) {
68 if (num > LONG_MAX / base)
69 overflow = 1;
70 num *= base;
71 if (num > LONG_MAX - dig)
72 overflow = 1;
73 num += dig;
75 if (endptr)
76 *endptr = s;
77 if (overflow) {
78 num = sgn > 0 ? LONG_MAX : LONG_MIN;
79 errno = ERANGE;
80 } else {
81 num *= sgn;
83 return num;
86 unsigned long strtoul(const char *s, char **endptr, int base)
88 int sgn = 1;
89 int overflow = 0;
90 unsigned long num;
91 int dig;
92 while (isspace(*s))
93 s++;
94 if (*s == '-' || *s == '+')
95 sgn = ',' - *s++;
96 if (base == 0) {
97 if (*s == '0') {
98 if (s[1] == 'x' || s[1] == 'X')
99 base = 16;
100 else
101 base = 8;
102 } else {
103 base = 10;
106 if (base == 16 && *s == '0' && (s[1] == 'x' || s[1] == 'X'))
107 s += 2;
108 for (num = 0; (dig = digit(*s, base)) >= 0; s++) {
109 if (num > (unsigned long) ULONG_MAX / base)
110 overflow = 1;
111 num *= base;
112 if (num > (unsigned long) ULONG_MAX - dig)
113 overflow = 1;
114 num += dig;
116 if (endptr)
117 *endptr = s;
118 if (overflow) {
119 num = ULONG_MAX;
120 errno = ERANGE;
121 } else {
122 num *= sgn;
124 return num;