glue.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. /*
  2. Copyright (c) 2018 Bruce A Henderson
  3. This software is provided 'as-is', without any express or implied
  4. warranty. In no event will the authors be held liable for any damages
  5. arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it
  8. freely, subject to the following restrictions:
  9. 1. The origin of this software must not be misrepresented; you must not
  10. claim that you wrote the original software. If you use this software
  11. in a product, an acknowledgment in the product documentation would be
  12. appreciated but is not required.
  13. 2. Altered source versions must be plainly marked as such, and must not be
  14. misrepresented as being the original software.
  15. 3. This notice may not be removed or altered from any source distribution.
  16. */
  17. #include "brl.mod/blitz.mod/blitz.h"
  18. #ifndef BMX_NG
  19. extern unsigned short maxToLowerData[];
  20. extern unsigned short maxToUpperData[];
  21. #define bbToLowerData maxToLowerData
  22. #define bbToUpperData maxToUpperData
  23. #else
  24. #include "brl.mod/blitz.mod/blitz_unicode.h"
  25. #endif
  26. struct MaxStringBuilder {
  27. BBChar * buffer;
  28. int count;
  29. int capacity;
  30. };
  31. struct MaxSplitBuffer {
  32. struct MaxStringBuilder * buffer;
  33. int count;
  34. int * startIndex;
  35. int * endIndex;
  36. };
  37. void bmx_stringbuilder_free(struct MaxStringBuilder * buf) {
  38. free(buf->buffer);
  39. free(buf);
  40. }
  41. struct MaxStringBuilder * bmx_stringbuilder_new(int initial) {
  42. struct MaxStringBuilder * buf = malloc(sizeof(struct MaxStringBuilder));
  43. buf->count = 0;
  44. buf->capacity = initial;
  45. buf->buffer = malloc(initial * sizeof(BBChar));
  46. return buf;
  47. }
  48. /* make more capacity if requested size greater */
  49. void bmx_stringbuilder_resize(struct MaxStringBuilder * buf, int size) {
  50. if (buf->capacity < size) {
  51. if (buf->capacity * 2 > size) {
  52. size = buf->capacity * 2;
  53. }
  54. short * newBuffer = malloc(size * sizeof(BBChar));
  55. /* copy text to new buffer */
  56. memcpy(newBuffer, buf->buffer, buf->count * sizeof(BBChar));
  57. /* free old buffer */
  58. free(buf->buffer);
  59. buf->buffer = newBuffer;
  60. buf->capacity = size;
  61. }
  62. }
  63. int bmx_stringbuilder_count(struct MaxStringBuilder * buf) {
  64. return buf->count;
  65. }
  66. int bmx_stringbuilder_capacity(struct MaxStringBuilder * buf) {
  67. return buf->capacity;
  68. }
  69. void bmx_stringbuilder_setlength(struct MaxStringBuilder * buf, int length) {
  70. bmx_stringbuilder_resize(buf, length);
  71. if (length < buf->count) {
  72. buf->count = length;
  73. }
  74. }
  75. BBString * bmx_stringbuilder_tostring(struct MaxStringBuilder * buf) {
  76. if (!buf->count) {
  77. return &bbEmptyString;
  78. } else {
  79. return bbStringFromShorts(buf->buffer, buf->count);
  80. }
  81. }
  82. void bmx_stringbuilder_append_string(struct MaxStringBuilder * buf, BBString * value) {
  83. if (value != &bbEmptyString) {
  84. bmx_stringbuilder_resize(buf, buf->count + value->length);
  85. BBChar * p = buf->buffer + buf->count;
  86. memcpy(p, value->buf, value->length * sizeof(BBChar));
  87. buf->count += value->length;
  88. }
  89. }
  90. void bmx_stringbuilder_remove(struct MaxStringBuilder * buf, int start, int end) {
  91. if (start < 0 || start > buf->count || start > end) {
  92. return;
  93. }
  94. /* trim end if it is too big */
  95. if (end > buf->count) {
  96. end = buf->count;
  97. }
  98. /* still something to remove ? */
  99. if (buf->count - end != 0) {
  100. memcpy(buf->buffer + start, buf->buffer + end, (buf->count - end) * sizeof(BBChar));
  101. }
  102. buf->count -= end - start;
  103. }
  104. void bmx_stringbuilder_insert(struct MaxStringBuilder * buf, int offset, BBString * value) {
  105. if (value != &bbEmptyString) {
  106. if (offset < 0 || offset > buf->count) {
  107. return;
  108. }
  109. int length = value->length;
  110. bmx_stringbuilder_resize(buf, buf->count + length);
  111. /* make some space for the insertion */
  112. /* using memmove because data overlaps */
  113. memmove(buf->buffer + offset + length, buf->buffer + offset, (buf->count - offset) * sizeof(BBChar));
  114. /* insert the string */
  115. memcpy(buf->buffer + offset, value->buf, length * sizeof(BBChar));
  116. buf->count += length;
  117. }
  118. }
  119. void bmx_stringbuilder_reverse(struct MaxStringBuilder * buf) {
  120. int i = buf->count >> 1;
  121. int n = buf->count - i;
  122. while (--i >= 0) {
  123. BBChar c = buf->buffer[i];
  124. buf->buffer[i] = buf->buffer[n];
  125. buf->buffer[n] = c;
  126. n++;
  127. }
  128. }
  129. BBString * bmx_stringbuilder_substring(struct MaxStringBuilder * buf, int beginIndex, int endIndex) {
  130. if (!endIndex) {
  131. endIndex = buf->count;
  132. }
  133. if (beginIndex < 0 || endIndex > buf->count || endIndex < beginIndex) {
  134. return &bbEmptyString;
  135. }
  136. return bbStringFromShorts(buf->buffer + beginIndex, endIndex - beginIndex);
  137. }
  138. void bmx_stringbuilder_append_stringbuffer(struct MaxStringBuilder * buf, struct MaxStringBuilder * other) {
  139. if (other->count > 0) {
  140. bmx_stringbuilder_resize(buf, buf->count + other->count);
  141. memcpy(buf->buffer + buf->count, other->buffer, other->count * sizeof(BBChar));
  142. buf->count += other->count;
  143. }
  144. }
  145. int bmx_stringbuilder_matches(struct MaxStringBuilder * buf, int offset, BBString * subString) {
  146. int length = subString->length;
  147. int index = 0;
  148. while (--length >= 0) {
  149. if (buf->buffer[offset++] != subString->buf[index++]) {
  150. return 0;
  151. }
  152. }
  153. return 1;
  154. }
  155. int bmx_stringbuilder_startswith(struct MaxStringBuilder * buf, BBString * subString) {
  156. if (subString->length <= buf->count) {
  157. return bmx_stringbuilder_matches(buf, 0, subString);
  158. }
  159. return 0;
  160. }
  161. int bmx_stringbuilder_endswith(struct MaxStringBuilder * buf, BBString * subString) {
  162. if (subString->length <= buf->count) {
  163. return bmx_stringbuilder_matches(buf, buf->count - subString->length, subString);
  164. }
  165. }
  166. int bmx_stringbuilder_find(struct MaxStringBuilder * buf, BBString * subString, int startIndex) {
  167. if (startIndex < 0) {
  168. startIndex = 0;
  169. }
  170. int limit = buf->count - subString->length;
  171. while (startIndex <= limit) {
  172. if (bmx_stringbuilder_matches(buf, startIndex, subString)) {
  173. return startIndex;
  174. }
  175. startIndex++;
  176. }
  177. return -1;
  178. }
  179. int bmx_stringbuilder_findlast(struct MaxStringBuilder * buf, BBString * subString, int startIndex) {
  180. if (startIndex < 0) {
  181. startIndex = 0;
  182. }
  183. startIndex = buf->count - startIndex;
  184. if (startIndex + subString->length > buf->count) {
  185. startIndex = buf->count - subString->length;
  186. }
  187. while (startIndex >= 0) {
  188. if (bmx_stringbuilder_matches(buf, startIndex, subString)) {
  189. return startIndex;
  190. }
  191. startIndex--;
  192. }
  193. return -1;
  194. }
  195. void bmx_stringbuilder_tolower(struct MaxStringBuilder * buf) {
  196. int i;
  197. for (i = 0; i < buf->count; i++ ) {
  198. int c = buf->buffer[i];
  199. if (c < 192) {
  200. c = ( c >= 'A' && c <= 'Z') ? (c|32) : c;
  201. } else {
  202. int lo = 0, hi = 3828 / 4 - 1;
  203. while (lo <= hi) {
  204. int mid = (lo+hi)/2;
  205. if (c < bbToLowerData[mid*2]) {
  206. hi = mid-1;
  207. } else if (c > bbToLowerData[mid*2]) {
  208. lo = mid + 1;
  209. } else {
  210. c = bbToLowerData[mid*2+1];
  211. break;
  212. }
  213. }
  214. }
  215. buf->buffer[i]=c;
  216. }
  217. }
  218. void bmx_stringbuilder_toupper(struct MaxStringBuilder * buf) {
  219. int i;
  220. for (i = 0; i < buf->count; i++) {
  221. int c = buf->buffer[i];
  222. if (c < 181) {
  223. c = (c >= 'a' && c <= 'z') ? (c&~32) : c;
  224. } else {
  225. int lo = 0, hi = 3860/4-1;
  226. while (lo<=hi) {
  227. int mid=(lo+hi)/2;
  228. if (c < bbToUpperData[mid*2]) {
  229. hi = mid - 1;
  230. } else if (c > bbToUpperData[mid*2]) {
  231. lo = mid + 1;
  232. } else {
  233. c = bbToUpperData[mid*2+1];
  234. break;
  235. }
  236. }
  237. }
  238. buf->buffer[i]=c;
  239. }
  240. }
  241. void bmx_stringbuilder_trim(struct MaxStringBuilder * buf) {
  242. int start = 0;
  243. int end = buf->count;
  244. while (start < end && buf->buffer[start] <= ' ') {
  245. ++start;
  246. }
  247. if (start == end ) {
  248. buf->count = 0;
  249. return;
  250. }
  251. while (buf->buffer[end - 1] <= ' ') {
  252. --end;
  253. }
  254. if (end - start == buf->count) {
  255. return;
  256. }
  257. memmove(buf->buffer, buf->buffer + start, (end - start) * sizeof(BBChar));
  258. buf->count = end - start;
  259. }
  260. void bmx_stringbuilder_replace(struct MaxStringBuilder * buf, BBString * subString, BBString * withString) {
  261. if (!subString->length) {
  262. return;
  263. }
  264. struct MaxStringBuilder * newbuf = bmx_stringbuilder_new(16);
  265. int j, n;
  266. int i = 0;
  267. int p = 0;
  268. while( (j = bmx_stringbuilder_find(buf, subString, i)) != -1) {
  269. n = j - i;
  270. if (n) {
  271. bmx_stringbuilder_resize(newbuf, newbuf->count + n);
  272. memcpy(newbuf->buffer + p, buf->buffer + i, n * sizeof(BBChar));
  273. newbuf->count += n;
  274. p += n;
  275. }
  276. n = withString->length;
  277. bmx_stringbuilder_resize(newbuf, newbuf->count + n);
  278. memcpy(newbuf->buffer + p, withString->buf, n * sizeof(BBChar));
  279. newbuf->count += n;
  280. p += n;
  281. i = j + subString->length;
  282. }
  283. n = buf->count - i;
  284. if (n) {
  285. bmx_stringbuilder_resize(newbuf, newbuf->count + n);
  286. memcpy(newbuf->buffer + p, buf->buffer + i, n*sizeof(BBChar));
  287. newbuf->count += n;
  288. }
  289. bmx_stringbuilder_setlength(buf, 0);
  290. bmx_stringbuilder_append_stringbuffer(buf, newbuf);
  291. bmx_stringbuilder_free(newbuf);
  292. }
  293. void bmx_stringbuilder_join(struct MaxStringBuilder * buf, BBArray * bits, struct MaxStringBuilder * newbuf) {
  294. if(bits == &bbEmptyArray) {
  295. return;
  296. }
  297. int i;
  298. int n_bits = bits->scales[0];
  299. BBString **p = (BBString**)BBARRAYDATA( bits,1 );
  300. for(i = 0; i < n_bits; ++i) {
  301. if (i) {
  302. bmx_stringbuilder_append_stringbuffer(newbuf, buf);
  303. }
  304. BBString *bit = *p++;
  305. bmx_stringbuilder_append_string(newbuf, bit);
  306. }
  307. }
  308. struct MaxSplitBuffer * bmx_stringbuilder_split(struct MaxStringBuilder * buf, BBString * separator) {
  309. struct MaxSplitBuffer * splitBuffer = malloc(sizeof(struct MaxSplitBuffer));
  310. splitBuffer->buffer = buf;
  311. int count = 1;
  312. int i = 0;
  313. int offset = 0;
  314. if (separator->length > 0) {
  315. /* get a count of fields */
  316. while ((offset = bmx_stringbuilder_find(buf, separator, i)) != -1 ) {
  317. ++count;
  318. i = offset + separator->length;
  319. }
  320. splitBuffer->count = count;
  321. splitBuffer->startIndex = malloc(count * sizeof(int));
  322. splitBuffer->endIndex = malloc(count * sizeof(int));
  323. i = 0;
  324. int * bufferStartIndex = splitBuffer->startIndex;
  325. int * bufferEndIndex = splitBuffer->endIndex;
  326. while( count-- ){
  327. offset = bmx_stringbuilder_find(buf, separator, i);
  328. if (offset == -1) {
  329. offset = buf->count;
  330. }
  331. *bufferStartIndex++ = i;
  332. *bufferEndIndex++ = offset;
  333. i = offset + separator->length;
  334. }
  335. } else {
  336. // TODO - properly handle Null separator
  337. splitBuffer->count = count;
  338. splitBuffer->startIndex = malloc(count * sizeof(int));
  339. splitBuffer->endIndex = malloc(count * sizeof(int));
  340. *splitBuffer->startIndex = 0;
  341. *splitBuffer->endIndex = buf->count;
  342. }
  343. return splitBuffer;
  344. }
  345. void bmx_stringbuilder_setcharat(struct MaxStringBuilder * buf, int index, int ch) {
  346. if (index < 0 || index > buf->count) {
  347. return;
  348. }
  349. buf->buffer[index] = ch;
  350. }
  351. int bmx_stringbuilder_charat(struct MaxStringBuilder * buf, int index) {
  352. if (index < 0 || index > buf->count) {
  353. return 0;
  354. }
  355. return buf->buffer[index];
  356. }
  357. void bmx_stringbuilder_removecharat(struct MaxStringBuilder * buf, int index) {
  358. if (index < 0 || index >= buf->count) {
  359. return;
  360. }
  361. if (index < buf->count - 1) {
  362. memcpy(buf->buffer + index, buf->buffer + index + 1, (buf->count - index - 1) * sizeof(BBChar));
  363. }
  364. buf->count--;
  365. }
  366. void bmx_stringbuilder_append_cstring(struct MaxStringBuilder * buf, const char * chars) {
  367. int length = strlen(chars);
  368. if (length > 0) {
  369. int count = length;
  370. bmx_stringbuilder_resize(buf, buf->count + length);
  371. char * p = chars;
  372. BBChar * b = buf->buffer + buf->count;
  373. while (length--) {
  374. *b++ = *p++;
  375. }
  376. buf->count += count;
  377. }
  378. }
  379. void bmx_stringbuilder_append_utf8string(struct MaxStringBuilder * buf, const char * chars) {
  380. int length = strlen(chars);
  381. if (length > 0) {
  382. int count = 0;
  383. bmx_stringbuilder_resize(buf, buf->count + length);
  384. int c;
  385. char * p = chars;
  386. BBChar * b = buf->buffer + buf->count;
  387. while( c=*p++ & 0xff ){
  388. if( c<0x80 ){
  389. *b++=c;
  390. }else{
  391. int d=*p++ & 0x3f;
  392. if( c<0xe0 ){
  393. *b++=((c&31)<<6) | d;
  394. }else{
  395. int e=*p++ & 0x3f;
  396. if( c<0xf0 ){
  397. *b++=((c&15)<<12) | (d<<6) | e;
  398. }else{
  399. int f=*p++ & 0x3f;
  400. int v=((c&7)<<18) | (d<<12) | (e<<6) | f;
  401. if( v & 0xffff0000 ) bbExThrowCString( "Unicode character out of UCS-2 range" );
  402. *b++=v;
  403. }
  404. }
  405. }
  406. count++;
  407. }
  408. buf->count += count;
  409. }
  410. }
  411. void bmx_stringbuilder_append_double(struct MaxStringBuilder * buf, double value) {
  412. char chars[64];
  413. sprintf(chars,"%#.17lg", value);
  414. bmx_stringbuilder_append_cstring(buf, chars);
  415. }
  416. void bmx_stringbuilder_append_float(struct MaxStringBuilder * buf, float value) {
  417. char chars[64];
  418. sprintf(chars,"%#.9g", value);
  419. bmx_stringbuilder_append_cstring(buf, chars);
  420. }
  421. void bmx_stringbuilder_append_int(struct MaxStringBuilder * buf, int value) {
  422. char chars[32];
  423. sprintf(chars, "%d", value);
  424. bmx_stringbuilder_append_cstring(buf, chars);
  425. }
  426. void bmx_stringbuilder_append_long(struct MaxStringBuilder * buf, BBInt64 value) {
  427. char chars[64];
  428. sprintf(chars, "%lld", value);
  429. bmx_stringbuilder_append_cstring(buf, chars);
  430. }
  431. void bmx_stringbuilder_append_short(struct MaxStringBuilder * buf, short value) {
  432. char chars[16];
  433. sprintf(chars, "%d", value);
  434. bmx_stringbuilder_append_cstring(buf, chars);
  435. }
  436. void bmx_stringbuilder_append_byte(struct MaxStringBuilder * buf, char value) {
  437. char chars[8];
  438. sprintf(chars, "%d", value);
  439. bmx_stringbuilder_append_cstring(buf, chars);
  440. }
  441. #ifdef BMX_NG
  442. void bmx_stringbuilder_append_uint(struct MaxStringBuilder * buf, unsigned int value) {
  443. char chars[16];
  444. sprintf(chars, "%u", value);
  445. bmx_stringbuilder_append_cstring(buf, chars);
  446. }
  447. void bmx_stringbuilder_append_ulong(struct MaxStringBuilder * buf, BBUInt64 value) {
  448. char chars[64];
  449. sprintf(chars, "%llu", value);
  450. bmx_stringbuilder_append_cstring(buf, chars);
  451. }
  452. void bmx_stringbuilder_append_sizet(struct MaxStringBuilder * buf, BBSIZET value) {
  453. char chars[64];
  454. #if UINTPTR_MAX == 0xffffffff
  455. sprintf(chars, "%u", value);
  456. #else
  457. sprintf(chars, "%llu", value);
  458. #endif
  459. bmx_stringbuilder_append_cstring(buf, chars);
  460. }
  461. #endif
  462. void bmx_stringbuilder_append_shorts(struct MaxStringBuilder * buf, short * shorts, int length) {
  463. if (length > 0) {
  464. bmx_stringbuilder_resize(buf, buf->count + length);
  465. BBChar * p = buf->buffer + buf->count;
  466. memcpy(p, shorts, length * sizeof(BBChar));
  467. buf->count += length;
  468. }
  469. }
  470. BBString * bmx_stringbuilder_left(struct MaxStringBuilder * buf, int length) {
  471. if (length <= 0) {
  472. return &bbEmptyString;
  473. } else if (length >= buf->count) {
  474. return bbStringFromShorts(buf->buffer, buf->count);
  475. } else {
  476. return bbStringFromShorts(buf->buffer, length);
  477. }
  478. }
  479. BBString * bmx_stringbuilder_right(struct MaxStringBuilder * buf, int length) {
  480. if (length <= 0) {
  481. return &bbEmptyString;
  482. } else if (length >= buf->count) {
  483. return bbStringFromShorts(buf->buffer, buf->count);
  484. } else {
  485. return bbStringFromShorts(buf->buffer + (buf->count - length), length);
  486. }
  487. }
  488. /* ----------------------------------------------------- */
  489. int bmx_stringbuilder_splitbuffer_length(struct MaxSplitBuffer * buf) {
  490. return buf->count;
  491. }
  492. BBString * bmx_stringbuilder_splitbuffer_text(struct MaxSplitBuffer * buf, int index) {
  493. if (index < 0 || index >= buf->count) {
  494. return &bbEmptyString;
  495. }
  496. return bmx_stringbuilder_substring(buf->buffer, buf->startIndex[index], buf->endIndex[index]);
  497. }
  498. void bmx_stringbuilder_splitbuffer_free(struct MaxSplitBuffer * buf) {
  499. free(buf->startIndex);
  500. free(buf->endIndex);
  501. free(buf);
  502. }
  503. BBArray * bmx_stringbuilder_splitbuffer_toarray(struct MaxSplitBuffer * buf) {
  504. int i, n;
  505. BBString **p,*bit;
  506. BBArray *bits;
  507. n = buf->count;
  508. bits = bbArrayNew1D("$", n);
  509. p = (BBString**)BBARRAYDATA(bits, 1);
  510. i = 0;
  511. while (n--) {
  512. bit = bmx_stringbuilder_substring(buf->buffer, buf->startIndex[i], buf->endIndex[i]);
  513. BBINCREFS( bit );
  514. *p++ = bit;
  515. i++;
  516. }
  517. return bits;
  518. }