PatchworkOS
Loading...
Searching...
No Matches
strtoll.c
Go to the documentation of this file.
1#include <ctype.h>
2#include <errno.h>
3#include <inttypes.h>
4#include <limits.h>
5#include <stdlib.h>
6#include <string.h>
7
8#include "common/digits.h"
9
10static const char* _strtoll_prelim(const char* p, char* sign, int* base)
11{
12 /* skipping leading whitespace */
13 while (isspace((unsigned char)*p))
14 {
15 ++p;
16 }
17
18 /* determining / skipping sign */
19 if (*p != '+' && *p != '-')
20 {
21 *sign = '+';
22 }
23 else
24 {
25 *sign = *(p++);
26 }
27
28 /* determining base */
29 if (*p == '0')
30 {
31 ++p;
32
33 if ((*base == 0 || *base == 16) && (*p == 'x' || *p == 'X'))
34 {
35 *base = 16;
36 ++p;
37
38 /* catching a border case here: "0x" followed by a non-digit should
39 be parsed as the unprefixed zero.
40 We have to "rewind" the parsing; having the base set to 16 if it
41 was zero previously does not hurt, as the result is zero anyway.
42 */
43 if (memchr(_digits, tolower((unsigned char)*p), *base) == NULL)
44 {
45 p -= 2;
46 }
47 }
48 else if (*base == 0)
49 {
50 *base = 8;
51 /* back up one digit, so that a plain zero is decoded correctly
52 (and endptr is set correctly as well).
53 (2019-01-15, Giovanni Mascellani)
54 */
55 --p;
56 }
57 else
58 {
59 --p;
60 }
61 }
62 else if (!*base)
63 {
64 *base = 10;
65 }
66
67 return ((*base >= 2) && (*base <= 36)) ? p : NULL;
68}
69
70static uintmax_t _strtoll_main(const char** p, unsigned int base, uintmax_t error, uintmax_t limval, int limdigit,
71 char* sign)
72{
73 uintmax_t rc = 0;
74 int digit = -1;
75 const char* x;
76
77 while ((x = (const char*)memchr(_digits, tolower((unsigned char)**p), base)) != NULL)
78 {
79 digit = x - _digits;
80
81 if ((rc < limval) || ((rc == limval) && (digit <= limdigit)))
82 {
83 rc = rc * base + (unsigned)digit;
84 ++(*p);
85 }
86 else
87 {
88 errno = ERANGE;
89
90 /* TODO: Only if endptr != NULL - but do we really want *another* parameter? */
91 /* TODO: Earlier version was missing tolower() here but was not caught by tests */
92 while (memchr(_digits, tolower((unsigned char)**p), base) != NULL)
93 {
94 ++(*p);
95 }
96
97 /* TODO: This is ugly, but keeps caller from negating the error value */
98 *sign = '+';
99 return error;
100 }
101 }
102
103 if (digit == -1)
104 {
105 *p = NULL;
106 return 0;
107 }
108
109 return rc;
110}
111
112long long int strtoll(const char* s, char** endptr, int base)
113{
114 long long int rc;
115 char sign = '+';
116 const char* p = _strtoll_prelim(s, &sign, &base);
117
118 if (base < 2 || base > 36)
119 {
120 return 0;
121 }
122
123 if (sign == '+')
124 {
125 rc = (long long int)_strtoll_main(&p, (unsigned)base, (uintmax_t)LLONG_MAX, (uintmax_t)(LLONG_MAX / base),
126 (int)(LLONG_MAX % base), &sign);
127 }
128 else
129 {
130 rc = (long long int)_strtoll_main(&p, (unsigned)base, (uintmax_t)LLONG_MIN, (uintmax_t)(LLONG_MIN / -base),
131 (int)(-(LLONG_MIN % base)), &sign);
132 }
133
134 if (endptr != NULL)
135 {
136 *endptr = (p != NULL) ? (char*)p : (char*)s;
137 }
138
139 return (sign == '+') ? rc : -rc;
140}
_PUBLIC int tolower(int c)
Definition tolower.c:5
_PUBLIC int isspace(int c)
Definition isspace.c:5
const char _digits[]
Definition digits.c:3
#define ERANGE
Math result not representable.
Definition errno.h:202
#define errno
Error number variable.
Definition errno.h:27
#define NULL
Pointer error value.
Definition NULL.h:23
__UINTMAX_TYPE__ uintmax_t
Definition inttypes.h:12
#define LLONG_MAX
Definition limits.h:15
#define LLONG_MIN
Definition limits.h:14
int64_t x
Definition main.c:152
_PUBLIC void * memchr(const void *s, int c, size_t n)
Definition memchr.c:3
long long int strtoll(const char *s, char **endptr, int base)
Definition strtoll.c:112
static const char * _strtoll_prelim(const char *p, char *sign, int *base)
Definition strtoll.c:10
static uintmax_t _strtoll_main(const char **p, unsigned int base, uintmax_t error, uintmax_t limval, int limdigit, char *sign)
Definition strtoll.c:70