blitz_string.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. #include "blitz.h"
  2. #include "blitz_unicode.h"
  3. static void bbStringFree( BBObject *o );
  4. static BBDebugScope debugScope={
  5. BBDEBUGSCOPE_USERTYPE,
  6. "String",
  7. BBDEBUGDECL_END
  8. };
  9. BBClass bbStringClass={
  10. &bbObjectClass, //super
  11. bbStringFree, //free
  12. &debugScope, //DebugScope
  13. 0, //instance_size
  14. 0, //ctor
  15. 0, //dtor
  16. (BBString*(*)(BBObject*))bbStringToString,
  17. (int(*)(BBObject*,BBObject*))bbStringCompare,
  18. bbObjectSendMessage,
  19. bbObjectReserved,
  20. bbObjectReserved,
  21. bbObjectReserved,
  22. bbStringFind,
  23. bbStringFindLast,
  24. bbStringTrim,
  25. bbStringReplace,
  26. bbStringToLower,
  27. bbStringToUpper,
  28. bbStringToInt,
  29. bbStringToLong,
  30. bbStringToFloat,
  31. bbStringToDouble,
  32. bbStringToCString,
  33. bbStringToWString,
  34. bbStringFromInt,
  35. bbStringFromLong,
  36. bbStringFromFloat,
  37. bbStringFromDouble,
  38. bbStringFromCString,
  39. bbStringFromWString,
  40. bbStringFromBytes,
  41. bbStringFromShorts,
  42. bbStringStartsWith,
  43. bbStringEndsWith,
  44. bbStringContains,
  45. bbStringSplit,
  46. bbStringJoin,
  47. bbStringFromUTF8String,
  48. bbStringToUTF8String
  49. };
  50. BBString bbEmptyString={
  51. &bbStringClass, //clas
  52. BBGC_MANYREFS, //refs
  53. 0 //length
  54. };
  55. static int wstrlen( const BBChar *p ){
  56. const BBChar *t=p;
  57. while( *t ) ++t;
  58. return t-p;
  59. }
  60. static int charsEqual( unsigned short *a,unsigned short *b,int n ){
  61. while( n-- ){
  62. if (*a!=*b) return 0;
  63. a++;b++;
  64. }
  65. return 1;
  66. }
  67. //***** Note: Not called in THREADED mode.
  68. static void bbStringFree( BBObject *o ){
  69. #ifdef BB_GC_RC
  70. BBString *str=(BBString*)o;
  71. if( str==&bbEmptyString ){
  72. str->refs=BBGC_MANYREFS;
  73. return;
  74. }
  75. bbGCDeallocObject( str,sizeof(BBString)+str->length*sizeof(BBChar) );
  76. #endif
  77. }
  78. BBString *bbStringNew( int len ){
  79. int flags;
  80. BBString *str;
  81. if( !len ) return &bbEmptyString;
  82. str=(BBString*)bbGCAllocObject( sizeof(BBString)+len*sizeof(BBChar),&bbStringClass,BBGC_ATOMIC );
  83. str->length=len;
  84. return str;
  85. }
  86. BBString *bbStringFromChar( int c ){
  87. BBString *str=bbStringNew(1);
  88. str->buf[0]=c;
  89. return str;
  90. }
  91. BBString *bbStringFromInt( int n ){
  92. char buf[64],*p=buf+64;
  93. int neg=n<0;
  94. if( neg ){
  95. n=-n;if( n<0 ) return bbStringFromBytes( "-2147483648",11 );
  96. }
  97. do{
  98. *--p=n%10+'0';
  99. }while(n/=10);
  100. if( neg ) *--p='-';
  101. return bbStringFromBytes( p,buf+64-p );
  102. }
  103. BBString *bbStringFromLong( BBInt64 n ){
  104. char buf[64],*p=buf+64;
  105. int neg=n<0;
  106. if( neg ){
  107. n=-n;if( n<0 ) return bbStringFromBytes( "-9223372036854775808",20 );
  108. }
  109. do{
  110. *--p=n%10+'0';
  111. }while(n/=10);
  112. if( neg ) *--p='-';
  113. return bbStringFromBytes( p,buf+64-p );
  114. }
  115. BBString *bbStringFromFloat( float n ){
  116. char buf[64];
  117. sprintf( buf,"%#.9g",n );
  118. return bbStringFromCString(buf);
  119. }
  120. BBString *bbStringFromDouble( double n ){
  121. char buf[64];
  122. sprintf( buf,"%#.17lg",n );
  123. return bbStringFromCString(buf);
  124. }
  125. BBString *bbStringFromBytes( const char *p,int n ){
  126. int k;
  127. BBString *str;
  128. if( !n ) return &bbEmptyString;
  129. str=bbStringNew( n );
  130. for( k=0;k<n;++k ) str->buf[k]=(unsigned char)p[k];
  131. return str;
  132. }
  133. BBString *bbStringFromShorts( const unsigned short *p,int n ){
  134. BBString *str;
  135. if( !n ) return &bbEmptyString;
  136. str=bbStringNew( n );
  137. bbMemCopy( str->buf,p,n*sizeof(short) );
  138. return str;
  139. }
  140. BBString *bbStringFromInts( const int *p,int n ){
  141. int k;
  142. BBString *str;
  143. if( !n ) return &bbEmptyString;
  144. str=bbStringNew( n );
  145. for( k=0;k<n;++k ) str->buf[k]=p[k];
  146. return str;
  147. }
  148. BBString *bbStringFromArray( BBArray *arr ){
  149. int n;
  150. void *p;
  151. if( arr->dims!=1 ) return &bbEmptyString;
  152. n=arr->scales[0];
  153. p=BBARRAYDATA(arr,arr->dims);
  154. switch( arr->type[0] ){
  155. case 'b':return bbStringFromBytes( p,n );
  156. case 's':return bbStringFromShorts( p,n );
  157. case 'i':return bbStringFromInts( p,n );
  158. }
  159. return &bbEmptyString;
  160. }
  161. BBString *bbStringFromCString( const char *p ){
  162. return p ? bbStringFromBytes( p,strlen(p) ) : &bbEmptyString;
  163. }
  164. BBString *bbStringFromWString( const BBChar *p ){
  165. return p ? bbStringFromShorts( p,wstrlen(p) ) : &bbEmptyString;
  166. }
  167. BBString *bbStringFromUTF8String( const char *p ){
  168. int c,n;
  169. short *d,*q;
  170. BBString *str;
  171. if( !p ) return &bbEmptyString;
  172. n=strlen(p);
  173. d=(short*)malloc( n*2 );
  174. q=d;
  175. while( c=*p++ & 0xff ){
  176. if( c<0x80 ){
  177. *q++=c;
  178. }else{
  179. int d=*p++ & 0x3f;
  180. if( c<0xe0 ){
  181. *q++=((c&31)<<6) | d;
  182. }else{
  183. int e=*p++ & 0x3f;
  184. if( c<0xf0 ){
  185. *q++=((c&15)<<12) | (d<<6) | e;
  186. }else{
  187. int f=*p++ & 0x3f;
  188. int v=((c&7)<<18) | (d<<12) | (e<<6) | f;
  189. if( v & 0xffff0000 ) bbExThrowCString( "Unicode character out of UCS-2 range" );
  190. *q++=v;
  191. }
  192. }
  193. }
  194. }
  195. str=bbStringFromShorts( d,q-d );
  196. free( d );
  197. return str;
  198. }
  199. BBString *bbStringToString( BBString *t ){
  200. return t;
  201. }
  202. int bbStringCompare( BBString *x,BBString *y ){
  203. int k,n,sz;
  204. sz=x->length<y->length ? x->length : y->length;
  205. for( k=0;k<sz;++k ) if( n=x->buf[k]-y->buf[k] ) return n;
  206. return x->length-y->length;
  207. }
  208. int bbStringStartsWith( BBString *x,BBString *y ){
  209. BBChar *p,*q;
  210. int k,sz=y->length;
  211. if( x->length<sz ) return 0;
  212. p=x->buf;
  213. q=y->buf;
  214. for( k=0;k<sz;++k ) if( *p++!=*q++ ) return 0;
  215. return 1;
  216. }
  217. int bbStringEndsWith( BBString *x,BBString *y ){
  218. BBChar *p,*q;
  219. int k,sz=y->length;
  220. if( x->length<sz ) return 0;
  221. p=x->buf+x->length-sz;
  222. q=y->buf;
  223. for( k=0;k<sz;++k ) if( *p++!=*q++ ) return 0;
  224. return 1;
  225. }
  226. int bbStringContains( BBString *x,BBString *y ){
  227. return bbStringFind( x,y,0 )!=-1;
  228. }
  229. BBString *bbStringConcat( BBString *x,BBString *y ){
  230. int len=x->length+y->length;
  231. BBString *t=bbStringNew(len);
  232. memcpy( t->buf,x->buf,x->length*sizeof(BBChar) );
  233. memcpy( t->buf+x->length,y->buf,y->length*sizeof(BBChar) );
  234. return t;
  235. }
  236. BBString *bbStringSlice( BBString *in,int beg,int end ){
  237. BBChar *p;
  238. BBString *out;
  239. int k,n,len,inlen;
  240. len=end-beg;
  241. if( len<=0 ) return &bbEmptyString;
  242. out=bbStringNew( len );
  243. p=out->buf;
  244. inlen=in->length;
  245. if( (n=-beg)>0 ){
  246. if( beg+n>end ) n=end-beg;
  247. for( k=0;k<n;++k ) *p++=' ';
  248. if( (beg+=n)==end ) return out;
  249. }
  250. if( (n=inlen-beg)>0 ){
  251. BBChar *q=in->buf+beg;
  252. if( beg+n>end ) n=end-beg;
  253. for( k=0;k<n;++k ) *p++=*q++;
  254. if( (beg+=n)==end ) return out;
  255. }
  256. if( (n=end-beg)>0 ){
  257. for( k=0;k<n;++k ) *p++=' ';
  258. }
  259. return out;
  260. }
  261. BBString *bbStringTrim( BBString *str ){
  262. int b=0,e=str->length;
  263. while( b<e && str->buf[b]<=' ' ) ++b;
  264. if( b==e ) return &bbEmptyString;
  265. while( str->buf[e-1]<=' ' ) --e;
  266. if( e-b==str->length ) return str;
  267. return bbStringFromShorts( str->buf+b,e-b );
  268. }
  269. BBString *bbStringReplace( BBString *str,BBString *sub,BBString *rep ){
  270. int i,d,n,j,p;
  271. if( !sub->length ) return str;
  272. i=0;n=0;
  273. while( (i=bbStringFind(str,sub,i))!=-1 ) {i+=sub->length;n++;}
  274. if (!n) return str;
  275. d=rep->length-sub->length;
  276. BBString *t=bbStringNew( str->length+d*n );
  277. i=0;p=0;
  278. while( (j=bbStringFind(str,sub,i))!=-1 )
  279. {
  280. n=j-i;if (n) {memcpy( t->buf+p,str->buf+i,n*sizeof(BBChar) );p+=n;}
  281. n=rep->length;memcpy( t->buf+p,rep->buf,n*sizeof(BBChar) );p+=n;
  282. i=j+sub->length;
  283. }
  284. n=str->length-i;
  285. if (n) memcpy( t->buf+p,str->buf+i,n*sizeof(BBChar) );
  286. return t;
  287. }
  288. int bbStringAsc( BBString *t ){
  289. return t->length ? t->buf[0] : -1;
  290. }
  291. int bbStringFind( BBString *x,BBString *y,int i ){
  292. if( i<0 ) i=0;
  293. while( i+y->length<=x->length ){
  294. if( charsEqual( x->buf+i,y->buf,y->length ) ) return i;
  295. ++i;
  296. }
  297. return -1;
  298. }
  299. int bbStringFindLast( BBString *x,BBString *y,int i ){
  300. bbassert( i>=0 );
  301. i=x->length-i;
  302. if (i+y->length>x->length) i=x->length-y->length;
  303. while (i>=0)
  304. {
  305. if( charsEqual( x->buf+i,y->buf,y->length ) ) return i;
  306. --i;
  307. }
  308. return -1;
  309. }
  310. int bbStringToInt( BBString *t ){
  311. int i=0,neg=0,n=0;
  312. while( i<t->length && isspace(t->buf[i]) ) ++i;
  313. if( i==t->length ) return 0;
  314. if( t->buf[i]=='+' ) ++i;
  315. else if( neg=(t->buf[i]=='-') ) ++i;
  316. if( i==t->length ) return 0;
  317. if( t->buf[i]=='%' ){
  318. for( ++i;i<t->length;++i ){
  319. int c=t->buf[i];
  320. if( c!='0' && c!='1' ) break;
  321. n=n*2+(c-'0');
  322. }
  323. }else if( t->buf[i]=='$' ){
  324. for( ++i;i<t->length;++i ){
  325. int c=toupper(t->buf[i]);
  326. if( !isxdigit(c) ) break;
  327. if( c>='A' ) c-=('A'-'0'-10);
  328. n=n*16+(c-'0');
  329. }
  330. }else{
  331. for( ;i<t->length;++i ){
  332. int c=t->buf[i];
  333. if( !isdigit(c) ) break;
  334. n=n*10+(c-'0');
  335. }
  336. }
  337. return neg ? -n : n;
  338. }
  339. void bbStringToLong( BBString *t,BBInt64 *r ){
  340. int i=0,neg=0;
  341. BBInt64 n=0;
  342. while( i<t->length && isspace(t->buf[i]) ) ++i;
  343. if( i==t->length ){ *r=0;return; }
  344. if( t->buf[i]=='+' ) ++i;
  345. else if( neg=(t->buf[i]=='-') ) ++i;
  346. if( i==t->length ){ *r=0;return; }
  347. if( t->buf[i]=='%' ){
  348. for( ++i;i<t->length;++i ){
  349. int c=t->buf[i];
  350. if( c!='0' && c!='1' ) break;
  351. n=n*2+(c-'0');
  352. }
  353. }else if( t->buf[i]=='$' ){
  354. for( ++i;i<t->length;++i ){
  355. int c=toupper(t->buf[i]);
  356. if( !isxdigit(c) ) break;
  357. if( c>='A' ) c-=('A'-'0'-10);
  358. n=n*16+(c-'0');
  359. }
  360. }else{
  361. for( ;i<t->length;++i ){
  362. int c=t->buf[i];
  363. if( !isdigit(c) ) break;
  364. n=n*10+(c-'0');
  365. }
  366. }
  367. *r=neg ? -n : n;
  368. }
  369. float bbStringToFloat( BBString *t ){
  370. char *p=bbStringToCString( t );
  371. float n=atof( p );
  372. bbMemFree( p );
  373. return n;
  374. }
  375. double bbStringToDouble( BBString *t ){
  376. char *p=bbStringToCString( t );
  377. double n=atof( p );
  378. bbMemFree( p );
  379. return n;
  380. }
  381. BBString *bbStringToLower( BBString *str ){
  382. int k;
  383. BBString *t;
  384. t=bbStringNew( str->length );
  385. for( k=0;k<str->length;++k ){
  386. int c=str->buf[k];
  387. if( c<192 ){
  388. c=(c>='A' && c<='Z') ? (c|32) : c;
  389. }else{
  390. int lo=0,hi=sizeof(bbToLowerData)/4-1;
  391. while( lo<=hi ){
  392. int mid=(lo+hi)/2;
  393. if( c<bbToLowerData[mid*2] ){
  394. hi=mid-1;
  395. }else if( c>bbToLowerData[mid*2] ){
  396. lo=mid+1;
  397. }else{
  398. c=bbToLowerData[mid*2+1];
  399. break;
  400. }
  401. }
  402. }
  403. t->buf[k]=c;
  404. }
  405. return t;
  406. }
  407. BBString *bbStringToUpper( BBString *str ){
  408. int k;
  409. BBString *t;
  410. t=bbStringNew( str->length );
  411. for( k=0;k<str->length;++k ){
  412. int c=str->buf[k];
  413. if( c<181 ){
  414. c=(c>='a' && c<='z') ? (c&~32) : c;
  415. }else{
  416. int lo=0,hi=sizeof(bbToUpperData)/4-1;
  417. while( lo<=hi ){
  418. int mid=(lo+hi)/2;
  419. if( c<bbToUpperData[mid*2] ){
  420. hi=mid-1;
  421. }else if( c>bbToUpperData[mid*2] ){
  422. lo=mid+1;
  423. }else{
  424. c=bbToUpperData[mid*2+1];
  425. break;
  426. }
  427. }
  428. }
  429. t->buf[k]=c;
  430. }
  431. return t;
  432. }
  433. char *bbStringToCString( BBString *str ){
  434. char *p;
  435. int k,sz=str->length;
  436. p=(char*)bbMemAlloc( sz+1 );
  437. for( k=0;k<sz;++k ) p[k]=str->buf[k];
  438. p[sz]=0;
  439. return p;
  440. }
  441. BBChar *bbStringToWString( BBString *str ){
  442. BBChar *p;
  443. int k,sz=str->length;
  444. p=(BBChar*)bbMemAlloc( (sz+1)*sizeof(BBChar) );
  445. memcpy(p,str->buf,sz*sizeof(BBChar));
  446. p[sz]=0;
  447. return p;
  448. }
  449. char *bbStringToUTF8String( BBString *str ){
  450. int i,len=str->length;
  451. char *buf=(char*)bbMemAlloc( len*3+1 );
  452. char *q=buf;
  453. unsigned short *p=str->buf;
  454. for( i=0;i<len;++i ){
  455. unsigned int c=*p++;
  456. if( c<0x80 ){
  457. *q++=c;
  458. }else if( c<0x800 ){
  459. *q++=0xc0|(c>>6);
  460. *q++=0x80|(c&0x3f);
  461. }else{
  462. *q++=0xe0|(c>>12);
  463. *q++=0x80|((c>>6)&0x3f);
  464. *q++=0x80|(c&0x3f);
  465. }
  466. }
  467. *q=0;
  468. return buf;
  469. }
  470. BBArray *bbStringSplit( BBString *str,BBString *sep ){
  471. int i,i2,n;
  472. BBString **p,*bit;
  473. BBArray *bits;
  474. if( sep->length ){
  475. i=0;n=1;
  476. while( (i2=bbStringFind( str,sep,i ))!=-1 ){
  477. ++n;
  478. i=i2+sep->length;
  479. }
  480. bits=bbArrayNew1D( "$",n );
  481. p=(BBString**)BBARRAYDATA( bits,1 );
  482. i=0;
  483. while( n-- ){
  484. i2=bbStringFind( str,sep,i );
  485. if( i2==-1 ) i2=str->length;
  486. bit=bbStringSlice( str,i,i2 );
  487. BBINCREFS( bit );
  488. *p++=bit;
  489. i=i2+sep->length;
  490. }
  491. return bits;
  492. }
  493. i=0;n=0;
  494. for(;;){
  495. while( i!=str->length && str->buf[i]<33 ) ++i;
  496. if( i++==str->length ) break;
  497. while( i!=str->length && str->buf[i]>32 ) ++i;
  498. ++n;
  499. }
  500. if( !n ) return &bbEmptyArray;
  501. bits=bbArrayNew1D( "$",n );
  502. p=(BBString**)BBARRAYDATA( bits,1 );
  503. i=0;
  504. while( n-- ){
  505. while( str->buf[i]<33 ) ++i;
  506. i2=i++;
  507. while( i!=str->length && str->buf[i]>32 ) ++i;
  508. bit=bbStringSlice( str,i2,i );
  509. BBINCREFS( bit );
  510. *p++=bit;
  511. }
  512. return bits;
  513. }
  514. BBString *bbStringJoin( BBString *sep,BBArray *bits ){
  515. int i,sz=0;
  516. int n_bits=bits->scales[0];
  517. BBString **p,*str;
  518. BBChar *t;
  519. if( bits==&bbEmptyArray ){
  520. return &bbEmptyString;
  521. }
  522. p=(BBString**)BBARRAYDATA( bits,1 );
  523. for( i=0;i<n_bits;++i ){
  524. BBString *bit=*p++;
  525. sz+=bit->length;
  526. }
  527. sz+=(n_bits-1)*sep->length;
  528. str=bbStringNew( sz );
  529. t=str->buf;
  530. p=(BBString**)BBARRAYDATA( bits,1 );
  531. for( i=0;i<n_bits;++i ){
  532. if( i ){
  533. memcpy( t,sep->buf,sep->length*sizeof(BBChar) );
  534. t+=sep->length;
  535. }
  536. BBString *bit=*p++;
  537. memcpy( t,bit->buf,bit->length*sizeof(BBChar) );
  538. t+=bit->length;
  539. }
  540. return str;
  541. }
  542. static void mktmp( void *p ){
  543. static int i;
  544. static void *bufs[32];
  545. int n=bbAtomicAdd( &i,1 ) & 31;
  546. bbMemFree( bufs[n] );
  547. bufs[n]=p;
  548. }
  549. char *bbTmpCString( BBString *str ){
  550. char *p=bbStringToCString( str );
  551. mktmp( p );
  552. return p;
  553. }
  554. BBChar *bbTmpWString( BBString *str ){
  555. BBChar *p=bbStringToWString( str );
  556. mktmp( p );
  557. return p;
  558. }
  559. char *bbTmpUTF8String( BBString *str ){
  560. char *p=bbStringToUTF8String( str );
  561. mktmp( p );
  562. return p;
  563. }