]> git.ipfire.org Git - thirdparty/squid.git/blob - src/parser/Tokenizer.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / parser / Tokenizer.cc
1 #include "squid.h"
2 #include "parser/Tokenizer.h"
3
4 #include <cerrno>
5 #if HAVE_CTYPE_H
6 #include <ctype.h>
7 #endif
8 #if HAVE_STDINT_H
9 #include <stdint.h>
10 #endif
11 #ifndef INT64_MIN
12 /* Native 64 bit system without strtoll() */
13 #if defined(LONG_MIN) && (SIZEOF_LONG == 8)
14 #define INT64_MIN LONG_MIN
15 #else
16 /* 32 bit system */
17 #define INT64_MIN (-9223372036854775807LL-1LL)
18 #endif
19 #endif
20
21 #ifndef INT64_MAX
22 /* Native 64 bit system without strtoll() */
23 #if defined(LONG_MAX) && (SIZEOF_LONG == 8)
24 #define INT64_MAX LONG_MAX
25 #else
26 /* 32 bit system */
27 #define INT64_MAX 9223372036854775807LL
28 #endif
29 #endif
30
31 /// convenience method: consumes up to n bytes, counts, and returns them
32 SBuf
33 Parser::Tokenizer::consume(const SBuf::size_type n)
34 {
35 // careful: n may be npos!
36 const SBuf result = buf_.consume(n);
37 parsed_ += result.length();
38 return result;
39 }
40
41 /// convenience method: consume()s up to n bytes and returns their count
42 SBuf::size_type
43 Parser::Tokenizer::success(const SBuf::size_type n)
44 {
45 return consume(n).length();
46 }
47
48 bool
49 Parser::Tokenizer::token(SBuf &returnedToken, const CharacterSet &delimiters)
50 {
51 const Tokenizer saved(*this);
52 skipAll(delimiters);
53 const SBuf::size_type tokenLen = buf_.findFirstOf(delimiters); // not found = npos => consume to end
54 if (tokenLen == SBuf::npos) {
55 *this = saved;
56 return false;
57 }
58 returnedToken = consume(tokenLen); // cannot be empty
59 skipAll(delimiters);
60 return true;
61 }
62
63 bool
64 Parser::Tokenizer::prefix(SBuf &returnedToken, const CharacterSet &tokenChars, const SBuf::size_type limit)
65 {
66 const SBuf::size_type prefixLen = buf_.substr(0,limit).findFirstNotOf(tokenChars);
67 if (prefixLen == 0)
68 return false;
69 returnedToken = consume(prefixLen);
70 return true;
71 }
72
73 SBuf::size_type
74 Parser::Tokenizer::skipAll(const CharacterSet &tokenChars)
75 {
76 const SBuf::size_type prefixLen = buf_.findFirstNotOf(tokenChars);
77 if (prefixLen == 0)
78 return 0;
79 return success(prefixLen);
80 }
81
82 bool
83 Parser::Tokenizer::skipOne(const CharacterSet &chars)
84 {
85 if (!buf_.isEmpty() && chars[buf_[0]])
86 return success(1);
87 return false;
88 }
89
90 bool
91 Parser::Tokenizer::skip(const SBuf &tokenToSkip)
92 {
93 if (buf_.startsWith(tokenToSkip))
94 return success(tokenToSkip.length());
95 return false;
96 }
97
98 bool
99 Parser::Tokenizer::skip(const char tokenChar)
100 {
101 if (!buf_.isEmpty() && buf_[0] == tokenChar)
102 return success(1);
103 return false;
104 }
105
106 /* reworked from compat/strtoll.c */
107 bool
108 Parser::Tokenizer::int64(int64_t & result, int base)
109 {
110 if (buf_.isEmpty())
111 return false;
112
113 //fixme: account for buf_.size()
114 bool neg = false;
115 const char *s = buf_.rawContent();
116 const char *end = buf_.rawContent() + buf_.length();
117
118 if (*s == '-') {
119 neg = true;
120 ++s;
121 } else if (*s == '+') {
122 ++s;
123 }
124 if (s >= end) return false;
125 if (( base == 0 || base == 16) && *s == '0' && (s+1 <= end ) &&
126 tolower(*(s+1)) == 'x') {
127 s += 2;
128 base = 16;
129 }
130 if (base == 0) {
131 if ( *s == '0') {
132 base = 8;
133 ++s;
134 } else {
135 base = 10;
136 }
137 }
138 if (s >= end) return false;
139
140 uint64_t cutoff;
141
142 cutoff = neg ? -static_cast<uint64_t>(INT64_MIN) : INT64_MAX;
143 const int cutlim = cutoff % static_cast<int64_t>(base);
144 cutoff /= static_cast<uint64_t>(base);
145
146 int any = 0, c;
147 int64_t acc = 0;
148 for (c = *s++; s <= end; c = *s++) {
149 if (xisdigit(c)) {
150 c -= '0';
151 } else if (xisalpha(c)) {
152 c -= xisupper(c) ? 'A' - 10 : 'a' - 10;
153 } else {
154 break;
155 }
156 if (c >= base)
157 break;
158 if (any < 0 || static_cast<uint64_t>(acc) > cutoff || (static_cast<uint64_t>(acc) == cutoff && c > cutlim))
159 any = -1;
160 else {
161 any = 1;
162 acc *= base;
163 acc += c;
164 }
165 }
166
167 if (any == 0) // nothing was parsed
168 return false;
169 if (any < 0) {
170 acc = neg ? INT64_MIN : INT64_MAX;
171 errno = ERANGE;
172 return false;
173 } else if (neg)
174 acc = -acc;
175
176 result = acc;
177 return success(s - buf_.rawContent() - 1);
178 }