]> git.ipfire.org Git - thirdparty/squid.git/blame - src/String.cc
Boilerplate: update copyright blurbs on Squid helpers
[thirdparty/squid.git] / src / String.cc
CommitLineData
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
43int
44String::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 52void
a7a42b14 53String::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 64void
a7a42b14 65String::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 73String::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 83String &
84String::operator =(char const *aString)
ad80164a 85{
e7e1bf60 86 reset(aString);
ad80164a 87 return *this;
88}
89
30abd221 90String &
9e9ef416 91String::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
99bool
9e9ef416 100String::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
108bool
9e9ef416 109String::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 118void
119String::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.
127void
128String::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 139String::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 149void
150String::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 167String::~String()
ad80164a 168{
30abd221 169 clean();
ad80164a 170#if DEBUGSTRINGS
171
30abd221 172 StringRegistry::Instance().remove(this);
ad80164a 173#endif
174}
175
176void
9e9ef416 177String::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
186void
9e9ef416 187String::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
216void
30abd221 217String::append(char const *str)
ad80164a 218{
9e9ef416
RP
219 assert(str);
220 append(str, strlen(str));
ad80164a 221}
222
223void
9e9ef416 224String::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
232void
30abd221 233String::append(String const &old)
ad80164a 234{
9e9ef416 235 append(old.rawBuf(), old.len_);
ad80164a 236}
237
30abd221 238void
239String::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 249String
a7a42b14 250String::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
263void
30abd221 264String::stat(StoreEntry *entry) const
ad80164a 265{
cb3b44fc 266 storeAppendPrintf(entry, "%p : %d/%d \"%.*s\"\n",this,len_, size_, size(), rawBuf());
ad80164a 267}
268
30abd221 269StringRegistry &
270StringRegistry::Instance()
ad80164a 271{
272 return Instance_;
273}
274
275template <class C>
276int
277ptrcmp(C const &lhs, C const &rhs)
278{
279 return lhs - rhs;
280}
281
6852be71 282StringRegistry::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
290void
6ca34f6f 291StringRegistry::add(String const *entry)
ad80164a 292{
293 entries.insert(entry, ptrcmp);
294}
295
296void
6ca34f6f 297StringRegistry::remove(String const *entry)
ad80164a 298{
299 entries.remove(entry, ptrcmp);
300}
301
30abd221 302StringRegistry StringRegistry::Instance_;
ad80164a 303
82afb125 304String::size_type memStringCount();
ad80164a 305
306void
30abd221 307StringRegistry::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
313void
30abd221 314StringRegistry::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 */
323int
324stringHasWhitespace(const char *s)
325{
326 return strpbrk(s, w_space) != NULL;
327}
328
329/* TODO: move onto String */
330int
331stringHasCntl(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 */
350char *
351strwordtok(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
427done:
5db6bf73 428 *d = '\0';
ad80164a 429
430error:
431 *t = (char *) p;
432 return (char *) word;
433}
434
30abd221 435const char *
436checkNullString(const char *p)
437{
438 return p ? p : "(NULL)";
439}
440
826a1fed
FC
441const char *
442String::pos(char const *aString) const
443{
4f4611bf
FC
444 if (undefined())
445 return NULL;
826a1fed
FC
446 return strstr(termedBuf(), aString);
447}
448
449const char *
450String::pos(char const ch) const
451{
4f4611bf
FC
452 if (undefined())
453 return NULL;
826a1fed
FC
454 return strchr(termedBuf(), ch);
455}
456
457const char *
458String::rpos(char const ch) const
459{
4f4611bf
FC
460 if (undefined())
461 return NULL;
826a1fed
FC
462 return strrchr(termedBuf(), (ch));
463}
464
465String::size_type
466String::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
475String::size_type
476String::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
485String::size_type
486String::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