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