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