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