/******************************************************************************** * * * S t r i n g O b j e c t * * * ********************************************************************************* * Copyright (C) 1997,2006 by Jeroen van der Zijp. All Rights Reserved. * ********************************************************************************* * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * ********************************************************************************* * $Id: FXString.cpp,v 1.218.2.1 2006/08/15 05:03:16 fox Exp $ * ********************************************************************************/ #include "xincs.h" #include "fxver.h" #include "fxdefs.h" #include "fxascii.h" #include "fxunicode.h" #include "FXHash.h" #include "FXStream.h" #include "FXString.h" /* Notes: - The special pointer-value null represents an empty "" string. - Strings are never NULL:- this speeds things up a lot as there is no need to check for NULL strings anymore. - In the new representation, '\0' is allowed as a character everywhere; but there is always an (uncounted) '\0' at the end. - The length preceeds the text in the buffer. */ // The string buffer is always rounded to a multiple of ROUNDVAL // which must be 2^n. Thus, small size changes will not result in any // actual resizing of the buffer except when ROUNDVAL is exceeded. #define ROUNDVAL 16 // Round up to nearest ROUNDVAL #define ROUNDUP(n) (((n)+ROUNDVAL-1)&-ROUNDVAL) // This will come in handy #define EMPTY ((FXchar*)&emptystring[1]) using namespace FX; /*******************************************************************************/ namespace FX { // For conversion from UTF16 to UTF32 const FXint SURROGATE_OFFSET=0x10000-(0xD800<<10)-0xDC00; // For conversion of UTF32 to UTF16 const FXint LEAD_OFFSET=0xD800-(0x10000>>10); // Empty string static const FXint emptystring[2]={0,0}; // Special NULL string const FXchar FXString::null[4]={0,0,0,0}; // Numbers for hexadecimal const FXchar FXString::hex[17]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',0}; const FXchar FXString::HEX[17]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F',0}; // Length of a utf8 character representation const signed char FXString::utfBytes[256]={ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1 }; /*******************************************************************************/ // Length of wide character string static inline FXint strlen(const FXchar *src){ return ::strlen(src); } // Length of wide character string static inline FXint strlen(const FXwchar *src){ register FXint i=0; while(src[i]) i++; return i; } // Length of narrow character string static inline FXint strlen(const FXnchar *src){ register FXint i=0; while(src[i]) i++; return i; } /*******************************************************************************/ // Return wide character from utf8 string at ptr FXwchar wc(const FXchar *ptr){ register FXwchar w=(FXuchar)ptr[0]; if(0xC0<=w){ w=(w<<6)^(FXuchar)ptr[1]^0x3080; if(0x800<=w){ w=(w<<6)^(FXuchar)ptr[2]^0x20080; if(0x10000<=w){ w=(w<<6)^(FXuchar)ptr[3]^0x400080; if(0x200000<=w){ w=(w<<6)^(FXuchar)ptr[4]^0x8000080; if(0x4000000<=w){ w=(w<<6)^(FXuchar)ptr[5]^0x80; }}}}} return w; } // Return wide character from utf16 string at ptr FXwchar wc(const FXnchar *ptr){ register FXwchar w=ptr[0]; if(0xD800<=w && w<0xDC00){ w=(w<<10)+ptr[1]+SURROGATE_OFFSET; } return w; } // Return number of FXchar's of wide character at ptr FXint wclen(const FXchar *ptr){ return FXString::utfBytes[(FXuchar)ptr[0]]; } // Return number of FXnchar's of narrow character at ptr FXint wclen(const FXnchar *ptr){ return (0xD800<=ptr[0] && ptr[0]<0xDC00) ? 2 : 1; } // Return start of utf8 character containing position FXint wcvalidate(const FXchar* string,FXint pos){ return (pos<=0 || FXISUTF(string[pos]) || --pos<=0 || FXISUTF(string[pos]) || --pos<=0 || FXISUTF(string[pos]) || --pos<=0 || FXISUTF(string[pos]) || --pos<=0 || FXISUTF(string[pos]) || --pos), pos; } // Return start of utf16 character containing position FXint wcvalidate(const FXnchar *string,FXint pos){ return (pos<=0 || !(0xDC00<=string[pos] && string[pos]<=0xDFFF) || --pos), pos; } // Advance to next utf8 character start FXint wcinc(const FXchar* string,FXint pos){ return (string[pos++]==0 || FXISUTF(string[pos]) || string[pos++]==0 || FXISUTF(string[pos]) || string[pos++]==0 || FXISUTF(string[pos]) || string[pos++]==0 || FXISUTF(string[pos]) || string[pos++]==0 || FXISUTF(string[pos]) || ++pos), pos; } // Advance to next utf16 character start FXint wcinc(const FXnchar *string,FXint pos){ return ((0xDC00<=string[++pos] && string[pos]<=0xDFFF) || ++pos),pos; } // Retreat to previous utf8 character start FXint wcdec(const FXchar* string,FXint pos){ return (--pos<=0 || FXISUTF(string[pos]) || --pos<=0 || FXISUTF(string[pos]) || --pos<=0 || FXISUTF(string[pos]) || --pos<=0 || FXISUTF(string[pos]) || --pos<=0 || FXISUTF(string[pos]) || --pos), pos; } // Retreat to previous utf16 character start FXint wcdec(const FXnchar *string,FXint pos){ return (--pos<=0 || !(0xDC00<=string[pos] && string[pos]<=0xDFFF) || --pos), pos; } // Return true if valid utf8 character sequence bool isutfvalid(const FXchar* str){ if((FXuchar)str[0]<0x80) return true; if((FXuchar)str[0]<0xC0) return false; if((FXuchar)str[1]<0x80) return false; if((FXuchar)str[1]>0xBF) return false; if((FXuchar)str[0]<0xE0) return true; if((FXuchar)str[2]<0x80) return false; if((FXuchar)str[2]>0xBF) return false; if((FXuchar)str[0]<0xF0) return true; if((FXuchar)str[3]<0x80) return false; if((FXuchar)str[3]>0xBF) return false; if((FXuchar)str[0]<0xF8) return true; if((FXuchar)str[4]<0x80) return false; if((FXuchar)str[4]>0xBF) return false; if((FXuchar)str[0]<0xFC) return true; if((FXuchar)str[5]<0x80) return false; if((FXuchar)str[5]>0xBF) return false; return true; } // Length of utf8 representation of wide characters string str of length n FXint utfslen(const FXwchar *str,FXint n){ register FXint len=0; register FXint p=0; register FXwchar w; while(p>10)+LEAD_OFFSET; w=(w&0x3FF)+0xDC00; }}} dst[len++]=w; } return len; } // Copy utf8 string to narrow character string dst FXint utf2ncs(FXnchar *dst,const FXchar *src){ return utf2ncs(dst,src,strlen(src)+1); } /*******************************************************************************/ // Copy wide character substring of length n to dst FXint wc2utfs(FXchar* dst,const FXwchar *src,FXint n){ register FXint len=0; register FXint p=0; register FXwchar w; while(p>6)|0xC0; dst[len++]=(w&0x3F)|0x80; continue; } if(w<0x10000){ dst[len++]=(w>>12)|0xE0; dst[len++]=((w>>6)&0x3F)|0x80; dst[len++]=(w&0x3F)|0x80; continue; } if(w<0x200000){ dst[len++]=(w>>18)|0xF0; dst[len++]=((w>>12)&0x3F)|0x80; dst[len++]=((w>>6)&0x3F)|0x80; dst[len++]=(w&0x3F)|0x80; continue; } if(w<0x4000000){ dst[len++]=(w>>24)|0xF8; dst[len++]=((w>>18)&0x3F)|0x80; dst[len++]=((w>>12)&0x3F)|0x80; dst[len++]=((w>>6)&0x3F)|0x80; dst[len++]=(w&0x3F)|0x80; continue; } dst[len++]=(w>>30)|0xFC; dst[len++]=((w>>24)&0X3F)|0x80; dst[len++]=((w>>18)&0X3F)|0x80; dst[len++]=((w>>12)&0X3F)|0x80; dst[len++]=((w>>6)&0X3F)|0x80; dst[len++]=(w&0X3F)|0x80; } return len; } // Copy wide character string to dst FXint wc2utfs(FXchar* dst,const FXwchar *src){ return wc2utfs(dst,src,strlen(src)+1); } // Copy narrow character substring of length n to dst // Test for surrogates is deferred till code possibly exceeds 0xD800 FXint nc2utfs(FXchar* dst,const FXnchar *src,FXint n){ register FXint len=0; register FXint p=0; register FXwchar w; while(p>6)|0xC0; dst[len++]=(w&0x3F)|0x80; continue; } if(0xD800<=w && w<0xDC00 && p>12)|0xE0; dst[len++]=((w>>6)&0x3F)|0x80; dst[len++]=(w&0x3F)|0x80; continue; } if(w<0x200000){ dst[len++]=(w>>18)|0xF0; dst[len++]=((w>>12)&0x3F)|0x80; dst[len++]=((w>>6)&0x3F)|0x80; dst[len++]=(w&0x3F)|0x80; continue; } if(w<0x4000000){ dst[len++]=(w>>24)|0xF8; dst[len++]=((w>>18)&0x3F)|0x80; dst[len++]=((w>>12)&0x3F)|0x80; dst[len++]=((w>>6)&0x3F)|0x80; dst[len++]=(w&0x3F)|0x80; continue; } dst[len++]=(w>>30)|0xFC; dst[len++]=((w>>24)&0X3F)|0x80; dst[len++]=((w>>18)&0X3F)|0x80; dst[len++]=((w>>12)&0X3F)|0x80; dst[len++]=((w>>6)&0X3F)|0x80; dst[len++]=(w&0X3F)|0x80; } return len; } // Copy narrow character string to dst FXint nc2utfs(FXchar* dst,const FXnchar *src){ return nc2utfs(dst,src,strlen(src)+1); } /*******************************************************************************/ // Change the length of the string to len void FXString::length(FXint len){ if(*(((FXint*)str)-1)!=len){ if(0=0){ if(delim[i]==c){ if(--start==0) goto a; break; } } } } a:e=s; if(0=0){ if(delim[i]==c){ if(--num==0) goto b; break; } } ++e; } } b:return FXString(str+s,e-s); } // Return partition of string separated by delimiters in delim FXString FXString::section(const FXchar* delim,FXint start,FXint num) const { return section(delim,strlen(delim),start,num); } // Return partition of string separated by delimiters in delim FXString FXString::section(const FXString& delim,FXint start,FXint num) const { return section(delim.text(),delim.length(),start,num); } // Adopt string s, leaving s empty FXString& FXString::adopt(FXString& s){ if(this!=&s){ if(str!=EMPTY){ free(str-sizeof(FXint)); } str=s.str; s.str=EMPTY; } return *this; } // Assign input character to this string FXString& FXString::assign(FXchar c){ length(1); str[0]=c; return *this; } // Assign input n characters c to this string FXString& FXString::assign(FXchar c,FXint n){ length(n); memset(str,c,n); return *this; } // Assign first n characters of input string to this string FXString& FXString::assign(const FXchar* s,FXint n){ if(s && 0=len){ str[len]=c; } else{ memmove(str+pos+1,str+pos,len-pos); str[pos]=c; } return *this; } // Insert n characters c at specified position FXString& FXString::insert(FXint pos,FXchar c,FXint n){ if(0=len){ memset(str+len,c,n); } else{ memmove(str+pos+n,str+pos,len-pos); memset(str+pos,c,n); } } return *this; } // Insert string at position FXString& FXString::insert(FXint pos,const FXchar* s,FXint n){ if(s && 0=len){ memcpy(str+len,s,n); } else{ memmove(str+pos+n,str+pos,len-pos); memcpy(str+pos,s,n); } } return *this; } // Insert wide character string at position FXString& FXString::insert(FXint pos,const FXwchar* s,FXint m){ if(s && 0=len){ wc2utfs(str+len,s,m); } else{ memmove(str+pos+n,str+pos,len-pos); wc2utfs(str+pos,s,m); } } return *this; } // Insert narrow character string at position FXString& FXString::insert(FXint pos,const FXnchar* s,FXint m){ if(s && 0=len){ nc2utfs(str+len,s,m); } else{ memmove(str+pos+n,str+pos,len-pos); nc2utfs(str+pos,s,m); } } return *this; } // Insert string at position FXString& FXString::insert(FXint pos,const FXchar* s){ if(s && s[0]){ register FXint len=length(); register FXint n=strlen(s); length(len+n); if(pos<=0){ memmove(str+n,str,len); memcpy(str,s,n); } else if(pos>=len){ memcpy(str+len,s,n); } else{ memmove(str+pos+n,str+pos,len-pos); memcpy(str+pos,s,n); } } return *this; } // Insert wide character string at position FXString& FXString::insert(FXint pos,const FXwchar* s){ if(s && s[0]){ register FXint len=length(); register FXint n=utfslen(s); length(len+n); if(pos<=0){ memmove(str+n,str,len); wc2utfs(str,s); } else if(pos>=len){ wc2utfs(str+len,s); } else{ memmove(str+pos+n,str+pos,len-pos); wc2utfs(str+pos,s); } } return *this; } // Insert narrow character string at position FXString& FXString::insert(FXint pos,const FXnchar* s){ if(s && s[0]){ register FXint len=length(); register FXint n=utfslen(s); length(len+n); if(pos<=0){ memmove(str+n,str,len); nc2utfs(str,s); } else if(pos>=len){ nc2utfs(str+len,s); } else{ memmove(str+pos+n,str+pos,len-pos); nc2utfs(str+pos,s); } } return *this; } // Insert string at position FXString& FXString::insert(FXint pos,const FXString& s){ return insert(pos,s.str,s.length()); } // Append character c to this string FXString& FXString::append(FXchar c){ register FXint len=length(); length(len+1); str[len]=c; return *this; } // Append n characters c to this string FXString& FXString::append(FXchar c,FXint n){ if(0=len){ length(len+1); str[len]=c; } else{ str[pos]=c; } return *this; } // Replace the m characters at pos with n characters c FXString& FXString::replace(FXint pos,FXint m,FXchar c,FXint n){ register FXint len=length(); if(pos<0){ m+=pos; if(m<0) m=0; pos=0; } if(pos+m>len){ if(pos>len) pos=len; m=len-pos; } if(mn){ memmove(str+pos+n,str+pos+m,len-pos-m); length(len+n-m); } memset(str+pos,c,n); return *this; } // Replace part of string FXString& FXString::replace(FXint pos,FXint m,const FXchar* s,FXint n){ register FXint len=length(); if(pos<0){ m+=pos; if(m<0) m=0; pos=0; } if(pos+m>len){ if(pos>len) pos=len; m=len-pos; } if(mn){ memmove(str+pos+n,str+pos+m,len-pos-m); length(len+n-m); } memcpy(str+pos,s,n); return *this; } // Replace part of wide character string FXString& FXString::replace(FXint pos,FXint m,const FXwchar* s,FXint n){ register FXint w=utfslen(s,n); register FXint len=length(); if(pos<0){ m+=pos; if(m<0) m=0; pos=0; } if(pos+m>len){ if(pos>len) pos=len; m=len-pos; } if(mw){ memmove(str+pos+w,str+pos+m,len-pos-m); length(len+w-m); } wc2utfs(str+pos,s,n); return *this; } // Replace part of narrow character string FXString& FXString::replace(FXint pos,FXint m,const FXnchar* s,FXint n){ register FXint w=utfslen(s,n); register FXint len=length(); if(pos<0){ m+=pos; if(m<0) m=0; pos=0; } if(pos+m>len){ if(pos>len) pos=len; m=len-pos; } if(mw){ memmove(str+pos+w,str+pos+m,len-pos-m); length(len+w-m); } nc2utfs(str+pos,s,n); return *this; } // Replace part of string FXString& FXString::replace(FXint pos,FXint m,const FXchar* s){ return replace(pos,m,s,strlen(s)); } // Replace part of string FXString& FXString::replace(FXint pos,FXint m,const FXwchar* s){ return replace(pos,m,s,strlen(s)); } // Replace part of string FXString& FXString::replace(FXint pos,FXint m,const FXnchar* s){ return replace(pos,m,s,strlen(s)); } // Replace part of string FXString& FXString::replace(FXint pos,FXint m,const FXString& s){ return replace(pos,m,s.str,s.length()); } // Move range of m characters from src position to dst position FXString& FXString::move(FXint dst,FXint src,FXint n){ register FXint len=length(); if(0len){ // Move beyond end if(dst>len) dst=len; length(dst+n); memmove(str+dst,str+src,n); } else{ memmove(str+dst,str+src,n); // Move inside } } return *this; } // Remove one character FXString& FXString::erase(FXint pos){ register FXint len=length(); if(0<=pos && pos0){ if(pos<0){n+=pos;pos=0;} if(pos+n>len){n=len-pos;} memmove(str+pos,str+pos+n,len-pos-n); length(len-n); } } return *this; } // Return number of occurrences of ch in string FXint FXString::contains(FXchar ch) const { register FXint len=length(); register FXint c=ch; register FXint m=0; register FXint i=0; while(i=e) break; str[d++]=' '; } length(d); } return *this; } // Remove leading and trailing whitespace FXString& FXString::trim(){ if(str!=EMPTY){ register FXint s=0; register FXint e=length(); while(0len) pos=len; length(pos); return *this; } // Clean string FXString& FXString::clear(){ length(0); return *this; } // Get leftmost part FXString FXString::left(FXint n) const { if(0len) n=len; return FXString(str,n); } return FXString::null; } // Get rightmost part FXString FXString::right(FXint n) const { if(0len) n=len; return FXString(str+len-n,n); } return FXString::null; } // Get some part in the middle FXString FXString::mid(FXint pos,FXint n) const { if(00){ if(pos<0){n+=pos;pos=0;} if(pos+n>len){n=len-pos;} return FXString(str+pos,n); } } return FXString::null; } // Return all characters before the nth occurrence of ch, searching forward FXString FXString::before(FXchar c,FXint n) const { register FXint len=length(); register FXint p=0; if(0 0x80 // so fold using Ascii [leaving upper 128 codes invariant], and // compare; they will be unequal so we'll fall out of the loop. // o Both characters are wide. This is the complex case, and // here we have to obtain the wide character, convert to lower // case using the Unicode, and compare. Skip to the start of // the next character by consulting character-width table. FXint comparecase(const FXchar* s1,const FXchar* s2){ register FXint c1,c2; do{ if((*s1 & 0x80) && (*s2 & 0x80)){ c1=Unicode::toLower(wc(s1)); s1+=wclen(s1); c2=Unicode::toLower(wc(s2)); s2+=wclen(s2); } else{ c1=Ascii::toLower(*s1); s1+=1; c2=Ascii::toLower(*s2); s2+=1; } } while(c1 && (c1==c2)); return c1-c2; } // Compare strings case insensitive up to n FXint comparecase(const FXchar* s1,const FXchar* s2,FXint n){ register FXint c1,c2; if(0(const FXString& s1,const FXString& s2){ return compare(s1.str,s2.str)>0; } bool operator>(const FXString& s1,const FXchar* s2){ return compare(s1.str,s2)>0; } bool operator>(const FXchar* s1,const FXString& s2){ return compare(s1,s2.str)>0; } bool operator>=(const FXString& s1,const FXString& s2){ return compare(s1.str,s2.str)>=0; } bool operator>=(const FXString& s1,const FXchar* s2){ return compare(s1.str,s2)>=0; } bool operator>=(const FXchar* s1,const FXString& s2){ return compare(s1,s2.str)>=0; } // Find n-th occurrence of character, searching forward; return position or -1 FXint FXString::find(FXchar c,FXint pos,FXint n) const { register FXint len=length(); register FXint p=pos; register FXint cc=c; if(p<0) p=0; if(n<=0) return p; while(p=len) p=len-1; if(n<=0) return p; while(0<=p){ if(str[p]==cc){ if(--n==0) return p; } --p; } return -1; } // Find a character, searching forward; return position or -1 FXint FXString::find(FXchar c,FXint pos) const { register FXint len=length(); register FXint p=pos; register FXint cc=c; if(p<0) p=0; while(p=len) p=len-1; while(0<=p){ if(str[p]==cc){ return p; } --p; } return -1; } // Find a substring of length n, searching forward; return position or -1 FXint FXString::find(const FXchar* substr,FXint n,FXint pos) const { register FXint len=length(); if(0<=pos && 0len) pos=len; while(0<=pos){ if(str[pos]==c){ if(!compare(str+pos,substr,n)){ return pos; } } pos--; } } return -1; } // Find a substring, searching backward; return position or -1 FXint FXString::rfind(const FXchar* substr,FXint pos) const { return rfind(substr,strlen(substr),pos); } // Find a substring, searching backward; return position or -1 FXint FXString::rfind(const FXString& substr,FXint pos) const { return rfind(substr.text(),substr.length(),pos); } // Find first character in the set of size n, starting from pos; return position or -1 FXint FXString::find_first_of(const FXchar* set,FXint n,FXint pos) const { register FXint len=length(); register FXint p=pos; if(p<0) p=0; while(p=0){ if(set[i]==c) return p; } p++; } return -1; } // Find first character in the set, starting from pos; return position or -1 FXint FXString::find_first_of(const FXchar* set,FXint pos) const { return find_first_of(set,strlen(set),pos); } // Find first character in the set, starting from pos; return position or -1 FXint FXString::find_first_of(const FXString& set,FXint pos) const { return find_first_of(set.text(),set.length(),pos); } // Find first character, starting from pos; return position or -1 FXint FXString::find_first_of(FXchar c,FXint pos) const { register FXint len=length(); register FXint p=pos; register FXint cc=c; if(p<0) p=0; while(p=len) p=len-1; while(0<=p){ register FXint c=str[p]; register FXint i=n; while(--i>=0){ if(set[i]==c) return p; } p--; } return -1; } // Find last character in the set, starting from pos; return position or -1 FXint FXString::find_last_of(const FXchar* set,FXint pos) const { return find_last_of(set,strlen(set),pos); } // Find last character in the set, starting from pos; return position or -1 FXint FXString::find_last_of(const FXString& set,FXint pos) const { return find_last_of(set.text(),set.length(),pos); } // Find last character, starting from pos; return position or -1 FXint FXString::find_last_of(FXchar c,FXint pos) const { register FXint len=length(); register FXint p=pos; register FXint cc=c; if(p>=len) p=len-1; while(0<=p){ if(str[p]==cc){ return p; } p--; } return -1; } // Find first character NOT in the set of size n, starting from pos; return position or -1 FXint FXString::find_first_not_of(const FXchar* set,FXint n,FXint pos) const { register FXint len=length(); register FXint p=pos; if(p<0) p=0; while(p=0){ if(set[i]==c) goto x; } return p; x: p++; } return -1; } // Find first character NOT in the set, starting from pos; return position or -1 FXint FXString::find_first_not_of(const FXchar* set,FXint pos) const { return find_first_not_of(set,strlen(set),pos); } // Find first character NOT in the set, starting from pos; return position or -1 FXint FXString::find_first_not_of(const FXString& set,FXint pos) const { return find_first_not_of(set.text(),set.length(),pos); } // Find first character NOT equal to c, starting from pos; return position or -1 FXint FXString::find_first_not_of(FXchar c,FXint pos) const { register FXint len=length(); register FXint p=pos; register FXint cc=c; if(p<0) p=0; while(p=len) p=len-1; while(0<=p){ register FXint c=str[p]; register FXint i=n; while(--i>=0){ if(set[i]==c) goto x; } return p; x: p--; } return -1; } // Find last character NOT in the set, starting from pos; return position or -1 FXint FXString::find_last_not_of(const FXchar* set,FXint pos) const { return find_last_not_of(set,strlen(set),pos); } // Find last character NOT in the set, starting from pos; return position or -1 FXint FXString::find_last_not_of(const FXString& set,FXint pos) const { return find_last_not_of(set.text(),set.length(),pos); } // Find last character NOT equal to c, starting from pos; return position or -1 FXint FXString::find_last_not_of(FXchar c,FXint pos) const { register FXint len=length(); register FXint p=pos; register FXint cc=c; if(p>=len) p=len-1; while(0<=p){ if(str[p]!=cc){ return p; } p--; } return -1; } // Get hash value FXuint FXString::hash() const { register FXint len=length(); register FXuint h=0; for(register FXint i=0; i>(FXStream& store,FXString& s){ // Note stream format incompatible with FOX 1.0 FXint len; store >> len; s.length(len); store.load(s.str,len); return store; } #ifdef WIN32 #ifndef va_copy #define va_copy(arg,list) ((arg)=(list)) #endif #endif // Print formatted string a-la vprintf FXString& FXString::vformat(const FXchar* fmt,va_list args){ FXint result=0; if(fmt && *fmt){ #if (_MSC_VER > 1300) // Have _vscprintf() va_list ag; va_copy(ag,args); result=_vscprintf(fmt,ag); va_end(ag); length(result); vsnprintf(str,length()+1,fmt,args); #elif defined(HAVE_VSNPRINTF) // Have vsnprintf() #if (__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)) || defined(__FreeBSD__) va_list ag; va_copy(ag,args); result=vsnprintf(str,empty()?0:length()+1,fmt,ag); va_end(ag); if(length()16){ fxerror("FXStringVal: base out of range.\n"); } if(num<0){nn=(FXulong)(~num)+1;} do{ *--p=FXString::HEX[nn%base]; nn/=base; } while(nn); if(num<0) *--p='-'; FXASSERT(buf<=p); return FXString(p,buf+66-p); } // Conversion of unsigned long to string FXString FXStringVal(FXulong num,FXint base){ FXchar buf[66]; register FXchar *p=buf+66; register FXulong nn=num; if(base<2 || base>16){ fxerror("FXStringVal: base out of range.\n"); } do{ *--p=FXString::HEX[nn%base]; nn/=base; } while(nn); FXASSERT(buf<=p); return FXString(p,buf+66-p); } // Conversion of integer to string FXString FXStringVal(FXint num,FXint base){ FXchar buf[34]; register FXchar *p=buf+34; register FXuint nn=(FXuint)num; if(base<2 || base>16){ fxerror("FXStringVal: base out of range.\n"); } if(num<0){nn=(FXuint)(~num)+1;} do{ *--p=FXString::HEX[nn%base]; nn/=base; } while(nn); if(num<0) *--p='-'; FXASSERT(buf<=p); return FXString(p,buf+34-p); } // Conversion of unsigned integer to string FXString FXStringVal(FXuint num,FXint base){ FXchar buf[34]; register FXchar *p=buf+34; register FXuint nn=num; if(base<2 || base>16){ fxerror("FXStringVal: base out of range.\n"); } do{ *--p=FXString::HEX[nn%base]; nn/=base; } while(nn); FXASSERT(buf<=p); return FXString(p,buf+34-p); } // Formatting for reals static const char *const expo[]={"%.*f","%.*E","%.*G"}; // Conversion of float to string FXString FXStringVal(FXfloat num,FXint prec,FXint exp){ return FXStringFormat(expo[exp],prec,num); } // Conversion of double to string FXString FXStringVal(FXdouble num,FXint prec,FXint exp){ return FXStringFormat(expo[exp],prec,num); } #ifndef HAVE_STRTOLL extern "C" FXlong strtoll(const char *nptr, char **endptr, int base); #endif #ifndef HAVE_STRTOULL extern "C" FXulong strtoull(const char *nptr, char **endptr, int base); #endif // Conversion of string to integer FXlong FXLongVal(const FXString& s,FXint base){ return (FXlong)strtoll(s.str,NULL,base); } // Conversion of string to unsigned integer FXulong FXULongVal(const FXString& s,FXint base){ return (FXulong)strtoull(s.str,NULL,base); } // Conversion of string to integer FXint FXIntVal(const FXString& s,FXint base){ return (FXint)strtol(s.str,NULL,base); } // Conversion of string to unsigned integer FXuint FXUIntVal(const FXString& s,FXint base){ return (FXuint)strtoul(s.str,NULL,base); } // Conversion of string to float FXfloat FXFloatVal(const FXString& s){ return (FXfloat)strtod(s.str,NULL); } // Conversion of string to double FXdouble FXDoubleVal(const FXString& s){ return strtod(s.str,NULL); } // Return utf8 from ascii containing unicode escapes FXString fromAscii(const FXString& s){ register FXint p=0; FXString result; FXwchar c; while(p>12)&15]); result.append(FXString::HEX[(c>>8)&15]); result.append(FXString::HEX[(c>>4)&15]); c=FXString::HEX[c&15]; } result.append(c); p+=s.extent(p); } return result; } // Escape special characters in a string FXString escape(const FXString& s){ register FXint p=0; register FXint c; FXString result; while(p>4)&15]); result.append(FXString::HEX[c&15]); } break; } } return result; } // Unescape special characters in a string FXString unescape(const FXString& s){ register FXint p=0; register FXint c; FXString result; while(p=kind){ register FXint p=0; register FXint n=0; while(pcs){ result[p]=us; result[p+1]=uf; if(p>0) p--; continue; } // Already in right order; advance by one p++; } return result; } // Compose characters from canonical/compatible decomposition static FXint compose(FXwchar* result,FXint len){ register FXint p,q,cc,starterpos,startercc; register FXwchar w; if(0