]>
Commit | Line | Data |
---|---|---|
ad80164a | 1 | |
2 | /* | |
ad80164a | 3 | * DEBUG: section 67 String |
4 | * AUTHOR: Duane Wessels | |
5 | * | |
6 | * SQUID Web Proxy Cache http://www.squid-cache.org/ | |
7 | * ---------------------------------------------------------- | |
8 | * | |
9 | * Squid is the result of efforts by numerous individuals from | |
10 | * the Internet community; see the CONTRIBUTORS file for full | |
11 | * details. Many organizations have provided support for Squid's | |
12 | * development; see the SPONSORS file for full details. Squid is | |
13 | * Copyrighted (C) 2001 by the Regents of the University of | |
14 | * California; see the COPYRIGHT file for full details. Squid | |
15 | * incorporates software developed and/or copyrighted by other | |
16 | * sources; see the CREDITS file for full details. | |
17 | * | |
18 | * This program is free software; you can redistribute it and/or modify | |
19 | * it under the terms of the GNU General Public License as published by | |
20 | * the Free Software Foundation; either version 2 of the License, or | |
21 | * (at your option) any later version. | |
26ac0430 | 22 | * |
ad80164a | 23 | * This program is distributed in the hope that it will be useful, |
24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
26 | * GNU General Public License for more details. | |
26ac0430 | 27 | * |
ad80164a | 28 | * You should have received a copy of the GNU General Public License |
29 | * along with this program; if not, write to the Free Software | |
30 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. | |
31 | * | |
32 | */ | |
33 | ||
582c2af2 | 34 | #include "squid.h" |
3d93a84d | 35 | #include "base/TextException.h" |
8a89c28f | 36 | #include "Mem.h" |
8822ebee | 37 | #include "mgr/Registration.h" |
582c2af2 | 38 | #include "profiler/Profiler.h" |
ad80164a | 39 | #include "Store.h" |
696a257c | 40 | |
074d6a40 | 41 | #include <climits> |
582c2af2 | 42 | |
696a257c FC |
43 | int |
44 | String::psize() const | |
45 | { | |
46 | Must(size() < INT_MAX); | |
47 | return size(); | |
48 | } | |
49 | ||
26ac0430 | 50 | // low-level buffer allocation, |
e7e1bf60 | 51 | // does not free old buffer and does not adjust or look at len_ |
ad80164a | 52 | void |
a7a42b14 | 53 | String::allocBuffer(String::size_type sz) |
ad80164a | 54 | { |
55 | PROF_start(StringInitBuf); | |
cb3b44fc | 56 | assert (undefined()); |
e7e1bf60 | 57 | char *newBuffer = (char*)memAllocString(sz, &sz); |
58 | setBuffer(newBuffer, sz); | |
ad80164a | 59 | PROF_stop(StringInitBuf); |
60 | } | |
61 | ||
e7e1bf60 | 62 | // low-level buffer assignment |
63 | // does not free old buffer and does not adjust or look at len_ | |
ad80164a | 64 | void |
a7a42b14 | 65 | String::setBuffer(char *aBuf, String::size_type aSize) |
ad80164a | 66 | { |
cb3b44fc | 67 | assert(undefined()); |
e7e1bf60 | 68 | assert(aSize < 65536); |
69 | buf_ = aBuf; | |
70 | size_ = aSize; | |
ad80164a | 71 | } |
72 | ||
9e9ef416 | 73 | String::String(char const *aString) : size_(0), len_(0), buf_(NULL) |
ad80164a | 74 | { |
e7e1bf60 | 75 | if (aString) |
76 | allocAndFill(aString, strlen(aString)); | |
ad80164a | 77 | #if DEBUGSTRINGS |
78 | ||
30abd221 | 79 | StringRegistry::Instance().add(this); |
ad80164a | 80 | #endif |
81 | } | |
82 | ||
30abd221 | 83 | String & |
84 | String::operator =(char const *aString) | |
ad80164a | 85 | { |
e7e1bf60 | 86 | reset(aString); |
ad80164a | 87 | return *this; |
88 | } | |
89 | ||
30abd221 | 90 | String & |
9e9ef416 | 91 | String::operator =(String const &old) |
ad80164a | 92 | { |
e7e1bf60 | 93 | clean(); // TODO: optimize to avoid cleaning the buffer we can use |
94 | if (old.size() > 0) | |
cb3b44fc | 95 | allocAndFill(old.rawBuf(), old.size()); |
ad80164a | 96 | return *this; |
97 | } | |
98 | ||
99 | bool | |
9e9ef416 | 100 | String::operator ==(String const &that) const |
ad80164a | 101 | { |
30abd221 | 102 | if (0 == this->cmp(that)) |
103 | return true; | |
ad80164a | 104 | |
30abd221 | 105 | return false; |
ad80164a | 106 | } |
107 | ||
108 | bool | |
9e9ef416 | 109 | String::operator !=(String const &that) const |
ad80164a | 110 | { |
30abd221 | 111 | if (0 == this->cmp(that)) |
112 | return false; | |
113 | ||
114 | return true; | |
ad80164a | 115 | } |
116 | ||
e7e1bf60 | 117 | // public interface, makes sure that we clean the old buffer first |
30abd221 | 118 | void |
119 | String::limitInit(const char *str, int len) | |
ad80164a | 120 | { |
e7e1bf60 | 121 | clean(); // TODO: optimize to avoid cleaning the buffer we can use |
122 | allocAndFill(str, len); | |
123 | } | |
4fbc2a54 | 124 | |
e7e1bf60 | 125 | // Allocates the buffer to fit the supplied string and fills it. |
126 | // Does not clean. | |
127 | void | |
128 | String::allocAndFill(const char *str, int len) | |
129 | { | |
130 | PROF_start(StringAllocAndFill); | |
131 | assert(this && str); | |
132 | allocBuffer(len + 1); | |
30abd221 | 133 | len_ = len; |
41d00cd3 | 134 | memcpy(buf_, str, len); |
30abd221 | 135 | buf_[len] = '\0'; |
e7e1bf60 | 136 | PROF_stop(StringAllocAndFill); |
ad80164a | 137 | } |
138 | ||
9e9ef416 | 139 | String::String(String const &old) : size_(0), len_(0), buf_(NULL) |
ad80164a | 140 | { |
dcb1fef8 | 141 | if (old.size() > 0) |
cb3b44fc | 142 | allocAndFill(old.rawBuf(), old.size()); |
30abd221 | 143 | #if DEBUGSTRINGS |
144 | ||
145 | StringRegistry::Instance().add(this); | |
146 | #endif | |
ad80164a | 147 | } |
148 | ||
30abd221 | 149 | void |
150 | String::clean() | |
ad80164a | 151 | { |
30abd221 | 152 | PROF_start(StringClean); |
153 | assert(this); | |
154 | ||
8536ad02 | 155 | /* TODO if mempools has already closed this will FAIL!! */ |
cb3b44fc | 156 | if (defined()) |
30abd221 | 157 | memFreeString(size_, buf_); |
158 | ||
159 | len_ = 0; | |
160 | ||
161 | size_ = 0; | |
162 | ||
163 | buf_ = NULL; | |
164 | PROF_stop(StringClean); | |
ad80164a | 165 | } |
166 | ||
30abd221 | 167 | String::~String() |
ad80164a | 168 | { |
30abd221 | 169 | clean(); |
ad80164a | 170 | #if DEBUGSTRINGS |
171 | ||
30abd221 | 172 | StringRegistry::Instance().remove(this); |
ad80164a | 173 | #endif |
174 | } | |
175 | ||
176 | void | |
9e9ef416 | 177 | String::reset(char const *str) |
30abd221 | 178 | { |
179 | PROF_start(StringReset); | |
e7e1bf60 | 180 | clean(); // TODO: optimize to avoid cleaning the buffer if we can reuse it |
181 | if (str) | |
182 | allocAndFill(str, strlen(str)); | |
30abd221 | 183 | PROF_stop(StringReset); |
184 | } | |
185 | ||
186 | void | |
9e9ef416 | 187 | String::append( char const *str, int len) |
ad80164a | 188 | { |
189 | assert(this); | |
30abd221 | 190 | assert(str && len >= 0); |
ad80164a | 191 | |
192 | PROF_start(StringAppend); | |
30abd221 | 193 | if (len_ + len < size_) { |
194 | strncat(buf_, str, len); | |
ad80164a | 195 | len_ += len; |
196 | } else { | |
e7e1bf60 | 197 | // Create a temporary string and absorb it later. |
30abd221 | 198 | String snew; |
44c26431 | 199 | assert(len_ + len < 65536); // otherwise snew.len_ overflows below |
30abd221 | 200 | snew.len_ = len_ + len; |
e7e1bf60 | 201 | snew.allocBuffer(snew.len_ + 1); |
ad80164a | 202 | |
e7e1bf60 | 203 | if (len_) |
41d00cd3 | 204 | memcpy(snew.buf_, rawBuf(), len_); |
ad80164a | 205 | |
206 | if (len) | |
41d00cd3 | 207 | memcpy(snew.buf_ + len_, str, len); |
ad80164a | 208 | |
30abd221 | 209 | snew.buf_[snew.len_] = '\0'; |
ad80164a | 210 | |
30abd221 | 211 | absorb(snew); |
ad80164a | 212 | } |
213 | PROF_stop(StringAppend); | |
214 | } | |
215 | ||
216 | void | |
30abd221 | 217 | String::append(char const *str) |
ad80164a | 218 | { |
9e9ef416 RP |
219 | assert(str); |
220 | append(str, strlen(str)); | |
ad80164a | 221 | } |
222 | ||
223 | void | |
9e9ef416 | 224 | String::append(char const chr) |
ad80164a | 225 | { |
226 | char myString[2]; | |
227 | myString[0]=chr; | |
228 | myString[1]='\0'; | |
9e9ef416 | 229 | append(myString, 1); |
ad80164a | 230 | } |
231 | ||
232 | void | |
30abd221 | 233 | String::append(String const &old) |
ad80164a | 234 | { |
9e9ef416 | 235 | append(old.rawBuf(), old.len_); |
ad80164a | 236 | } |
237 | ||
30abd221 | 238 | void |
239 | String::absorb(String &old) | |
73d41272 | 240 | { |
30abd221 | 241 | clean(); |
e7e1bf60 | 242 | setBuffer(old.buf_, old.size_); |
30abd221 | 243 | len_ = old.len_; |
244 | old.size_ = 0; | |
245 | old.buf_ = NULL; | |
246 | old.len_ = 0; | |
73d41272 | 247 | } |
248 | ||
9b558d8a | 249 | String |
a7a42b14 | 250 | String::substr(String::size_type from, String::size_type to) const |
9b558d8a | 251 | { |
1545d2d1 AJ |
252 | // Must(from >= 0 && from < size()); |
253 | Must(from < size()); | |
9b558d8a FC |
254 | Must(to > 0 && to <= size()); |
255 | Must(to > from); | |
256 | ||
257 | String rv; | |
258 | rv.limitInit(rawBuf()+from,to-from); | |
259 | return rv; | |
260 | } | |
261 | ||
ad80164a | 262 | #if DEBUGSTRINGS |
263 | void | |
30abd221 | 264 | String::stat(StoreEntry *entry) const |
ad80164a | 265 | { |
cb3b44fc | 266 | storeAppendPrintf(entry, "%p : %d/%d \"%.*s\"\n",this,len_, size_, size(), rawBuf()); |
ad80164a | 267 | } |
268 | ||
30abd221 | 269 | StringRegistry & |
270 | StringRegistry::Instance() | |
ad80164a | 271 | { |
272 | return Instance_; | |
273 | } | |
274 | ||
275 | template <class C> | |
276 | int | |
277 | ptrcmp(C const &lhs, C const &rhs) | |
278 | { | |
279 | return lhs - rhs; | |
280 | } | |
281 | ||
6852be71 | 282 | StringRegistry::StringRegistry() |
ad80164a | 283 | { |
6852be71 | 284 | #if DEBUGSTRINGS |
8822ebee | 285 | Mgr::RegisterAction("strings", |
d9fc6862 | 286 | "Strings in use in squid", Stat, 0, 1); |
6852be71 | 287 | #endif |
ad80164a | 288 | } |
289 | ||
290 | void | |
6ca34f6f | 291 | StringRegistry::add(String const *entry) |
ad80164a | 292 | { |
293 | entries.insert(entry, ptrcmp); | |
294 | } | |
295 | ||
296 | void | |
6ca34f6f | 297 | StringRegistry::remove(String const *entry) |
ad80164a | 298 | { |
299 | entries.remove(entry, ptrcmp); | |
300 | } | |
301 | ||
30abd221 | 302 | StringRegistry StringRegistry::Instance_; |
ad80164a | 303 | |
82afb125 | 304 | String::size_type memStringCount(); |
ad80164a | 305 | |
306 | void | |
30abd221 | 307 | StringRegistry::Stat(StoreEntry *entry) |
ad80164a | 308 | { |
309 | storeAppendPrintf(entry, "%lu entries, %lu reported from MemPool\n", (unsigned long) Instance().entries.elements, (unsigned long) memStringCount()); | |
310 | Instance().entries.head->walk(Stater, entry); | |
311 | } | |
312 | ||
313 | void | |
30abd221 | 314 | StringRegistry::Stater(String const * const & nodedata, void *state) |
ad80164a | 315 | { |
316 | StoreEntry *entry = (StoreEntry *) state; | |
317 | nodedata->stat(entry); | |
318 | } | |
319 | ||
320 | #endif | |
321 | ||
30abd221 | 322 | /* TODO: move onto String */ |
323 | int | |
324 | stringHasWhitespace(const char *s) | |
325 | { | |
326 | return strpbrk(s, w_space) != NULL; | |
327 | } | |
328 | ||
329 | /* TODO: move onto String */ | |
330 | int | |
331 | stringHasCntl(const char *s) | |
332 | { | |
333 | unsigned char c; | |
334 | ||
335 | while ((c = (unsigned char) *s++) != '\0') { | |
336 | if (c <= 0x1f) | |
337 | return 1; | |
338 | ||
339 | if (c >= 0x7f && c <= 0x9f) | |
340 | return 1; | |
341 | } | |
342 | ||
343 | return 0; | |
344 | } | |
345 | ||
ad80164a | 346 | /* |
347 | * Similar to strtok, but has some rudimentary knowledge | |
348 | * of quoting | |
349 | */ | |
350 | char * | |
351 | strwordtok(char *buf, char **t) | |
352 | { | |
353 | unsigned char *word = NULL; | |
354 | unsigned char *p = (unsigned char *) buf; | |
355 | unsigned char *d; | |
356 | unsigned char ch; | |
357 | int quoted = 0; | |
358 | ||
359 | if (!p) | |
360 | p = (unsigned char *) *t; | |
361 | ||
362 | if (!p) | |
363 | goto error; | |
364 | ||
365 | while (*p && xisspace(*p)) | |
5db6bf73 | 366 | ++p; |
ad80164a | 367 | |
368 | if (!*p) | |
369 | goto error; | |
370 | ||
371 | word = d = p; | |
372 | ||
373 | while ((ch = *p)) { | |
374 | switch (ch) { | |
375 | ||
376 | case '\\': | |
b48a944e AJ |
377 | if (quoted) |
378 | ++p; | |
ad80164a | 379 | |
380 | switch (*p) { | |
381 | ||
382 | case 'n': | |
383 | ch = '\n'; | |
384 | ||
385 | break; | |
386 | ||
387 | case 'r': | |
388 | ch = '\r'; | |
389 | ||
390 | break; | |
391 | ||
392 | default: | |
393 | ch = *p; | |
394 | ||
395 | break; | |
396 | ||
397 | } | |
398 | ||
5db6bf73 FC |
399 | *d = ch; |
400 | ++d; | |
ad80164a | 401 | |
402 | if (ch) | |
5db6bf73 | 403 | ++p; |
ad80164a | 404 | |
405 | break; | |
406 | ||
407 | case '"': | |
408 | quoted = !quoted; | |
409 | ||
5db6bf73 | 410 | ++p; |
ad80164a | 411 | |
412 | break; | |
413 | ||
414 | default: | |
415 | if (!quoted && xisspace(*p)) { | |
5db6bf73 | 416 | ++p; |
ad80164a | 417 | goto done; |
418 | } | |
419 | ||
aec55359 FC |
420 | *d = *p; |
421 | ++d; | |
422 | ++p; | |
ad80164a | 423 | break; |
424 | } | |
425 | } | |
426 | ||
427 | done: | |
5db6bf73 | 428 | *d = '\0'; |
ad80164a | 429 | |
430 | error: | |
431 | *t = (char *) p; | |
432 | return (char *) word; | |
433 | } | |
434 | ||
30abd221 | 435 | const char * |
436 | checkNullString(const char *p) | |
437 | { | |
438 | return p ? p : "(NULL)"; | |
439 | } | |
440 | ||
826a1fed FC |
441 | const char * |
442 | String::pos(char const *aString) const | |
443 | { | |
4f4611bf FC |
444 | if (undefined()) |
445 | return NULL; | |
826a1fed FC |
446 | return strstr(termedBuf(), aString); |
447 | } | |
448 | ||
449 | const char * | |
450 | String::pos(char const ch) const | |
451 | { | |
4f4611bf FC |
452 | if (undefined()) |
453 | return NULL; | |
826a1fed FC |
454 | return strchr(termedBuf(), ch); |
455 | } | |
456 | ||
457 | const char * | |
458 | String::rpos(char const ch) const | |
459 | { | |
4f4611bf FC |
460 | if (undefined()) |
461 | return NULL; | |
826a1fed FC |
462 | return strrchr(termedBuf(), (ch)); |
463 | } | |
464 | ||
465 | String::size_type | |
466 | String::find(char const ch) const | |
467 | { | |
468 | const char *c; | |
469 | c=pos(ch); | |
470 | if (c==NULL) | |
471 | return npos; | |
472 | return c-rawBuf(); | |
473 | } | |
474 | ||
475 | String::size_type | |
476 | String::find(char const *aString) const | |
477 | { | |
478 | const char *c; | |
479 | c=pos(aString); | |
480 | if (c==NULL) | |
481 | return npos; | |
482 | return c-rawBuf(); | |
483 | } | |
484 | ||
485 | String::size_type | |
486 | String::rfind(char const ch) const | |
487 | { | |
488 | const char *c; | |
489 | c=rpos(ch); | |
490 | if (c==NULL) | |
491 | return npos; | |
492 | return c-rawBuf(); | |
493 | } | |
494 | ||
32d002cb | 495 | #if !_USE_INLINE_ |
30abd221 | 496 | #include "String.cci" |
ad80164a | 497 | #endif |