]> git.ipfire.org Git - thirdparty/squid.git/blob - src/parser/Tokenizer.cc
Sync with trunk rev.13542
[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 if (prefixLen == SBuf::npos && (atEnd() || limit == 0))
70 return false;
71 returnedToken = consume(prefixLen); // cannot be empty after the npos check
72 return true;
73 }
74
75 SBuf::size_type
76 Parser::Tokenizer::skipAll(const CharacterSet &tokenChars)
77 {
78 const SBuf::size_type prefixLen = buf_.findFirstNotOf(tokenChars);
79 if (prefixLen == 0)
80 return 0;
81 return success(prefixLen);
82 }
83
84 bool
85 Parser::Tokenizer::skipOne(const CharacterSet &chars)
86 {
87 if (!buf_.isEmpty() && chars[buf_[0]])
88 return success(1);
89 return false;
90 }
91
92 bool
93 Parser::Tokenizer::skip(const SBuf &tokenToSkip)
94 {
95 if (buf_.startsWith(tokenToSkip))
96 return success(tokenToSkip.length());
97 return false;
98 }
99
100 bool
101 Parser::Tokenizer::skip(const char tokenChar)
102 {
103 if (!buf_.isEmpty() && buf_[0] == tokenChar)
104 return success(1);
105 return false;
106 }
107
108 /* reworked from compat/strtoll.c */
109 bool
110 Parser::Tokenizer::int64(int64_t & result, int base)
111 {
112 if (buf_.isEmpty())
113 return false;
114
115 //fixme: account for buf_.size()
116 bool neg = false;
117 const char *s = buf_.rawContent();
118 const char *end = buf_.rawContent() + buf_.length();
119
120 if (*s == '-') {
121 neg = true;
122 ++s;
123 } else if (*s == '+') {
124 ++s;
125 }
126 if (s >= end) return false;
127 if (( base == 0 || base == 16) && *s == '0' && (s+1 <= end ) &&
128 tolower(*(s+1)) == 'x') {
129 s += 2;
130 base = 16;
131 }
132 if (base == 0) {
133 if ( *s == '0') {
134 base = 8;
135 ++s;
136 } else {
137 base = 10;
138 }
139 }
140 if (s >= end) return false;
141
142 uint64_t cutoff;
143
144 cutoff = neg ? -static_cast<uint64_t>(INT64_MIN) : INT64_MAX;
145 const int cutlim = cutoff % static_cast<int64_t>(base);
146 cutoff /= static_cast<uint64_t>(base);
147
148 int any = 0, c;
149 int64_t acc = 0;
150 for (c = *s++; s <= end; c = *s++) {
151 if (xisdigit(c)) {
152 c -= '0';
153 } else if (xisalpha(c)) {
154 c -= xisupper(c) ? 'A' - 10 : 'a' - 10;
155 } else {
156 break;
157 }
158 if (c >= base)
159 break;
160 if (any < 0 || static_cast<uint64_t>(acc) > cutoff || (static_cast<uint64_t>(acc) == cutoff && c > cutlim))
161 any = -1;
162 else {
163 any = 1;
164 acc *= base;
165 acc += c;
166 }
167 }
168
169 if (any == 0) // nothing was parsed
170 return false;
171 if (any < 0) {
172 acc = neg ? INT64_MIN : INT64_MAX;
173 errno = ERANGE;
174 return false;
175 } else if (neg)
176 acc = -acc;
177
178 result = acc;
179 return success(s - buf_.rawContent() - 1);
180 }