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