diff options
author | Dimitri van Heesch <doxygen@gmail.com> | 2021-03-26 18:18:22 (GMT) |
---|---|---|
committer | Dimitri van Heesch <doxygen@gmail.com> | 2021-03-26 18:18:22 (GMT) |
commit | 1b03538eb097fd32896554749fb6cefc9e195e61 (patch) | |
tree | 5858e3e304c2312cff65fc6f906a9f893aa4caa5 /src/qcstring.cpp | |
parent | 30d9199b4ae662a8d2094f60e4dd4190718dd7c6 (diff) | |
parent | d68805522f642e6c47ad2d285d5cacc3329ce7fd (diff) | |
download | Doxygen-1b03538eb097fd32896554749fb6cefc9e195e61.zip Doxygen-1b03538eb097fd32896554749fb6cefc9e195e61.tar.gz Doxygen-1b03538eb097fd32896554749fb6cefc9e195e61.tar.bz2 |
Merge branch 'qcstring'
Diffstat (limited to 'src/qcstring.cpp')
-rw-r--r-- | src/qcstring.cpp | 560 |
1 files changed, 560 insertions, 0 deletions
diff --git a/src/qcstring.cpp b/src/qcstring.cpp new file mode 100644 index 0000000..2a595cd --- /dev/null +++ b/src/qcstring.cpp @@ -0,0 +1,560 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2015 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + */ + +#include "qcstring.h" + +#include <limits.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <ctype.h> + +QCString &QCString::sprintf( const char *format, ... ) +{ + va_list ap; + va_start( ap, format ); + const int minlen=256; + int l = length(); + if (l<minlen) { resize(minlen); l=minlen; } + int n=vsnprintf( rawData(), l, format, ap); + if (n<0) n=l; + resize(n+1); + va_end( ap ); + return *this; +} + +int QCString::find( char c, int index, bool cs ) const +{ + if (index<0 || index>=(int)length()) return -1; // index outside string + const char *pos; + if (cs) + { + pos = strchr(data()+index,c); + } + else + { + pos = data()+index; + c = tolower((unsigned char)c); + while (*pos && tolower((unsigned char)*pos)!=c) pos++; + if (!*pos && c) pos=0; // not found + } + return pos ? (int)(pos - data()) : -1; +} + +int QCString::find( const char *str, int index, bool cs ) const +{ + int l = length(); + if (index<0 || index>=l) return -1; // index outside string + if (!str) return -1; // no string to search for + if (!*str) return index; // empty string matching at index + const char *pos; + if (cs) // case sensitive + { + pos = strstr(data()+index,str); + } + else // case insensitive + { + pos = data(); + int len = qstrlen(str); + while (*pos) + { + if (qstrnicmp(pos,str,len)==0) break; + pos++; + } + if (!*pos) pos = 0; // not found + } + return pos ? (int)(pos - data()) : -1; +} + +int QCString::find( const QCString &str, int index, bool cs ) const +{ + return find(str.data(),index,cs); +} + +int QCString::findRev( char c, int index, bool cs) const +{ + const char *b = data(); + const char *pos; + int len = length(); + if (len==0) return -1; // empty string + if (index<0) // start from end + { + if (cs) + { + pos = strrchr(b,c); + return pos ? (int)(pos - b) : -1; + } + index=len; + } + else if (index>len) // bad index + { + return -1; + } + pos = b+index; + if (cs) + { + while ( pos>=b && *pos!=c) pos--; + } + else + { + c = tolower((unsigned char)c); + while ( pos>=b && tolower((unsigned char)*pos)!=c) pos--; + } + return pos>=b ? (int)(pos - b) : -1; +} + +int QCString::findRev( const char *str, int index, bool cs) const +{ + int slen = qstrlen(str); + int len = length(); + if (index<0) index = len-slen; // start from end + else if (index>len) return -1; // bad index + else if (index+slen>len) index=len-slen; // str would be too long + if (index<0) return -1; // no match possible + const char *pos = data()+index; + if (cs) // case sensitive + { + for (int i=index; i>=0; i--) if (qstrncmp(pos--,str,slen)==0) return i; + } + else // case insensitive + { + for (int i=index; i>=0; i--) if (qstrnicmp(pos,str,slen)==0) return i; + } + return -1; +} + +int QCString::contains( char c, bool cs ) const +{ + if (length()==0) return 0; + int count=0; + const char *pos = data(); + if (cs) + { + while (*pos) if (*pos++ == c) count++; + } + else + { + c = tolower((unsigned char)c); + while (*pos) + { + if (tolower((unsigned char)*pos)==c) count++; + pos++; + } + } + return count; +} + +int QCString::contains( const char *str, bool cs ) const +{ + if (str==0 || length()==0) return 0; + int count=0; + const char *pos = data(); + int len = qstrlen(str); + while (*pos) + { + if (cs) + { + if (qstrncmp(pos,str,len)==0) count++; + } + else + { + if (qstrnicmp(pos,str,len)==0) count++; + } + pos++; + } + return count; +} + +QCString QCString::simplifyWhiteSpace() const +{ + if ( isEmpty() ) // nothing to do + return *this; + + QCString result( length()+1 ); + const char *from = data(); + char *to = result.rawData(); + char *first = to; + while ( TRUE ) + { + while ( *from && isspace((uchar) *from) ) + from++; + while ( *from && !isspace((uchar)*from) ) + *to++ = *from++; + if ( *from ) + *to++ = 0x20; // ' ' + else + break; + } + if ( to > first && *(to-1) == 0x20 ) + to--; + *to = '\0'; + result.resize( (int)(to - result.data()) + 1 ); + return result; +} + +QCString &QCString::replace( uint index, uint len, const char *s) +{ + remove( index, len ); + insert( index, s ); + return *this; +} + +static bool ok_in_base( char c, int base ) +{ + if ( base <= 10 ) + return c>='0' && c<='9' && (c-'0') < base; + else + return (c>='0' && c<='9') || + (c >= 'a' && c < char('a'+base-10)) || + (c >= 'A' && c < char('A'+base-10)); +} + +short QCString::toShort(bool *ok, int base) const +{ + long v = toLong( ok, base ); + if ( ok && *ok && (v < -32768 || v > 32767) ) { + *ok = FALSE; + v = 0; + } + return (short)v; +} + +ushort QCString::toUShort(bool *ok,int base) const +{ + ulong v = toULong( ok, base ); + if ( ok && *ok && (v > 65535) ) { + *ok = FALSE; + v = 0; + } + return (ushort)v; +} + +int QCString::toInt(bool *ok, int base) const +{ + return (int)toLong( ok, base ); +} + +uint QCString::toUInt(bool *ok,int base) const +{ + return (uint)toULong( ok, base ); +} + + +long QCString::toLong(bool *ok,int base) const +{ + const char *p = data(); + long val=0; + int l = length(); + const long max_mult = INT_MAX / base; + bool is_ok = FALSE; + int neg = 0; + if ( !p ) + goto bye; + while ( l && isspace(*p) ) // skip leading space + l--,p++; + if ( l && *p == '-' ) { + l--; + p++; + neg = 1; + } else if ( *p == '+' ) { + l--; + p++; + } + + // NOTE: toULong() code is similar + if ( !l || !ok_in_base(*p,base) ) + goto bye; + while ( l && ok_in_base(*p,base) ) { + l--; + int dv; + if ( *p>='0' && *p<='9' ) { + dv = *p-'0'; + } else { + if ( *p >= 'a' && *p <= 'z' ) + dv = *p - 'a' + 10; + else + dv = *p - 'A' + 10; + } + if ( val > max_mult || (val == max_mult && dv > (INT_MAX%base)+neg) ) + goto bye; + val = base*val + dv; + p++; + } + if ( neg ) + val = -val; + while ( l && isspace(*p) ) // skip trailing space + l--,p++; + if ( !l ) + is_ok = TRUE; +bye: + if ( ok ) + *ok = is_ok; + return is_ok ? val : 0; +} + +ulong QCString::toULong(bool *ok,int base) const +{ + const char *p = data(); + ulong val=0; + int l = length(); + const ulong max_mult = 429496729; // UINT_MAX/10, rounded down + bool is_ok = FALSE; + if ( !p ) + goto bye; + while ( l && isspace(*p) ) // skip leading space + l--,p++; + if ( *p == '+' ) + l--,p++; + + // NOTE: toLong() code is similar + if ( !l || !ok_in_base(*p,base) ) + goto bye; + while ( l && ok_in_base(*p,base) ) { + l--; + uint dv; + if ( *p>='0' && *p<='9' ) { + dv = *p-'0'; + } else { + if ( *p >= 'a' && *p <= 'z' ) + dv = *p - 'a' + 10; + else + dv = *p - 'A' + 10; + } + if ( val > max_mult || (val == max_mult && dv > (UINT_MAX%base)) ) + goto bye; + val = base*val + dv; + p++; + } + + while ( l && isspace(*p) ) // skip trailing space + l--,p++; + if ( !l ) + is_ok = TRUE; +bye: + if ( ok ) + *ok = is_ok; + return is_ok ? val : 0; +} + +uint64 QCString::toUInt64(bool *ok,int base) const +{ + const char *p = data(); + uint64 val=0; + int l = length(); + const uint64 max_mult = 1844674407370955161ULL; // ULLONG_MAX/10, rounded down + bool is_ok = FALSE; + if ( !p ) + goto bye; + while ( l && isspace(*p) ) // skip leading space + l--,p++; + if ( *p == '+' ) + l--,p++; + + // NOTE: toULong() code is similar + if ( !l || !ok_in_base(*p,base) ) + goto bye; + while ( l && ok_in_base(*p,base) ) { + l--; + uint dv; + if ( *p>='0' && *p<='9' ) { + dv = *p-'0'; + } else { + if ( *p >= 'a' && *p <= 'z' ) + dv = *p - 'a' + 10; + else + dv = *p - 'A' + 10; + } + if ( val > max_mult || (val == max_mult && dv > (ULLONG_MAX%base)) ) + goto bye; + val = base*val + dv; + p++; + } + + while ( l && isspace(*p) ) // skip trailing space + l--,p++; + if ( !l ) + is_ok = TRUE; +bye: + if ( ok ) + *ok = is_ok; + return is_ok ? val : 0; +} + +//------------------------------------------------- + +void *qmemmove( void *dst, const void *src, uint len ) +{ + char *d; + char *s; + if ( dst > src ) { + d = (char *)dst + len - 1; + s = (char *)src + len - 1; + while ( len-- ) + *d-- = *s--; + } else if ( dst < src ) { + d = (char *)dst; + s = (char *)src; + while ( len-- ) + *d++ = *s++; + } + return dst; +} + +char *qstrdup( const char *str ) +{ + if ( !str ) + return 0; + char *dst = new char[qstrlen(str)+1]; + return strcpy( dst, str ); +} + +char *qstrncpy( char *dst, const char *src, uint len ) +{ + if ( !src ) + return 0; + strncpy( dst, src, len ); + if ( len > 0 ) + dst[len-1] = '\0'; + return dst; +} + +int qstricmp( const char *str1, const char *str2 ) +{ + const uchar *s1 = (const uchar *)str1; + const uchar *s2 = (const uchar *)str2; + int res; + uchar c; + if ( !s1 || !s2 ) + return s1 == s2 ? 0 : (int)(s2 - s1); + for ( ; !(res = (c=tolower(*s1)) - tolower(*s2)); s1++, s2++ ) + if ( !c ) // strings are equal + break; + return res; +} + +int qstrnicmp( const char *str1, const char *str2, uint len ) +{ + const uchar *s1 = (const uchar *)str1; + const uchar *s2 = (const uchar *)str2; + int res; + uchar c; + if ( !s1 || !s2 ) + return (int)(s2 - s1); + for ( ; len--; s1++, s2++ ) { + if ( (res = (c=tolower(*s1)) - tolower(*s2)) ) + return res; + if ( !c ) // strings are equal + break; + } + return 0; +} + +/// substitute all occurrences of \a src in \a s by \a dst +QCString substitute(const QCString &s,const QCString &src,const QCString &dst) +{ + if (s.isEmpty() || src.isEmpty()) return s; + const char *p, *q; + int srcLen = src.length(); + int dstLen = dst.length(); + int resLen; + if (srcLen!=dstLen) + { + int count; + for (count=0, p=s.data(); (q=strstr(p,src))!=0; p=q+srcLen) count++; + resLen = s.length()+count*(dstLen-srcLen); + } + else // result has same size as s + { + resLen = s.length(); + } + QCString result(resLen+1); + char *r; + for (r=result.rawData(), p=s; (q=strstr(p,src))!=0; p=q+srcLen) + { + int l = (int)(q-p); + memcpy(r,p,l); + r+=l; + + if (dst) memcpy(r,dst,dstLen); + r+=dstLen; + } + if (r) + { + qstrcpy(r,p); + } + //printf("substitute(%s,%s,%s)->%s\n",s,src,dst,result.data()); + return result; +} + + +/// substitute all occurrences of \a src in \a s by \a dst, but skip +/// each consecutive sequence of \a src where the number consecutive +/// \a src matches \a skip_seq; if \a skip_seq is negative, skip any +/// number of consecutive \a src +QCString substitute(const QCString &s,const QCString &src,const QCString &dst,int skip_seq) +{ + if (s.isEmpty() || src.isEmpty()) return s; + const char *p, *q; + int srcLen = src.length(); + int dstLen = dst.length(); + int resLen; + if (srcLen!=dstLen) + { + int count; + for (count=0, p=s.data(); (q=strstr(p,src))!=0; p=q+srcLen) count++; + resLen = s.length()+count*(dstLen-srcLen); + } + else // result has same size as s + { + resLen = s.length(); + } + QCString result(resLen+1); + char *r; + for (r=result.rawData(), p=s; (q=strstr(p,src))!=0; p=q+srcLen) + { + // search a consecutive sequence of src + int seq = 0, skip = 0; + if (skip_seq) + { + for (const char *n=q+srcLen; qstrncmp(n,src,srcLen)==0; seq=1+skip, n+=srcLen) + ++skip; // number of consecutive src after the current one + + // verify the allowed number of consecutive src to skip + if (skip_seq > 0 && skip_seq != seq) + seq = skip = 0; + } + + // skip a consecutive sequence of src when necessary + int l = (int)((q + seq * srcLen)-p); + memcpy(r,p,l); + r+=l; + + if (skip) + { + // skip only the consecutive src found after the current one + q += skip * srcLen; + // the next loop will skip the current src, aka (p=q+srcLen) + continue; + } + + if (dst) memcpy(r,dst,dstLen); + r+=dstLen; + } + qstrcpy(r,p); + result.resize((int)strlen(result.data())+1); + //printf("substitute(%s,%s,%s)->%s\n",s,src,dst,result.data()); + return result; +} + |