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