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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors