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