]> git.ipfire.org Git - thirdparty/squid.git/blob - src/String.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / String.cc
1 /*
2 * Copyright (C) 1996-2015 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 int
20 String::psize() const
21 {
22 Must(size() < INT_MAX);
23 return size();
24 }
25
26 // low-level buffer allocation,
27 // does not free old buffer and does not adjust or look at len_
28 void
29 String::allocBuffer(String::size_type sz)
30 {
31 PROF_start(StringInitBuf);
32 assert (undefined());
33 char *newBuffer = (char*)memAllocString(sz, &sz);
34 setBuffer(newBuffer, sz);
35 PROF_stop(StringInitBuf);
36 }
37
38 // low-level buffer assignment
39 // does not free old buffer and does not adjust or look at len_
40 void
41 String::setBuffer(char *aBuf, String::size_type aSize)
42 {
43 assert(undefined());
44 assert(aSize < 65536);
45 buf_ = aBuf;
46 size_ = aSize;
47 }
48
49 String::String(char const *aString) : size_(0), len_(0), buf_(NULL)
50 {
51 if (aString)
52 allocAndFill(aString, strlen(aString));
53 #if DEBUGSTRINGS
54
55 StringRegistry::Instance().add(this);
56 #endif
57 }
58
59 String &
60 String::operator =(char const *aString)
61 {
62 reset(aString);
63 return *this;
64 }
65
66 String &
67 String::operator =(String const &old)
68 {
69 clean(); // TODO: optimize to avoid cleaning the buffer we can use
70 if (old.size() > 0)
71 allocAndFill(old.rawBuf(), old.size());
72 return *this;
73 }
74
75 bool
76 String::operator ==(String const &that) const
77 {
78 if (0 == this->cmp(that))
79 return true;
80
81 return false;
82 }
83
84 bool
85 String::operator !=(String const &that) const
86 {
87 if (0 == this->cmp(that))
88 return false;
89
90 return true;
91 }
92
93 // public interface, makes sure that we clean the old buffer first
94 void
95 String::limitInit(const char *str, int len)
96 {
97 clean(); // TODO: optimize to avoid cleaning the buffer we can use
98 allocAndFill(str, len);
99 }
100
101 // Allocates the buffer to fit the supplied string and fills it.
102 // Does not clean.
103 void
104 String::allocAndFill(const char *str, int len)
105 {
106 PROF_start(StringAllocAndFill);
107 assert(str);
108 allocBuffer(len + 1);
109 len_ = len;
110 memcpy(buf_, str, len);
111 buf_[len] = '\0';
112 PROF_stop(StringAllocAndFill);
113 }
114
115 String::String(String const &old) : size_(0), len_(0), buf_(NULL)
116 {
117 if (old.size() > 0)
118 allocAndFill(old.rawBuf(), old.size());
119 #if DEBUGSTRINGS
120
121 StringRegistry::Instance().add(this);
122 #endif
123 }
124
125 void
126 String::clean()
127 {
128 PROF_start(StringClean);
129
130 /* TODO if mempools has already closed this will FAIL!! */
131 if (defined())
132 memFreeString(size_, buf_);
133
134 len_ = 0;
135
136 size_ = 0;
137
138 buf_ = NULL;
139 PROF_stop(StringClean);
140 }
141
142 String::~String()
143 {
144 clean();
145 #if DEBUGSTRINGS
146
147 StringRegistry::Instance().remove(this);
148 #endif
149 }
150
151 void
152 String::reset(char const *str)
153 {
154 PROF_start(StringReset);
155 clean(); // TODO: optimize to avoid cleaning the buffer if we can reuse it
156 if (str)
157 allocAndFill(str, strlen(str));
158 PROF_stop(StringReset);
159 }
160
161 void
162 String::append( char const *str, int len)
163 {
164 assert(str && len >= 0);
165
166 PROF_start(StringAppend);
167 if (len_ + len < size_) {
168 strncat(buf_, str, len);
169 len_ += len;
170 } else {
171 // Create a temporary string and absorb it later.
172 String snew;
173 assert(len_ + len < 65536); // otherwise snew.len_ overflows below
174 snew.len_ = len_ + len;
175 snew.allocBuffer(snew.len_ + 1);
176
177 if (len_)
178 memcpy(snew.buf_, rawBuf(), len_);
179
180 if (len)
181 memcpy(snew.buf_ + len_, str, len);
182
183 snew.buf_[snew.len_] = '\0';
184
185 absorb(snew);
186 }
187 PROF_stop(StringAppend);
188 }
189
190 void
191 String::append(char const *str)
192 {
193 assert(str);
194 append(str, strlen(str));
195 }
196
197 void
198 String::append(char const chr)
199 {
200 char myString[2];
201 myString[0]=chr;
202 myString[1]='\0';
203 append(myString, 1);
204 }
205
206 void
207 String::append(String const &old)
208 {
209 append(old.rawBuf(), old.len_);
210 }
211
212 void
213 String::absorb(String &old)
214 {
215 clean();
216 setBuffer(old.buf_, old.size_);
217 len_ = old.len_;
218 old.size_ = 0;
219 old.buf_ = NULL;
220 old.len_ = 0;
221 }
222
223 String
224 String::substr(String::size_type from, String::size_type to) const
225 {
226 // Must(from >= 0 && from < size());
227 Must(from < size());
228 Must(to > 0 && to <= size());
229 Must(to > from);
230
231 String rv;
232 rv.limitInit(rawBuf()+from,to-from);
233 return rv;
234 }
235
236 #if DEBUGSTRINGS
237 void
238 String::stat(StoreEntry *entry) const
239 {
240 storeAppendPrintf(entry, "%p : %d/%d \"%.*s\"\n",this,len_, size_, size(), rawBuf());
241 }
242
243 StringRegistry &
244 StringRegistry::Instance()
245 {
246 return Instance_;
247 }
248
249 template <class C>
250 int
251 ptrcmp(C const &lhs, C const &rhs)
252 {
253 return lhs - rhs;
254 }
255
256 StringRegistry::StringRegistry()
257 {
258 #if DEBUGSTRINGS
259 Mgr::RegisterAction("strings",
260 "Strings in use in squid", Stat, 0, 1);
261 #endif
262 }
263
264 void
265 StringRegistry::add(String const *entry)
266 {
267 entries.insert(entry, ptrcmp);
268 }
269
270 void
271 StringRegistry::remove(String const *entry)
272 {
273 entries.remove(entry, ptrcmp);
274 }
275
276 StringRegistry StringRegistry::Instance_;
277
278 String::size_type memStringCount();
279
280 void
281 StringRegistry::Stat(StoreEntry *entry)
282 {
283 storeAppendPrintf(entry, "%lu entries, %lu reported from MemPool\n", (unsigned long) Instance().entries.elements, (unsigned long) memStringCount());
284 Instance().entries.head->walk(Stater, entry);
285 }
286
287 void
288 StringRegistry::Stater(String const * const & nodedata, void *state)
289 {
290 StoreEntry *entry = (StoreEntry *) state;
291 nodedata->stat(entry);
292 }
293
294 #endif
295
296 /* TODO: move onto String */
297 int
298 stringHasWhitespace(const char *s)
299 {
300 return strpbrk(s, w_space) != NULL;
301 }
302
303 /* TODO: move onto String */
304 int
305 stringHasCntl(const char *s)
306 {
307 unsigned char c;
308
309 while ((c = (unsigned char) *s++) != '\0') {
310 if (c <= 0x1f)
311 return 1;
312
313 if (c >= 0x7f && c <= 0x9f)
314 return 1;
315 }
316
317 return 0;
318 }
319
320 /*
321 * Similar to strtok, but has some rudimentary knowledge
322 * of quoting
323 */
324 char *
325 strwordtok(char *buf, char **t)
326 {
327 unsigned char *word = NULL;
328 unsigned char *p = (unsigned char *) buf;
329 unsigned char *d;
330 unsigned char ch;
331 int quoted = 0;
332
333 if (!p)
334 p = (unsigned char *) *t;
335
336 if (!p)
337 goto error;
338
339 while (*p && xisspace(*p))
340 ++p;
341
342 if (!*p)
343 goto error;
344
345 word = d = p;
346
347 while ((ch = *p)) {
348 switch (ch) {
349
350 case '\\':
351 if (quoted)
352 ++p;
353
354 switch (*p) {
355
356 case 'n':
357 ch = '\n';
358
359 break;
360
361 case 'r':
362 ch = '\r';
363
364 break;
365
366 default:
367 ch = *p;
368
369 break;
370
371 }
372
373 *d = ch;
374 ++d;
375
376 if (ch)
377 ++p;
378
379 break;
380
381 case '"':
382 quoted = !quoted;
383
384 ++p;
385
386 break;
387
388 default:
389 if (!quoted && xisspace(*p)) {
390 ++p;
391 goto done;
392 }
393
394 *d = *p;
395 ++d;
396 ++p;
397 break;
398 }
399 }
400
401 done:
402 *d = '\0';
403
404 error:
405 *t = (char *) p;
406 return (char *) word;
407 }
408
409 const char *
410 checkNullString(const char *p)
411 {
412 return p ? p : "(NULL)";
413 }
414
415 const char *
416 String::pos(char const *aString) const
417 {
418 if (undefined())
419 return NULL;
420 return strstr(termedBuf(), aString);
421 }
422
423 const char *
424 String::pos(char const ch) const
425 {
426 if (undefined())
427 return NULL;
428 return strchr(termedBuf(), ch);
429 }
430
431 const char *
432 String::rpos(char const ch) const
433 {
434 if (undefined())
435 return NULL;
436 return strrchr(termedBuf(), (ch));
437 }
438
439 String::size_type
440 String::find(char const ch) const
441 {
442 const char *c;
443 c=pos(ch);
444 if (c==NULL)
445 return npos;
446 return c-rawBuf();
447 }
448
449 String::size_type
450 String::find(char const *aString) const
451 {
452 const char *c;
453 c=pos(aString);
454 if (c==NULL)
455 return npos;
456 return c-rawBuf();
457 }
458
459 String::size_type
460 String::rfind(char const ch) const
461 {
462 const char *c;
463 c=rpos(ch);
464 if (c==NULL)
465 return npos;
466 return c-rawBuf();
467 }
468
469 #if !_USE_INLINE_
470 #include "String.cci"
471 #endif
472