Branch data Line data Source code
1 : : #ifndef PPARSEINT_H
2 : : #define PPARSEINT_H
3 : :
4 : : /*
5 : : * Type specific integer parsers:
6 : : *
7 : : * const char *
8 : : * parse_<type-name>(const char *buf, int len, <type> *value, int *status);
9 : : *
10 : : * parse_uint64, parse_int64
11 : : * parse_uint32, parse_int32
12 : : * parse_uint16, parse_int16
13 : : * parse_uint8, parse_int8
14 : : * parse_ushort, parse_short
15 : : * parse_uint, parse_int
16 : : * parse_ulong, parse_long
17 : : *
18 : : * Leading space must be stripped in advance. Status argument can be
19 : : * null.
20 : : *
21 : : * Returns pointer to end of match and a non-negative status code
22 : : * on succcess (0 for unsigned, 1 for signed):
23 : : *
24 : : * PARSE_INTEGER_UNSIGNED
25 : : * PARSE_INTEGER_SIGNED
26 : : *
27 : : * Returns null with a negative status code and unmodified value on
28 : : * invalid integer formats:
29 : : *
30 : : * PARSE_INTEGER_OVERFLOW
31 : : * PARSE_INTEGER_UNDERFLOW
32 : : * PARSE_INTEGER_INVALID
33 : : *
34 : : * Returns input buffer with negative status code and unmodified value
35 : : * if first character does not start an integer (not a sign or a digit).
36 : : *
37 : : * PARSE_INTEGER_UNMATCHED
38 : : * PARSE_INTEGER_END
39 : : *
40 : : * The signed parsers only works with two's complement architectures.
41 : : *
42 : : * Note: the corresponding parse_float and parse_double parsers do not
43 : : * have a status argument because +/-Inf and NaN are conventionally used
44 : : * for this.
45 : : */
46 : :
47 : : #include "limits.h"
48 : : #ifndef UINT8_MAX
49 : : #include <stdint.h>
50 : : #endif
51 : :
52 : : #define PARSE_INTEGER_UNSIGNED 0
53 : : #define PARSE_INTEGER_SIGNED 1
54 : : #define PARSE_INTEGER_OVERFLOW -1
55 : : #define PARSE_INTEGER_UNDERFLOW -2
56 : : #define PARSE_INTEGER_INVALID -3
57 : : #define PARSE_INTEGER_UNMATCHED -4
58 : : #define PARSE_INTEGER_END -5
59 : :
60 : : /*
61 : : * Generic integer parser that holds 64-bit unsigned values and stores
62 : : * sign separately. Leading space is not valid.
63 : : *
64 : : * Note: this function differs from the type specific parsers like
65 : : * parse_int64 by not negating the value when there is a sign. It
66 : : * differs from parse_uint64 by being able to return a negative
67 : : * UINT64_MAX successfully.
68 : : *
69 : : * This parser is used by all type specific integer parsers.
70 : : *
71 : : * Status argument can be null.
72 : : */
73 : 287 : static const char *parse_integer(const char *buf, int len, uint64_t *value, int *status)
74 : : {
75 : : uint64_t x0, x = 0;
76 : 287 : const char *k, *end = buf + len;
77 : : int sign, status_;
78 : :
79 [ - + ]: 287 : if (!status) {
80 : : status = &status_;
81 : : }
82 [ - + ]: 287 : if (buf == end) {
83 : 0 : *status = PARSE_INTEGER_END;
84 : 0 : return buf;
85 : : }
86 : : k = buf;
87 : 287 : sign = *buf == '-';
88 : 287 : buf += sign;
89 [ + + ][ + - ]: 765 : while (buf != end && *buf >= '0' && *buf <= '9') {
[ + - ]
90 : : x0 = x;
91 : 478 : x = x * 10 + *buf - '0';
92 [ - + ]: 478 : if (x0 > x) {
93 [ # # ]: 0 : *status = sign ? PARSE_INTEGER_UNDERFLOW : PARSE_INTEGER_OVERFLOW;
94 : 0 : return 0;
95 : : }
96 : 478 : ++buf;
97 : : }
98 [ - + ]: 287 : if (buf == k) {
99 : : /* No number was matched, but it isn't an invalid number either. */
100 : 0 : *status = PARSE_INTEGER_UNMATCHED;
101 : 0 : return buf;
102 : : }
103 [ - + ]: 287 : if (buf == k + sign) {
104 : 0 : *status = PARSE_INTEGER_INVALID;
105 : 0 : return 0;
106 : : }
107 [ - + ]: 287 : if (buf != end)
108 [ # # ]: 0 : switch (*buf) {
109 : : case 'e': case 'E': case '.': case 'p': case 'P':
110 : 0 : *status = PARSE_INTEGER_INVALID;
111 : 0 : return 0;
112 : : }
113 : 287 : *value = x;
114 : 287 : *status = sign;
115 : 287 : return buf;
116 : : }
117 : :
118 : : #define __portable_define_parse_unsigned(NAME, TYPE, LIMIT) \
119 : : static inline const char *parse_ ## NAME \
120 : : (const char *buf, int len, TYPE *value, int *status) \
121 : : { \
122 : : int status_ = 0; \
123 : : uint64_t x; \
124 : : \
125 : : if (!status) { \
126 : : status = &status_; \
127 : : } \
128 : : buf = parse_integer(buf, len, &x, status); \
129 : : switch (*status) { \
130 : : case PARSE_INTEGER_UNSIGNED: \
131 : : if (x <= LIMIT) { \
132 : : *value = (TYPE)x; \
133 : : return buf; \
134 : : } \
135 : : *status = PARSE_INTEGER_OVERFLOW; \
136 : : return 0; \
137 : : case PARSE_INTEGER_SIGNED: \
138 : : *status = PARSE_INTEGER_UNDERFLOW; \
139 : : return 0; \
140 : : default: \
141 : : return buf; \
142 : : } \
143 : : }
144 : :
145 : : /* This assumes two's complement. */
146 : : #define __portable_define_parse_signed(NAME, TYPE, LIMIT) \
147 : : static inline const char *parse_ ## NAME \
148 : : (const char *buf, int len, TYPE *value, int *status) \
149 : : { \
150 : : int status_ = 0; \
151 : : uint64_t x; \
152 : : \
153 : : if (!status) { \
154 : : status = &status_; \
155 : : } \
156 : : buf = parse_integer(buf, len, &x, status); \
157 : : switch (*status) { \
158 : : case PARSE_INTEGER_UNSIGNED: \
159 : : if (x <= LIMIT) { \
160 : : *value = (TYPE)x; \
161 : : return buf; \
162 : : } \
163 : : *status = PARSE_INTEGER_OVERFLOW; \
164 : : return 0; \
165 : : case PARSE_INTEGER_SIGNED: \
166 : : if (x <= (uint64_t)(LIMIT) + 1) { \
167 : : *value = (TYPE)-(int64_t)x; \
168 : : return buf; \
169 : : } \
170 : : *status = PARSE_INTEGER_UNDERFLOW; \
171 : : return 0; \
172 : : default: \
173 : : return buf; \
174 : : } \
175 : : }
176 : :
177 : : static inline const char *parse_uint64(const char *buf, int len, uint64_t *value, int *status)
178 : : {
179 : : buf = parse_integer(buf, len, value, status);
180 : : if (*status == PARSE_INTEGER_SIGNED) {
181 : : *status = PARSE_INTEGER_UNDERFLOW;
182 : : return 0;
183 : : }
184 : : return buf;
185 : : }
186 : :
187 : : __portable_define_parse_signed(int64, int64_t, INT64_MAX)
188 : : __portable_define_parse_signed(int32, int32_t, INT32_MAX)
189 : : __portable_define_parse_unsigned(uint16, uint16_t, UINT16_MAX)
190 : : __portable_define_parse_signed(int16, int16_t, INT16_MAX)
191 : : __portable_define_parse_unsigned(uint8, uint8_t, UINT8_MAX)
192 : : __portable_define_parse_signed(int8, int8_t, INT8_MAX)
193 : :
194 : : __portable_define_parse_unsigned(ushort, unsigned short, USHRT_MAX)
195 : : __portable_define_parse_signed(short, short, SHRT_MAX)
196 : : __portable_define_parse_unsigned(uint, unsigned int, UINT_MAX)
197 : : __portable_define_parse_signed(int, int, INT_MAX)
198 : : __portable_define_parse_unsigned(ulong, unsigned long, ULONG_MAX)
199 : : __portable_define_parse_signed(long, unsigned long, LONG_MAX)
200 : :
201 : : #endif /* PPARSEINT_H */
|