]>
Commit | Line | Data |
---|---|---|
bbc27441 AJ |
1 | /* |
2 | * Copyright (C) 1996-2014 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 | ||
c9a4e310 | 9 | #include "squid.h" |
5d4cfe02 | 10 | #include "parser/Tokenizer.h" |
c9a4e310 | 11 | |
1a30fdf5 | 12 | #include <cerrno> |
12d28df0 FC |
13 | #if HAVE_CTYPE_H |
14 | #include <ctype.h> | |
15 | #endif | |
12d28df0 FC |
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 */ | |
880d2ea6 | 25 | #define INT64_MIN (-9223372036854775807LL-1LL) |
12d28df0 FC |
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 */ | |
880d2ea6 | 35 | #define INT64_MAX 9223372036854775807LL |
12d28df0 FC |
36 | #endif |
37 | #endif | |
38 | ||
0c67864a AR |
39 | /// convenience method: consumes up to n bytes, counts, and returns them |
40 | SBuf | |
27c841f6 AR |
41 | Parser::Tokenizer::consume(const SBuf::size_type n) |
42 | { | |
0c67864a AR |
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 | |
27c841f6 AR |
51 | Parser::Tokenizer::success(const SBuf::size_type n) |
52 | { | |
0c67864a AR |
53 | return consume(n).length(); |
54 | } | |
55 | ||
c9a4e310 | 56 | bool |
90bba30a | 57 | Parser::Tokenizer::token(SBuf &returnedToken, const CharacterSet &delimiters) |
c9a4e310 | 58 | { |
0c67864a AR |
59 | const Tokenizer saved(*this); |
60 | skipAll(delimiters); | |
c71e91de | 61 | const SBuf::size_type tokenLen = buf_.findFirstOf(delimiters); // not found = npos => consume to end |
0c67864a AR |
62 | if (tokenLen == SBuf::npos) { |
63 | *this = saved; | |
badfbcf0 AJ |
64 | return false; |
65 | } | |
0c67864a AR |
66 | returnedToken = consume(tokenLen); // cannot be empty |
67 | skipAll(delimiters); | |
c9a4e310 FC |
68 | return true; |
69 | } | |
70 | ||
71 | bool | |
90bba30a | 72 | Parser::Tokenizer::prefix(SBuf &returnedToken, const CharacterSet &tokenChars, const SBuf::size_type limit) |
c9a4e310 | 73 | { |
c71e91de | 74 | const SBuf::size_type prefixLen = buf_.substr(0,limit).findFirstNotOf(tokenChars); |
c9a4e310 FC |
75 | if (prefixLen == 0) |
76 | return false; | |
1d53a60a AR |
77 | if (prefixLen == SBuf::npos && (atEnd() || limit == 0)) |
78 | return false; | |
79 | returnedToken = consume(prefixLen); // cannot be empty after the npos check | |
c9a4e310 FC |
80 | return true; |
81 | } | |
82 | ||
0c67864a AR |
83 | SBuf::size_type |
84 | Parser::Tokenizer::skipAll(const CharacterSet &tokenChars) | |
c9a4e310 | 85 | { |
c71e91de | 86 | const SBuf::size_type prefixLen = buf_.findFirstNotOf(tokenChars); |
c9a4e310 | 87 | if (prefixLen == 0) |
0c67864a AR |
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; | |
c9a4e310 FC |
98 | } |
99 | ||
100 | bool | |
90bba30a | 101 | Parser::Tokenizer::skip(const SBuf &tokenToSkip) |
c9a4e310 | 102 | { |
0c67864a AR |
103 | if (buf_.startsWith(tokenToSkip)) |
104 | return success(tokenToSkip.length()); | |
c9a4e310 FC |
105 | return false; |
106 | } | |
107 | ||
108 | bool | |
90bba30a | 109 | Parser::Tokenizer::skip(const char tokenChar) |
c9a4e310 | 110 | { |
0c67864a AR |
111 | if (!buf_.isEmpty() && buf_[0] == tokenChar) |
112 | return success(1); | |
c9a4e310 FC |
113 | return false; |
114 | } | |
957143e6 | 115 | |
01f2137d | 116 | /* reworked from compat/strtoll.c */ |
957143e6 | 117 | bool |
52ed45a1 | 118 | Parser::Tokenizer::int64(int64_t & result, int base) |
957143e6 | 119 | { |
957143e6 FC |
120 | if (buf_.isEmpty()) |
121 | return false; | |
122 | ||
01f2137d FC |
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 ) && | |
11bd4370 | 136 | tolower(*(s+1)) == 'x') { |
01f2137d FC |
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; | |
957143e6 | 151 | |
01f2137d | 152 | cutoff = neg ? -static_cast<uint64_t>(INT64_MIN) : INT64_MAX; |
c71e91de | 153 | const int cutlim = cutoff % static_cast<int64_t>(base); |
01f2137d | 154 | cutoff /= static_cast<uint64_t>(base); |
957143e6 | 155 | |
01f2137d FC |
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 | } | |
a56b469c | 176 | |
01f2137d FC |
177 | if (any == 0) // nothing was parsed |
178 | return false; | |
179 | if (any < 0) { | |
180 | acc = neg ? INT64_MIN : INT64_MAX; | |
181 | errno = ERANGE; | |
a56b469c | 182 | return false; |
01f2137d FC |
183 | } else if (neg) |
184 | acc = -acc; | |
a56b469c | 185 | |
01f2137d | 186 | result = acc; |
0c67864a | 187 | return success(s - buf_.rawContent() - 1); |
957143e6 | 188 | } |