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 l--,p++;
277 if ( l && *p == '-' ) {
278 l--;
279 p++;
280 neg = 1;
281 } else if ( *p == '+' ) {
282 l--;
283 p++;
284 }
285
286 // NOTE: toULong() code is similar
287 if ( !l || !ok_in_base(*p,base) )
288 goto bye;
289 while ( l && ok_in_base(*p,base) ) {
290 l--;
291 int dv = 0;
292 if ( *p>='0' && *p<='9' ) {
293 dv = *p-'0';
294 } else {
295 if ( *p >= 'a' && *p <= 'z' )
296 dv = *p - 'a' + 10;
297 else
298 dv = *p - 'A' + 10;
299 }
300 if ( val > max_mult || (val == max_mult && dv > (INT_MAX%base)+neg) )
301 goto bye;
302 val = base*val + dv;
303 p++;
304 }
305 if ( neg )
306 val = -val;
307 while ( l && qisspace(*p) ) // skip trailing space
308 l--,p++;
309 if ( !l )
310 is_ok = TRUE;
311bye:
312 if ( ok )
313 *ok = is_ok;
314 return is_ok ? val : 0;
315}
316
317unsigned long QCString::toULong(bool *ok,int base) const
318{
319 const char *p = data();
320 unsigned long val=0;
321 int l = static_cast<int>(length());
322 const unsigned long max_mult = 429496729; // UINT_MAX/10, rounded down
323 bool is_ok = FALSE;
324 if ( !p )
325 goto bye;
326 while ( l && qisspace(*p) ) // skip leading space
327 l--,p++;
328 if ( *p == '+' )
329 l--,p++;
330
331 // NOTE: toLong() code is similar
332 if ( !l || !ok_in_base(*p,base) )
333 goto bye;
334 while ( l && ok_in_base(*p,base) ) {
335 l--;
336 uint32_t dv = 0;
337 if ( *p>='0' && *p<='9' ) {
338 dv = *p-'0';
339 } else {
340 if ( *p >= 'a' && *p <= 'z' )
341 dv = *p - 'a' + 10;
342 else
343 dv = *p - 'A' + 10;
344 }
345 if ( val > max_mult || (val == max_mult && dv > (UINT_MAX%base)) )
346 goto bye;
347 val = base*val + dv;
348 p++;
349 }
350
351 while ( l && qisspace(*p) ) // skip trailing space
352 l--,p++;
353 if ( !l )
354 is_ok = TRUE;
355bye:
356 if ( ok )
357 *ok = is_ok;
358 return is_ok ? val : 0;
359}
360
361uint64_t QCString::toUInt64(bool *ok,int base) const
362{
363 const char *p = data();
364 uint64_t val=0;
365 int l = static_cast<int>(length());
366 const uint64_t max_mult = 1844674407370955161ULL; // ULLONG_MAX/10, rounded down
367 bool is_ok = FALSE;
368 if ( !p )
369 goto bye;
370 while ( l && qisspace(*p) ) // skip leading space
371 l--,p++;
372 if ( *p == '+' )
373 l--,p++;
374
375 // NOTE: toULong() code is similar
376 if ( !l || !ok_in_base(*p,base) )
377 goto bye;
378 while ( l && ok_in_base(*p,base) ) {
379 l--;
380 uint32_t dv = 0;
381 if ( *p>='0' && *p<='9' ) {
382 dv = *p-'0';
383 } else {
384 if ( *p >= 'a' && *p <= 'z' )
385 dv = *p - 'a' + 10;
386 else
387 dv = *p - 'A' + 10;
388 }
389 if ( val > max_mult || (val == max_mult && dv > (ULLONG_MAX%base)) )
390 goto bye;
391 val = base*val + dv;
392 p++;
393 }
394
395 while ( l && qisspace(*p) ) // skip trailing space
396 l--,p++;
397 if ( !l )
398 is_ok = TRUE;
399bye:
400 if ( ok )
401 *ok = is_ok;
402 return is_ok ? val : 0;
403}
404
405//-------------------------------------------------
406
407void *qmemmove( void *dst, const void *src, size_t len )
408{
409 if ( dst > src ) {
410 char *d = static_cast<char *>(dst) + len - 1;
411 const char *s = static_cast<const char *>(src) + len - 1;
412 while ( len-- )
413 *d-- = *s--;
414 }
415 else if ( dst < src ) {
416 char *d = static_cast<char *>(dst);
417 const char *s = static_cast<const char *>(src);
418 while ( len-- )
419 *d++ = *s++;
420 }
421 return dst;
422}
423
424char *qstrdup( const char *str )
425{
426 if ( !str )
427 return nullptr;
428 char *dst = new char[qstrlen(str)+1];
429 return strcpy( dst, str );
430}
431
432void qstrfree( const char *str )
433{
434 delete[](str);
435}
436
437char *qstrncpy( char *dst, const char *src, size_t len )
438{
439 if ( !src )
440 return nullptr;
441 strncpy( dst, src, len );
442 if ( len > 0 )
443 dst[len-1] = '\0';
444 return dst;
445}
446
447int qstricmp( const char *s1, const char *s2 )
448{
449 if ( !s1 || !s2 )
450 {
451 return s1 == s2 ? 0 : static_cast<int>(s2 - s1);
452 }
453 int res = 0;
454 char c = 0;
455 for ( ; !(res = ((c=toLowerChar(*s1)) - toLowerChar(*s2))); s1++, s2++ )
456 {
457 if ( !c ) // strings are equal
458 break;
459 }
460 return res;
461}
462
463int qstrnicmp( const char *s1, const char *s2, size_t len )
464{
465 if ( !s1 || !s2 )
466 {
467 return static_cast<int>(s2 - s1);
468 }
469 for ( ; len--; s1++, s2++ )
470 {
471 char c = toLowerChar(*s1);
472 int res = c-toLowerChar(*s2);
473 if ( res!=0 ) // strings are not equal
474 return res;
475 if ( c==0 ) // strings are equal
476 break;
477 }
478 return 0;
479}
480
481/// substitute all occurrences of \a src in \a s by \a dst
482QCString substitute(const QCString &s,const QCString &src,const QCString &dst)
483{
484 if (s.isEmpty() || src.isEmpty()) return s;
485 const char *q = nullptr, *p = nullptr;
486 size_t srcLen = src.length();
487 size_t dstLen = dst.length();
488 size_t resLen = 0;
489 if (srcLen!=dstLen)
490 {
491 int count = 0;
492 for (p = s.data(); (q=strstr(p,src.data()))!=nullptr; p=q+srcLen) count++;
493 resLen = s.length()+count*(dstLen-srcLen);
494 }
495 else // result has same size as s
496 {
497 resLen = s.length();
498 }
499 QCString result(resLen, QCString::ExplicitSize);
500 char *r = result.rawData();
501 for (p = s.data(); (q=strstr(p,src.data()))!=nullptr; p=q+srcLen)
502 {
503 int l = static_cast<int>(q-p);
504 memcpy(r,p,l);
505 r+=l;
506
507 if (dstLen>0) memcpy(r,dst.data(),dstLen);
508 r+=dstLen;
509 }
510 if (r)
511 {
512 qstrcpy(r,p);
513 }
514 //printf("substitute(%s,%s,%s)->%s\n",s,src,dst,result.data());
515 return result;
516}
517
518
519/// substitute all occurrences of \a src in \a s by \a dst, but skip
520/// each consecutive sequence of \a src where the number consecutive
521/// \a src matches \a skip_seq; if \a skip_seq is negative, skip any
522/// number of consecutive \a src
523QCString substitute(const QCString &s,const QCString &src,const QCString &dst,int skip_seq)
524{
525 if (s.isEmpty() || src.isEmpty()) return s;
526 const char *p = nullptr, *q = nullptr;
527 size_t srcLen = src.length();
528 size_t dstLen = dst.length();
529 size_t resLen = 0;
530 if (srcLen!=dstLen)
531 {
532 int count = 0;
533 for (p=s.data(); (q=strstr(p,src.data()))!=nullptr; p=q+srcLen) count++;
534 resLen = s.length()+count*(dstLen-srcLen);
535 }
536 else // result has same size as s
537 {
538 resLen = s.length();
539 }
540 QCString result(resLen, QCString::ExplicitSize);
541 char *r = result.rawData();
542 for (p = s.data(); (q=strstr(p,src.data()))!=nullptr; p=q+srcLen)
543 {
544 // search a consecutive sequence of src
545 int seq = 0, skip = 0;
546 if (skip_seq)
547 {
548 for (const char *n=q+srcLen; qstrncmp(n,src.data(),srcLen)==0; seq=1+skip, n+=srcLen)
549 ++skip; // number of consecutive src after the current one
550
551 // verify the allowed number of consecutive src to skip
552 if (skip_seq > 0 && skip_seq != seq)
553 seq = skip = 0;
554 }
555
556 // skip a consecutive sequence of src when necessary
557 int l = static_cast<int>((q + seq * srcLen)-p);
558 memcpy(r,p,l);
559 r+=l;
560
561 if (skip)
562 {
563 // skip only the consecutive src found after the current one
564 q += skip * srcLen;
565 // the next loop will skip the current src, aka (p=q+srcLen)
566 continue;
567 }
568
569 if (dstLen>0) memcpy(r,dst.data(),dstLen);
570 r+=dstLen;
571 }
572 qstrcpy(r,p);
573 result.resize(strlen(result.data()));
574 //printf("substitute(%s,%s,%s)->%s\n",s,src,dst,result.data());
575 return result;
576}
577
579{
580 if (isEmpty()) return QCString();
581 const std::string &s = m_rep;
582 int end=static_cast<int>(s.length());
583 int start=0,p=0;
584 // skip leading empty lines
585 for (;;)
586 {
587 int c;
588 while ((c=s[p]) && (c==' ' || c=='\t')) p++;
589 if (s[p]=='\n')
590 {
591 start=++p;
592 }
593 else
594 {
595 break;
596 }
597 }
598 // skip trailing empty lines
599 p=end-1;
600 if (p>=start && s.at(p)=='\n') p--;
601 while (p>=start)
602 {
603 int c;
604 while ((c=s[p]) && (c==' ' || c=='\t')) p--;
605 if (s[p]=='\n')
606 {
607 end=p+1;
608 }
609 else
610 {
611 break;
612 }
613 p--;
614 }
615 //printf("stripLeadingAndTrailingEmptyLines(%d-%d)\n",start,end);
616 return s.substr(start,end-start);
617}
618
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:361
unsigned long toULong(bool *ok=nullptr, int base=10) const
Definition qcstring.cpp:317
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:578
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:424
char * qstrncpy(char *dst, const char *src, size_t len)
Definition qcstring.cpp:437
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:447
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition qcstring.cpp:482
void qstrfree(const char *str)
Frees the memory allocated using qstrdup().
Definition qcstring.cpp:432
void * qmemmove(void *dst, const void *src, size_t len)
Definition qcstring.cpp:407
int qstrnicmp(const char *s1, const char *s2, size_t len)
Definition qcstring.cpp:463
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:463
#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