PageRenderTime 36ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/fox-1.6.37/src/FXString.cpp

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