Doxygen
Loading...
Searching...
No Matches
dstring.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2015 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16#include "dstring.h"
17
18#include <limits.h>
19#include <stdlib.h>
20#include <stdio.h>
21#include <stdarg.h>
22#include <ctype.h>
23
24inline char toLowerChar(char c)
25{
26 return c>='A' && c<='Z' ? c|0x20 : c;
27}
28
29DString &DString::sprintf( const char *format, ... )
30{
31 va_list ap;
32 va_start( ap, format );
33 const size_t minlen=256;
34 size_t l = length();
35 if (l<minlen) { resize(minlen+1); l=minlen; }
36 int n=vsnprintf( rawData(), l+1, format, ap);
37 if (n<0) n=static_cast<int>(l);
38 resize(n);
39 va_end( ap );
40 return *this;
41}
42
43size_t DString::rfind_insensitive( char c, size_t index) const
44{
45 const char *b = data();
46 const char *pos = nullptr;
47 size_t len = length();
48 if (len==0) return -1; // empty string
49 if (index==npos) // start from end
50 {
51 index=len;
52 }
53 else if (index>len) // bad index
54 {
55 return DString::npos;
56 }
57 pos = b+index;
58 c = toLowerChar(c);
59 while ( pos>=b && toLowerChar(*pos)!=c) pos--;
60 return pos>=b ? static_cast<size_t>(pos-b) : DString::npos;
61}
62
63size_t DString::rfind_insensitive( const char *str, size_t index) const
64{
65 size_t slen = dstrlen(str);
66 size_t len = length();
67 if (slen>len) return DString::npos; // length of search string is longer than this string
68 if (index==DString::npos) index = len-slen; // start from end
69 else if (index>len) return DString::npos; // bad index
70 else if (index+slen>len) index = len-slen; // str would be too long
71 const char *pos = data()+index;
72 for (int i=index; i>=0; i--) if (dstrnicmp(pos--,str,slen)==0) return i;
73 return DString::npos;
74}
75
76int DString::contains( char c, bool cs ) const
77{
78 if (length()==0) return 0;
79 int count=0;
80 const char *pos = data();
81 if (cs)
82 {
83 while (*pos) if (*pos++ == c) count++;
84 }
85 else
86 {
87 c = toLowerChar(c);
88 while (*pos)
89 {
90 if (toLowerChar(*pos)==c) count++;
91 pos++;
92 }
93 }
94 return count;
95}
96
97int DString::contains( const char *str, bool cs ) const
98{
99 if (str==nullptr || length()==0) return 0;
100 int count=0;
101 const char *pos = data();
102 int len = dstrlen(str);
103 while (*pos)
104 {
105 if (cs)
106 {
107 if (dstrncmp(pos,str,len)==0) count++;
108 }
109 else
110 {
111 if (dstrnicmp(pos,str,len)==0) count++;
112 }
113 pos++;
114 }
115 return count;
116}
117
119{
120 if ( empty() ) // nothing to do
121 return *this;
122
123 DString result( length(), ExplicitSize );
124 const char *from = data();
125 char *to = result.rawData();
126 char *first = to;
127 while ( true )
128 {
129 while ( *from && disspace(*from) )
130 from++;
131 while ( *from && !disspace(*from) )
132 *to++ = *from++;
133 if ( *from )
134 *to++ = 0x20; // ' '
135 else
136 break;
137 }
138 if ( to > first && *(to-1) == 0x20 )
139 to--;
140 *to = '\0';
141 result.resize( static_cast<int>(to - result.data()) );
142 return result;
143}
144
145DString &DString::replace( size_t index, size_t len, const char *s)
146{
147 remove( index, len );
148 insert( index, s );
149 return *this;
150}
151
152static bool ok_in_base( char c, int base )
153{
154 if ( base <= 10 )
155 return c>='0' && c<='9' && (c-'0') < base;
156 else
157 return (c>='0' && c<='9') ||
158 (c >= 'a' && c < char('a'+base-10)) ||
159 (c >= 'A' && c < char('A'+base-10));
160}
161
162short DString::toShort(bool *ok, int base) const
163{
164 long v = toLong( ok, base );
165 if ( ok && *ok && (v < -32768 || v > 32767) ) {
166 *ok = false;
167 v = 0;
168 }
169 return static_cast<short>(v);
170}
171
172uint16_t DString::toUShort(bool *ok,int base) const
173{
174 unsigned long v = toULong( ok, base );
175 if ( ok && *ok && (v > 65535) ) {
176 *ok = false;
177 v = 0;
178 }
179 return static_cast<uint16_t>(v);
180}
181
182int DString::toInt(bool *ok, int base) const
183{
184 return static_cast<int>(toLong( ok, base ));
185}
186
187uint32_t DString::toUInt(bool *ok,int base) const
188{
189 return static_cast<uint32_t>(toULong( ok, base ));
190}
191
192
193long DString::toLong(bool *ok,int base) const
194{
195 const char *p = data();
196 long val=0;
197 int l = static_cast<int>(length());
198 const long max_mult = INT_MAX / base;
199 bool is_ok = false;
200 int neg = 0;
201 if ( !p )
202 goto bye;
203 while ( l && disspace(*p) ) // skip leading space
204 {
205 l--;
206 p++;
207 }
208 if ( l && *p == '-' )
209 {
210 l--;
211 p++;
212 neg = 1;
213 } else if ( *p == '+' )
214 {
215 l--;
216 p++;
217 }
218
219 // NOTE: toULong() code is similar
220 if ( !l || !ok_in_base(*p,base) )
221 {
222 goto bye;
223 }
224 while ( l && ok_in_base(*p,base) )
225 {
226 l--;
227 int dv = 0;
228 if ( *p>='0' && *p<='9' )
229 {
230 dv = *p-'0';
231 }
232 else
233 {
234 if ( *p >= 'a' && *p <= 'z' )
235 {
236 dv = *p - 'a' + 10;
237 }
238 else
239 {
240 dv = *p - 'A' + 10;
241 }
242 }
243 if ( val > max_mult || (val == max_mult && dv > (INT_MAX%base)+neg) )
244 {
245 goto bye;
246 }
247 val = base*val + dv;
248 p++;
249 }
250 if ( neg )
251 {
252 val = -val;
253 }
254 while ( l && disspace(*p) ) // skip trailing space
255 {
256 l--;
257 p++;
258 }
259 if ( !l )
260 {
261 is_ok = true;
262 }
263bye:
264 if ( ok )
265 {
266 *ok = is_ok;
267 }
268 return is_ok ? val : 0;
269}
270
271unsigned long DString::toULong(bool *ok,int base) const
272{
273 const char *p = data();
274 unsigned long val=0;
275 int l = static_cast<int>(length());
276 const unsigned long max_mult = 429496729; // UINT_MAX/10, rounded down
277 bool is_ok = false;
278 if ( !p )
279 {
280 goto bye;
281 }
282 while ( l && disspace(*p) ) // skip leading space
283 {
284 l--;
285 p++;
286 }
287 if ( *p == '+' )
288 {
289 l--;
290 p++;
291 }
292
293 // NOTE: toLong() code is similar
294 if ( !l || !ok_in_base(*p,base) )
295 {
296 goto bye;
297 }
298 while ( l && ok_in_base(*p,base) )
299 {
300 l--;
301 uint32_t dv = 0;
302 if ( *p>='0' && *p<='9' )
303 {
304 dv = *p-'0';
305 }
306 else
307 {
308 if ( *p >= 'a' && *p <= 'z' )
309 {
310 dv = *p - 'a' + 10;
311 }
312 else
313 {
314 dv = *p - 'A' + 10;
315 }
316 }
317 if ( val > max_mult || (val == max_mult && dv > (UINT_MAX%base)) )
318 {
319 goto bye;
320 }
321 val = base*val + dv;
322 p++;
323 }
324
325 while ( l && disspace(*p) ) // skip trailing space
326 {
327 l--;
328 p++;
329 }
330 if ( !l )
331 {
332 is_ok = true;
333 }
334bye:
335 if ( ok )
336 {
337 *ok = is_ok;
338 }
339 return is_ok ? val : 0;
340}
341
342uint64_t DString::toUInt64(bool *ok,int base) const
343{
344 const char *p = data();
345 uint64_t val=0;
346 int l = static_cast<int>(length());
347 const uint64_t max_mult = 1844674407370955161ULL; // ULLONG_MAX/10, rounded down
348 bool is_ok = false;
349 if ( !p )
350 {
351 goto bye;
352 }
353 while ( l && disspace(*p) ) // skip leading space
354 {
355 l--;
356 p++;
357 }
358 if ( *p == '+' )
359 {
360 l--;
361 p++;
362 }
363
364 // NOTE: toULong() code is similar
365 if ( !l || !ok_in_base(*p,base) )
366 {
367 goto bye;
368 }
369 while ( l && ok_in_base(*p,base) )
370 {
371 l--;
372 uint32_t dv = 0;
373 if ( *p>='0' && *p<='9' )
374 {
375 dv = *p-'0';
376 }
377 else
378 {
379 if ( *p >= 'a' && *p <= 'z' )
380 {
381 dv = *p - 'a' + 10;
382 }
383 else
384 {
385 dv = *p - 'A' + 10;
386 }
387 }
388 if ( val > max_mult || (val == max_mult && dv > (ULLONG_MAX%base)) )
389 {
390 goto bye;
391 }
392 val = base*val + dv;
393 p++;
394 }
395
396 while ( l && disspace(*p) ) // skip trailing space
397 {
398 l--;
399 p++;
400 }
401 if ( !l )
402 {
403 is_ok = true;
404 }
405bye:
406 if ( ok )
407 {
408 *ok = is_ok;
409 }
410 return is_ok ? val : 0;
411}
412
413//-------------------------------------------------
414
415char *dstrdup( const char *str )
416{
417 if ( !str ) return nullptr;
418 char *dst = new char[dstrlen(str)+1];
419 return strcpy( dst, str );
420}
421
422void dstrfree( const char *str )
423{
424 delete [](str);
425}
426
427char *dstrncpy( char *dst, const char *src, size_t len )
428{
429 if ( !src ) return nullptr;
430 strncpy( dst, src, len );
431 if ( len > 0 ) dst[len-1] = '\0';
432 return dst;
433}
434
435int dstricmp( const char *s1, const char *s2 )
436{
437 if ( !s1 || !s2 )
438 {
439 return s1 == s2 ? 0 : static_cast<int>(s2 - s1);
440 }
441 int res = 0;
442 char c = 0;
443 for ( ; !(res = ((c=toLowerChar(*s1)) - toLowerChar(*s2))); s1++, s2++ )
444 {
445 if ( !c ) // strings are equal
446 {
447 break;
448 }
449 }
450 return res;
451}
452
453int dstrnicmp( const char *s1, const char *s2, size_t len )
454{
455 if ( !s1 || !s2 )
456 {
457 return static_cast<int>(s2 - s1);
458 }
459 for ( ; len--; s1++, s2++ )
460 {
461 char c = toLowerChar(*s1);
462 int res = c-toLowerChar(*s2);
463 if ( res!=0 ) // strings are not equal
464 {
465 return res;
466 }
467 if ( c==0 ) // strings are equal
468 {
469 break;
470 }
471 }
472 return 0;
473}
474
475/// substitute all occurrences of \a src in \a s by \a dst
476DString substitute(const DString &s,const DString &src,const DString &dst)
477{
478 if (s.empty() || src.empty()) return s;
479 const char *q = nullptr, *p = nullptr;
480 size_t srcLen = src.length();
481 size_t dstLen = dst.length();
482 size_t resLen = 0;
483 if (srcLen!=dstLen)
484 {
485 int count = 0;
486 for (p = s.data(); (q=strstr(p,src.data()))!=nullptr; p=q+srcLen) count++;
487 resLen = s.length()+count*(dstLen-srcLen);
488 }
489 else // result has same size as s
490 {
491 resLen = s.length();
492 }
493 DString result(resLen, DString::ExplicitSize);
494 char *r = result.rawData();
495 for (p = s.data(); (q=strstr(p,src.data()))!=nullptr; p=q+srcLen)
496 {
497 int l = static_cast<int>(q-p);
498 memcpy(r,p,l);
499 r+=l;
500
501 if (dstLen>0) memcpy(r,dst.data(),dstLen);
502 r+=dstLen;
503 }
504 if (r)
505 {
506 dstrcpy(r,p);
507 }
508 //printf("substitute(%s,%s,%s)->%s\n",s,src,dst,result.data());
509 return result;
510}
511
512
513/// substitute all occurrences of \a src in \a s by \a dst, but skip
514/// each consecutive sequence of \a src where the number consecutive
515/// \a src matches \a skip_seq; if \a skip_seq is negative, skip any
516/// number of consecutive \a src
517DString substitute(const DString &s,const DString &src,const DString &dst,int skip_seq)
518{
519 if (s.empty() || src.empty()) return s;
520 const char *p = nullptr, *q = nullptr;
521 size_t srcLen = src.length();
522 size_t dstLen = dst.length();
523 size_t resLen = 0;
524 if (srcLen!=dstLen)
525 {
526 int count = 0;
527 for (p=s.data(); (q=strstr(p,src.data()))!=nullptr; p=q+srcLen) count++;
528 resLen = s.length()+count*(dstLen-srcLen);
529 }
530 else // result has same size as s
531 {
532 resLen = s.length();
533 }
534 DString result(resLen, DString::ExplicitSize);
535 char *r = result.rawData();
536 for (p = s.data(); (q=strstr(p,src.data()))!=nullptr; p=q+srcLen)
537 {
538 // search a consecutive sequence of src
539 int seq = 0, skip = 0;
540 if (skip_seq)
541 {
542 for (const char *n=q+srcLen; dstrncmp(n,src.data(),srcLen)==0; seq=1+skip, n+=srcLen)
543 ++skip; // number of consecutive src after the current one
544
545 // verify the allowed number of consecutive src to skip
546 if (skip_seq > 0 && skip_seq != seq)
547 seq = skip = 0;
548 }
549
550 // skip a consecutive sequence of src when necessary
551 int l = static_cast<int>((q + seq * srcLen)-p);
552 memcpy(r,p,l);
553 r+=l;
554
555 if (skip)
556 {
557 // skip only the consecutive src found after the current one
558 q += skip * srcLen;
559 // the next loop will skip the current src, aka (p=q+srcLen)
560 continue;
561 }
562
563 if (dstLen>0) memcpy(r,dst.data(),dstLen);
564 r+=dstLen;
565 }
566 dstrcpy(r,p);
567 result.resize(strlen(result.data()));
568 //printf("substitute(%s,%s,%s)->%s\n",s,src,dst,result.data());
569 return result;
570}
571
573{
574 if (empty()) return DString();
575 const std::string &s = m_rep;
576 int end=static_cast<int>(s.length());
577 int start=0,p=0;
578 // skip leading empty lines
579 for (;;)
580 {
581 int c;
582 while ((c=s[p]) && (c==' ' || c=='\t')) p++;
583 if (s[p]=='\n')
584 {
585 start=++p;
586 }
587 else
588 {
589 break;
590 }
591 }
592 // skip trailing empty lines
593 p=end-1;
594 if (p>=start && s.at(p)=='\n') p--;
595 while (p>=start)
596 {
597 int c;
598 while ((c=s[p]) && (c==' ' || c=='\t')) p--;
599 if (s[p]=='\n')
600 {
601 end=p+1;
602 }
603 else
604 {
605 break;
606 }
607 p--;
608 }
609 //printf("stripLeadingAndTrailingEmptyLines(%d-%d)\n",start,end);
610 return s.substr(start,end-start);
611}
612
A String class for use with Doxygen wrapping std::string and adding some additional functionality off...
Definition dstring.h:89
void resize(size_t newlen)
Definition dstring.h:214
DString stripLeadingAndTrailingEmptyLines() const
Definition dstring.cpp:572
DString()=default
unsigned long toULong(bool *ok=nullptr, int base=10) const
Definition dstring.cpp:271
uint16_t toUShort(bool *ok=nullptr, int base=10) const
Definition dstring.cpp:172
DString simplifyWhiteSpace() const
return a copy of this string with leading and trailing whitespace removed and multiple whitespace cha...
Definition dstring.cpp:118
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
Definition dstring.h:153
iterator end()
Definition dstring.h:188
DString & replace(size_t index, size_t len, const char *s)
Definition dstring.cpp:145
uint32_t toUInt(bool *ok=nullptr, int base=10) const
Definition dstring.cpp:187
uint64_t toUInt64(bool *ok=nullptr, int base=10) const
Definition dstring.cpp:342
char * rawData()
Returns a writable pointer to the data.
Definition dstring.h:171
short toShort(bool *ok=nullptr, int base=10) const
Definition dstring.cpp:162
DString & remove(size_t index, size_t len)
Definition dstring.h:524
static constexpr size_t npos
value used to indicate 'not found' or 'to the end of the string', matching std::string::npos
Definition dstring.h:183
size_t rfind_insensitive(char c, size_t pos=npos) const
Definition dstring.cpp:43
std::string m_rep
Definition dstring.h:697
int contains(char c, bool cs=true) const
Definition dstring.cpp:76
DString & sprintf(const char *format,...)
Definition dstring.cpp:29
int toInt(bool *ok=nullptr, int base=10) const
Definition dstring.cpp:182
@ ExplicitSize
Definition dstring.h:136
long toLong(bool *ok=nullptr, int base=10) const
Definition dstring.cpp:193
const std::string & str() const
Definition dstring.h:634
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition dstring.h:162
DString & insert(size_t index, const DString &s)
Definition dstring.h:414
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition dstring.h:156
void dstrfree(const char *str)
Frees the memory allocated using dstrdup().
Definition dstring.cpp:422
char * dstrdup(const char *str)
Definition dstring.cpp:415
static bool ok_in_base(char c, int base)
Definition dstring.cpp:152
char * dstrncpy(char *dst, const char *src, size_t len)
Definition dstring.cpp:427
char toLowerChar(char c)
Definition dstring.cpp:24
int dstrnicmp(const char *s1, const char *s2, size_t len)
Definition dstring.cpp:453
DString substitute(const DString &s, const DString &src, const DString &dst)
substitute all occurrences of src in s by dst
Definition dstring.cpp:476
int dstricmp(const char *s1, const char *s2)
Definition dstring.cpp:435
int dstrnicmp(const char *str1, const char *str2, size_t len)
Definition dstring.cpp:453
char * dstrcpy(char *dst, const char *src)
Definition dstring.h:47
int dstrncmp(const char *str1, const char *str2, size_t len)
Definition dstring.h:61
uint32_t dstrlen(const char *str)
Returns the length of string str, or 0 if a null pointer is passed.
Definition dstring.h:44
bool disspace(char c)
Definition dstring.h:67