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