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