String.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2022 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 "base/TextException.h"
11 #include "mgr/Registration.h"
12 #include "Store.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  char *newBuffer = (char*)memAllocString(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 
38 {
39 #if DEBUGSTRINGS
40  StringRegistry::Instance().add(this);
41 #endif
42 }
43 
44 String::String(char const *aString)
45 {
46  if (aString)
47  allocAndFill(aString, strlen(aString));
48 #if DEBUGSTRINGS
49  StringRegistry::Instance().add(this);
50 #endif
51 }
52 
53 String &
54 String::operator =(char const *aString)
55 {
56  reset(aString);
57  return *this;
58 }
59 
60 String &
62 {
63  clean(); // TODO: optimize to avoid cleaning the buffer we can use
64  if (old.size() > 0)
65  allocAndFill(old.rawBuf(), old.size());
66  return *this;
67 }
68 
69 bool
70 String::operator ==(String const &that) const
71 {
72  if (0 == this->cmp(that))
73  return true;
74 
75  return false;
76 }
77 
78 bool
79 String::operator !=(String const &that) const
80 {
81  if (0 == this->cmp(that))
82  return false;
83 
84  return true;
85 }
86 
87 // public interface, makes sure that we clean the old buffer first
88 void
89 String::assign(const char *str, int len)
90 {
91  clean(); // TODO: optimize to avoid cleaning the buffer we can use
92  allocAndFill(str, len);
93 }
94 
95 // Allocates the buffer to fit the supplied string and fills it.
96 // Does not clean.
97 void
98 String::allocAndFill(const char *str, int len)
99 {
100  assert(str);
101  allocBuffer(len + 1);
102  len_ = len;
103  memcpy(buf_, str, len);
104  buf_[len] = '\0';
105 }
106 
107 String::String(String const &old) : size_(0), len_(0), buf_(NULL)
108 {
109  if (old.size() > 0)
110  allocAndFill(old.rawBuf(), old.size());
111 #if DEBUGSTRINGS
112 
113  StringRegistry::Instance().add(this);
114 #endif
115 }
116 
117 void
119 {
120  /* TODO if mempools has already closed this will FAIL!! */
121  if (defined())
123 
124  len_ = 0;
125 
126  size_ = 0;
127 
128  buf_ = NULL;
129 }
130 
132 {
133  clean();
134 #if DEBUGSTRINGS
135 
136  StringRegistry::Instance().remove(this);
137 #endif
138 }
139 
140 void
141 String::reset(char const *str)
142 {
143  clean(); // TODO: optimize to avoid cleaning the buffer if we can reuse it
144  if (str)
145  allocAndFill(str, strlen(str));
146 }
147 
148 void
149 String::append( char const *str, int len)
150 {
151  assert(str && len >= 0);
152 
153  if (len_ + len + 1 /*'\0'*/ < size_) {
154  xstrncpy(buf_+len_, str, len+1);
155  len_ += len;
156  } else {
157  // Create a temporary string and absorb it later.
158  String snew;
159  assert(canGrowBy(len)); // otherwise snew.len_ may overflow below
160  snew.len_ = len_ + len;
161  snew.allocBuffer(snew.len_ + 1);
162 
163  if (len_)
164  memcpy(snew.buf_, rawBuf(), len_);
165 
166  if (len)
167  memcpy(snew.buf_ + len_, str, len);
168 
169  snew.buf_[snew.len_] = '\0';
170 
171  absorb(snew);
172  }
173 }
174 
175 void
176 String::append(char const *str)
177 {
178  assert(str);
179  append(str, strlen(str));
180 }
181 
182 void
183 String::append(char const chr)
184 {
185  char myString[2];
186  myString[0]=chr;
187  myString[1]='\0';
188  append(myString, 1);
189 }
190 
191 void
193 {
194  append(old.rawBuf(), old.len_);
195 }
196 
197 void
199 {
200  clean();
201  setBuffer(old.buf_, old.size_);
202  len_ = old.len_;
203  old.size_ = 0;
204  old.buf_ = NULL;
205  old.len_ = 0;
206 }
207 
208 String
210 {
211 // Must(from >= 0 && from < size());
212  Must(from < size());
213  Must(to > 0 && to <= size());
214  Must(to > from);
215 
216  String rv;
217  rv.assign(rawBuf()+from, to-from);
218  return rv;
219 }
220 
221 void
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 
238 static bool
239 nilCmp(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 
254 int
255 String::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 
264 int
265 String::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 
274 int
275 String::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 
284 int
285 String::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 
294 int
295 String::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 
304 #if DEBUGSTRINGS
305 void
306 String::stat(StoreEntry *entry) const
307 {
308  storeAppendPrintf(entry, "%p : %d/%d \"%.*s\"\n",this,len_, size_, size(), rawBuf());
309 }
310 
311 StringRegistry &
313 {
314  return Instance_;
315 }
316 
317 template <class C>
318 int
319 ptrcmp(C const &lhs, C const &rhs)
320 {
321  return lhs - rhs;
322 }
323 
324 StringRegistry::StringRegistry()
325 {
326 #if DEBUGSTRINGS
327  Mgr::RegisterAction("strings",
328  "Strings in use in squid", Stat, 0, 1);
329 #endif
330 }
331 
332 void
333 StringRegistry::add(String const *entry)
334 {
335  entries.insert(entry, ptrcmp);
336 }
337 
338 void
339 StringRegistry::remove(String const *entry)
340 {
341  entries.remove(entry, ptrcmp);
342 }
343 
344 StringRegistry StringRegistry::Instance_;
345 
347 
348 void
349 StringRegistry::Stat(StoreEntry *entry)
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 
355 void
356 StringRegistry::Stater(String const * const & nodedata, void *state)
357 {
358  StoreEntry *entry = (StoreEntry *) state;
359  nodedata->stat(entry);
360 }
361 
362 #endif
363 
364 /* TODO: move onto String */
365 int
366 stringHasWhitespace(const char *s)
367 {
368  return strpbrk(s, w_space) != NULL;
369 }
370 
371 /* TODO: move onto String */
372 int
373 stringHasCntl(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 
388 /*
389  * Similar to strtok, but has some rudimentary knowledge
390  * of quoting
391  */
392 char *
393 strwordtok(char *buf, char **t)
394 {
395  unsigned char *word = NULL;
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))
408  ++p;
409 
410  if (!*p)
411  goto error;
412 
413  word = d = p;
414 
415  while ((ch = *p)) {
416  switch (ch) {
417 
418  case '\\':
419  if (quoted)
420  ++p;
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 
441  *d = ch;
442  ++d;
443 
444  if (ch)
445  ++p;
446 
447  break;
448 
449  case '"':
450  quoted = !quoted;
451 
452  ++p;
453 
454  break;
455 
456  default:
457  if (!quoted && xisspace(*p)) {
458  ++p;
459  goto done;
460  }
461 
462  *d = *p;
463  ++d;
464  ++p;
465  break;
466  }
467  }
468 
469 done:
470  *d = '\0';
471 
472 error:
473  *t = (char *) p;
474  return (char *) word;
475 }
476 
477 const char *
478 checkNullString(const char *p)
479 {
480  return p ? p : "(NULL)";
481 }
482 
483 const char *
484 String::pos(char const *aString) const
485 {
486  if (undefined())
487  return NULL;
488  return strstr(termedBuf(), aString);
489 }
490 
491 const char *
492 String::pos(char const ch) const
493 {
494  if (undefined())
495  return NULL;
496  return strchr(termedBuf(), ch);
497 }
498 
499 const char *
500 String::rpos(char const ch) const
501 {
502  if (undefined())
503  return NULL;
504  return strrchr(termedBuf(), (ch));
505 }
506 
508 String::find(char const ch) const
509 {
510  const char *c;
511  c=pos(ch);
512  if (c==NULL)
513  return npos;
514  return c-rawBuf();
515 }
516 
518 String::find(char const *aString) const
519 {
520  const char *c;
521  c=pos(aString);
522  if (c==NULL)
523  return npos;
524  return c-rawBuf();
525 }
526 
528 String::rfind(char const ch) const
529 {
530  const char *c;
531  c=rpos(ch);
532  if (c==NULL)
533  return npos;
534  return c-rawBuf();
535 }
536 
bool undefined() const
Definition: SquidString.h:136
int caseCmp(char const *) const
Definition: String.cc:285
static CodeContext::Pointer & Instance()
guarantees the forever existence of the pointer, starting from the first use
Definition: CodeContext.cc:26
size_type len_
Definition: SquidString.h:141
bool operator!=(String const &) const
Definition: String.cc:79
size_type rfind(char const ch) const
Definition: String.cc:528
String()
Definition: String.cc:37
String & operator=(char const *)
Definition: String.cc:54
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:830
void error(char *format,...)
size_type size_
Definition: SquidString.h:139
void setBuffer(char *buf, size_type sz)
Definition: String.cc:29
int stringHasCntl(const char *s)
Definition: String.cc:373
int cmp(char const *) const
Definition: String.cc:255
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
static const size_type npos
Definition: SquidString.h:39
#define w_space
bool operator==(String const &) const
Definition: String.cc:70
bool canGrowBy(const size_type growthLen) const
whether appending growthLen characters is safe (i.e., unlikely to assert)
Definition: SquidString.h:124
char * buf_
Definition: SquidString.h:147
#define NULL
Definition: types.h:166
void append(char const *buf, int len)
Definition: String.cc:149
const char * rpos(char const ch) const
Definition: String.cc:500
char * strwordtok(char *buf, char **t)
Definition: String.cc:393
const char * checkNullString(const char *p)
Definition: String.cc:478
void memFreeString(size_t size, void *)
Definition: minimal.cc:72
bool defined() const
Definition: SquidString.h:135
int stringHasWhitespace(const char *s)
Definition: String.cc:366
void allocAndFill(const char *str, int len)
Definition: String.cc:98
#define assert(EX)
Definition: assert.h:19
static bool nilCmp(const bool thisIsNilOrEmpty, const bool otherIsNilOrEmpty, int &result)
Definition: String.cc:239
char const * termedBuf() const
Definition: SquidString.h:92
static uint32 C
Definition: md4.c:43
void absorb(String &old)
Definition: String.cc:198
void const char int sz
Definition: stub_cbdata.cc:16
const char * pos(char const *aString) const
Definition: String.cc:484
~String()
Definition: String.cc:131
size_t size_type
Definition: SquidString.h:38
static const size_type SizeMax_
Definition: SquidString.h:143
void cut(size_type newLength)
Definition: String.cc:222
size_type size() const
Definition: SquidString.h:73
void allocBuffer(size_type sz)
Definition: String.cc:19
#define Must(condition)
Definition: TextException.h:71
void reset(char const *str)
Definition: String.cc:141
void assign(const char *str, int len)
Definition: String.cc:89
size_type find(char const ch) const
Definition: String.cc:508
void * memAllocString(size_t net_size, size_t *gross_size)
Definition: minimal.cc:66
String substr(size_type from, size_type to) const
Definition: String.cc:209
#define xisspace(x)
Definition: xis.h:17
void RegisterAction(char const *action, char const *desc, OBJH *handler, int pw_req_flag, int atomic)
Definition: Registration.cc:16
char const * rawBuf() const
Definition: SquidString.h:86
size_t memStringCount()
Definition: old_api.cc:264
void clean()
Definition: String.cc:118

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors