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