]> 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 #include <climits>
42
43 int
44 String::psize() const
45 {
46 Must(size() < INT_MAX);
47 return size();
48 }
49
50 // low-level buffer allocation,
51 // does not free old buffer and does not adjust or look at len_
52 void
53 String::allocBuffer(String::size_type sz)
54 {
55 PROF_start(StringInitBuf);
56 assert (undefined());
57 char *newBuffer = (char*)memAllocString(sz, &sz);
58 setBuffer(newBuffer, sz);
59 PROF_stop(StringInitBuf);
60 }
61
62 // low-level buffer assignment
63 // does not free old buffer and does not adjust or look at len_
64 void
65 String::setBuffer(char *aBuf, String::size_type aSize)
66 {
67 assert(undefined());
68 assert(aSize < 65536);
69 buf_ = aBuf;
70 size_ = aSize;
71 }
72
73 String::String(char const *aString) : size_(0), len_(0), buf_(NULL)
74 {
75 if (aString)
76 allocAndFill(aString, strlen(aString));
77 #if DEBUGSTRINGS
78
79 StringRegistry::Instance().add(this);
80 #endif
81 }
82
83 String &
84 String::operator =(char const *aString)
85 {
86 reset(aString);
87 return *this;
88 }
89
90 String &
91 String::operator =(String const &old)
92 {
93 clean(); // TODO: optimize to avoid cleaning the buffer we can use
94 if (old.size() > 0)
95 allocAndFill(old.rawBuf(), old.size());
96 return *this;
97 }
98
99 bool
100 String::operator ==(String const &that) const
101 {
102 if (0 == this->cmp(that))
103 return true;
104
105 return false;
106 }
107
108 bool
109 String::operator !=(String const &that) const
110 {
111 if (0 == this->cmp(that))
112 return false;
113
114 return true;
115 }
116
117 // public interface, makes sure that we clean the old buffer first
118 void
119 String::limitInit(const char *str, int len)
120 {
121 clean(); // TODO: optimize to avoid cleaning the buffer we can use
122 allocAndFill(str, len);
123 }
124
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);
133 len_ = len;
134 memcpy(buf_, str, len);
135 buf_[len] = '\0';
136 PROF_stop(StringAllocAndFill);
137 }
138
139 String::String(String const &old) : size_(0), len_(0), buf_(NULL)
140 {
141 if (old.size() > 0)
142 allocAndFill(old.rawBuf(), old.size());
143 #if DEBUGSTRINGS
144
145 StringRegistry::Instance().add(this);
146 #endif
147 }
148
149 void
150 String::clean()
151 {
152 PROF_start(StringClean);
153 assert(this);
154
155 /* TODO if mempools has already closed this will FAIL!! */
156 if (defined())
157 memFreeString(size_, buf_);
158
159 len_ = 0;
160
161 size_ = 0;
162
163 buf_ = NULL;
164 PROF_stop(StringClean);
165 }
166
167 String::~String()
168 {
169 clean();
170 #if DEBUGSTRINGS
171
172 StringRegistry::Instance().remove(this);
173 #endif
174 }
175
176 void
177 String::reset(char const *str)
178 {
179 PROF_start(StringReset);
180 clean(); // TODO: optimize to avoid cleaning the buffer if we can reuse it
181 if (str)
182 allocAndFill(str, strlen(str));
183 PROF_stop(StringReset);
184 }
185
186 void
187 String::append( char const *str, int len)
188 {
189 assert(this);
190 assert(str && len >= 0);
191
192 PROF_start(StringAppend);
193 if (len_ + len < size_) {
194 strncat(buf_, str, len);
195 len_ += len;
196 } else {
197 // Create a temporary string and absorb it later.
198 String snew;
199 assert(len_ + len < 65536); // otherwise snew.len_ overflows below
200 snew.len_ = len_ + len;
201 snew.allocBuffer(snew.len_ + 1);
202
203 if (len_)
204 memcpy(snew.buf_, rawBuf(), len_);
205
206 if (len)
207 memcpy(snew.buf_ + len_, str, len);
208
209 snew.buf_[snew.len_] = '\0';
210
211 absorb(snew);
212 }
213 PROF_stop(StringAppend);
214 }
215
216 void
217 String::append(char const *str)
218 {
219 assert(str);
220 append(str, strlen(str));
221 }
222
223 void
224 String::append(char const chr)
225 {
226 char myString[2];
227 myString[0]=chr;
228 myString[1]='\0';
229 append(myString, 1);
230 }
231
232 void
233 String::append(String const &old)
234 {
235 append(old.rawBuf(), old.len_);
236 }
237
238 void
239 String::absorb(String &old)
240 {
241 clean();
242 setBuffer(old.buf_, old.size_);
243 len_ = old.len_;
244 old.size_ = 0;
245 old.buf_ = NULL;
246 old.len_ = 0;
247 }
248
249 String
250 String::substr(String::size_type from, String::size_type to) const
251 {
252 // Must(from >= 0 && from < size());
253 Must(from < size());
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
262 #if DEBUGSTRINGS
263 void
264 String::stat(StoreEntry *entry) const
265 {
266 storeAppendPrintf(entry, "%p : %d/%d \"%.*s\"\n",this,len_, size_, size(), rawBuf());
267 }
268
269 StringRegistry &
270 StringRegistry::Instance()
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
282 StringRegistry::StringRegistry()
283 {
284 #if DEBUGSTRINGS
285 Mgr::RegisterAction("strings",
286 "Strings in use in squid", Stat, 0, 1);
287 #endif
288 }
289
290 void
291 StringRegistry::add(String const *entry)
292 {
293 entries.insert(entry, ptrcmp);
294 }
295
296 void
297 StringRegistry::remove(String const *entry)
298 {
299 entries.remove(entry, ptrcmp);
300 }
301
302 StringRegistry StringRegistry::Instance_;
303
304 String::size_type memStringCount();
305
306 void
307 StringRegistry::Stat(StoreEntry *entry)
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
314 StringRegistry::Stater(String const * const & nodedata, void *state)
315 {
316 StoreEntry *entry = (StoreEntry *) state;
317 nodedata->stat(entry);
318 }
319
320 #endif
321
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
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))
366 ++p;
367
368 if (!*p)
369 goto error;
370
371 word = d = p;
372
373 while ((ch = *p)) {
374 switch (ch) {
375
376 case '\\':
377 if (quoted)
378 ++p;
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
399 *d = ch;
400 ++d;
401
402 if (ch)
403 ++p;
404
405 break;
406
407 case '"':
408 quoted = !quoted;
409
410 ++p;
411
412 break;
413
414 default:
415 if (!quoted && xisspace(*p)) {
416 ++p;
417 goto done;
418 }
419
420 *d = *p;
421 ++d;
422 ++p;
423 break;
424 }
425 }
426
427 done:
428 *d = '\0';
429
430 error:
431 *t = (char *) p;
432 return (char *) word;
433 }
434
435 const char *
436 checkNullString(const char *p)
437 {
438 return p ? p : "(NULL)";
439 }
440
441 const char *
442 String::pos(char const *aString) const
443 {
444 if (undefined())
445 return NULL;
446 return strstr(termedBuf(), aString);
447 }
448
449 const char *
450 String::pos(char const ch) const
451 {
452 if (undefined())
453 return NULL;
454 return strchr(termedBuf(), ch);
455 }
456
457 const char *
458 String::rpos(char const ch) const
459 {
460 if (undefined())
461 return NULL;
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
495 #if !_USE_INLINE_
496 #include "String.cci"
497 #endif