Imported Upstream version 1.8.15
[platform/upstream/doxygen.git] / qtools / 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 #include "qgstring.h"
18
19 #include <qstring.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <ctype.h>
24 #include <qregexp.h>
25 #include <qdatastream.h>
26
27 QCString &QCString::sprintf( const char *format, ... )
28 {
29   va_list ap;
30   va_start( ap, format );
31   const int minlen=256;
32   int l = length();
33   if (l<minlen) { resize(minlen); l=minlen; }
34   int n=vsnprintf( rawData(), l, format, ap);
35   if (n<0) n=l;
36   resize(n+1);
37   va_end( ap );
38   return *this;
39 }
40
41 int QCString::find( char c, int index, bool cs ) const
42 {
43   if (index<0 || index>=(int)length()) return -1; // index outside string
44   const char *pos;
45   if (cs)
46   {
47     pos = strchr(data()+index,c);
48   }
49   else
50   {
51     pos = data()+index;
52     c = tolower((unsigned char)c);
53     while (*pos && tolower((unsigned char)*pos)!=c) pos++;
54     if (!*pos && c) pos=0; // not found
55   }
56   return pos ? (int)(pos - data()) : -1;
57 }
58
59 int QCString::find( const char *str, int index, bool cs ) const
60 {
61   int l = length();
62   if (index<0 || index>=l) return -1; // index outside string
63   if (!str)  return -1;               // no string to search for
64   if (!*str) return index;           // empty string matching at index
65   const char *pos;
66   if (cs) // case sensitive
67   {
68     pos = strstr(data()+index,str);
69   }
70   else // case insensitive
71   {
72     pos = data();
73     int len = qstrlen(str);
74     while (*pos)
75     {
76       if (qstrnicmp(pos,str,len)==0) break;
77       pos++;
78     }
79     if (!*pos) pos = 0; // not found
80   }
81   return pos ? (int)(pos - data()) : -1;
82 }
83
84 int QCString::find( const QCString &str, int index, bool cs ) const
85 {
86   return find(str.data(),index,cs);
87 }
88
89 int QCString::find( const QRegExp &rx, int index ) const
90 {
91   QString d = QString::fromLatin1( data() );
92   return d.find( rx, index );
93 }
94
95 int QCString::findRev( char c, int index, bool cs) const
96 {
97   const char *b = data();
98   const char *pos;
99   int len = length();
100   if (len==0) return -1; // empty string
101   if (index<0) // start from end
102   {
103     if (cs)
104     {
105       pos = strrchr(b,c);
106       return pos ? (int)(pos - b) : -1;
107     }
108     index=len;
109   }
110   else if (index>len) // bad index
111   {
112     return -1;
113   }
114   pos = b+index;
115   if (cs)
116   {
117     while ( pos>=b && *pos!=c) pos--;
118   }
119   else
120   {
121     c = tolower((unsigned char)c);
122     while ( pos>=b && tolower((unsigned char)*pos)!=c) pos--;
123   }
124   return pos>=b ? (int)(pos - b) : -1;
125 }
126
127 int QCString::findRev( const char *str, int index, bool cs) const
128 {
129   int slen = qstrlen(str);
130   int len = length();
131   if (index<0) index = len-slen; // start from end
132   else if (index>len) return -1; // bad index
133   else if (index+slen>len) index=len-slen; // str would be too long
134   if (index<0) return -1; // no match possible
135   const char *pos = data()+index;
136   if (cs) // case sensitive
137   {
138     for (int i=index; i>=0; i--) if (qstrncmp(pos--,str,slen)==0) return i;
139   }
140   else // case insensitive
141   {
142     for (int i=index; i>=0; i--) if (qstrnicmp(pos,str,slen)==0) return i;
143   }
144   return -1;
145 }
146
147 int QCString::findRev( const QRegExp &rx, int index ) const
148 {
149   QString d = QString::fromLatin1( data() );
150   return d.findRev( rx, index );
151 }
152
153 int QCString::contains( char c, bool cs ) const
154 {
155   if (length()==0) return 0;
156   int count=0;
157   const char *pos = data();
158   if (cs)
159   {
160     while (*pos) if (*pos++ == c) count++;
161   }
162   else
163   {
164     c = tolower((unsigned char)c);
165     while (*pos)
166     {
167       if (tolower((unsigned char)*pos)==c) count++;
168       pos++;
169     }
170   }
171   return count;
172 }
173
174 int QCString::contains( const char *str, bool cs ) const
175 {
176   if (str==0 || length()==0) return 0;
177   int count=0;
178   const char *pos = data();
179   int len = qstrlen(str);
180   while (*pos)
181   {
182     if (cs)
183     {
184       if (qstrncmp(pos,str,len)==0) count++;
185     }
186     else
187     {
188       if (qstrnicmp(pos,str,len)==0) count++;
189     }
190     pos++;
191   }
192   return count;
193 }
194
195 int QCString::contains( const QRegExp &rx ) const
196 {
197   QString d = QString::fromLatin1( data() );
198   return d.contains( rx );
199 }
200
201 bool QCString::stripPrefix(const char *prefix)
202 {
203   if (prefix==0 || length()==0) return FALSE;
204   int len = qstrlen(prefix);
205   if (qstrncmp(prefix,data(),len)==0)
206   {
207     m_rep=mid(len,length()-len).m_rep; // need to make a deep copy
208     return TRUE;
209   }
210   return FALSE;
211 }
212
213 QCString QCString::left( uint len )  const
214 {
215   if (isEmpty())
216   {
217     return QCString();
218   }
219   else if (len>=length())
220   {
221     return QCString(data());
222   }
223   else
224   {
225     QCString s( len+1 );
226     memcpy( s.rawData(), data(), len);
227     return s;
228   }
229 }
230
231 QCString QCString::right( uint len ) const
232 {
233   if (isEmpty())
234   {
235     return QCString();
236   }
237   else
238   {
239     int l = length();
240     if ((int)len>l) len=l;
241     const char *pos = data() + (l-len);
242     return QCString(pos);
243   }
244 }
245
246 QCString QCString::mid( uint index, uint len) const
247 {
248   uint slen = (uint)length();
249   if (len==0xffffffff) len = slen-index;
250   if (isEmpty() || index>=slen || len==0)
251   {
252     return QCString();
253   }
254   else
255   {
256     const char *p = data()+index;
257     QCString s(len+1);
258     qstrncpy( s.rawData(), p, len+1 );
259     return s;
260   }
261 }
262
263 QCString QCString::lower() const
264 {
265   if (length()==0) return QCString();
266   QCString s(data());
267   char *pos = s.rawData();
268   if (pos)
269   {
270     while (*pos)
271     {
272       *pos = tolower((unsigned char)*pos);
273       pos++;
274     }
275   }
276   return s;
277 }
278
279 QCString QCString::upper() const
280 {
281   if (length()==0) return QCString();
282   QCString s(data());
283   char *pos = s.rawData();
284   if (pos)
285   {
286     while (*pos)
287     {
288       *pos = toupper((unsigned char)*pos);
289       pos++;
290     }
291   }
292   return s;
293 }
294
295 QCString QCString::stripWhiteSpace() const
296 {
297   if ( isEmpty() )                            // nothing to do
298     return *this;
299
300   const char *cs = data();
301   int reslen = length();
302   if ( !isspace((uchar)cs[0]) && !isspace((uchar)cs[reslen-1]) )
303     return *this;                             // returns a copy
304
305   QCString result(cs);
306   char *s = result.rawData();
307   int start = 0;
308   int end = reslen - 1;
309   while ( isspace((uchar) s[start]) )                 // skip white space from start
310     start++;
311   if ( s[start] == '\0' )
312   {                                                   // only white space
313     return QCString();
314   }
315   while ( end && isspace((uchar) s[end]) )            // skip white space from end
316     end--;
317   end -= start - 1;
318   qmemmove( s, &s[start], end );
319   result.resize( end + 1 );
320   return result;
321 }
322
323 QCString QCString::simplifyWhiteSpace() const
324 {
325   if ( isEmpty() )                            // nothing to do
326     return *this;
327
328   QCString result( length()+1 );
329   const char *from  = data();
330   char *to    = result.rawData();
331   char *first = to;
332   while ( TRUE )
333   {
334     while ( *from && isspace((uchar) *from) )
335       from++;
336     while ( *from && !isspace((uchar)*from) )
337       *to++ = *from++;
338     if ( *from )
339       *to++ = 0x20;                       // ' '
340     else
341       break;
342   }
343   if ( to > first && *(to-1) == 0x20 )
344     to--;
345   *to = '\0';
346   result.resize( (int)((long)to - (long)result.data()) + 1 );
347   return result;
348 }
349
350 QCString &QCString::assign( const char *str )
351 {
352   return operator=(str);
353 }
354
355 QCString &QCString::insert( uint index, const char *s )
356 {
357   int len = s ? qstrlen(s) : 0;
358   if ( len == 0 ) return *this;
359   int olen = length();
360   int nlen = olen + len;
361   if ((int)index>=olen)
362   {
363     resize(nlen+index-olen+1);
364     memset(rawData()+olen, ' ', index-olen);
365     memcpy(rawData()+index,s, len+1);
366   }
367   else
368   {
369     resize(nlen+1);
370     qmemmove(rawData()+index+len,data()+index,olen-index+1);
371     memcpy(rawData()+index,s,len);
372   }
373   return *this;
374 }
375
376 QCString &QCString::insert( uint index, char c)
377 {
378   char buf[2];
379   buf[0] = c;
380   buf[1] = '\0';
381   return insert( index, buf );
382 }
383 QCString &QCString::append( const char *s )
384 {
385   return operator+=(s);
386 }
387 QCString &QCString::prepend( const char *s )
388 {
389   return insert(0,s);
390 }
391 QCString &QCString::remove( uint index, uint len )
392 {
393   uint olen = length();
394   if ( index + len >= olen ) // range problems
395   {
396     if ( index < olen )  // index ok
397     {
398       resize( index+1 );
399     }
400   }
401   else if ( len != 0 )
402   {
403     QCString tmp(olen-index-len+1);
404     qmemmove( tmp.rawData(), data()+index+len, olen-index-len+1 );
405     resize( olen-len+1 );
406     memcpy( rawData()+index,tmp.data(),tmp.length() );
407   }
408   return *this;
409 }
410
411 QCString &QCString::replace( uint index, uint len, const char *s)
412 {
413   remove( index, len );
414   insert( index, s );
415   return *this;
416 }
417
418 QCString &QCString::replace( const QRegExp &rx, const char *str )
419 {
420   QString d = QString::fromLatin1( data() );
421   QString r = QString::fromLatin1( str );
422   d.replace( rx, r );
423   operator=( d.ascii() );
424   return *this;
425 }
426
427 short QCString::toShort(bool *ok) const
428 {
429   QString s(data());
430   return s.toShort(ok);
431 }
432
433 ushort QCString::toUShort(bool *ok) const
434 {
435   QString s(data());
436   return s.toUShort(ok);
437 }
438
439 int QCString::toInt(bool *ok) const
440 {
441   QString s(data());
442   return s.toInt(ok);
443 }
444
445 uint QCString::toUInt(bool *ok) const
446 {
447   QString s(data());
448   return s.toUInt(ok);
449 }
450
451 long QCString::toLong(bool *ok) const
452 {
453   QString s(data());
454   return s.toLong(ok);
455 }
456
457 ulong QCString::toULong(bool *ok) const
458 {
459   QString s(data());
460   return s.toULong(ok);
461 }
462
463 uint64 QCString::toUInt64(bool *ok) const
464 {
465   QString s(data());
466   return s.toUInt64(ok);
467 }
468
469 QCString &QCString::setNum(short n)
470 {
471   return setNum((long)n);
472 }
473
474 QCString &QCString::setNum(ushort n)
475 {
476   return setNum((ulong)n);
477 }
478
479 QCString &QCString::setNum(int n)
480 {
481   return setNum((long)n);
482 }
483
484 QCString &QCString::setNum(uint n)
485 {
486   return setNum((ulong)n);
487 }
488
489 QCString &QCString::setNum(long n)
490 {
491   char buf[20];
492   char *p = &buf[19];
493   bool neg;
494   if ( n < 0 )
495   {
496     neg = TRUE;
497     n = -n;
498   }
499   else
500   {
501     neg = FALSE;
502   }
503   *p = '\0';
504   do
505   {
506     *--p = ((int)(n%10)) + '0';
507     n /= 10;
508   } while ( n );
509   if ( neg ) *--p = '-';
510   operator=( p );
511   return *this;
512 }
513
514 QCString &QCString::setNum( ulong n)
515 {
516   char buf[20];
517   char *p = &buf[19];
518   *p = '\0';
519   do
520   {
521     *--p = ((int)(n%10)) + '0';
522     n /= 10;
523   } while ( n );
524   operator=( p );
525   return *this;
526 }
527
528 //-------------------------------------------------
529
530 void *qmemmove( void *dst, const void *src, uint len )
531 {
532     char *d;
533     char *s;
534     if ( dst > src ) {
535         d = (char *)dst + len - 1;
536         s = (char *)src + len - 1;
537         while ( len-- )
538             *d-- = *s--;
539     } else if ( dst < src ) {
540         d = (char *)dst;
541         s = (char *)src;
542         while ( len-- )
543             *d++ = *s++;
544     }
545     return dst;
546 }
547
548 char *qstrdup( const char *str )
549 {
550     if ( !str )
551         return 0;
552     char *dst = new char[qstrlen(str)+1];
553     CHECK_PTR( dst );
554     return strcpy( dst, str );
555 }
556
557 char *qstrncpy( char *dst, const char *src, uint len )
558 {
559     if ( !src )
560         return 0;
561     strncpy( dst, src, len );
562     if ( len > 0 )
563         dst[len-1] = '\0';
564     return dst;
565 }
566
567 int qstricmp( const char *str1, const char *str2 )
568 {
569     const uchar *s1 = (const uchar *)str1;
570     const uchar *s2 = (const uchar *)str2;
571     int res;
572     uchar c;
573     if ( !s1 || !s2 )
574         return s1 == s2 ? 0 : (int)((long)s2 - (long)s1);
575     for ( ; !(res = (c=tolower(*s1)) - tolower(*s2)); s1++, s2++ )
576         if ( !c )                               // strings are equal
577             break;
578     return res;
579 }
580
581 int qstrnicmp( const char *str1, const char *str2, uint len )
582 {
583     const uchar *s1 = (const uchar *)str1;
584     const uchar *s2 = (const uchar *)str2;
585     int res;
586     uchar c;
587     if ( !s1 || !s2 )
588         return (int)((long)s2 - (long)s1);
589     for ( ; len--; s1++, s2++ ) {
590         if ( (res = (c=tolower(*s1)) - tolower(*s2)) )
591             return res;
592         if ( !c )                               // strings are equal
593             break;
594     }
595     return 0;
596 }
597
598 #ifndef QT_NO_DATASTREAM
599
600 QDataStream &operator<<( QDataStream &s, const QByteArray &a )
601 {
602     return s.writeBytes( a.data(), a.size() );
603 }
604
605 QDataStream &operator>>( QDataStream &s, QByteArray &a )
606 {
607     Q_UINT32 len;
608     s >> len;                                   // read size of array
609     if ( len == 0 || s.eof() ) {                // end of file reached
610         a.resize( 0 );
611         return s;
612     }
613     if ( !a.resize( (uint)len ) ) {             // resize array
614 #if defined(CHECK_NULL)
615         qWarning( "QDataStream: Not enough memory to read QByteArray" );
616 #endif
617         len = 0;
618     }
619     if ( len > 0 )                              // not null array
620         s.readRawBytes( a.data(), (uint)len );
621     return s;
622 }
623
624 QDataStream &operator<<( QDataStream &s, const QCString &str )
625 {
626     return s.writeBytes( str.data(), str.size() );
627 }
628
629 QDataStream &operator>>( QDataStream &s, QCString &str )
630 {
631     Q_UINT32 len;
632     s >> len;                                   // read size of string
633     if ( len == 0 || s.eof() ) {                // end of file reached
634         str.resize( 0 );
635         return s;
636     }
637     if ( !str.resize( (uint)len )) {// resize string
638 #if defined(CHECK_NULL)
639         qWarning( "QDataStream: Not enough memory to read QCString" );
640 #endif
641         len = 0;
642     }
643     if ( len > 0 )                              // not null array
644         s.readRawBytes( str.rawData(), (uint)len );
645     return s;
646 }
647
648 #endif //QT_NO_DATASTREAM
649
650 inline QCString operator+( const QCString &s1, const QGString &s2 )
651 {
652     QCString tmp(s1);
653     tmp += s2.data();
654     return tmp;
655 }
656
657 inline QCString operator+( const QGString &s1, const QCString &s2 )
658 {
659     QCString tmp(s1.data());
660     tmp += s2;
661     return tmp;
662 }
663