Doxygen
Loading...
Searching...
No Matches
qcstring.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 "qcstring.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
29QCString &QCString::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
43int QCString::find( char c, int index, bool cs ) const
44{
45 if (index<0 || index>=static_cast<int>(length())) return -1; // index outside string
46 const char *pos = nullptr;
47 if (cs)
48 {
49 pos = strchr(data()+index,c);
50 }
51 else
52 {
53 pos = data()+index;
54 c = toLowerChar(c);
55 while (*pos && toLowerChar(*pos)!=c) pos++;
56 if (!*pos && c) pos=nullptr; // not found
57 }
58 return pos ? static_cast<int>(pos - data()) : -1;
59}
60
61int QCString::find( const char *str, int index, bool cs ) const
62{
63 int l = static_cast<int>(length());
64 if (index<0 || index>=l) return -1; // index outside string
65 if (!str) return -1; // no string to search for
66 if (!*str) return index; // empty string matching at index
67 const char *pos = nullptr;
68 if (cs) // case sensitive
69 {
70 pos = strstr(data()+index,str);
71 }
72 else // case insensitive
73 {
74 pos = data();
75 int len = qstrlen(str);
76 while (*pos)
77 {
78 if (qstrnicmp(pos,str,len)==0) break;
79 pos++;
80 }
81 if (!*pos) pos = nullptr; // not found
82 }
83 return pos ? static_cast<int>(pos - data()) : -1;
84}
85
86int QCString::find( const std::string &str, int index, bool cs ) const
87{
88 return find(str.c_str(),index,cs);
89}
90
91int QCString::find( const QCString &str, int index, bool cs ) const
92{
93 return find(str.data(),index,cs);
94}
95
96int QCString::findRev( char c, int index, bool cs) const
97{
98 const char *b = data();
99 const char *pos = nullptr;
100 int len = static_cast<int>(length());
101 if (len==0) return -1; // empty string
102 if (index<0) // start from end
103 {
104 if (cs)
105 {
106 pos = strrchr(b,c);
107 return pos ? static_cast<int>(pos - b) : -1;
108 }
109 index=len;
110 }
111 else if (index>len) // bad index
112 {
113 return -1;
114 }
115 pos = b+index;
116 if (cs)
117 {
118 while ( pos>=b && *pos!=c) pos--;
119 }
120 else
121 {
122 c = toLowerChar(c);
123 while ( pos>=b && toLowerChar(*pos)!=c) pos--;
124 }
125 return pos>=b ? static_cast<int>(pos - b) : -1;
126}
127
128int QCString::findRev( const char *str, int index, bool cs) const
129{
130 int slen = static_cast<int>(qstrlen(str));
131 int len = static_cast<int>(length());
132 if (index<0) index = len-slen; // start from end
133 else if (index>len) return -1; // bad index
134 else if (index+slen>len) index=len-slen; // str would be too long
135 if (index<0) return -1; // no match possible
136 const char *pos = data()+index;
137 if (cs) // case sensitive
138 {
139 for (int i=index; i>=0; i--) if (qstrncmp(pos--,str,slen)==0) return i;
140 }
141 else // case insensitive
142 {
143 for (int i=index; i>=0; i--) if (qstrnicmp(pos,str,slen)==0) return i;
144 }
145 return -1;
146}
147
148int QCString::contains( char c, bool cs ) const
149{
150 if (length()==0) return 0;
151 int count=0;
152 const char *pos = data();
153 if (cs)
154 {
155 while (*pos) if (*pos++ == c) count++;
156 }
157 else
158 {
159 c = toLowerChar(c);
160 while (*pos)
161 {
162 if (toLowerChar(*pos)==c) count++;
163 pos++;
164 }
165 }
166 return count;
167}
168
169int QCString::contains( const char *str, bool cs ) const
170{
171 if (str==nullptr || length()==0) return 0;
172 int count=0;
173 const char *pos = data();
174 int len = qstrlen(str);
175 while (*pos)
176 {
177 if (cs)
178 {
179 if (qstrncmp(pos,str,len)==0) count++;
180 }
181 else
182 {
183 if (qstrnicmp(pos,str,len)==0) count++;
184 }
185 pos++;
186 }
187 return count;
188}
189
191{
192 if ( isEmpty() ) // nothing to do
193 return *this;
194
195 QCString result( length(), ExplicitSize );
196 const char *from = data();
197 char *to = result.rawData();
198 char *first = to;
199 while ( TRUE )
200 {
201 while ( *from && qisspace(*from) )
202 from++;
203 while ( *from && !qisspace(*from) )
204 *to++ = *from++;
205 if ( *from )
206 *to++ = 0x20; // ' '
207 else
208 break;
209 }
210 if ( to > first && *(to-1) == 0x20 )
211 to--;
212 *to = '\0';
213 result.resize( static_cast<int>(to - result.data()) );
214 return result;
215}
216
217QCString &QCString::replace( size_t index, size_t len, const char *s)
218{
219 remove( index, len );
220 insert( index, s );
221 return *this;
222}
223
224static bool ok_in_base( char c, int base )
225{
226 if ( base <= 10 )
227 return c>='0' && c<='9' && (c-'0') < base;
228 else
229 return (c>='0' && c<='9') ||
230 (c >= 'a' && c < char('a'+base-10)) ||
231 (c >= 'A' && c < char('A'+base-10));
232}
233
234short QCString::toShort(bool *ok, int base) const
235{
236 long v = toLong( ok, base );
237 if ( ok && *ok && (v < -32768 || v > 32767) ) {
238 *ok = FALSE;
239 v = 0;
240 }
241 return static_cast<short>(v);
242}
243
244uint16_t QCString::toUShort(bool *ok,int base) const
245{
246 unsigned long v = toULong( ok, base );
247 if ( ok && *ok && (v > 65535) ) {
248 *ok = FALSE;
249 v = 0;
250 }
251 return static_cast<uint16_t>(v);
252}
253
254int QCString::toInt(bool *ok, int base) const
255{
256 return static_cast<int>(toLong( ok, base ));
257}
258
259uint32_t QCString::toUInt(bool *ok,int base) const
260{
261 return static_cast<uint32_t>(toULong( ok, base ));
262}
263
264
265long QCString::toLong(bool *ok,int base) const
266{
267 const char *p = data();
268 long val=0;
269 int l = static_cast<int>(length());
270 const long max_mult = INT_MAX / base;
271 bool is_ok = FALSE;
272 int neg = 0;
273 if ( !p )
274 goto bye;
275 while ( l && qisspace(*p) ) // skip leading space
276 {
277 l--;
278 p++;
279 }
280 if ( l && *p == '-' )
281 {
282 l--;
283 p++;
284 neg = 1;
285 } else if ( *p == '+' )
286 {
287 l--;
288 p++;
289 }
290
291 // NOTE: toULong() code is similar
292 if ( !l || !ok_in_base(*p,base) )
293 {
294 goto bye;
295 }
296 while ( l && ok_in_base(*p,base) )
297 {
298 l--;
299 int dv = 0;
300 if ( *p>='0' && *p<='9' )
301 {
302 dv = *p-'0';
303 }
304 else
305 {
306 if ( *p >= 'a' && *p <= 'z' )
307 {
308 dv = *p - 'a' + 10;
309 }
310 else
311 {
312 dv = *p - 'A' + 10;
313 }
314 }
315 if ( val > max_mult || (val == max_mult && dv > (INT_MAX%base)+neg) )
316 {
317 goto bye;
318 }
319 val = base*val + dv;
320 p++;
321 }
322 if ( neg )
323 {
324 val = -val;
325 }
326 while ( l && qisspace(*p) ) // skip trailing space
327 {
328 l--;
329 p++;
330 }
331 if ( !l )
332 {
333 is_ok = TRUE;
334 }
335bye:
336 if ( ok )
337 {
338 *ok = is_ok;
339 }
340 return is_ok ? val : 0;
341}
342
343unsigned long QCString::toULong(bool *ok,int base) const
344{
345 const char *p = data();
346 unsigned long val=0;
347 int l = static_cast<int>(length());
348 const unsigned long max_mult = 429496729; // UINT_MAX/10, rounded down
349 bool is_ok = FALSE;
350 if ( !p )
351 {
352 goto bye;
353 }
354 while ( l && qisspace(*p) ) // skip leading space
355 {
356 l--;
357 p++;
358 }
359 if ( *p == '+' )
360 {
361 l--;
362 p++;
363 }
364
365 // NOTE: toLong() code is similar
366 if ( !l || !ok_in_base(*p,base) )
367 {
368 goto bye;
369 }
370 while ( l && ok_in_base(*p,base) )
371 {
372 l--;
373 uint32_t dv = 0;
374 if ( *p>='0' && *p<='9' )
375 {
376 dv = *p-'0';
377 }
378 else
379 {
380 if ( *p >= 'a' && *p <= 'z' )
381 {
382 dv = *p - 'a' + 10;
383 }
384 else
385 {
386 dv = *p - 'A' + 10;
387 }
388 }
389 if ( val > max_mult || (val == max_mult && dv > (UINT_MAX%base)) )
390 {
391 goto bye;
392 }
393 val = base*val + dv;
394 p++;
395 }
396
397 while ( l && qisspace(*p) ) // skip trailing space
398 {
399 l--;
400 p++;
401 }
402 if ( !l )
403 {
404 is_ok = TRUE;
405 }
406bye:
407 if ( ok )
408 {
409 *ok = is_ok;
410 }
411 return is_ok ? val : 0;
412}
413
414uint64_t QCString::toUInt64(bool *ok,int base) const
415{
416 const char *p = data();
417 uint64_t val=0;
418 int l = static_cast<int>(length());
419 const uint64_t max_mult = 1844674407370955161ULL; // ULLONG_MAX/10, rounded down
420 bool is_ok = FALSE;
421 if ( !p )
422 {
423 goto bye;
424 }
425 while ( l && qisspace(*p) ) // skip leading space
426 {
427 l--;
428 p++;
429 }
430 if ( *p == '+' )
431 {
432 l--;
433 p++;
434 }
435
436 // NOTE: toULong() code is similar
437 if ( !l || !ok_in_base(*p,base) )
438 {
439 goto bye;
440 }
441 while ( l && ok_in_base(*p,base) )
442 {
443 l--;
444 uint32_t dv = 0;
445 if ( *p>='0' && *p<='9' )
446 {
447 dv = *p-'0';
448 }
449 else
450 {
451 if ( *p >= 'a' && *p <= 'z' )
452 {
453 dv = *p - 'a' + 10;
454 }
455 else
456 {
457 dv = *p - 'A' + 10;
458 }
459 }
460 if ( val > max_mult || (val == max_mult && dv > (ULLONG_MAX%base)) )
461 {
462 goto bye;
463 }
464 val = base*val + dv;
465 p++;
466 }
467
468 while ( l && qisspace(*p) ) // skip trailing space
469 {
470 l--;
471 p++;
472 }
473 if ( !l )
474 {
475 is_ok = TRUE;
476 }
477bye:
478 if ( ok )
479 {
480 *ok = is_ok;
481 }
482 return is_ok ? val : 0;
483}
484
485//-------------------------------------------------
486
487void *qmemmove( void *dst, const void *src, size_t len )
488{
489 if ( dst > src )
490 {
491 char *d = static_cast<char *>(dst) + len - 1;
492 const char *s = static_cast<const char *>(src) + len - 1;
493 while ( len-- )
494 {
495 *d-- = *s--;
496 }
497 }
498 else if ( dst < src )
499 {
500 char *d = static_cast<char *>(dst);
501 const char *s = static_cast<const char *>(src);
502 while ( len-- )
503 {
504 *d++ = *s++;
505 }
506 }
507 return dst;
508}
509
510char *qstrdup( const char *str )
511{
512 if ( !str ) return nullptr;
513 char *dst = new char[qstrlen(str)+1];
514 return strcpy( dst, str );
515}
516
517void qstrfree( const char *str )
518{
519 delete [](str);
520}
521
522char *qstrncpy( char *dst, const char *src, size_t len )
523{
524 if ( !src ) return nullptr;
525 strncpy( dst, src, len );
526 if ( len > 0 ) dst[len-1] = '\0';
527 return dst;
528}
529
530int qstricmp( const char *s1, const char *s2 )
531{
532 if ( !s1 || !s2 )
533 {
534 return s1 == s2 ? 0 : static_cast<int>(s2 - s1);
535 }
536 int res = 0;
537 char c = 0;
538 for ( ; !(res = ((c=toLowerChar(*s1)) - toLowerChar(*s2))); s1++, s2++ )
539 {
540 if ( !c ) // strings are equal
541 {
542 break;
543 }
544 }
545 return res;
546}
547
548int qstrnicmp( const char *s1, const char *s2, size_t len )
549{
550 if ( !s1 || !s2 )
551 {
552 return static_cast<int>(s2 - s1);
553 }
554 for ( ; len--; s1++, s2++ )
555 {
556 char c = toLowerChar(*s1);
557 int res = c-toLowerChar(*s2);
558 if ( res!=0 ) // strings are not equal
559 {
560 return res;
561 }
562 if ( c==0 ) // strings are equal
563 {
564 break;
565 }
566 }
567 return 0;
568}
569
570/// substitute all occurrences of \a src in \a s by \a dst
571QCString substitute(const QCString &s,const QCString &src,const QCString &dst)
572{
573 if (s.isEmpty() || src.isEmpty()) return s;
574 const char *q = nullptr, *p = nullptr;
575 size_t srcLen = src.length();
576 size_t dstLen = dst.length();
577 size_t resLen = 0;
578 if (srcLen!=dstLen)
579 {
580 int count = 0;
581 for (p = s.data(); (q=strstr(p,src.data()))!=nullptr; p=q+srcLen) count++;
582 resLen = s.length()+count*(dstLen-srcLen);
583 }
584 else // result has same size as s
585 {
586 resLen = s.length();
587 }
588 QCString result(resLen, QCString::ExplicitSize);
589 char *r = result.rawData();
590 for (p = s.data(); (q=strstr(p,src.data()))!=nullptr; p=q+srcLen)
591 {
592 int l = static_cast<int>(q-p);
593 memcpy(r,p,l);
594 r+=l;
595
596 if (dstLen>0) memcpy(r,dst.data(),dstLen);
597 r+=dstLen;
598 }
599 if (r)
600 {
601 qstrcpy(r,p);
602 }
603 //printf("substitute(%s,%s,%s)->%s\n",s,src,dst,result.data());
604 return result;
605}
606
607
608/// substitute all occurrences of \a src in \a s by \a dst, but skip
609/// each consecutive sequence of \a src where the number consecutive
610/// \a src matches \a skip_seq; if \a skip_seq is negative, skip any
611/// number of consecutive \a src
612QCString substitute(const QCString &s,const QCString &src,const QCString &dst,int skip_seq)
613{
614 if (s.isEmpty() || src.isEmpty()) return s;
615 const char *p = nullptr, *q = nullptr;
616 size_t srcLen = src.length();
617 size_t dstLen = dst.length();
618 size_t resLen = 0;
619 if (srcLen!=dstLen)
620 {
621 int count = 0;
622 for (p=s.data(); (q=strstr(p,src.data()))!=nullptr; p=q+srcLen) count++;
623 resLen = s.length()+count*(dstLen-srcLen);
624 }
625 else // result has same size as s
626 {
627 resLen = s.length();
628 }
629 QCString result(resLen, QCString::ExplicitSize);
630 char *r = result.rawData();
631 for (p = s.data(); (q=strstr(p,src.data()))!=nullptr; p=q+srcLen)
632 {
633 // search a consecutive sequence of src
634 int seq = 0, skip = 0;
635 if (skip_seq)
636 {
637 for (const char *n=q+srcLen; qstrncmp(n,src.data(),srcLen)==0; seq=1+skip, n+=srcLen)
638 ++skip; // number of consecutive src after the current one
639
640 // verify the allowed number of consecutive src to skip
641 if (skip_seq > 0 && skip_seq != seq)
642 seq = skip = 0;
643 }
644
645 // skip a consecutive sequence of src when necessary
646 int l = static_cast<int>((q + seq * srcLen)-p);
647 memcpy(r,p,l);
648 r+=l;
649
650 if (skip)
651 {
652 // skip only the consecutive src found after the current one
653 q += skip * srcLen;
654 // the next loop will skip the current src, aka (p=q+srcLen)
655 continue;
656 }
657
658 if (dstLen>0) memcpy(r,dst.data(),dstLen);
659 r+=dstLen;
660 }
661 qstrcpy(r,p);
662 result.resize(strlen(result.data()));
663 //printf("substitute(%s,%s,%s)->%s\n",s,src,dst,result.data());
664 return result;
665}
666
668{
669 if (isEmpty()) return QCString();
670 const std::string &s = m_rep;
671 int end=static_cast<int>(s.length());
672 int start=0,p=0;
673 // skip leading empty lines
674 for (;;)
675 {
676 int c;
677 while ((c=s[p]) && (c==' ' || c=='\t')) p++;
678 if (s[p]=='\n')
679 {
680 start=++p;
681 }
682 else
683 {
684 break;
685 }
686 }
687 // skip trailing empty lines
688 p=end-1;
689 if (p>=start && s.at(p)=='\n') p--;
690 while (p>=start)
691 {
692 int c;
693 while ((c=s[p]) && (c==' ' || c=='\t')) p--;
694 if (s[p]=='\n')
695 {
696 end=p+1;
697 }
698 else
699 {
700 break;
701 }
702 p--;
703 }
704 //printf("stripLeadingAndTrailingEmptyLines(%d-%d)\n",start,end);
705 return s.substr(start,end-start);
706}
707
This is an alternative implementation of QCString.
Definition qcstring.h:101
int find(char c, int index=0, bool cs=TRUE) const
Definition qcstring.cpp:43
int toInt(bool *ok=nullptr, int base=10) const
Definition qcstring.cpp:254
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:166
uint64_t toUInt64(bool *ok=nullptr, int base=10) const
Definition qcstring.cpp:414
unsigned long toULong(bool *ok=nullptr, int base=10) const
Definition qcstring.cpp:343
char * rawData()
Returns a writable pointer to the data.
Definition qcstring.h:178
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:163
QCString stripLeadingAndTrailingEmptyLines() const
Definition qcstring.cpp:667
QCString & remove(size_t index, size_t len)
Definition qcstring.h:442
void resize(size_t newlen)
Definition qcstring.h:180
std::string m_rep
Definition qcstring.h:615
const std::string & str() const
Definition qcstring.h:552
uint16_t toUShort(bool *ok=nullptr, int base=10) const
Definition qcstring.cpp:244
QCString simplifyWhiteSpace() const
return a copy of this string with leading and trailing whitespace removed and multiple whitespace cha...
Definition qcstring.cpp:190
QCString & sprintf(const char *format,...)
Definition qcstring.cpp:29
long toLong(bool *ok=nullptr, int base=10) const
Definition qcstring.cpp:265
@ ExplicitSize
Definition qcstring.h:146
uint32_t toUInt(bool *ok=nullptr, int base=10) const
Definition qcstring.cpp:259
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition qcstring.cpp:96
QCString & replace(size_t index, size_t len, const char *s)
Definition qcstring.cpp:217
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:172
QCString()=default
QCString & insert(size_t index, const QCString &s)
Definition qcstring.h:332
int contains(char c, bool cs=TRUE) const
Definition qcstring.cpp:148
short toShort(bool *ok=nullptr, int base=10) const
Definition qcstring.cpp:234
DirIterator end(const DirIterator &) noexcept
Definition dir.cpp:175
char * qstrdup(const char *str)
Definition qcstring.cpp:510
char * qstrncpy(char *dst, const char *src, size_t len)
Definition qcstring.cpp:522
static bool ok_in_base(char c, int base)
Definition qcstring.cpp:224
char toLowerChar(char c)
Definition qcstring.cpp:24
int qstricmp(const char *s1, const char *s2)
Definition qcstring.cpp:530
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition qcstring.cpp:571
void qstrfree(const char *str)
Frees the memory allocated using qstrdup().
Definition qcstring.cpp:517
void * qmemmove(void *dst, const void *src, size_t len)
Definition qcstring.cpp:487
int qstrnicmp(const char *s1, const char *s2, size_t len)
Definition qcstring.cpp:548
int qstrncmp(const char *str1, const char *str2, size_t len)
Definition qcstring.h:75
bool qisspace(char c)
Definition qcstring.h:81
int qstrnicmp(const char *str1, const char *str2, size_t len)
Definition qcstring.cpp:548
#define TRUE
Definition qcstring.h:37
#define FALSE
Definition qcstring.h:34
uint32_t qstrlen(const char *str)
Returns the length of string str, or 0 if a null pointer is passed.
Definition qcstring.h:58
char * qstrcpy(char *dst, const char *src)
Definition qcstring.h:61