String.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2025 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 #include "squid.h"
10 #include "mem/forward.h"
11 #include "sbuf/SBuf.h"
12 #include "SquidString.h"
13 
14 #include <climits>
15 
16 // low-level buffer allocation,
17 // does not free old buffer and does not adjust or look at len_
18 void
20 {
21  assert (undefined());
22  auto *newBuffer = static_cast<char*>(memAllocBuf(sz, &sz));
23  setBuffer(newBuffer, sz);
24 }
25 
26 // low-level buffer assignment
27 // does not free old buffer and does not adjust or look at len_
28 void
30 {
31  assert(undefined());
32  assert(aSize <= SizeMax_);
33  buf_ = aBuf;
34  size_ = aSize;
35 }
36 
37 String::String(char const *aString)
38 {
39  if (aString)
40  allocAndFill(aString, strlen(aString));
41 }
42 
43 String &
44 String::operator =(char const *aString)
45 {
46  reset(aString);
47  return *this;
48 }
49 
50 String &
52 {
53  clean(); // TODO: optimize to avoid cleaning the buffer we can use
54  if (old.size() > 0)
55  allocAndFill(old.rawBuf(), old.size());
56  return *this;
57 }
58 
59 bool
60 String::operator ==(String const &that) const
61 {
62  if (0 == this->cmp(that))
63  return true;
64 
65  return false;
66 }
67 
68 bool
69 String::operator !=(String const &that) const
70 {
71  if (0 == this->cmp(that))
72  return false;
73 
74  return true;
75 }
76 
77 // public interface, makes sure that we clean the old buffer first
78 void
79 String::assign(const char *str, int len)
80 {
81  clean(); // TODO: optimize to avoid cleaning the buffer we can use
82  allocAndFill(str, len);
83 }
84 
85 // Allocates the buffer to fit the supplied string and fills it.
86 // Does not clean.
87 void
88 String::allocAndFill(const char *str, int len)
89 {
90  assert(str);
91  allocBuffer(len + 1);
92  len_ = len;
93  memcpy(buf_, str, len);
94  buf_[len] = '\0';
95 }
96 
97 String::String(String const &old) : size_(0), len_(0), buf_(nullptr)
98 {
99  if (old.size() > 0)
100  allocAndFill(old.rawBuf(), old.size());
101 }
102 
103 void
105 {
106  /* TODO if mempools has already closed this will FAIL!! */
107  if (defined())
109 
110  len_ = 0;
111 
112  size_ = 0;
113 
114  buf_ = nullptr;
115 }
116 
118 {
119  clean();
120 }
121 
122 void
123 String::reset(char const *str)
124 {
125  clean(); // TODO: optimize to avoid cleaning the buffer if we can reuse it
126  if (str)
127  allocAndFill(str, strlen(str));
128 }
129 
130 void
131 String::append( char const *str, int len)
132 {
133  assert(str && len >= 0);
134 
135  if (len_ + len + 1 /*'\0'*/ < size_) {
136  xstrncpy(buf_+len_, str, len+1);
137  len_ += len;
138  } else {
139  // Create a temporary string and absorb it later.
140  String snew;
141  assert(canGrowBy(len)); // otherwise snew.len_ may overflow below
142  snew.len_ = len_ + len;
143  snew.allocBuffer(snew.len_ + 1);
144 
145  if (len_)
146  memcpy(snew.buf_, rawBuf(), len_);
147 
148  if (len)
149  memcpy(snew.buf_ + len_, str, len);
150 
151  snew.buf_[snew.len_] = '\0';
152 
153  absorb(snew);
154  }
155 }
156 
157 void
158 String::append(char const *str)
159 {
160  assert(str);
161  append(str, strlen(str));
162 }
163 
164 void
165 String::append(char const chr)
166 {
167  char myString[2];
168  myString[0]=chr;
169  myString[1]='\0';
170  append(myString, 1);
171 }
172 
173 void
175 {
176  append(old.rawBuf(), old.len_);
177 }
178 
179 void
180 String::append(const SBuf &buf)
181 {
182  append(buf.rawContent(), buf.length());
183 }
184 
185 void
187 {
188  clean();
189  setBuffer(old.buf_, old.size_);
190  len_ = old.len_;
191  old.size_ = 0;
192  old.buf_ = nullptr;
193  old.len_ = 0;
194 }
195 
196 String
198 {
199 // Must(from >= 0 && from < size());
200  Must(from < size());
201  Must(to > 0 && to <= size());
202  Must(to > from);
203 
204  String rv;
205  rv.assign(rawBuf()+from, to-from);
206  return rv;
207 }
208 
209 void
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 
226 static bool
227 nilCmp(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 
242 int
243 String::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 
252 int
253 String::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 
262 int
263 String::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 
272 int
273 String::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 
282 int
283 String::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 
292 /* TODO: move onto String */
293 int
294 stringHasWhitespace(const char *s)
295 {
296  return strpbrk(s, w_space) != nullptr;
297 }
298 
299 /* TODO: move onto String */
300 int
301 stringHasCntl(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 
316 /*
317  * Similar to strtok, but has some rudimentary knowledge
318  * of quoting
319  */
320 char *
321 strwordtok(char *buf, char **t)
322 {
323  unsigned char *word = nullptr;
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))
336  ++p;
337 
338  if (!*p)
339  goto error;
340 
341  word = d = p;
342 
343  while ((ch = *p)) {
344  switch (ch) {
345 
346  case '\\':
347  if (quoted)
348  ++p;
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 
369  *d = ch;
370  ++d;
371 
372  if (ch)
373  ++p;
374 
375  break;
376 
377  case '"':
378  quoted = !quoted;
379 
380  ++p;
381 
382  break;
383 
384  default:
385  if (!quoted && xisspace(*p)) {
386  ++p;
387  goto done;
388  }
389 
390  *d = *p;
391  ++d;
392  ++p;
393  break;
394  }
395  }
396 
397 done:
398  *d = '\0';
399 
400 error:
401  *t = (char *) p;
402  return (char *) word;
403 }
404 
405 const char *
406 checkNullString(const char *p)
407 {
408  return p ? p : "(NULL)";
409 }
410 
411 const char *
412 String::pos(char const *aString) const
413 {
414  if (undefined())
415  return nullptr;
416  return strstr(termedBuf(), aString);
417 }
418 
419 const char *
420 String::pos(char const ch) const
421 {
422  if (undefined())
423  return nullptr;
424  return strchr(termedBuf(), ch);
425 }
426 
427 const char *
428 String::rpos(char const ch) const
429 {
430  if (undefined())
431  return nullptr;
432  return strrchr(termedBuf(), (ch));
433 }
434 
436 String::find(char const ch) const
437 {
438  const char *c;
439  c=pos(ch);
440  if (c==nullptr)
441  return npos;
442  return c-rawBuf();
443 }
444 
446 String::find(char const *aString) const
447 {
448  const char *c;
449  c=pos(aString);
450  if (c==nullptr)
451  return npos;
452  return c-rawBuf();
453 }
454 
456 String::rfind(char const ch) const
457 {
458  const char *c;
459  c=rpos(ch);
460  if (c==nullptr)
461  return npos;
462  return c-rawBuf();
463 }
464 
bool undefined() const
Definition: SquidString.h:138
int caseCmp(char const *) const
Definition: String.cc:273
size_type len_
Definition: SquidString.h:143
bool operator!=(String const &) const
Definition: String.cc:69
const char * rawBuf() const
Definition: SquidString.h:87
size_type rfind(char const ch) const
Definition: String.cc:456
String & operator=(char const *)
Definition: String.cc:44
void * memAllocBuf(size_t net_size, size_t *gross_size)
Definition: minimal.cc:46
void error(char *format,...)
Definition: SBuf.h:93
size_type size_
Definition: SquidString.h:141
void setBuffer(char *buf, size_type sz)
Definition: String.cc:29
int stringHasCntl(const char *s)
Definition: String.cc:301
int cmp(char const *) const
Definition: String.cc:243
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
String()=default
#define w_space
const static size_type npos
Definition: SquidString.h:40
bool operator==(String const &) const
Definition: String.cc:60
bool canGrowBy(const size_type growthLen) const
whether appending growthLen characters is safe (i.e., unlikely to assert)
Definition: SquidString.h:126
char * buf_
Definition: SquidString.h:158
const char * rawContent() const
Definition: SBuf.cc:509
void append(char const *buf, int len)
Definition: String.cc:131
const char * rpos(char const ch) const
Definition: String.cc:428
char * strwordtok(char *buf, char **t)
Definition: String.cc:321
const char * checkNullString(const char *p)
Definition: String.cc:406
bool defined() const
Definition: SquidString.h:137
int stringHasWhitespace(const char *s)
Definition: String.cc:294
void allocAndFill(const char *str, int len)
Definition: String.cc:88
#define assert(EX)
Definition: assert.h:17
static bool nilCmp(const bool thisIsNilOrEmpty, const bool otherIsNilOrEmpty, int &result)
Definition: String.cc:227
void absorb(String &old)
Definition: String.cc:186
size_type length() const
Returns the number of bytes stored in SBuf.
Definition: SBuf.h:419
const char * pos(char const *aString) const
Definition: String.cc:412
~String()
Definition: String.cc:117
size_t size_type
Definition: SquidString.h:39
static const size_type SizeMax_
Definition: SquidString.h:153
const char * termedBuf() const
Definition: SquidString.h:93
void cut(size_type newLength)
Definition: String.cc:210
size_type size() const
Definition: SquidString.h:74
void allocBuffer(size_type sz)
Definition: String.cc:19
#define Must(condition)
Definition: TextException.h:75
void reset(char const *str)
Definition: String.cc:123
void assign(const char *str, int len)
Definition: String.cc:79
size_type find(char const ch) const
Definition: String.cc:436
String substr(size_type from, size_type to) const
Definition: String.cc:197
#define xisspace(x)
Definition: xis.h:15
void memFreeBuf(size_t size, void *)
Definition: minimal.cc:67
void clean()
Definition: String.cc:104

 

Introduction

Documentation

Support

Miscellaneous