]> git.ipfire.org Git - thirdparty/squid.git/blame - src/String.cc
Simplify appending SBuf to String (#2108)
[thirdparty/squid.git] / src / String.cc
CommitLineData
ad80164a 1/*
1f7b830e 2 * Copyright (C) 1996-2025 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"
8ee00d73 10#include "mem/forward.h"
e93eda7e 11#include "sbuf/SBuf.h"
8ee00d73 12#include "SquidString.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());
460f7f5e 22 auto *newBuffer = static_cast<char*>(memAllocBuf(sz, &sz));
e7e1bf60 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 37String::String(char const *aString)
ad80164a 38{
e7e1bf60 39 if (aString)
40 allocAndFill(aString, strlen(aString));
ad80164a 41}
42
30abd221 43String &
44String::operator =(char const *aString)
ad80164a 45{
e7e1bf60 46 reset(aString);
ad80164a 47 return *this;
48}
49
30abd221 50String &
9e9ef416 51String::operator =(String const &old)
ad80164a 52{
e7e1bf60 53 clean(); // TODO: optimize to avoid cleaning the buffer we can use
54 if (old.size() > 0)
cb3b44fc 55 allocAndFill(old.rawBuf(), old.size());
ad80164a 56 return *this;
57}
58
59bool
9e9ef416 60String::operator ==(String const &that) const
ad80164a 61{
30abd221 62 if (0 == this->cmp(that))
63 return true;
ad80164a 64
30abd221 65 return false;
ad80164a 66}
67
68bool
9e9ef416 69String::operator !=(String const &that) const
ad80164a 70{
30abd221 71 if (0 == this->cmp(that))
72 return false;
73
74 return true;
ad80164a 75}
76
e7e1bf60 77// public interface, makes sure that we clean the old buffer first
30abd221 78void
2fe0439c 79String::assign(const char *str, int len)
ad80164a 80{
e7e1bf60 81 clean(); // TODO: optimize to avoid cleaning the buffer we can use
82 allocAndFill(str, len);
83}
4fbc2a54 84
e7e1bf60 85// Allocates the buffer to fit the supplied string and fills it.
86// Does not clean.
87void
88String::allocAndFill(const char *str, int len)
89{
328a07ab 90 assert(str);
e7e1bf60 91 allocBuffer(len + 1);
30abd221 92 len_ = len;
41d00cd3 93 memcpy(buf_, str, len);
30abd221 94 buf_[len] = '\0';
ad80164a 95}
96
aee3523a 97String::String(String const &old) : size_(0), len_(0), buf_(nullptr)
ad80164a 98{
dcb1fef8 99 if (old.size() > 0)
cb3b44fc 100 allocAndFill(old.rawBuf(), old.size());
ad80164a 101}
102
30abd221 103void
104String::clean()
ad80164a 105{
8536ad02 106 /* TODO if mempools has already closed this will FAIL!! */
cb3b44fc 107 if (defined())
460f7f5e 108 memFreeBuf(size_, buf_);
30abd221 109
110 len_ = 0;
111
112 size_ = 0;
113
aee3523a 114 buf_ = nullptr;
ad80164a 115}
116
30abd221 117String::~String()
ad80164a 118{
30abd221 119 clean();
ad80164a 120}
121
122void
9e9ef416 123String::reset(char const *str)
30abd221 124{
e7e1bf60 125 clean(); // TODO: optimize to avoid cleaning the buffer if we can reuse it
126 if (str)
127 allocAndFill(str, strlen(str));
30abd221 128}
129
130void
9e9ef416 131String::append( char const *str, int len)
ad80164a 132{
30abd221 133 assert(str && len >= 0);
ad80164a 134
5358a024
AJ
135 if (len_ + len + 1 /*'\0'*/ < size_) {
136 xstrncpy(buf_+len_, str, len+1);
ad80164a 137 len_ += len;
138 } else {
e7e1bf60 139 // Create a temporary string and absorb it later.
30abd221 140 String snew;
70df76e3 141 assert(canGrowBy(len)); // otherwise snew.len_ may overflow below
30abd221 142 snew.len_ = len_ + len;
e7e1bf60 143 snew.allocBuffer(snew.len_ + 1);
ad80164a 144
e7e1bf60 145 if (len_)
41d00cd3 146 memcpy(snew.buf_, rawBuf(), len_);
ad80164a 147
148 if (len)
41d00cd3 149 memcpy(snew.buf_ + len_, str, len);
ad80164a 150
30abd221 151 snew.buf_[snew.len_] = '\0';
ad80164a 152
30abd221 153 absorb(snew);
ad80164a 154 }
ad80164a 155}
156
157void
30abd221 158String::append(char const *str)
ad80164a 159{
9e9ef416
RP
160 assert(str);
161 append(str, strlen(str));
ad80164a 162}
163
164void
9e9ef416 165String::append(char const chr)
ad80164a 166{
167 char myString[2];
168 myString[0]=chr;
169 myString[1]='\0';
9e9ef416 170 append(myString, 1);
ad80164a 171}
172
173void
30abd221 174String::append(String const &old)
ad80164a 175{
9e9ef416 176 append(old.rawBuf(), old.len_);
ad80164a 177}
178
e93eda7e
AR
179void
180String::append(const SBuf &buf)
181{
182 append(buf.rawContent(), buf.length());
183}
184
30abd221 185void
186String::absorb(String &old)
73d41272 187{
30abd221 188 clean();
e7e1bf60 189 setBuffer(old.buf_, old.size_);
30abd221 190 len_ = old.len_;
191 old.size_ = 0;
aee3523a 192 old.buf_ = nullptr;
30abd221 193 old.len_ = 0;
73d41272 194}
195
9b558d8a 196String
a7a42b14 197String::substr(String::size_type from, String::size_type to) const
9b558d8a 198{
1545d2d1
AJ
199// Must(from >= 0 && from < size());
200 Must(from < size());
9b558d8a
FC
201 Must(to > 0 && to <= size());
202 Must(to > from);
203
204 String rv;
2fe0439c 205 rv.assign(rawBuf()+from, to-from);
9b558d8a
FC
206 return rv;
207}
208
f63c4b05
AJ
209void
210String::cut(String::size_type newLength)
211{
212 // size_type is size_t, unsigned. No need to check for newLength <0
213 if (newLength > len_) return;
214
215 len_ = newLength;
216
217 // buf_ may be nullptr on zero-length strings.
218 if (len_ == 0 && !buf_)
219 return;
220
221 buf_[newLength] = '\0';
222}
223
224/// compare NULL and empty strings because str*cmp() may fail on NULL strings
225/// and because we need to return consistent results for strncmp(count == 0).
226static bool
227nilCmp(const bool thisIsNilOrEmpty, const bool otherIsNilOrEmpty, int &result)
228{
229 if (!thisIsNilOrEmpty && !otherIsNilOrEmpty)
230 return false; // result does not matter
231
232 if (thisIsNilOrEmpty && otherIsNilOrEmpty)
233 result = 0;
234 else if (thisIsNilOrEmpty)
235 result = -1;
236 else // otherIsNilOrEmpty
237 result = +1;
238
239 return true;
240}
241
242int
243String::cmp(char const *aString) const
244{
245 int result = 0;
246 if (nilCmp(!size(), (!aString || !*aString), result))
247 return result;
248
249 return strcmp(termedBuf(), aString);
250}
251
252int
253String::cmp(char const *aString, String::size_type count) const
254{
255 int result = 0;
256 if (nilCmp((!size() || !count), (!aString || !*aString || !count), result))
257 return result;
258
259 return strncmp(termedBuf(), aString, count);
260}
261
262int
263String::cmp(String const &aString) const
264{
265 int result = 0;
266 if (nilCmp(!size(), !aString.size(), result))
267 return result;
268
269 return strcmp(termedBuf(), aString.termedBuf());
270}
271
272int
273String::caseCmp(char const *aString) const
274{
275 int result = 0;
276 if (nilCmp(!size(), (!aString || !*aString), result))
277 return result;
278
279 return strcasecmp(termedBuf(), aString);
280}
281
282int
283String::caseCmp(char const *aString, String::size_type count) const
284{
285 int result = 0;
286 if (nilCmp((!size() || !count), (!aString || !*aString || !count), result))
287 return result;
288
289 return strncasecmp(termedBuf(), aString, count);
290}
291
30abd221 292/* TODO: move onto String */
293int
294stringHasWhitespace(const char *s)
295{
aee3523a 296 return strpbrk(s, w_space) != nullptr;
30abd221 297}
298
299/* TODO: move onto String */
300int
301stringHasCntl(const char *s)
302{
303 unsigned char c;
304
305 while ((c = (unsigned char) *s++) != '\0') {
306 if (c <= 0x1f)
307 return 1;
308
309 if (c >= 0x7f && c <= 0x9f)
310 return 1;
311 }
312
313 return 0;
314}
315
ad80164a 316/*
317 * Similar to strtok, but has some rudimentary knowledge
318 * of quoting
319 */
320char *
321strwordtok(char *buf, char **t)
322{
aee3523a 323 unsigned char *word = nullptr;
ad80164a 324 unsigned char *p = (unsigned char *) buf;
325 unsigned char *d;
326 unsigned char ch;
327 int quoted = 0;
328
329 if (!p)
330 p = (unsigned char *) *t;
331
332 if (!p)
333 goto error;
334
335 while (*p && xisspace(*p))
5db6bf73 336 ++p;
ad80164a 337
338 if (!*p)
339 goto error;
340
341 word = d = p;
342
343 while ((ch = *p)) {
344 switch (ch) {
345
346 case '\\':
b48a944e
AJ
347 if (quoted)
348 ++p;
ad80164a 349
350 switch (*p) {
351
352 case 'n':
353 ch = '\n';
354
355 break;
356
357 case 'r':
358 ch = '\r';
359
360 break;
361
362 default:
363 ch = *p;
364
365 break;
366
367 }
368
5db6bf73
FC
369 *d = ch;
370 ++d;
ad80164a 371
372 if (ch)
5db6bf73 373 ++p;
ad80164a 374
375 break;
376
377 case '"':
378 quoted = !quoted;
379
5db6bf73 380 ++p;
ad80164a 381
382 break;
383
384 default:
385 if (!quoted && xisspace(*p)) {
5db6bf73 386 ++p;
ad80164a 387 goto done;
388 }
389
aec55359
FC
390 *d = *p;
391 ++d;
392 ++p;
ad80164a 393 break;
394 }
395 }
396
397done:
5db6bf73 398 *d = '\0';
ad80164a 399
400error:
401 *t = (char *) p;
402 return (char *) word;
403}
404
30abd221 405const char *
406checkNullString(const char *p)
407{
408 return p ? p : "(NULL)";
409}
410
826a1fed
FC
411const char *
412String::pos(char const *aString) const
413{
4f4611bf 414 if (undefined())
aee3523a 415 return nullptr;
826a1fed
FC
416 return strstr(termedBuf(), aString);
417}
418
419const char *
420String::pos(char const ch) const
421{
4f4611bf 422 if (undefined())
aee3523a 423 return nullptr;
826a1fed
FC
424 return strchr(termedBuf(), ch);
425}
426
427const char *
428String::rpos(char const ch) const
429{
4f4611bf 430 if (undefined())
aee3523a 431 return nullptr;
826a1fed
FC
432 return strrchr(termedBuf(), (ch));
433}
434
435String::size_type
436String::find(char const ch) const
437{
438 const char *c;
439 c=pos(ch);
aee3523a 440 if (c==nullptr)
826a1fed
FC
441 return npos;
442 return c-rawBuf();
443}
444
445String::size_type
446String::find(char const *aString) const
447{
448 const char *c;
449 c=pos(aString);
aee3523a 450 if (c==nullptr)
826a1fed
FC
451 return npos;
452 return c-rawBuf();
453}
454
455String::size_type
456String::rfind(char const ch) const
457{
458 const char *c;
459 c=rpos(ch);
aee3523a 460 if (c==nullptr)
826a1fed
FC
461 return npos;
462 return c-rawBuf();
463}
464