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