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