1 /********************************************************************************
2 *                                                                               *
3 *                           S t r i n g   O b j e c t                           *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 1997,2006 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or                 *
9 * modify it under the terms of the GNU Lesser General Public                    *
10 * License as published by the Free Software Foundation; either                  *
11 * version 2.1 of the License, or (at your option) any later version.            *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU             *
16 * Lesser General Public License for more details.                               *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public              *
19 * License along with this library; if not, write to the Free Software           *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.    *
21 *********************************************************************************
22 * $Id: FXString.cpp,v 1.218.2.1 2006/08/15 05:03:16 fox Exp $                       *
23 ********************************************************************************/
24 #include "xincs.h"
25 #include "fxver.h"
26 #include "fxdefs.h"
27 #include "fxascii.h"
28 #include "fxunicode.h"
29 #include "FXHash.h"
30 #include "FXStream.h"
31 #include "FXString.h"
32 
33 
34 /*
35   Notes:
36   - The special pointer-value null represents an empty "" string.
37   - Strings are never NULL:- this speeds things up a lot as there is no
38     need to check for NULL strings anymore.
39   - In the new representation, '\0' is allowed as a character everywhere; but there
40     is always an (uncounted) '\0' at the end.
41   - The length preceeds the text in the buffer.
42 */
43 
44 
45 // The string buffer is always rounded to a multiple of ROUNDVAL
46 // which must be 2^n.  Thus, small size changes will not result in any
47 // actual resizing of the buffer except when ROUNDVAL is exceeded.
48 #define ROUNDVAL    16
49 
50 // Round up to nearest ROUNDVAL
51 #define ROUNDUP(n)  (((n)+ROUNDVAL-1)&-ROUNDVAL)
52 
53 // This will come in handy
54 #define EMPTY       ((FXchar*)&emptystring[1])
55 
56 using namespace FX;
57 
58 /*******************************************************************************/
59 
60 namespace FX {
61 
62 
63 // For conversion from UTF16 to UTF32
64 const FXint SURROGATE_OFFSET=0x10000-(0xD800<<10)-0xDC00;
65 
66 // For conversion of UTF32 to UTF16
67 const FXint LEAD_OFFSET=0xD800-(0x10000>>10);
68 
69 
70 // Empty string
71 static const FXint emptystring[2]={0,0};
72 
73 
74 // Special NULL string
75 const FXchar FXString::null[4]={0,0,0,0};
76 
77 
78 // Numbers for hexadecimal
79 const FXchar FXString::hex[17]={'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f',0};
80 const FXchar FXString::HEX[17]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F',0};
81 
82 
83 // Length of a utf8 character representation
84 const signed char FXString::utfBytes[256]={
85   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,
86   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,
87   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,
88   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,
89   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,
90   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,
91   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,
92   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
93   };
94 
95 
96 /*******************************************************************************/
97 
98 // Length of wide character string
strlen(const FXchar * src)99 static inline FXint strlen(const FXchar *src){
100   return ::strlen(src);
101   }
102 
103 // Length of wide character string
strlen(const FXwchar * src)104 static inline FXint strlen(const FXwchar *src){
105   register FXint i=0;
106   while(src[i]) i++;
107   return i;
108   }
109 
110 
111 // Length of narrow character string
strlen(const FXnchar * src)112 static inline FXint strlen(const FXnchar *src){
113   register FXint i=0;
114   while(src[i]) i++;
115   return i;
116   }
117 
118 
119 /*******************************************************************************/
120 
121 
122 // Return wide character from utf8 string at ptr
wc(const FXchar * ptr)123 FXwchar wc(const FXchar *ptr){
124   register FXwchar w=(FXuchar)ptr[0];
125   if(0xC0<=w){ w=(w<<6)^(FXuchar)ptr[1]^0x3080;
126   if(0x800<=w){ w=(w<<6)^(FXuchar)ptr[2]^0x20080;
127   if(0x10000<=w){ w=(w<<6)^(FXuchar)ptr[3]^0x400080;
128   if(0x200000<=w){ w=(w<<6)^(FXuchar)ptr[4]^0x8000080;
129   if(0x4000000<=w){ w=(w<<6)^(FXuchar)ptr[5]^0x80; }}}}}
130   return w;
131   }
132 
133 
134 // Return wide character from utf16 string at ptr
wc(const FXnchar * ptr)135 FXwchar wc(const FXnchar *ptr){
136   register FXwchar w=ptr[0];
137   if(0xD800<=w && w<0xDC00){ w=(w<<10)+ptr[1]+SURROGATE_OFFSET; }
138   return w;
139   }
140 
141 
142 // Return number of FXchar's of wide character at ptr
wclen(const FXchar * ptr)143 FXint wclen(const FXchar *ptr){
144   return FXString::utfBytes[(FXuchar)ptr[0]];
145   }
146 
147 
148 // Return number of FXnchar's of narrow character at ptr
wclen(const FXnchar * ptr)149 FXint wclen(const FXnchar *ptr){
150   return (0xD800<=ptr[0] && ptr[0]<0xDC00) ? 2 : 1;
151   }
152 
153 
154 // Return start of utf8 character containing position
wcvalidate(const FXchar * string,FXint pos)155 FXint wcvalidate(const FXchar* string,FXint pos){
156   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;
157   }
158 
159 
160 // Return start of utf16 character containing position
wcvalidate(const FXnchar * string,FXint pos)161 FXint wcvalidate(const FXnchar *string,FXint pos){
162   return (pos<=0 || !(0xDC00<=string[pos] && string[pos]<=0xDFFF) || --pos), pos;
163   }
164 
165 
166 
167 // Advance to next utf8 character start
wcinc(const FXchar * string,FXint pos)168 FXint wcinc(const FXchar* string,FXint pos){
169   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;
170   }
171 
172 
173 // Advance to next utf16 character start
wcinc(const FXnchar * string,FXint pos)174 FXint wcinc(const FXnchar *string,FXint pos){
175   return ((0xDC00<=string[++pos] && string[pos]<=0xDFFF) || ++pos),pos;
176   }
177 
178 
179 
180 // Retreat to previous utf8 character start
wcdec(const FXchar * string,FXint pos)181 FXint wcdec(const FXchar* string,FXint pos){
182   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;
183   }
184 
185 
186 // Retreat to previous utf16 character start
wcdec(const FXnchar * string,FXint pos)187 FXint wcdec(const FXnchar *string,FXint pos){
188   return (--pos<=0 || !(0xDC00<=string[pos] && string[pos]<=0xDFFF) || --pos), pos;
189   }
190 
191 
192 
193 // Return true if valid utf8 character sequence
isutfvalid(const FXchar * str)194 bool isutfvalid(const FXchar* str){
195   if((FXuchar)str[0]<0x80) return true;
196   if((FXuchar)str[0]<0xC0) return false;
197   if((FXuchar)str[1]<0x80) return false;
198   if((FXuchar)str[1]>0xBF) return false;
199   if((FXuchar)str[0]<0xE0) return true;
200   if((FXuchar)str[2]<0x80) return false;
201   if((FXuchar)str[2]>0xBF) return false;
202   if((FXuchar)str[0]<0xF0) return true;
203   if((FXuchar)str[3]<0x80) return false;
204   if((FXuchar)str[3]>0xBF) return false;
205   if((FXuchar)str[0]<0xF8) return true;
206   if((FXuchar)str[4]<0x80) return false;
207   if((FXuchar)str[4]>0xBF) return false;
208   if((FXuchar)str[0]<0xFC) return true;
209   if((FXuchar)str[5]<0x80) return false;
210   if((FXuchar)str[5]>0xBF) return false;
211   return true;
212   }
213 
214 
215 // Length of utf8 representation of wide characters string str of length n
utfslen(const FXwchar * str,FXint n)216 FXint utfslen(const FXwchar *str,FXint n){
217   register FXint len=0;
218   register FXint p=0;
219   register FXwchar w;
220   while(p<n){
221     w=str[p++];
222     len++;
223     if(0x80<=w){ len++;
224     if(0x800<=w){ len++;
225     if(0x10000<=w){ len++;
226     if(0x200000<=w){ len++;
227     if(0x4000000<=w){ len++; }}}}}
228     }
229   return len;
230   }
231 
232 
233 // Length of utf8 representation of wide character string str
utfslen(const FXwchar * str)234 FXint utfslen(const FXwchar *str){
235   return utfslen(str,strlen(str));
236   }
237 
238 
239 // Length of utf8 representation of narrow characters string str of length n
240 // Test for surrogates is deferred till code possibly exceeds 0xD800
utfslen(const FXnchar * str,FXint n)241 FXint utfslen(const FXnchar *str,FXint n){
242   register FXint len=0;
243   register FXint p=0;
244   register FXwchar w;
245   while(p<n){
246     w=str[p++];
247     len++;
248     if(0x80<=w){ len++;
249     if(0x800<=w){ len++; if(0xD800<=w && w<0xDC00 && p<n){ w=(w<<10)+str[p++]+SURROGATE_OFFSET; }
250     if(0x10000<=w){ len++;
251     if(0x200000<=w){ len++;
252     if(0x4000000<=w){ len++; }}}}}
253     }
254   return len;
255   }
256 
257 
258 // Length of utf8 representation of narrow characters string str
utfslen(const FXnchar * str)259 FXint utfslen(const FXnchar *str){
260   return utfslen(str,strlen(str));
261   }
262 
263 
264 // Length of wide character representation of utf8 string str of length n
wcslen(const FXchar * str,FXint n)265 FXint wcslen(const FXchar *str,FXint n){
266   register FXint len=0;
267   register FXint p=0;
268   while(p<n){
269     p+=FXString::utfBytes[(FXuchar)str[p]];
270     len++;
271     }
272   return len;
273   }
274 
275 
276 // Length of wide character representation of utf8 string str
wcslen(const FXchar * str)277 FXint wcslen(const FXchar *str){
278   return wcslen(str,strlen(str));
279   }
280 
281 
282 // Length of narrow character representation of utf8 string str of length n
283 // Assume surrogates are needed if utf8 code is more than 16 bits
ncslen(const FXchar * str,FXint n)284 FXint ncslen(const FXchar *str,FXint n){
285   register FXint len=0;
286   register FXint p=0;
287   register FXwchar c;
288   while(p<n){
289     c=(FXuchar)str[p++];
290     if(0xC0<=c){ p++;
291     if(0xE0<=c){ p++;
292     if(0xF0<=c){ p++;
293     if(0xF8<=c){ p++;
294     if(0xFC<=c){ p++; }} len++; }}}
295     len++;
296     }
297   return len;
298   }
299 
300 
301 // Length of narrow character representation of utf8 string str
ncslen(const FXchar * str)302 FXint ncslen(const FXchar *str){
303   return ncslen(str,strlen(str));
304   }
305 
306 
307 /*******************************************************************************/
308 
309 
310 // Copy utf8 string of length n to wide character string dst
utf2wcs(FXwchar * dst,const FXchar * src,FXint n)311 FXint utf2wcs(FXwchar *dst,const FXchar *src,FXint n){
312   register FXint len=0;
313   register FXint p=0;
314   register FXwchar w;
315   while(p<n){
316     w=(FXuchar)src[p++];
317     if(0xC0<=w){ w=(w<<6)^(FXuchar)src[p++]^0x3080;
318     if(0x800<=w){ w=(w<<6)^(FXuchar)src[p++]^0x20080;
319     if(0x10000<=w){ w=(w<<6)^(FXuchar)src[p++]^0x400080;
320     if(0x200000<=w){ w=(w<<6)^(FXuchar)src[p++]^0x8000080;
321     if(0x4000000<=w){ w=(w<<6)^(FXuchar)src[p++]^0x80; }}}}}
322     dst[len++]=w;
323     }
324   return len;
325   }
326 
327 
328 // Copy utf8 string to wide character string dst
utf2wcs(FXwchar * dst,const FXchar * src)329 FXint utf2wcs(FXwchar *dst,const FXchar *src){
330   return utf2wcs(dst,src,strlen(src)+1);
331   }
332 
333 
334 // Copy utf8 string of length n to narrow character string dst
335 // Assume surrogates are needed if utf8 code is more than 16 bits
utf2ncs(FXnchar * dst,const FXchar * src,FXint n)336 FXint utf2ncs(FXnchar *dst,const FXchar *src,FXint n){
337   register FXint len=0;
338   register FXint p=0;
339   register FXwchar w;
340   while(p<n){
341     w=(FXuchar)src[p++];
342     if(0xC0<=w){ w=(w<<6)^(FXuchar)src[p++]^0x3080;
343     if(0x800<=w){ w=(w<<6)^(FXuchar)src[p++]^0x20080;
344     if(0x10000<=w){ w=(w<<6)^(FXuchar)src[p++]^0x400080;
345     if(0x200000<=w){ w=(w<<6)^(FXuchar)src[p++]^0x8000080;
346     if(0x4000000<=w){ w=(w<<6)^(FXuchar)src[p++]^0x80; }} dst[len++]=(w>>10)+LEAD_OFFSET; w=(w&0x3FF)+0xDC00; }}}
347     dst[len++]=w;
348     }
349   return len;
350   }
351 
352 
353 // Copy utf8 string to narrow character string dst
utf2ncs(FXnchar * dst,const FXchar * src)354 FXint utf2ncs(FXnchar *dst,const FXchar *src){
355   return utf2ncs(dst,src,strlen(src)+1);
356   }
357 
358 
359 /*******************************************************************************/
360 
361 // Copy wide character substring of length n to dst
wc2utfs(FXchar * dst,const FXwchar * src,FXint n)362 FXint wc2utfs(FXchar* dst,const FXwchar *src,FXint n){
363   register FXint len=0;
364   register FXint p=0;
365   register FXwchar w;
366   while(p<n){
367     w=src[p++];
368     if(w<0x80){
369       dst[len++]=w;
370       continue;
371       }
372     if(w<0x800){
373       dst[len++]=(w>>6)|0xC0;
374       dst[len++]=(w&0x3F)|0x80;
375       continue;
376       }
377     if(w<0x10000){
378       dst[len++]=(w>>12)|0xE0;
379       dst[len++]=((w>>6)&0x3F)|0x80;
380       dst[len++]=(w&0x3F)|0x80;
381       continue;
382       }
383     if(w<0x200000){
384       dst[len++]=(w>>18)|0xF0;
385       dst[len++]=((w>>12)&0x3F)|0x80;
386       dst[len++]=((w>>6)&0x3F)|0x80;
387       dst[len++]=(w&0x3F)|0x80;
388       continue;
389       }
390     if(w<0x4000000){
391       dst[len++]=(w>>24)|0xF8;
392       dst[len++]=((w>>18)&0x3F)|0x80;
393       dst[len++]=((w>>12)&0x3F)|0x80;
394       dst[len++]=((w>>6)&0x3F)|0x80;
395       dst[len++]=(w&0x3F)|0x80;
396       continue;
397       }
398     dst[len++]=(w>>30)|0xFC;
399     dst[len++]=((w>>24)&0X3F)|0x80;
400     dst[len++]=((w>>18)&0X3F)|0x80;
401     dst[len++]=((w>>12)&0X3F)|0x80;
402     dst[len++]=((w>>6)&0X3F)|0x80;
403     dst[len++]=(w&0X3F)|0x80;
404     }
405   return len;
406   }
407 
408 
409 // Copy wide character string to dst
wc2utfs(FXchar * dst,const FXwchar * src)410 FXint wc2utfs(FXchar* dst,const FXwchar *src){
411   return wc2utfs(dst,src,strlen(src)+1);
412   }
413 
414 
415 // Copy narrow character substring of length n to dst
416 // Test for surrogates is deferred till code possibly exceeds 0xD800
nc2utfs(FXchar * dst,const FXnchar * src,FXint n)417 FXint nc2utfs(FXchar* dst,const FXnchar *src,FXint n){
418   register FXint len=0;
419   register FXint p=0;
420   register FXwchar w;
421   while(p<n){
422     w=src[p++];
423     if(w<0x80){
424       dst[len++]=w;
425       continue;
426       }
427     if(w<0x800){
428       dst[len++]=(w>>6)|0xC0;
429       dst[len++]=(w&0x3F)|0x80;
430       continue;
431       }
432     if(0xD800<=w && w<0xDC00 && p<n){ w=(w<<10)+src[p++]+SURROGATE_OFFSET; }
433     if(w<0x10000){
434       dst[len++]=(w>>12)|0xE0;
435       dst[len++]=((w>>6)&0x3F)|0x80;
436       dst[len++]=(w&0x3F)|0x80;
437       continue;
438       }
439     if(w<0x200000){
440       dst[len++]=(w>>18)|0xF0;
441       dst[len++]=((w>>12)&0x3F)|0x80;
442       dst[len++]=((w>>6)&0x3F)|0x80;
443       dst[len++]=(w&0x3F)|0x80;
444       continue;
445       }
446     if(w<0x4000000){
447       dst[len++]=(w>>24)|0xF8;
448       dst[len++]=((w>>18)&0x3F)|0x80;
449       dst[len++]=((w>>12)&0x3F)|0x80;
450       dst[len++]=((w>>6)&0x3F)|0x80;
451       dst[len++]=(w&0x3F)|0x80;
452       continue;
453       }
454     dst[len++]=(w>>30)|0xFC;
455     dst[len++]=((w>>24)&0X3F)|0x80;
456     dst[len++]=((w>>18)&0X3F)|0x80;
457     dst[len++]=((w>>12)&0X3F)|0x80;
458     dst[len++]=((w>>6)&0X3F)|0x80;
459     dst[len++]=(w&0X3F)|0x80;
460     }
461   return len;
462   }
463 
464 
465 // Copy narrow character string to dst
nc2utfs(FXchar * dst,const FXnchar * src)466 FXint nc2utfs(FXchar* dst,const FXnchar *src){
467   return nc2utfs(dst,src,strlen(src)+1);
468   }
469 
470 /*******************************************************************************/
471 
472 // Change the length of the string to len
length(FXint len)473 void FXString::length(FXint len){
474   if(*(((FXint*)str)-1)!=len){
475     if(0<len){
476       if(str==EMPTY)
477         str=sizeof(FXint)+(FXchar*)malloc(ROUNDUP(1+len)+sizeof(FXint));
478       else
479         str=sizeof(FXint)+(FXchar*)realloc(str-sizeof(FXint),ROUNDUP(1+len)+sizeof(FXint));
480       str[len]=0;
481       *(((FXint*)str)-1)=len;
482       }
483     else if(str!=EMPTY){
484       free(str-sizeof(FXint));
485       str=EMPTY;
486       }
487     }
488   }
489 
490 
491 // Return start of utf8 character containing position
validate(FXint p) const492 FXint FXString::validate(FXint p) const { return wcvalidate(str,p); }
493 
494 
495 // Advance to next utf8 character start
inc(FXint p) const496 FXint FXString::inc(FXint p) const { return wcinc(str,p); }
497 
498 
499 // Retreat to previous utf8 character start
dec(FXint p) const500 FXint FXString::dec(FXint p) const { return wcdec(str,p); }
501 
502 
503 // Return wide character starting at offset i
wc(FXint i) const504 FXwchar FXString::wc(FXint i) const {
505   register FXwchar w=(FXuchar)str[i];
506   if(0xC0<=w){ w=(w<<6)^(FXuchar)str[i+1]^0x3080;
507   if(0x800<=w){ w=(w<<6)^(FXuchar)str[i+2]^0x20080;
508   if(0x10000<=w){ w=(w<<6)^(FXuchar)str[i+3]^0x400080;
509   if(0x200000<=w){ w=(w<<6)^(FXuchar)str[i+4]^0x8000080;
510   if(0x4000000<=w){ w=(w<<6)^(FXuchar)str[i+5]^0x80; }}}}}
511   return w;
512   }
513 
514 
515 // Count number of utf8 characters in subrange
count(FXint pos,FXint len) const516 FXint FXString::count(FXint pos,FXint len) const {
517   register FXint cnt=0;
518   while(pos<len){
519     pos+=utfBytes[(FXuchar)str[pos]];
520     cnt++;
521     }
522   return cnt;
523   }
524 
525 
526 // Count number of utf8 characters
count() const527 FXint FXString::count() const {
528   return count(0,length());
529   }
530 
531 
532 // Return index of utf8 character at byte offset
index(FXint offs) const533 FXint FXString::index(FXint offs) const {
534   register FXint len=length();
535   register FXint i=0;
536   register FXint p=0;
537   while(p<offs && p<len){
538     p+=utfBytes[(FXuchar)str[p]];
539     i++;
540     }
541   return i;
542   }
543 
544 
545 // Return byte offset of utf8 character at index
offset(FXint indx) const546 FXint FXString::offset(FXint indx) const {
547   register FXint len=length();
548   register FXint i=0;
549   register FXint p=0;
550   while(i<indx && p<len){
551     p+=utfBytes[(FXuchar)str[p]];
552     i++;
553     }
554   return p;
555   }
556 
557 
558 // Simple construct
FXString()559 FXString::FXString():str(EMPTY){
560   }
561 
562 
563 // Copy construct
FXString(const FXString & s)564 FXString::FXString(const FXString& s):str(EMPTY){
565   register FXint n=s.length();
566   if(0<n){
567     length(n);
568     memcpy(str,s.str,n);
569     }
570   }
571 
572 
573 // Construct and init
FXString(const FXchar * s)574 FXString::FXString(const FXchar* s):str(EMPTY){
575   if(s && s[0]){
576     register FXint n=strlen(s);
577     length(n);
578     memcpy(str,s,n);
579     }
580   }
581 
582 
583 // Construct and init
FXString(const FXwchar * s)584 FXString::FXString(const FXwchar* s):str(EMPTY){
585   if(s && s[0]){
586     register FXint n=utfslen(s);
587     length(n);
588     wc2utfs(str,s);
589     }
590   }
591 
592 
593 // Construct and init
FXString(const FXnchar * s)594 FXString::FXString(const FXnchar* s):str(EMPTY){
595   if(s && s[0]){
596     register FXint n=utfslen(s);
597     length(n);
598     nc2utfs(str,s);
599     }
600   }
601 
602 
603 // Construct and init with substring
FXString(const FXchar * s,FXint n)604 FXString::FXString(const FXchar* s,FXint n):str(EMPTY){
605   if(s && 0<n){
606     length(n);
607     memcpy(str,s,n);
608     }
609   }
610 
611 
612 // Construct and init with wide character substring
FXString(const FXwchar * s,FXint m)613 FXString::FXString(const FXwchar* s,FXint m):str(EMPTY){
614   if(s && 0<m){
615     register FXint n=utfslen(s,m);
616     length(n);
617     wc2utfs(str,s,m);
618     }
619   }
620 
621 
622 // Construct and init with narrow character substring
FXString(const FXnchar * s,FXint m)623 FXString::FXString(const FXnchar* s,FXint m):str(EMPTY){
624   if(s && 0<m){
625     register FXint n=utfslen(s,m);
626     length(n);
627     nc2utfs(str,s,m);
628     }
629   }
630 
631 
632 // Construct and fill with constant
FXString(FXchar c,FXint n)633 FXString::FXString(FXchar c,FXint n):str(EMPTY){
634   if(0<n){
635     length(n);
636     memset(str,c,n);
637     }
638   }
639 
640 
641 // Return partition of string separated by delimiter delim
section(FXchar delim,FXint start,FXint num) const642 FXString FXString::section(FXchar delim,FXint start,FXint num) const {
643   register FXint len=length(),s,e;
644   s=0;
645   if(0<start){
646     while(s<len){
647       ++s;
648       if(str[s-1]==delim && --start==0) break;
649       }
650     }
651   e=s;
652   if(0<num){
653     while(e<len){
654       if(str[e]==delim && --num==0) break;
655       ++e;
656       }
657     }
658   return FXString(str+s,e-s);
659   }
660 
661 
662 // Return partition of string separated by delimiters in delim
section(const FXchar * delim,FXint n,FXint start,FXint num) const663 FXString FXString::section(const FXchar* delim,FXint n,FXint start,FXint num) const {
664   register FXint len=length(),s,e,i;
665   register FXchar c;
666   s=0;
667   if(0<start){
668     while(s<len){
669       c=str[s++];
670       i=n;
671       while(--i>=0){
672         if(delim[i]==c){
673           if(--start==0) goto a;
674           break;
675           }
676         }
677       }
678     }
679 a:e=s;
680   if(0<num){
681     while(e<len){
682       c=str[e];
683       i=n;
684       while(--i>=0){
685         if(delim[i]==c){
686           if(--num==0) goto b;
687           break;
688           }
689         }
690       ++e;
691       }
692     }
693 b:return FXString(str+s,e-s);
694   }
695 
696 
697 // Return partition of string separated by delimiters in delim
section(const FXchar * delim,FXint start,FXint num) const698 FXString FXString::section(const FXchar* delim,FXint start,FXint num) const {
699   return section(delim,strlen(delim),start,num);
700   }
701 
702 
703 // Return partition of string separated by delimiters in delim
section(const FXString & delim,FXint start,FXint num) const704 FXString FXString::section(const FXString& delim,FXint start,FXint num) const {
705   return section(delim.text(),delim.length(),start,num);
706   }
707 
708 
709 // Adopt string s, leaving s empty
adopt(FXString & s)710 FXString& FXString::adopt(FXString& s){
711   if(this!=&s){
712     if(str!=EMPTY){ free(str-sizeof(FXint)); }
713     str=s.str;
714     s.str=EMPTY;
715     }
716   return *this;
717   }
718 
719 
720 // Assign input character to this string
assign(FXchar c)721 FXString& FXString::assign(FXchar c){
722   length(1);
723   str[0]=c;
724   return *this;
725   }
726 
727 
728 // Assign input n characters c to this string
assign(FXchar c,FXint n)729 FXString& FXString::assign(FXchar c,FXint n){
730   length(n);
731   memset(str,c,n);
732   return *this;
733   }
734 
735 
736 // Assign first n characters of input string to this string
assign(const FXchar * s,FXint n)737 FXString& FXString::assign(const FXchar* s,FXint n){
738   if(s && 0<n){
739     length(n);
740     memmove(str,s,n);
741     }
742   else{
743     length(0);
744     }
745   return *this;
746   }
747 
748 
749 // Assign first n characters of wide character string s to this string
assign(const FXwchar * s,FXint m)750 FXString& FXString::assign(const FXwchar* s,FXint m){
751   if(s && 0<m){
752     register FXint n=utfslen(s,m);
753     length(n);
754     wc2utfs(str,s,m);
755     }
756   else{
757     length(0);
758     }
759   return *this;
760   }
761 
762 
763 // Assign first n characters of narrow character string s to this string
assign(const FXnchar * s,FXint m)764 FXString& FXString::assign(const FXnchar* s,FXint m){
765   if(s && 0<m){
766     register FXint n=utfslen(s,m);
767     length(n);
768     nc2utfs(str,s,m);
769     }
770   else{
771     length(0);
772     }
773   return *this;
774   }
775 
776 
777 // Assign input string to this string
assign(const FXchar * s)778 FXString& FXString::assign(const FXchar* s){
779   if(s && s[0]){
780     register FXint n=strlen(s);
781     length(n);
782     memmove(str,s,n);
783     }
784   else{
785     length(0);
786     }
787   return *this;
788   }
789 
790 
791 // Assign wide character string s to this string
assign(const FXwchar * s)792 FXString& FXString::assign(const FXwchar* s){
793   if(s && s[0]){
794     register FXint n=utfslen(s);
795     length(n);
796     wc2utfs(str,s);
797     }
798   else{
799     length(0);
800     }
801   return *this;
802   }
803 
804 
805 // Assign narrow character string s to this string
assign(const FXnchar * s)806 FXString& FXString::assign(const FXnchar* s){
807   if(s && s[0]){
808     register FXint n=utfslen(s);
809     length(n);
810     nc2utfs(str,s);
811     }
812   else{
813     length(0);
814     }
815   return *this;
816   }
817 
818 
819 // Assign input string to this string
assign(const FXString & s)820 FXString& FXString::assign(const FXString& s){
821   if(str!=s.str) assign(s.str,s.length());
822   return *this;
823   }
824 
825 
826 // Assign a string
operator =(const FXchar * s)827 FXString& FXString::operator=(const FXchar* s){
828   return assign(s);
829   }
830 
831 
832 // Assign a wide character string to this
operator =(const FXwchar * s)833 FXString& FXString::operator=(const FXwchar* s){
834   return assign(s);
835   }
836 
837 
838 // Assign a narrow character string to this
operator =(const FXnchar * s)839 FXString& FXString::operator=(const FXnchar* s){
840   return assign(s);
841   }
842 
843 
844 // Assignment
operator =(const FXString & s)845 FXString& FXString::operator=(const FXString& s){
846   if(str!=s.str) assign(s.str,s.length());
847   return *this;
848   }
849 
850 
851 // Insert character at position
insert(FXint pos,FXchar c)852 FXString& FXString::insert(FXint pos,FXchar c){
853   register FXint len=length();
854   length(len+1);
855   if(pos<=0){
856     memmove(str+1,str,len);
857     str[0]=c;
858     }
859   else if(pos>=len){
860     str[len]=c;
861     }
862   else{
863     memmove(str+pos+1,str+pos,len-pos);
864     str[pos]=c;
865     }
866   return *this;
867   }
868 
869 
870 // Insert n characters c at specified position
insert(FXint pos,FXchar c,FXint n)871 FXString& FXString::insert(FXint pos,FXchar c,FXint n){
872   if(0<n){
873     register FXint len=length();
874     length(len+n);
875     if(pos<=0){
876       memmove(str+n,str,len);
877       memset(str,c,n);
878       }
879     else if(pos>=len){
880       memset(str+len,c,n);
881       }
882     else{
883       memmove(str+pos+n,str+pos,len-pos);
884       memset(str+pos,c,n);
885       }
886     }
887   return *this;
888   }
889 
890 
891 
892 // Insert string at position
insert(FXint pos,const FXchar * s,FXint n)893 FXString& FXString::insert(FXint pos,const FXchar* s,FXint n){
894   if(s && 0<n){
895     register FXint len=length();
896     length(len+n);
897     if(pos<=0){
898       memmove(str+n,str,len);
899       memcpy(str,s,n);
900       }
901     else if(pos>=len){
902       memcpy(str+len,s,n);
903       }
904     else{
905       memmove(str+pos+n,str+pos,len-pos);
906       memcpy(str+pos,s,n);
907       }
908     }
909   return *this;
910   }
911 
912 
913 // Insert wide character string at position
insert(FXint pos,const FXwchar * s,FXint m)914 FXString& FXString::insert(FXint pos,const FXwchar* s,FXint m){
915   if(s && 0<m){
916     register FXint len=length();
917     register FXint n=utfslen(s,m);
918     length(len+n);
919     if(pos<=0){
920       memmove(str+n,str,len);
921       wc2utfs(str,s,m);
922       }
923     else if(pos>=len){
924       wc2utfs(str+len,s,m);
925       }
926     else{
927       memmove(str+pos+n,str+pos,len-pos);
928       wc2utfs(str+pos,s,m);
929       }
930     }
931   return *this;
932   }
933 
934 
935 // Insert narrow character string at position
insert(FXint pos,const FXnchar * s,FXint m)936 FXString& FXString::insert(FXint pos,const FXnchar* s,FXint m){
937   if(s && 0<m){
938     register FXint len=length();
939     register FXint n=utfslen(s,m);
940     length(len+n);
941     if(pos<=0){
942       memmove(str+n,str,len);
943       nc2utfs(str,s,m);
944       }
945     else if(pos>=len){
946       nc2utfs(str+len,s,m);
947       }
948     else{
949       memmove(str+pos+n,str+pos,len-pos);
950       nc2utfs(str+pos,s,m);
951       }
952     }
953   return *this;
954   }
955 
956 
957 // Insert string at position
insert(FXint pos,const FXchar * s)958 FXString& FXString::insert(FXint pos,const FXchar* s){
959   if(s && s[0]){
960     register FXint len=length();
961     register FXint n=strlen(s);
962     length(len+n);
963     if(pos<=0){
964       memmove(str+n,str,len);
965       memcpy(str,s,n);
966       }
967     else if(pos>=len){
968       memcpy(str+len,s,n);
969       }
970     else{
971       memmove(str+pos+n,str+pos,len-pos);
972       memcpy(str+pos,s,n);
973       }
974     }
975   return *this;
976   }
977 
978 
979 // Insert wide character string at position
insert(FXint pos,const FXwchar * s)980 FXString& FXString::insert(FXint pos,const FXwchar* s){
981   if(s && s[0]){
982     register FXint len=length();
983     register FXint n=utfslen(s);
984     length(len+n);
985     if(pos<=0){
986       memmove(str+n,str,len);
987       wc2utfs(str,s);
988       }
989     else if(pos>=len){
990       wc2utfs(str+len,s);
991       }
992     else{
993       memmove(str+pos+n,str+pos,len-pos);
994       wc2utfs(str+pos,s);
995       }
996     }
997   return *this;
998   }
999 
1000 
1001 // Insert narrow character string at position
insert(FXint pos,const FXnchar * s)1002 FXString& FXString::insert(FXint pos,const FXnchar* s){
1003   if(s && s[0]){
1004     register FXint len=length();
1005     register FXint n=utfslen(s);
1006     length(len+n);
1007     if(pos<=0){
1008       memmove(str+n,str,len);
1009       nc2utfs(str,s);
1010       }
1011     else if(pos>=len){
1012       nc2utfs(str+len,s);
1013       }
1014     else{
1015       memmove(str+pos+n,str+pos,len-pos);
1016       nc2utfs(str+pos,s);
1017       }
1018     }
1019   return *this;
1020   }
1021 
1022 
1023 // Insert string at position
insert(FXint pos,const FXString & s)1024 FXString& FXString::insert(FXint pos,const FXString& s){
1025   return insert(pos,s.str,s.length());
1026   }
1027 
1028 
1029 // Append character c to this string
append(FXchar c)1030 FXString& FXString::append(FXchar c){
1031   register FXint len=length();
1032   length(len+1);
1033   str[len]=c;
1034   return *this;
1035   }
1036 
1037 
1038 // Append n characters c to this string
append(FXchar c,FXint n)1039 FXString& FXString::append(FXchar c,FXint n){
1040   if(0<n){
1041     register FXint len=length();
1042     length(len+n);
1043     memset(str+len,c,n);
1044     }
1045   return *this;
1046   }
1047 
1048 
1049 // Append string to this string
append(const FXchar * s,FXint n)1050 FXString& FXString::append(const FXchar* s,FXint n){
1051   if(s && 0<n){
1052     register FXint len=length();
1053     length(len+n);
1054     memcpy(str+len,s,n);
1055     }
1056   return *this;
1057   }
1058 
1059 
1060 // Append string to this string
append(const FXwchar * s,FXint m)1061 FXString& FXString::append(const FXwchar* s,FXint m){
1062   if(s && 0<m){
1063     register FXint len=length();
1064     register FXint n=utfslen(s,m);
1065     length(len+n);
1066     wc2utfs(str+len,s,m);
1067     }
1068   return *this;
1069   }
1070 
1071 
1072 // Append string to this string
append(const FXnchar * s,FXint m)1073 FXString& FXString::append(const FXnchar* s,FXint m){
1074   if(s && 0<m){
1075     register FXint len=length();
1076     register FXint n=utfslen(s,m);
1077     length(len+n);
1078     nc2utfs(str+len,s,m);
1079     }
1080   return *this;
1081   }
1082 
1083 
1084 // Append string to this string
append(const FXchar * s)1085 FXString& FXString::append(const FXchar* s){
1086   if(s && s[0]){
1087     register FXint len=length();
1088     register FXint n=strlen(s);
1089     length(len+n);
1090     memcpy(str+len,s,n);
1091     }
1092   return *this;
1093   }
1094 
1095 
1096 // Append string to this string
append(const FXwchar * s)1097 FXString& FXString::append(const FXwchar* s){
1098   if(s && s[0]){
1099     register FXint len=length();
1100     register FXint n=utfslen(s);
1101     length(len+n);
1102     wc2utfs(str+len,s);
1103     }
1104   return *this;
1105   }
1106 
1107 
1108 // Append string to this string
append(const FXnchar * s)1109 FXString& FXString::append(const FXnchar* s){
1110   if(s && s[0]){
1111     register FXint len=length();
1112     register FXint n=utfslen(s);
1113     length(len+n);
1114     nc2utfs(str+len,s);
1115     }
1116   return *this;
1117   }
1118 
1119 
1120 // Append string to this string
append(const FXString & s)1121 FXString& FXString::append(const FXString& s){
1122   return append(s.str,s.length());
1123   }
1124 
1125 
1126 // Append character
operator +=(FXchar c)1127 FXString& FXString::operator+=(FXchar c){
1128   return append(c);
1129   }
1130 
1131 
1132 // Append string
operator +=(const FXchar * s)1133 FXString& FXString::operator+=(const FXchar* s){
1134   return append(s);
1135   }
1136 
1137 
1138 // Append string
operator +=(const FXwchar * s)1139 FXString& FXString::operator+=(const FXwchar* s){
1140   return append(s);
1141   }
1142 
1143 
1144 // Append string
operator +=(const FXnchar * s)1145 FXString& FXString::operator+=(const FXnchar* s){
1146   return append(s);
1147   }
1148 
1149 
1150 // Append FXString
operator +=(const FXString & s)1151 FXString& FXString::operator+=(const FXString& s){
1152   return append(s);
1153   }
1154 
1155 
1156 // Prepend character
prepend(FXchar c)1157 FXString& FXString::prepend(FXchar c){
1158   register FXint len=length();
1159   length(len+1);
1160   memmove(str+1,str,len);
1161   str[0]=c;
1162   return *this;
1163   }
1164 
1165 
1166 // Prepend string with n characters c
prepend(FXchar c,FXint n)1167 FXString& FXString::prepend(FXchar c,FXint n){
1168   if(0<n){
1169     register FXint len=length();
1170     length(len+n);
1171     memmove(str+n,str,len);
1172     memset(str,c,n);
1173     }
1174   return *this;
1175   }
1176 
1177 
1178 // Prepend string
prepend(const FXchar * s,FXint n)1179 FXString& FXString::prepend(const FXchar* s,FXint n){
1180   if(s && 0<n){
1181     register FXint len=length();
1182     length(len+n);
1183     memmove(str+n,str,len);
1184     memcpy(str,s,n);
1185     }
1186   return *this;
1187   }
1188 
1189 
1190 // Prepend wide character string
prepend(const FXwchar * s,FXint m)1191 FXString& FXString::prepend(const FXwchar* s,FXint m){
1192   if(s && 0<m){
1193     register FXint len=length();
1194     register FXint n=utfslen(s,m);
1195     length(len+n);
1196     memmove(str+n,str,len);
1197     wc2utfs(str,s,m);
1198     }
1199   return *this;
1200   }
1201 
1202 
1203 // Prepend narrow character string
prepend(const FXnchar * s,FXint m)1204 FXString& FXString::prepend(const FXnchar* s,FXint m){
1205   if(s && 0<m){
1206     register FXint len=length();
1207     register FXint n=utfslen(s,m);
1208     length(len+n);
1209     memmove(str+n,str,len);
1210     nc2utfs(str,s,m);
1211     }
1212   return *this;
1213   }
1214 
1215 
1216 // Prepend string
prepend(const FXchar * s)1217 FXString& FXString::prepend(const FXchar* s){
1218   if(s && s[0]){
1219     register FXint len=length();
1220     register FXint n=strlen(s);
1221     length(len+n);
1222     memmove(str+n,str,len);
1223     memcpy(str,s,n);
1224     }
1225   return *this;
1226   }
1227 
1228 
1229 // Prepend wide character string
prepend(const FXwchar * s)1230 FXString& FXString::prepend(const FXwchar* s){
1231   if(s && s[0]){
1232     register FXint len=length();
1233     register FXint n=utfslen(s);
1234     length(len+n);
1235     memmove(str+n,str,len);
1236     wc2utfs(str,s);
1237     }
1238   return *this;
1239   }
1240 
1241 
1242 // Prepend narrow character string
prepend(const FXnchar * s)1243 FXString& FXString::prepend(const FXnchar* s){
1244   if(s && s[0]){
1245     register FXint len=length();
1246     register FXint n=utfslen(s);
1247     length(len+n);
1248     memmove(str+n,str,len);
1249     nc2utfs(str,s);
1250     }
1251   return *this;
1252   }
1253 
1254 
1255 // Prepend string
prepend(const FXString & s)1256 FXString& FXString::prepend(const FXString& s){
1257   return prepend(s.str,s.length());
1258   }
1259 
1260 
1261 // Replace character in string
replace(FXint pos,FXchar c)1262 FXString& FXString::replace(FXint pos,FXchar c){
1263   register FXint len=length();
1264   if(pos<0){
1265     length(len+1);
1266     memmove(str+1,str,len);
1267     str[0]=c;
1268     }
1269   else if(pos>=len){
1270     length(len+1);
1271     str[len]=c;
1272     }
1273   else{
1274     str[pos]=c;
1275     }
1276   return *this;
1277   }
1278 
1279 
1280 // Replace the m characters at pos with n characters c
replace(FXint pos,FXint m,FXchar c,FXint n)1281 FXString& FXString::replace(FXint pos,FXint m,FXchar c,FXint n){
1282   register FXint len=length();
1283   if(pos<0){
1284     m+=pos;
1285     if(m<0) m=0;
1286     pos=0;
1287     }
1288   if(pos+m>len){
1289     if(pos>len) pos=len;
1290     m=len-pos;
1291     }
1292   if(m<n){
1293     length(len+n-m);
1294     memmove(str+pos+n,str+pos+m,len-pos-m);
1295     }
1296   else if(m>n){
1297     memmove(str+pos+n,str+pos+m,len-pos-m);
1298     length(len+n-m);
1299     }
1300   memset(str+pos,c,n);
1301   return *this;
1302   }
1303 
1304 
1305 // Replace part of string
replace(FXint pos,FXint m,const FXchar * s,FXint n)1306 FXString& FXString::replace(FXint pos,FXint m,const FXchar* s,FXint n){
1307   register FXint len=length();
1308   if(pos<0){
1309     m+=pos;
1310     if(m<0) m=0;
1311     pos=0;
1312     }
1313   if(pos+m>len){
1314     if(pos>len) pos=len;
1315     m=len-pos;
1316     }
1317   if(m<n){
1318     length(len+n-m);
1319     memmove(str+pos+n,str+pos+m,len-pos-m);
1320     }
1321   else if(m>n){
1322     memmove(str+pos+n,str+pos+m,len-pos-m);
1323     length(len+n-m);
1324     }
1325   memcpy(str+pos,s,n);
1326   return *this;
1327   }
1328 
1329 
1330 // Replace part of wide character string
replace(FXint pos,FXint m,const FXwchar * s,FXint n)1331 FXString& FXString::replace(FXint pos,FXint m,const FXwchar* s,FXint n){
1332   register FXint w=utfslen(s,n);
1333   register FXint len=length();
1334   if(pos<0){
1335     m+=pos;
1336     if(m<0) m=0;
1337     pos=0;
1338     }
1339   if(pos+m>len){
1340     if(pos>len) pos=len;
1341     m=len-pos;
1342     }
1343   if(m<w){
1344     length(len+w-m);
1345     memmove(str+pos+w,str+pos+m,len-pos-m);
1346     }
1347   else if(m>w){
1348     memmove(str+pos+w,str+pos+m,len-pos-m);
1349     length(len+w-m);
1350     }
1351   wc2utfs(str+pos,s,n);
1352   return *this;
1353   }
1354 
1355 
1356 // Replace part of narrow character string
replace(FXint pos,FXint m,const FXnchar * s,FXint n)1357 FXString& FXString::replace(FXint pos,FXint m,const FXnchar* s,FXint n){
1358   register FXint w=utfslen(s,n);
1359   register FXint len=length();
1360   if(pos<0){
1361     m+=pos;
1362     if(m<0) m=0;
1363     pos=0;
1364     }
1365   if(pos+m>len){
1366     if(pos>len) pos=len;
1367     m=len-pos;
1368     }
1369   if(m<w){
1370     length(len+w-m);
1371     memmove(str+pos+w,str+pos+m,len-pos-m);
1372     }
1373   else if(m>w){
1374     memmove(str+pos+w,str+pos+m,len-pos-m);
1375     length(len+w-m);
1376     }
1377   nc2utfs(str+pos,s,n);
1378   return *this;
1379   }
1380 
1381 
1382 // Replace part of string
replace(FXint pos,FXint m,const FXchar * s)1383 FXString& FXString::replace(FXint pos,FXint m,const FXchar* s){
1384   return replace(pos,m,s,strlen(s));
1385   }
1386 
1387 
1388 // Replace part of string
replace(FXint pos,FXint m,const FXwchar * s)1389 FXString& FXString::replace(FXint pos,FXint m,const FXwchar* s){
1390   return replace(pos,m,s,strlen(s));
1391   }
1392 
1393 
1394 // Replace part of string
replace(FXint pos,FXint m,const FXnchar * s)1395 FXString& FXString::replace(FXint pos,FXint m,const FXnchar* s){
1396   return replace(pos,m,s,strlen(s));
1397   }
1398 
1399 
1400 // Replace part of string
replace(FXint pos,FXint m,const FXString & s)1401 FXString& FXString::replace(FXint pos,FXint m,const FXString& s){
1402   return replace(pos,m,s.str,s.length());
1403   }
1404 
1405 
1406 // Move range of m characters from src position to dst position
move(FXint dst,FXint src,FXint n)1407 FXString& FXString::move(FXint dst,FXint src,FXint n){
1408   register FXint len=length();
1409   if(0<n && 0<=src && src+n<=len){
1410     if(dst<0){                                  // Move below begin
1411       if(dst<-n) dst=-n;
1412       length(len-dst);
1413       memmove(str-dst,str,len);
1414       memmove(str,str-dst+src,n);
1415       }
1416     else if(dst+n>len){                         // Move beyond end
1417       if(dst>len) dst=len;
1418       length(dst+n);
1419       memmove(str+dst,str+src,n);
1420       }
1421     else{
1422       memmove(str+dst,str+src,n);               // Move inside
1423       }
1424     }
1425   return *this;
1426   }
1427 
1428 
1429 // Remove one character
erase(FXint pos)1430 FXString& FXString::erase(FXint pos){
1431   register FXint len=length();
1432   if(0<=pos && pos<len){
1433     memmove(str+pos,str+pos+1,len-pos-1);
1434     length(len-1);
1435     }
1436   return *this;
1437   }
1438 
1439 
1440 // Remove section from buffer
erase(FXint pos,FXint n)1441 FXString& FXString::erase(FXint pos,FXint n){
1442   if(0<n){
1443     register FXint len=length();
1444     if(pos<len && pos+n>0){
1445       if(pos<0){n+=pos;pos=0;}
1446       if(pos+n>len){n=len-pos;}
1447       memmove(str+pos,str+pos+n,len-pos-n);
1448       length(len-n);
1449       }
1450     }
1451   return *this;
1452   }
1453 
1454 
1455 // Return number of occurrences of ch in string
contains(FXchar ch) const1456 FXint FXString::contains(FXchar ch) const {
1457   register FXint len=length();
1458   register FXint c=ch;
1459   register FXint m=0;
1460   register FXint i=0;
1461   while(i<len){
1462     if(str[i]==c){
1463       m++;
1464       }
1465     i++;
1466     }
1467   return m;
1468   }
1469 
1470 
1471 // Return number of occurrences of string sub in string
contains(const FXchar * sub,FXint n) const1472 FXint FXString::contains(const FXchar* sub,FXint n) const {
1473   register FXint len=length()-n;
1474   register FXint m=0;
1475   register FXint i=0;
1476   while(i<=len){
1477     if(compare(str+i,sub,n)==0){
1478       m++;
1479       }
1480     i++;
1481     }
1482   return m;
1483   }
1484 
1485 
1486 // Return number of occurrences of string sub in string
contains(const FXchar * sub) const1487 FXint FXString::contains(const FXchar* sub) const {
1488   return contains(sub,strlen(sub));
1489   }
1490 
1491 
1492 // Return number of occurrences of string sub in string
contains(const FXString & sub) const1493 FXint FXString::contains(const FXString& sub) const {
1494   return contains(sub.text(),sub.length());
1495   }
1496 
1497 
1498 // Concatenate two FXStrings
operator +(const FXString & s1,const FXString & s2)1499 FXString operator+(const FXString& s1,const FXString& s2){
1500   FXString result(s1);
1501   return result.append(s2);
1502   }
1503 
1504 
1505 // Concatenate FXString and string
operator +(const FXString & s1,const FXchar * s2)1506 FXString operator+(const FXString& s1,const FXchar* s2){
1507   FXString result(s1);
1508   return result.append(s2);
1509   }
1510 
1511 
1512 // Concatenate FXString and wide character string
operator +(const FXString & s1,const FXwchar * s2)1513 FXString operator+(const FXString& s1,const FXwchar* s2){
1514   FXString result(s1);
1515   return result.append(s2);
1516   }
1517 
1518 
1519 // Concatenate FXString and narrow character string
operator +(const FXString & s1,const FXnchar * s2)1520 FXString operator+(const FXString& s1,const FXnchar* s2){
1521   FXString result(s1);
1522   return result.append(s2);
1523   }
1524 
1525 
1526 // Concatenate string and FXString
operator +(const FXchar * s1,const FXString & s2)1527 FXString operator+(const FXchar* s1,const FXString& s2){
1528   FXString result(s1);
1529   return result.append(s2);
1530   }
1531 
1532 
1533 // Concatenate wide character string and FXString
operator +(const FXwchar * s1,const FXString & s2)1534 FXString operator+(const FXwchar* s1,const FXString& s2){
1535   FXString result(s1);
1536   return result.append(s2);
1537   }
1538 
1539 
1540 // Concatenate narrow character string and FXString
operator +(const FXnchar * s1,const FXString & s2)1541 FXString operator+(const FXnchar* s1,const FXString& s2){
1542   FXString result(s1);
1543   return result.append(s2);
1544   }
1545 
1546 
1547 // Concatenate FXString and character
operator +(const FXString & s,FXchar c)1548 FXString operator+(const FXString& s,FXchar c){
1549   FXString result(s);
1550   return result.append(c);
1551   }
1552 
1553 
1554 // Concatenate character and FXString
operator +(FXchar c,const FXString & s)1555 FXString operator+(FXchar c,const FXString& s){
1556   FXString result(&c,1);
1557   return result.append(s);
1558   }
1559 
1560 
1561 // Substitute one character by another
substitute(FXchar org,FXchar sub,bool all)1562 FXString& FXString::substitute(FXchar org,FXchar sub,bool all){
1563   register FXint len=length();
1564   register FXint c=org;
1565   register FXint s=sub;
1566   register FXint i=0;
1567   while(i<len){
1568     if(str[i]==c){
1569       str[i]=s;
1570       if(!all) break;
1571       }
1572     i++;
1573     }
1574   return *this;
1575   }
1576 
1577 
1578 // Substitute one string by another
substitute(const FXchar * org,FXint olen,const FXchar * rep,FXint rlen,bool all)1579 FXString& FXString::substitute(const FXchar* org,FXint olen,const FXchar* rep,FXint rlen,bool all){
1580   if(0<olen){
1581     register FXint pos=0;
1582     while(pos<=length()-olen){
1583       if(compare(str+pos,org,olen)==0){
1584         replace(pos,olen,rep,rlen);
1585         if(!all) break;
1586         pos+=rlen;
1587         continue;
1588         }
1589       pos++;
1590       }
1591     }
1592   return *this;
1593   }
1594 
1595 
1596 // Substitute one string by another
substitute(const FXchar * org,const FXchar * rep,bool all)1597 FXString& FXString::substitute(const FXchar* org,const FXchar* rep,bool all){
1598   return substitute(org,strlen(org),rep,strlen(rep),all);
1599   }
1600 
1601 
1602 // Substitute one string by another
substitute(const FXString & org,const FXString & rep,bool all)1603 FXString& FXString::substitute(const FXString& org,const FXString& rep,bool all){
1604   return substitute(org.text(),org.length(),rep.text(),rep.length(),all);
1605   }
1606 
1607 
1608 // Simplify whitespace in string
simplify()1609 FXString& FXString::simplify(){
1610   if(str!=EMPTY){
1611     register FXint s=0;
1612     register FXint d=0;
1613     register FXint e=length();
1614     while(s<e && Ascii::isSpace(str[s])) s++;
1615     while(1){
1616       while(s<e && !Ascii::isSpace(str[s])) str[d++]=str[s++];
1617       while(s<e && Ascii::isSpace(str[s])) s++;
1618       if(s>=e) break;
1619       str[d++]=' ';
1620       }
1621     length(d);
1622     }
1623   return *this;
1624   }
1625 
1626 
1627 // Remove leading and trailing whitespace
trim()1628 FXString& FXString::trim(){
1629   if(str!=EMPTY){
1630     register FXint s=0;
1631     register FXint e=length();
1632     while(0<e && Ascii::isSpace(str[e-1])) e--;
1633     while(s<e && Ascii::isSpace(str[s])) s++;
1634     memmove(str,&str[s],e-s);
1635     length(e-s);
1636     }
1637   return *this;
1638   }
1639 
1640 
1641 // Remove leading whitespace
trimBegin()1642 FXString& FXString::trimBegin(){
1643   if(str!=EMPTY){
1644     register FXint s=0;
1645     register FXint e=length();
1646     while(s<e && Ascii::isSpace(str[s])) s++;
1647     memmove(str,str+s,e-s);
1648     length(e-s);
1649     }
1650   return *this;
1651   }
1652 
1653 
1654 // Remove trailing whitespace
trimEnd()1655 FXString& FXString::trimEnd(){
1656   if(str!=EMPTY){
1657     register FXint e=length();
1658     while(0<e && Ascii::isSpace(str[e-1])) e--;
1659     length(e);
1660     }
1661   return *this;
1662   }
1663 
1664 
1665 // Truncate string
trunc(FXint pos)1666 FXString& FXString::trunc(FXint pos){
1667   register FXint len=length();
1668   if(pos>len) pos=len;
1669   length(pos);
1670   return *this;
1671   }
1672 
1673 
1674 // Clean string
clear()1675 FXString& FXString::clear(){
1676   length(0);
1677   return *this;
1678   }
1679 
1680 
1681 // Get leftmost part
left(FXint n) const1682 FXString FXString::left(FXint n) const {
1683   if(0<n){
1684     register FXint len=length();
1685     if(n>len) n=len;
1686     return FXString(str,n);
1687     }
1688   return FXString::null;
1689   }
1690 
1691 
1692 // Get rightmost part
right(FXint n) const1693 FXString FXString::right(FXint n) const {
1694   if(0<n){
1695     register FXint len=length();
1696     if(n>len) n=len;
1697     return FXString(str+len-n,n);
1698     }
1699   return FXString::null;
1700   }
1701 
1702 
1703 // Get some part in the middle
mid(FXint pos,FXint n) const1704 FXString FXString::mid(FXint pos,FXint n) const {
1705   if(0<n){
1706     register FXint len=length();
1707     if(pos<len && pos+n>0){
1708       if(pos<0){n+=pos;pos=0;}
1709       if(pos+n>len){n=len-pos;}
1710       return FXString(str+pos,n);
1711       }
1712     }
1713   return FXString::null;
1714   }
1715 
1716 
1717 // Return all characters before the nth occurrence of ch, searching forward
before(FXchar c,FXint n) const1718 FXString FXString::before(FXchar c,FXint n) const {
1719   register FXint len=length();
1720   register FXint p=0;
1721   if(0<n){
1722     while(p<len){
1723       if(str[p]==c && --n==0) break;
1724       p++;
1725       }
1726     }
1727   return FXString(str,p);
1728   }
1729 
1730 
1731 // Return all characters before the nth occurrence of ch, searching backward
rbefore(FXchar c,FXint n) const1732 FXString FXString::rbefore(FXchar c,FXint n) const {
1733   register FXint p=length();
1734   if(0<n){
1735     while(0<p){
1736       p--;
1737       if(str[p]==c && --n==0) break;
1738       }
1739     }
1740   return FXString(str,p);
1741   }
1742 
1743 
1744 // Return all characters after the nth occurrence of ch, searching forward
after(FXchar c,FXint n) const1745 FXString FXString::after(FXchar c,FXint n) const {
1746   register FXint len=length();
1747   register FXint p=0;
1748   if(0<n){
1749     while(p<len){
1750       p++;
1751       if(str[p-1]==c && --n==0) break;
1752       }
1753     }
1754   return FXString(str+p,len-p);
1755   }
1756 
1757 
1758 // Return all characters after the nth occurrence of ch, searching backward
rafter(FXchar c,FXint n) const1759 FXString FXString::rafter(FXchar c,FXint n) const {
1760   register FXint len=length();
1761   register FXint p=len;
1762   if(0<n){
1763     while(0<p){
1764       if(str[p-1]==c && --n==0) break;
1765       p--;
1766       }
1767     }
1768   return FXString(str+p,len-p);
1769   }
1770 
1771 
1772 // Convert to lower case
lower()1773 FXString& FXString::lower(){
1774   FXString string;
1775   for(FXint p=0; p<length(); p=inc(p)){
1776     FXwchar w=Unicode::toLower(wc(p));
1777     string.append(&w,1);
1778     }
1779   adopt(string);
1780   return *this;
1781   }
1782 
1783 
1784 // Convert to upper case
upper()1785 FXString& FXString::upper(){
1786   FXString string;
1787   for(FXint p=0; p<length(); p=inc(p)){
1788     FXwchar w=Unicode::toUpper(wc(p));
1789     string.append(&w,1);
1790     }
1791   adopt(string);
1792   return *this;
1793   }
1794 
1795 
1796 // Compare strings
compare(const FXchar * s1,const FXchar * s2)1797 FXint compare(const FXchar* s1,const FXchar* s2){
1798   register const FXuchar *p1=(const FXuchar *)s1;
1799   register const FXuchar *p2=(const FXuchar *)s2;
1800   register FXint c1,c2;
1801   do{
1802     c1=*p1++;
1803     c2=*p2++;
1804     }
1805   while(c1 && (c1==c2));
1806   return c1-c2;
1807   }
1808 
1809 
compare(const FXchar * s1,const FXString & s2)1810 FXint compare(const FXchar* s1,const FXString& s2){
1811   return compare(s1,s2.str);
1812   }
1813 
1814 
compare(const FXString & s1,const FXchar * s2)1815 FXint compare(const FXString& s1,const FXchar* s2){
1816   return compare(s1.str,s2);
1817   }
1818 
1819 
compare(const FXString & s1,const FXString & s2)1820 FXint compare(const FXString& s1,const FXString& s2){
1821   return compare(s1.str,s2.str);
1822   }
1823 
1824 
1825 // Compare strings up to n
compare(const FXchar * s1,const FXchar * s2,FXint n)1826 FXint compare(const FXchar* s1,const FXchar* s2,FXint n){
1827   register const FXuchar *p1=(const FXuchar *)s1;
1828   register const FXuchar *p2=(const FXuchar *)s2;
1829   register FXint c1,c2;
1830   if(0<n){
1831     do{
1832       c1=*p1++;
1833       c2=*p2++;
1834       }
1835     while(--n && c1 && (c1==c2));
1836     return c1-c2;
1837     }
1838   return 0;
1839   }
1840 
1841 
compare(const FXchar * s1,const FXString & s2,FXint n)1842 FXint compare(const FXchar* s1,const FXString& s2,FXint n){
1843   return compare(s1,s2.str,n);
1844   }
1845 
1846 
compare(const FXString & s1,const FXchar * s2,FXint n)1847 FXint compare(const FXString& s1,const FXchar* s2,FXint n){
1848   return compare(s1.str,s2,n);
1849   }
1850 
1851 
compare(const FXString & s1,const FXString & s2,FXint n)1852 FXint compare(const FXString& s1,const FXString& s2,FXint n){
1853   return compare(s1.str,s2.str,n);
1854   }
1855 
1856 
1857 // Compare utf-8 strings case insensitive
1858 // At each iteration through the loop, the following is true:
1859 //   o Both characters are ascii.  In this case, fold using Ascii
1860 //     and compare.
1861 //   o One of the two is ascii.  This means the other is > 0x80
1862 //     so fold using Ascii [leaving upper 128 codes invariant], and
1863 //     compare; they will be unequal so we'll fall out of the loop.
1864 //   o Both characters are wide.  This is the complex case, and
1865 //     here we have to obtain the wide character, convert to lower
1866 //     case using the Unicode, and compare.  Skip to the start of
1867 //     the next character by consulting character-width table.
comparecase(const FXchar * s1,const FXchar * s2)1868 FXint comparecase(const FXchar* s1,const FXchar* s2){
1869   register FXint c1,c2;
1870   do{
1871     if((*s1 & 0x80) && (*s2 & 0x80)){
1872       c1=Unicode::toLower(wc(s1)); s1+=wclen(s1);
1873       c2=Unicode::toLower(wc(s2)); s2+=wclen(s2);
1874       }
1875     else{
1876       c1=Ascii::toLower(*s1); s1+=1;
1877       c2=Ascii::toLower(*s2); s2+=1;
1878       }
1879     }
1880   while(c1 && (c1==c2));
1881   return c1-c2;
1882   }
1883 
1884 
1885 // Compare strings case insensitive up to n
comparecase(const FXchar * s1,const FXchar * s2,FXint n)1886 FXint comparecase(const FXchar* s1,const FXchar* s2,FXint n){
1887   register FXint c1,c2;
1888   if(0<n){
1889     do{
1890       if((*s1 & 0x80) && (*s2 & 0x80)){
1891         c1=Unicode::toLower(wc(s1)); s1+=wclen(s1);
1892         c2=Unicode::toLower(wc(s2)); s2+=wclen(s2);
1893         }
1894       else{
1895         c1=Ascii::toLower(*s1); s1+=1;
1896         c2=Ascii::toLower(*s2); s2+=1;
1897         }
1898       }
1899     while(--n && c1 && (c1==c2));
1900     return c1-c2;
1901     }
1902   return 0;
1903   }
1904 
1905 
1906 #if 0
1907 // Compare strings case insensitive
1908 FXint comparecase(const FXchar* s1,const FXchar* s2){
1909   register const FXuchar *p1=(const FXuchar *)s1;
1910   register const FXuchar *p2=(const FXuchar *)s2;
1911   register FXint c1,c2;
1912   do{
1913     c1=Ascii::toLower(*p1++);
1914     c2=Ascii::toLower(*p2++);
1915     }
1916   while(c1 && (c1==c2));
1917   return c1-c2;
1918   }
1919 #endif
1920 
comparecase(const FXchar * s1,const FXString & s2)1921 FXint comparecase(const FXchar* s1,const FXString& s2){
1922   return comparecase(s1,s2.str);
1923   }
1924 
1925 
comparecase(const FXString & s1,const FXchar * s2)1926 FXint comparecase(const FXString& s1,const FXchar* s2){
1927   return comparecase(s1.str,s2);
1928   }
1929 
1930 
comparecase(const FXString & s1,const FXString & s2)1931 FXint comparecase(const FXString& s1,const FXString& s2){
1932   return comparecase(s1.str,s2.str);
1933   }
1934 
1935 
1936 #if 0
1937 // Compare strings case insensitive up to n
1938 FXint comparecase(const FXchar* s1,const FXchar* s2,FXint n){
1939   register const FXuchar *p1=(const FXuchar *)s1;
1940   register const FXuchar *p2=(const FXuchar *)s2;
1941   register FXint c1,c2;
1942   if(0<n){
1943     do{
1944       c1=Ascii::toLower(*p1++);
1945       c2=Ascii::toLower(*p2++);
1946       }
1947     while(--n && c1 && (c1==c2));
1948     return c1-c2;
1949     }
1950   return 0;
1951   }
1952 #endif
1953 
comparecase(const FXchar * s1,const FXString & s2,FXint n)1954 FXint comparecase(const FXchar* s1,const FXString& s2,FXint n){
1955   return comparecase(s1,s2.str,n);
1956   }
1957 
comparecase(const FXString & s1,const FXchar * s2,FXint n)1958 FXint comparecase(const FXString& s1,const FXchar* s2,FXint n){
1959   return comparecase(s1.str,s2,n);
1960   }
1961 
comparecase(const FXString & s1,const FXString & s2,FXint n)1962 FXint comparecase(const FXString& s1,const FXString& s2,FXint n){
1963   return comparecase(s1.str,s2.str,n);
1964   }
1965 
1966 // Comparison operators
operator ==(const FXString & s1,const FXString & s2)1967 bool operator==(const FXString& s1,const FXString& s2){
1968   return compare(s1.str,s2.str)==0;
1969   }
1970 
operator ==(const FXString & s1,const FXchar * s2)1971 bool operator==(const FXString& s1,const FXchar* s2){
1972   return compare(s1.str,s2)==0;
1973   }
1974 
operator ==(const FXchar * s1,const FXString & s2)1975 bool operator==(const FXchar* s1,const FXString& s2){
1976   return compare(s1,s2.str)==0;
1977   }
1978 
operator !=(const FXString & s1,const FXString & s2)1979 bool operator!=(const FXString& s1,const FXString& s2){
1980   return compare(s1.str,s2.str)!=0;
1981   }
1982 
operator !=(const FXString & s1,const FXchar * s2)1983 bool operator!=(const FXString& s1,const FXchar* s2){
1984   return compare(s1.str,s2)!=0;
1985   }
1986 
operator !=(const FXchar * s1,const FXString & s2)1987 bool operator!=(const FXchar* s1,const FXString& s2){
1988   return compare(s1,s2.str)!=0;
1989   }
1990 
operator <(const FXString & s1,const FXString & s2)1991 bool operator<(const FXString& s1,const FXString& s2){
1992   return compare(s1.str,s2.str)<0;
1993   }
1994 
operator <(const FXString & s1,const FXchar * s2)1995 bool operator<(const FXString& s1,const FXchar* s2){
1996   return compare(s1.str,s2)<0;
1997   }
1998 
operator <(const FXchar * s1,const FXString & s2)1999 bool operator<(const FXchar* s1,const FXString& s2){
2000   return compare(s1,s2.str)<0;
2001   }
2002 
operator <=(const FXString & s1,const FXString & s2)2003 bool operator<=(const FXString& s1,const FXString& s2){
2004   return compare(s1.str,s2.str)<=0;
2005   }
2006 
operator <=(const FXString & s1,const FXchar * s2)2007 bool operator<=(const FXString& s1,const FXchar* s2){
2008   return compare(s1.str,s2)<=0;
2009   }
2010 
operator <=(const FXchar * s1,const FXString & s2)2011 bool operator<=(const FXchar* s1,const FXString& s2){
2012   return compare(s1,s2.str)<=0;
2013   }
2014 
operator >(const FXString & s1,const FXString & s2)2015 bool operator>(const FXString& s1,const FXString& s2){
2016   return compare(s1.str,s2.str)>0;
2017   }
2018 
operator >(const FXString & s1,const FXchar * s2)2019 bool operator>(const FXString& s1,const FXchar* s2){
2020   return compare(s1.str,s2)>0;
2021   }
2022 
operator >(const FXchar * s1,const FXString & s2)2023 bool operator>(const FXchar* s1,const FXString& s2){
2024   return compare(s1,s2.str)>0;
2025   }
2026 
operator >=(const FXString & s1,const FXString & s2)2027 bool operator>=(const FXString& s1,const FXString& s2){
2028   return compare(s1.str,s2.str)>=0;
2029   }
2030 
operator >=(const FXString & s1,const FXchar * s2)2031 bool operator>=(const FXString& s1,const FXchar* s2){
2032   return compare(s1.str,s2)>=0;
2033   }
2034 
operator >=(const FXchar * s1,const FXString & s2)2035 bool operator>=(const FXchar* s1,const FXString& s2){
2036   return compare(s1,s2.str)>=0;
2037   }
2038 
2039 
2040 // Find n-th occurrence of character, searching forward; return position or -1
find(FXchar c,FXint pos,FXint n) const2041 FXint FXString::find(FXchar c,FXint pos,FXint n) const {
2042   register FXint len=length();
2043   register FXint p=pos;
2044   register FXint cc=c;
2045   if(p<0) p=0;
2046   if(n<=0) return p;
2047   while(p<len){
2048     if(str[p]==cc){ if(--n==0) return p; }
2049     ++p;
2050     }
2051   return -1;
2052   }
2053 
2054 
2055 // Find n-th occurrence of character, searching backward; return position or -1
rfind(FXchar c,FXint pos,FXint n) const2056 FXint FXString::rfind(FXchar c,FXint pos,FXint n) const {
2057   register FXint len=length();
2058   register FXint p=pos;
2059   register FXint cc=c;
2060   if(p>=len) p=len-1;
2061   if(n<=0) return p;
2062   while(0<=p){
2063     if(str[p]==cc){ if(--n==0) return p; }
2064     --p;
2065     }
2066   return -1;
2067   }
2068 
2069 
2070 // Find a character, searching forward; return position or -1
find(FXchar c,FXint pos) const2071 FXint FXString::find(FXchar c,FXint pos) const {
2072   register FXint len=length();
2073   register FXint p=pos;
2074   register FXint cc=c;
2075   if(p<0) p=0;
2076   while(p<len){ if(str[p]==cc){ return p; } ++p; }
2077   return -1;
2078   }
2079 
2080 
2081 // Find a character, searching backward; return position or -1
rfind(FXchar c,FXint pos) const2082 FXint FXString::rfind(FXchar c,FXint pos) const {
2083   register FXint len=length();
2084   register FXint p=pos;
2085   register FXint cc=c;
2086   if(p>=len) p=len-1;
2087   while(0<=p){ if(str[p]==cc){ return p; } --p; }
2088   return -1;
2089   }
2090 
2091 
2092 // Find a substring of length n, searching forward; return position or -1
find(const FXchar * substr,FXint n,FXint pos) const2093 FXint FXString::find(const FXchar* substr,FXint n,FXint pos) const {
2094   register FXint len=length();
2095   if(0<=pos && 0<n && n<=len){
2096     register FXint c=substr[0];
2097     len=len-n+1;
2098     while(pos<len){
2099       if(str[pos]==c){
2100         if(!compare(str+pos,substr,n)){
2101           return pos;
2102           }
2103         }
2104       pos++;
2105       }
2106     }
2107   return -1;
2108   }
2109 
2110 
2111 // Find a substring, searching forward; return position or -1
find(const FXchar * substr,FXint pos) const2112 FXint FXString::find(const FXchar* substr,FXint pos) const {
2113   return find(substr,strlen(substr),pos);
2114   }
2115 
2116 
2117 // Find a substring, searching forward; return position or -1
find(const FXString & substr,FXint pos) const2118 FXint FXString::find(const FXString& substr,FXint pos) const {
2119   return find(substr.text(),substr.length(),pos);
2120   }
2121 
2122 
2123 // Find a substring of length n, searching backward; return position or -1
rfind(const FXchar * substr,FXint n,FXint pos) const2124 FXint FXString::rfind(const FXchar* substr,FXint n,FXint pos) const {
2125   register FXint len=length();
2126   if(0<=pos && 0<n && n<=len){
2127     register FXint c=substr[0];
2128     len-=n;
2129     if(pos>len) pos=len;
2130     while(0<=pos){
2131       if(str[pos]==c){
2132         if(!compare(str+pos,substr,n)){
2133           return pos;
2134           }
2135         }
2136       pos--;
2137       }
2138     }
2139   return -1;
2140   }
2141 
2142 
2143 // Find a substring, searching backward; return position or -1
rfind(const FXchar * substr,FXint pos) const2144 FXint FXString::rfind(const FXchar* substr,FXint pos) const {
2145   return rfind(substr,strlen(substr),pos);
2146   }
2147 
2148 
2149 // Find a substring, searching backward; return position or -1
rfind(const FXString & substr,FXint pos) const2150 FXint FXString::rfind(const FXString& substr,FXint pos) const {
2151   return rfind(substr.text(),substr.length(),pos);
2152   }
2153 
2154 
2155 // Find first character in the set of size n, starting from pos; return position or -1
find_first_of(const FXchar * set,FXint n,FXint pos) const2156 FXint FXString::find_first_of(const FXchar* set,FXint n,FXint pos) const {
2157   register FXint len=length();
2158   register FXint p=pos;
2159   if(p<0) p=0;
2160   while(p<len){
2161     register FXint c=str[p];
2162     register FXint i=n;
2163     while(--i>=0){ if(set[i]==c) return p; }
2164     p++;
2165     }
2166   return -1;
2167   }
2168 
2169 
2170 // Find first character in the set, starting from pos; return position or -1
find_first_of(const FXchar * set,FXint pos) const2171 FXint FXString::find_first_of(const FXchar* set,FXint pos) const {
2172   return find_first_of(set,strlen(set),pos);
2173   }
2174 
2175 
2176 // Find first character in the set, starting from pos; return position or -1
find_first_of(const FXString & set,FXint pos) const2177 FXint FXString::find_first_of(const FXString& set,FXint pos) const {
2178   return find_first_of(set.text(),set.length(),pos);
2179   }
2180 
2181 
2182 // Find first character, starting from pos; return position or -1
find_first_of(FXchar c,FXint pos) const2183 FXint FXString::find_first_of(FXchar c,FXint pos) const {
2184   register FXint len=length();
2185   register FXint p=pos;
2186   register FXint cc=c;
2187   if(p<0) p=0;
2188   while(p<len){ if(str[p]==cc){ return p; } p++; }
2189   return -1;
2190   }
2191 
2192 
2193 // Find last character in the set of size n, starting from pos; return position or -1
find_last_of(const FXchar * set,FXint n,FXint pos) const2194 FXint FXString::find_last_of(const FXchar* set,FXint n,FXint pos) const {
2195   register FXint len=length();
2196   register FXint p=pos;
2197   if(p>=len) p=len-1;
2198   while(0<=p){
2199     register FXint c=str[p];
2200     register FXint i=n;
2201     while(--i>=0){ if(set[i]==c) return p; }
2202     p--;
2203     }
2204   return -1;
2205   }
2206 
2207 
2208 // Find last character in the set, starting from pos; return position or -1
find_last_of(const FXchar * set,FXint pos) const2209 FXint FXString::find_last_of(const FXchar* set,FXint pos) const {
2210   return find_last_of(set,strlen(set),pos);
2211   }
2212 
2213 
2214 // Find last character in the set, starting from pos; return position or -1
find_last_of(const FXString & set,FXint pos) const2215 FXint FXString::find_last_of(const FXString& set,FXint pos) const {
2216   return find_last_of(set.text(),set.length(),pos);
2217   }
2218 
2219 
2220 // Find last character, starting from pos; return position or -1
find_last_of(FXchar c,FXint pos) const2221 FXint FXString::find_last_of(FXchar c,FXint pos) const {
2222   register FXint len=length();
2223   register FXint p=pos;
2224   register FXint cc=c;
2225   if(p>=len) p=len-1;
2226   while(0<=p){ if(str[p]==cc){ return p; } p--; }
2227   return -1;
2228   }
2229 
2230 
2231 
2232 // Find first character NOT in the set of size n, starting from pos; return position or -1
find_first_not_of(const FXchar * set,FXint n,FXint pos) const2233 FXint FXString::find_first_not_of(const FXchar* set,FXint n,FXint pos) const {
2234   register FXint len=length();
2235   register FXint p=pos;
2236   if(p<0) p=0;
2237   while(p<len){
2238     register FXint c=str[p];
2239     register FXint i=n;
2240     while(--i>=0){ if(set[i]==c) goto x; }
2241     return p;
2242 x:  p++;
2243     }
2244   return -1;
2245   }
2246 
2247 
2248 // Find first character NOT in the set, starting from pos; return position or -1
find_first_not_of(const FXchar * set,FXint pos) const2249 FXint FXString::find_first_not_of(const FXchar* set,FXint pos) const {
2250   return find_first_not_of(set,strlen(set),pos);
2251   }
2252 
2253 
2254 // Find first character NOT in the set, starting from pos; return position or -1
find_first_not_of(const FXString & set,FXint pos) const2255 FXint FXString::find_first_not_of(const FXString& set,FXint pos) const {
2256   return find_first_not_of(set.text(),set.length(),pos);
2257   }
2258 
2259 
2260 // Find first character NOT equal to c, starting from pos; return position or -1
find_first_not_of(FXchar c,FXint pos) const2261 FXint FXString::find_first_not_of(FXchar c,FXint pos) const {
2262   register FXint len=length();
2263   register FXint p=pos;
2264   register FXint cc=c;
2265   if(p<0) p=0;
2266   while(p<len){ if(str[p]!=cc){ return p; } p++; }
2267   return -1;
2268   }
2269 
2270 
2271 
2272 // Find last character NOT in the set of size n, starting from pos; return position or -1
find_last_not_of(const FXchar * set,FXint n,FXint pos) const2273 FXint FXString::find_last_not_of(const FXchar* set,FXint n,FXint pos) const {
2274   register FXint len=length();
2275   register FXint p=pos;
2276   if(p>=len) p=len-1;
2277   while(0<=p){
2278     register FXint c=str[p];
2279     register FXint i=n;
2280     while(--i>=0){ if(set[i]==c) goto x; }
2281     return p;
2282 x:  p--;
2283     }
2284   return -1;
2285   }
2286 
2287 // Find last character NOT in the set, starting from pos; return position or -1
find_last_not_of(const FXchar * set,FXint pos) const2288 FXint FXString::find_last_not_of(const FXchar* set,FXint pos) const {
2289   return find_last_not_of(set,strlen(set),pos);
2290   }
2291 
2292 // Find last character NOT in the set, starting from pos; return position or -1
find_last_not_of(const FXString & set,FXint pos) const2293 FXint FXString::find_last_not_of(const FXString& set,FXint pos) const {
2294   return find_last_not_of(set.text(),set.length(),pos);
2295   }
2296 
2297 
2298 // Find last character NOT equal to c, starting from pos; return position or -1
find_last_not_of(FXchar c,FXint pos) const2299 FXint FXString::find_last_not_of(FXchar c,FXint pos) const {
2300   register FXint len=length();
2301   register FXint p=pos;
2302   register FXint cc=c;
2303   if(p>=len) p=len-1;
2304   while(0<=p){ if(str[p]!=cc){ return p; } p--; }
2305   return -1;
2306   }
2307 
2308 
2309 // Get hash value
hash() const2310 FXuint FXString::hash() const {
2311   register FXint len=length();
2312   register FXuint h=0;
2313   for(register FXint i=0; i<len; i++){  // This should be a very good hash function:- just 4 collisions
2314     h = ((h << 5) + h) ^ str[i];        // on the webster web2 dictionary of 234936 words, and no
2315     }                                   // collisions at all on the standard dict!
2316   return h;
2317   }
2318 
2319 
2320 // Save
operator <<(FXStream & store,const FXString & s)2321 FXStream& operator<<(FXStream& store,const FXString& s){        // Note stream format incompatible with FOX 1.0
2322   FXint len=s.length();
2323   store << len;
2324   store.save(s.str,len);
2325   return store;
2326   }
2327 
2328 
2329 // Load
operator >>(FXStream & store,FXString & s)2330 FXStream& operator>>(FXStream& store,FXString& s){              // Note stream format incompatible with FOX 1.0
2331   FXint len;
2332   store >> len;
2333   s.length(len);
2334   store.load(s.str,len);
2335   return store;
2336   }
2337 
2338 #ifdef WIN32
2339 #ifndef va_copy
2340 #define va_copy(arg,list) ((arg)=(list))
2341 #endif
2342 #endif
2343 
2344 // Print formatted string a-la vprintf
vformat(const FXchar * fmt,va_list args)2345 FXString& FXString::vformat(const FXchar* fmt,va_list args){
2346   FXint result=0;
2347   if(fmt && *fmt){
2348 #if (_MSC_VER > 1300)                   // Have _vscprintf()
2349     va_list ag;
2350     va_copy(ag,args);
2351     result=_vscprintf(fmt,ag);
2352     va_end(ag);
2353     length(result);
2354     vsnprintf(str,length()+1,fmt,args);
2355 #elif defined(HAVE_VSNPRINTF)           // Have vsnprintf()
2356 #if (__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)) || defined(__FreeBSD__)
2357     va_list ag;
2358     va_copy(ag,args);
2359     result=vsnprintf(str,empty()?0:length()+1,fmt,ag);
2360     va_end(ag);
2361     if(length()<result && 0<result){
2362       length(result);
2363       result=vsnprintf(str,length()+1,fmt,args);
2364       }
2365 #else
2366     va_list ag;
2367 x:  va_copy(ag,args);
2368     result=vsnprintf(str,empty()?0:length()+1,fmt,ag);
2369     va_end(ag);
2370     if(result<0){ length(FXMAX(64,length()*2)); goto x; }
2371     if(length()<result){ length(result); goto x; }
2372 #endif
2373 #else                                   // No vsnprintf()
2374     length(strlen(fmt)+1024);
2375     result=vsprintf(str,fmt,args);
2376     FXASSERT(0<=result && result<=length());
2377 #endif
2378     }
2379   length(result);
2380   return *this;
2381   }
2382 
2383 
2384 // Print formatted string a-la printf
format(const FXchar * fmt,...)2385 FXString& FXString::format(const FXchar* fmt,...){
2386   va_list args;
2387   va_start(args,fmt);
2388   vformat(fmt,args);
2389   va_end(args);
2390   return *this;
2391   }
2392 
2393 
2394 // Furnish our own version if we have to
2395 #ifndef HAVE_VSSCANF
2396 extern "C" int vsscanf(const char* str, const char* format, va_list arg_ptr);
2397 #endif
2398 
2399 
2400 // Scan
vscan(const FXchar * fmt,va_list args) const2401 FXint FXString::vscan(const FXchar* fmt,va_list args) const {
2402   return vsscanf((char*)str,fmt,args);          // Cast needed for HP-UX 11, which has wrong prototype for vsscanf
2403   }
2404 
2405 
scan(const FXchar * fmt,...) const2406 FXint FXString::scan(const FXchar* fmt,...) const {
2407   FXint result;
2408   va_list args;
2409   va_start(args,fmt);
2410   result=vscan(fmt,args);
2411   va_end(args);
2412   return result;
2413   }
2414 
2415 
2416 // Format a string a-la vprintf
FXStringVFormat(const FXchar * fmt,va_list args)2417 FXString FXStringVFormat(const FXchar* fmt,va_list args){
2418   FXString result;
2419   result.vformat(fmt,args);
2420   return result;
2421   }
2422 
2423 
2424 // Format a string a-la printf
FXStringFormat(const FXchar * fmt,...)2425 FXString FXStringFormat(const FXchar* fmt,...){
2426   FXString result;
2427   va_list args;
2428   va_start(args,fmt);
2429   result.vformat(fmt,args);
2430   va_end(args);
2431   return result;
2432   }
2433 
2434 
2435 // Conversion of integer to string
FXStringVal(FXlong num,FXint base)2436 FXString FXStringVal(FXlong num,FXint base){
2437   FXchar buf[66];
2438   register FXchar *p=buf+66;
2439   register FXulong nn=(FXulong)num;
2440   if(base<2 || base>16){ fxerror("FXStringVal: base out of range.\n"); }
2441   if(num<0){nn=(FXulong)(~num)+1;}
2442   do{
2443     *--p=FXString::HEX[nn%base];
2444     nn/=base;
2445     }
2446   while(nn);
2447   if(num<0) *--p='-';
2448   FXASSERT(buf<=p);
2449   return FXString(p,buf+66-p);
2450   }
2451 
2452 
2453 // Conversion of unsigned long to string
FXStringVal(FXulong num,FXint base)2454 FXString FXStringVal(FXulong num,FXint base){
2455   FXchar buf[66];
2456   register FXchar *p=buf+66;
2457   register FXulong nn=num;
2458   if(base<2 || base>16){ fxerror("FXStringVal: base out of range.\n"); }
2459   do{
2460     *--p=FXString::HEX[nn%base];
2461     nn/=base;
2462     }
2463   while(nn);
2464   FXASSERT(buf<=p);
2465   return FXString(p,buf+66-p);
2466   }
2467 
2468 
2469 // Conversion of integer to string
FXStringVal(FXint num,FXint base)2470 FXString FXStringVal(FXint num,FXint base){
2471   FXchar buf[34];
2472   register FXchar *p=buf+34;
2473   register FXuint nn=(FXuint)num;
2474   if(base<2 || base>16){ fxerror("FXStringVal: base out of range.\n"); }
2475   if(num<0){nn=(FXuint)(~num)+1;}
2476   do{
2477     *--p=FXString::HEX[nn%base];
2478     nn/=base;
2479     }
2480   while(nn);
2481   if(num<0) *--p='-';
2482   FXASSERT(buf<=p);
2483   return FXString(p,buf+34-p);
2484   }
2485 
2486 
2487 // Conversion of unsigned integer to string
FXStringVal(FXuint num,FXint base)2488 FXString FXStringVal(FXuint num,FXint base){
2489   FXchar buf[34];
2490   register FXchar *p=buf+34;
2491   register FXuint nn=num;
2492   if(base<2 || base>16){ fxerror("FXStringVal: base out of range.\n"); }
2493   do{
2494     *--p=FXString::HEX[nn%base];
2495     nn/=base;
2496     }
2497   while(nn);
2498   FXASSERT(buf<=p);
2499   return FXString(p,buf+34-p);
2500   }
2501 
2502 
2503 // Formatting for reals
2504 static const char *const expo[]={"%.*f","%.*E","%.*G"};
2505 
2506 
2507 // Conversion of float to string
FXStringVal(FXfloat num,FXint prec,FXint exp)2508 FXString FXStringVal(FXfloat num,FXint prec,FXint exp){
2509   return FXStringFormat(expo[exp],prec,num);
2510   }
2511 
2512 
2513 // Conversion of double to string
FXStringVal(FXdouble num,FXint prec,FXint exp)2514 FXString FXStringVal(FXdouble num,FXint prec,FXint exp){
2515   return FXStringFormat(expo[exp],prec,num);
2516   }
2517 
2518 
2519 #ifndef HAVE_STRTOLL
2520 extern "C" FXlong strtoll(const char *nptr, char **endptr, int base);
2521 #endif
2522 
2523 
2524 #ifndef HAVE_STRTOULL
2525 extern "C" FXulong strtoull(const char *nptr, char **endptr, int base);
2526 #endif
2527 
2528 
2529 // Conversion of string to integer
FXLongVal(const FXString & s,FXint base)2530 FXlong FXLongVal(const FXString& s,FXint base){
2531   return (FXlong)strtoll(s.str,NULL,base);
2532   }
2533 
2534 // Conversion of string to unsigned integer
FXULongVal(const FXString & s,FXint base)2535 FXulong FXULongVal(const FXString& s,FXint base){
2536   return (FXulong)strtoull(s.str,NULL,base);
2537   }
2538 
2539 // Conversion of string to integer
FXIntVal(const FXString & s,FXint base)2540 FXint FXIntVal(const FXString& s,FXint base){
2541   return (FXint)strtol(s.str,NULL,base);
2542   }
2543 
2544 
2545 // Conversion of string to unsigned integer
FXUIntVal(const FXString & s,FXint base)2546 FXuint FXUIntVal(const FXString& s,FXint base){
2547   return (FXuint)strtoul(s.str,NULL,base);
2548   }
2549 
2550 
2551 // Conversion of string to float
FXFloatVal(const FXString & s)2552 FXfloat FXFloatVal(const FXString& s){
2553   return (FXfloat)strtod(s.str,NULL);
2554   }
2555 
2556 
2557 // Conversion of string to double
FXDoubleVal(const FXString & s)2558 FXdouble FXDoubleVal(const FXString& s){
2559   return strtod(s.str,NULL);
2560   }
2561 
2562 
2563 // Return utf8 from ascii containing unicode escapes
fromAscii(const FXString & s)2564 FXString fromAscii(const FXString& s){
2565   register FXint p=0;
2566   FXString result;
2567   FXwchar c;
2568   while(p<s.length()){
2569     c=s[p++];
2570     if(c=='\\' && p<s.length()){
2571       c=s[p++];
2572       if(c=='u'){
2573         if(Ascii::isHexDigit(s[p])){
2574           c=Ascii::digitValue(s[p++]);
2575           if(Ascii::isHexDigit(s[p])){
2576             c=(c<<4)+Ascii::digitValue(s[p++]);
2577             if(Ascii::isHexDigit(s[p])){
2578               c=(c<<4)+Ascii::digitValue(s[p++]);
2579               if(Ascii::isHexDigit(s[p])){
2580                 c=(c<<4)+Ascii::digitValue(s[p++]);
2581                 }
2582               }
2583             }
2584           }
2585         result.append(&c,1);
2586         continue;
2587         }
2588       }
2589     result.append(c);
2590     }
2591   return result;
2592   }
2593 
2594 
2595 // Return ascii containing unicode escapes from utf8
toAscii(const FXString & s)2596 FXString toAscii(const FXString& s){
2597   register FXint p=0;
2598   FXString result;
2599   FXwchar c;
2600   while(p<s.length()){
2601     c=s.wc(p);
2602     if(0x80<=c){
2603       result.append("\\u");
2604       result.append(FXString::HEX[(c>>12)&15]);
2605       result.append(FXString::HEX[(c>>8)&15]);
2606       result.append(FXString::HEX[(c>>4)&15]);
2607       c=FXString::HEX[c&15];
2608       }
2609     result.append(c);
2610     p+=s.extent(p);
2611     }
2612   return result;
2613   }
2614 
2615 
2616 // Escape special characters in a string
escape(const FXString & s)2617 FXString escape(const FXString& s){
2618   register FXint p=0;
2619   register FXint c;
2620   FXString result;
2621   while(p<s.length()){
2622     c=s[p++];
2623     switch(c){
2624       case '\n':
2625         result.append("\\n");
2626         break;
2627       case '\r':
2628         result.append("\\r");
2629         break;
2630       case '\b':
2631         result.append("\\b");
2632         break;
2633       case '\v':
2634         result.append("\\v");
2635         break;
2636       case '\a':
2637         result.append("\\a");
2638         break;
2639       case '\f':
2640         result.append("\\f");
2641         break;
2642       case '\t':
2643         result.append("\\t");
2644         break;
2645       case '\\':
2646         result.append("\\\\");
2647         break;
2648       case '"':
2649         result.append("\\\"");
2650         break;
2651       case '\'':
2652         result.append("\\\'");
2653         break;
2654       default:
2655         if(0x20<=c && c<=0x7F){
2656           result.append(c);
2657           }
2658         else{
2659           result.append("\\x");
2660           result.append(FXString::HEX[(c>>4)&15]);
2661           result.append(FXString::HEX[c&15]);
2662           }
2663         break;
2664       }
2665     }
2666   return result;
2667   }
2668 
2669 
2670 // Unescape special characters in a string
unescape(const FXString & s)2671 FXString unescape(const FXString& s){
2672   register FXint p=0;
2673   register FXint c;
2674   FXString result;
2675   while(p<s.length()){
2676     c=s[p++];
2677     if(c=='\\' && p<s.length()){
2678       c=s[p++];
2679       switch(c){
2680         case 'n':
2681           result.append('\n');
2682           break;
2683         case 'r':
2684           result.append('\r');
2685           break;
2686         case 'b':
2687           result.append('\b');
2688           break;
2689         case 'v':
2690           result.append('\v');
2691           break;
2692         case 'a':
2693           result.append('\a');
2694           break;
2695         case 'f':
2696           result.append('\f');
2697           break;
2698         case 't':
2699           result.append('\t');
2700           break;
2701         case '\\':
2702           result.append('\\');
2703           break;
2704         case '"':
2705           result.append('\"');
2706           break;
2707         case '\'':
2708           result.append('\'');
2709           break;
2710         case 'x':               // Hex escape
2711           if(Ascii::isHexDigit(s[p])){
2712             c=Ascii::digitValue(s[p++]);
2713             if(Ascii::isHexDigit(s[p])){
2714               c=(c<<4)+Ascii::digitValue(s[p++]);
2715               }
2716             }
2717           result.append(c);
2718           break;
2719         case '0':               // Octal escape
2720         case '1':
2721         case '2':
2722         case '3':
2723         case '4':
2724         case '5':
2725         case '6':
2726         case '7':
2727           c=c-'0';
2728           if('0'<=s[p] && s[p]<='7'){
2729             c=(c<<3)+s[p++]-'0';
2730             if('0'<=s[p] && s[p]<='7'){
2731               c=(c<<3)+s[p++]-'0';
2732               }
2733             }
2734           result.append(c);
2735           break;
2736         default:
2737           result.append(c);
2738           break;
2739         }
2740       continue;
2741       }
2742     result.append(c);
2743     }
2744   return result;
2745   }
2746 
2747 
2748 // Hangul decomposition
2749 enum {
2750   SBase  = 0xAC00,
2751   LBase  = 0x1100,
2752   VBase  = 0x1161,
2753   TBase  = 0x11A7,
2754   LCount = 19,
2755   VCount = 21,
2756   TCount = 28,
2757   NCount = VCount*TCount,
2758   SCount = LCount*NCount
2759   };
2760 
2761 
2762 // Decompose hangul method, if it is hangul (from TR# 15)
decomposehangul(FXwchar * result,FXwchar w)2763 static FXint decomposehangul(FXwchar *result,FXwchar w){
2764   register FXwchar SIndex=w-SBase;
2765   register FXwchar L,V,T;
2766   if(0<=SIndex && SIndex<SCount){
2767     L=LBase+SIndex/NCount;
2768     V=VBase+(SIndex%NCount)/TCount;
2769     T=TBase+SIndex%TCount;
2770     result[0]=L;
2771     result[1]=V;
2772     if(T!=TBase){
2773       result[2]=T;
2774       return 3;
2775       }
2776     return 2;
2777     }
2778   result[0]=w;
2779   return 1;
2780   }
2781 
2782 
2783 // Compose hangul in situ; return new length (from TR# 15)
composehangul(FXwchar * result,FXint len)2784 static FXint composehangul(FXwchar *result,FXint len){
2785   register FXwchar w,last,LIndex,VIndex,SIndex,TIndex;
2786   register FXint p,q;
2787   if(0<len){
2788     last=result[0];
2789     for(p=q=1; q<len; q++){
2790       w=result[q];
2791 
2792       // Check to see if two current characters are L and V
2793       LIndex=last-LBase;
2794       if(0<=LIndex && LIndex<LCount){
2795 
2796         // Make syllable of form LV
2797         VIndex=w-VBase;
2798         if(0<=VIndex && VIndex<VCount){
2799           last=SBase+(LIndex*VCount+VIndex)*TCount;
2800           result[p-1]=last;
2801           continue;
2802           }
2803         }
2804 
2805       // Check to see if two current characters are LV and T
2806       SIndex=last-SBase;
2807       if(0<=SIndex && SIndex<SCount && (SIndex%TCount)==0){
2808 
2809         // Make syllable of form LVT
2810         TIndex=w-TBase;
2811         if(0<TIndex && TIndex<TCount){
2812           last+=TIndex;
2813           result[p-1]=last;
2814           continue;
2815           }
2816         }
2817 
2818       // Otherwise just add the character
2819       last=w;
2820       result[p++]=w;
2821       }
2822     return p;
2823     }
2824   return 0;
2825   }
2826 
2827 
2828 // Recursive decomposition of type kind
decomposerecursive(FXwchar * result,FXwchar w,FXuint kind)2829 static FXint decomposerecursive(FXwchar *result,FXwchar w,FXuint kind){
2830   register const FXwchar* decomposition=Unicode::charDecompose(w);
2831   if((FXuint)decomposition[-2]>=kind){
2832     register FXint p=0;
2833     register FXint n=0;
2834     while(p<decomposition[-1]){
2835       n+=decomposerecursive(result+n,decomposition[p++],kind);
2836       }
2837     return n;
2838     }
2839   return decomposehangul(result,w);
2840   }
2841 
2842 
2843 // Canonicalize wide character string s, by rearranging combining marks
normalize(FXwchar * result,FXint len)2844 static FXwchar *normalize(FXwchar* result,FXint len){
2845   register FXwchar uf,us,cf,cs;
2846   register FXint p=0;
2847   while(p+1<len){
2848 
2849     // Second character is a starter; advance by 2
2850     us=result[p+1];
2851     FXASSERT(us<0x110000);
2852     cs=Unicode::charCombining(us);
2853     if(cs==0){
2854       p+=2;
2855       continue;
2856       }
2857 
2858     // First character class greater; swap and back off by 1
2859     uf=result[p];
2860     FXASSERT(uf<0x110000);
2861     cf=Unicode::charCombining(uf);
2862     if(cf>cs){
2863       result[p]=us;
2864       result[p+1]=uf;
2865       if(p>0) p--;
2866       continue;
2867       }
2868 
2869     // Already in right order; advance by one
2870     p++;
2871     }
2872   return result;
2873   }
2874 
2875 
2876 // Compose characters from canonical/compatible decomposition
compose(FXwchar * result,FXint len)2877 static FXint compose(FXwchar* result,FXint len){
2878   register FXint p,q,cc,starterpos,startercc;
2879   register FXwchar w;
2880   if(0<len){
2881     starterpos=0;
2882     startercc=0;
2883     for(q=0; q<len; q++){
2884       cc=Unicode::charCombining(result[q]);
2885       if(0<q && (startercc==0 || startercc<cc) && (w=Unicode::charCompose(result[starterpos],result[q]))!=0){
2886         result[starterpos]=w;
2887         for(p=q+1; p<len; p++) result[p-1]=result[p];
2888         len--;
2889         q--;
2890         if(q==starterpos)
2891           startercc=0;
2892         else
2893           startercc=Unicode::charCombining(result[q-1]);
2894 
2895         continue;
2896         }
2897       if(cc==0) starterpos=q;
2898       startercc=cc;
2899       }
2900     }
2901   return len;
2902   }
2903 
2904 
2905 
2906 // Return normalized string
normalize(const FXString & s)2907 FXString normalize(const FXString& s){
2908   FXwchar* wcs=(FXwchar*)malloc(s.length()*sizeof(FXwchar));
2909   FXString result;
2910   if(wcs){
2911     FXint n=utf2wcs(wcs,s.text(),s.length());
2912     normalize(wcs,n);
2913     result.assign(wcs,n);
2914     free(wcs);
2915     }
2916   return result;
2917   }
2918 
2919 
2920 // Return decomposition of string, as utf8; this depends on knowing
2921 // the length of the worst recursive decomposition (18).  If unicode
2922 // tables change, make sure this code is updated.   We have an assert
2923 // just in case.
decompose(const FXString & s,FXuint kind)2924 FXString decompose(const FXString& s,FXuint kind){
2925   FXwchar* wcs=(FXwchar*)malloc(s.length()*sizeof(FXwchar)*18);
2926   FXString result;
2927   if(wcs){
2928     FXwchar* ptr=wcs+s.length()*17;
2929     FXint m=utf2wcs(ptr,s.text(),s.length());
2930     FXint p=0;
2931     FXint n=0;
2932     while(p<m){
2933       n+=decomposerecursive(&wcs[n],ptr[p++],kind);
2934       }
2935     FXASSERT(n<=s.length()*18);
2936     normalize(wcs,n);
2937     result.assign(wcs,n);
2938     free(wcs);
2939     }
2940   return result;
2941   }
2942 
2943 
2944 // Return normalized composition of string, as utf8
compose(const FXString & s,FXuint kind)2945 FXString compose(const FXString& s,FXuint kind){
2946   FXwchar* wcs=(FXwchar*)malloc(s.length()*sizeof(FXwchar)*18);
2947   FXString result;
2948   if(wcs){
2949     FXwchar* ptr=wcs+s.length()*17;
2950     FXint m=utf2wcs(ptr,s.text(),s.length());
2951     FXint p=0;
2952     FXint n=0;
2953     while(p<m){
2954       n+=decomposerecursive(&wcs[n],ptr[p++],kind);
2955       }
2956     FXASSERT(n<=s.length()*18);
2957     normalize(wcs,n);
2958     n=compose(wcs,n);
2959     result.assign(wcs,n);
2960     free(wcs);
2961     }
2962   return result;
2963   }
2964 
2965 
2966 enum {
2967   S_N = 0x0,    // Normal
2968   S_I = 0x4,    // comparing integral part
2969   S_F = 0x8,    // comparing fractional parts
2970   S_Z = 0xC     // idem but with leading Zeroes only
2971   };
2972 
2973 enum {
2974   CMP = 2,      // return diff
2975   LEN = 3       // compare using len_diff/diff
2976   };
2977 
2978 
2979 // Compare S1 and S2 as strings holding indices/version numbers,
2980 // returning less than, equal to or greater than zero if S1 is less than,
2981 // equal to or greater than S2 (for more info, see the texinfo doc).
compareversion(const FXchar * s1,const FXchar * s2)2982 FXint compareversion(const FXchar *s1,const FXchar *s2){
2983   register const FXuchar *p1=(const FXuchar*)s1;
2984   register const FXuchar *p2=(const FXuchar*)s2;
2985   register FXuchar c1,c2;
2986   register FXint state;
2987   register FXint diff;
2988 
2989   /* Symbol(s)    0       [1-9]   others  (padding)
2990      Transition   (10) 0  (01) d  (00) x  (11) -   */
2991   static const unsigned int next_state[]={
2992     /* state    x    d    0    - */
2993     /* S_N */  S_N, S_I, S_Z, S_N,
2994     /* S_I */  S_N, S_I, S_I, S_I,
2995     /* S_F */  S_N, S_F, S_F, S_F,
2996     /* S_Z */  S_N, S_F, S_Z, S_Z
2997     };
2998 
2999   static const int result_type[]={
3000     /* state   x/x  x/d  x/0  x/-  d/x  d/d  d/0  d/-  0/x  0/d  0/0  0/-  -/x  -/d  -/0  -/- */
3001     /* S_N */  CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
3002     /* S_I */  CMP,  -1,  -1, CMP,  +1, LEN, LEN, CMP,  +1, LEN, LEN, CMP, CMP, CMP, CMP, CMP,
3003     /* S_F */  CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP,
3004     /* S_Z */  CMP,  +1,  +1, CMP,  -1, CMP, CMP, CMP,  -1, CMP, CMP, CMP
3005     };
3006 
3007   if(p1==p2) return 0;
3008 
3009   c1 = *p1++;
3010   c2 = *p2++;
3011 
3012   // Hint: '0' is a digit too.
3013   state=S_N | ((c1=='0')+(Ascii::isDigit(c1)!=0));
3014   while((diff=c1-c2)==0 && c1!='\0'){
3015     state=next_state[state];
3016     c1=*p1++;
3017     c2=*p2++;
3018     state|=(c1=='0')+(Ascii::isDigit(c1)!=0);
3019     }
3020   state=result_type[state<<2 | (((c2=='0')+(Ascii::isDigit(c2)!=0)))];
3021   switch(state){
3022     case LEN:
3023       while(Ascii::isDigit(*p1++)){
3024 	if(!Ascii::isDigit(*p2++)) return 1;
3025         }
3026       if(Ascii::isDigit(*p2)) return -1;
3027     case CMP:
3028       return diff;
3029     }
3030   return state;
3031   }
3032 
3033 
compareversion(const FXchar * s1,const FXString & s2)3034 FXint compareversion(const FXchar* s1,const FXString& s2){
3035   return compareversion(s1,s2.str);
3036   }
3037 
3038 
compareversion(const FXString & s1,const FXchar * s2)3039 FXint compareversion(const FXString& s1,const FXchar* s2){
3040   return compareversion(s1.str,s2);
3041   }
3042 
3043 
compareversion(const FXString & s1,const FXString & s2)3044 FXint compareversion(const FXString& s1,const FXString& s2){
3045   return compareversion(s1.str,s2.str);
3046   }
3047 
3048 
3049 // Convert to dos
unixToDos(FXString & str)3050 FXString& unixToDos(FXString& str){
3051   register FXint f=0;
3052   register FXint t=0;
3053   while(f<str.length()){
3054     if(str[f++]=='\n') t++; t++;
3055     }
3056   str.length(t);
3057   while(0<f){
3058     if((str[--t]=str[--f])=='\n') str[--t]='\r';
3059     }
3060   return str;
3061   }
3062 
3063 
3064 // Convert from dos
dosToUnix(FXString & str)3065 FXString& dosToUnix(FXString& str){
3066   register FXint f=0,t=0,c;
3067   while(f<str.length()){
3068     if((c=str[f++])!='\r') str[t++]=c;
3069     }
3070   str.length(t);
3071   return str;
3072   }
3073 
3074 
3075 // Delete
~FXString()3076 FXString::~FXString(){
3077   if(str!=EMPTY){free(str-sizeof(FXint));}
3078   }
3079 
3080 }
3081 
3082 
3083