]> git.ipfire.org Git - thirdparty/squid.git/blame - src/parser/Tokenizer.cc
Boilerplate: update copyright blurbs on src/
[thirdparty/squid.git] / src / parser / Tokenizer.cc
CommitLineData
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
40SBuf
27c841f6
AR
41Parser::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
50SBuf::size_type
27c841f6
AR
51Parser::Tokenizer::success(const SBuf::size_type n)
52{
0c67864a
AR
53 return consume(n).length();
54}
55
c9a4e310 56bool
90bba30a 57Parser::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
71bool
90bba30a 72Parser::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
83SBuf::size_type
84Parser::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
92bool
93Parser::Tokenizer::skipOne(const CharacterSet &chars)
94{
95 if (!buf_.isEmpty() && chars[buf_[0]])
96 return success(1);
97 return false;
c9a4e310
FC
98}
99
100bool
90bba30a 101Parser::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
108bool
90bba30a 109Parser::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 117bool
52ed45a1 118Parser::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}