mutant-melbourne 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/LICENSE +25 -0
  2. data/README.md +69 -0
  3. data/Rakefile +14 -0
  4. data/ext/melbourne/.gitignore +3 -0
  5. data/ext/melbourne/bstring-license.txt +29 -0
  6. data/ext/melbourne/bstrlib.c +2687 -0
  7. data/ext/melbourne/bstrlib.h +267 -0
  8. data/ext/melbourne/encoding_compat.cpp +188 -0
  9. data/ext/melbourne/encoding_compat.hpp +57 -0
  10. data/ext/melbourne/extconf.rb +87 -0
  11. data/ext/melbourne/grammar18.cpp +11280 -0
  12. data/ext/melbourne/grammar18.hpp +13 -0
  13. data/ext/melbourne/grammar18.y +6088 -0
  14. data/ext/melbourne/grammar19.cpp +12420 -0
  15. data/ext/melbourne/grammar19.hpp +11 -0
  16. data/ext/melbourne/grammar19.y +7113 -0
  17. data/ext/melbourne/lex.c.blt +152 -0
  18. data/ext/melbourne/lex.c.tab +136 -0
  19. data/ext/melbourne/local_state.hpp +43 -0
  20. data/ext/melbourne/melbourne.cpp +88 -0
  21. data/ext/melbourne/melbourne.hpp +19 -0
  22. data/ext/melbourne/node18.hpp +262 -0
  23. data/ext/melbourne/node19.hpp +271 -0
  24. data/ext/melbourne/node_types.rb +304 -0
  25. data/ext/melbourne/node_types18.cpp +255 -0
  26. data/ext/melbourne/node_types18.hpp +129 -0
  27. data/ext/melbourne/node_types19.cpp +249 -0
  28. data/ext/melbourne/node_types19.hpp +126 -0
  29. data/ext/melbourne/parser_state18.hpp +181 -0
  30. data/ext/melbourne/parser_state19.hpp +251 -0
  31. data/ext/melbourne/quark.cpp +42 -0
  32. data/ext/melbourne/quark.hpp +45 -0
  33. data/ext/melbourne/symbols.cpp +224 -0
  34. data/ext/melbourne/symbols.hpp +119 -0
  35. data/ext/melbourne/var_table18.cpp +83 -0
  36. data/ext/melbourne/var_table18.hpp +33 -0
  37. data/ext/melbourne/var_table19.cpp +65 -0
  38. data/ext/melbourne/var_table19.hpp +35 -0
  39. data/ext/melbourne/visitor18.cpp +963 -0
  40. data/ext/melbourne/visitor18.hpp +12 -0
  41. data/ext/melbourne/visitor19.cpp +960 -0
  42. data/ext/melbourne/visitor19.hpp +15 -0
  43. data/lib/compiler/ast/constants.rb +81 -0
  44. data/lib/compiler/ast/control_flow.rb +290 -0
  45. data/lib/compiler/ast/data.rb +14 -0
  46. data/lib/compiler/ast/definitions.rb +749 -0
  47. data/lib/compiler/ast/encoding.rb +18 -0
  48. data/lib/compiler/ast/exceptions.rb +138 -0
  49. data/lib/compiler/ast/file.rb +11 -0
  50. data/lib/compiler/ast/grapher.rb +89 -0
  51. data/lib/compiler/ast/literals.rb +207 -0
  52. data/lib/compiler/ast/node.rb +362 -0
  53. data/lib/compiler/ast/operators.rb +106 -0
  54. data/lib/compiler/ast/self.rb +15 -0
  55. data/lib/compiler/ast/sends.rb +615 -0
  56. data/lib/compiler/ast/transforms.rb +298 -0
  57. data/lib/compiler/ast/values.rb +88 -0
  58. data/lib/compiler/ast/variables.rb +351 -0
  59. data/lib/compiler/ast.rb +20 -0
  60. data/lib/compiler/locals.rb +109 -0
  61. data/lib/melbourne/processor.rb +651 -0
  62. data/lib/melbourne/version.rb +3 -0
  63. data/lib/melbourne.rb +143 -0
  64. metadata +112 -0
@@ -0,0 +1,2687 @@
1
+ /*
2
+ * This source file is part of the bstring string library. This code was
3
+ * written by Paul Hsieh in 2002-2007, and is covered by the BSD open source
4
+ * license. Refer to the accompanying documentation for details on usage and
5
+ * license.
6
+ */
7
+
8
+ /*
9
+ * bstrlib.c
10
+ *
11
+ * This file is the core module for implementing the bstring functions.
12
+ */
13
+
14
+ #include <stdio.h>
15
+ #include <stddef.h>
16
+ #include <stdarg.h>
17
+ #include <stdlib.h>
18
+ #include <string.h>
19
+ #include <ctype.h>
20
+ #include "bstrlib.h"
21
+
22
+ /* Optionally include a mechanism for debugging memory */
23
+
24
+ #if defined(MEMORY_DEBUG) || defined(BSTRLIB_MEMORY_DEBUG)
25
+ /* TODO: temporarily disable include until dependency grapher
26
+ * properly parses expressions.
27
+ *
28
+ * #include "memdbg.h"
29
+ */
30
+ #endif
31
+
32
+ #ifndef bstr__alloc
33
+ #define bstr__alloc(x) malloc (x)
34
+ #endif
35
+
36
+ #ifndef bstr__free
37
+ #define bstr__free(p) free (p)
38
+ #endif
39
+
40
+ #ifndef bstr__realloc
41
+ #define bstr__realloc(p,x) realloc ((p), (x))
42
+ #endif
43
+
44
+ #ifndef bstr__memcpy
45
+ #define bstr__memcpy(d,s,l) memcpy ((d), (s), (l))
46
+ #endif
47
+
48
+ #ifndef bstr__memmove
49
+ #define bstr__memmove(d,s,l) memmove ((d), (s), (l))
50
+ #endif
51
+
52
+ #ifndef bstr__memset
53
+ #define bstr__memset(d,c,l) memset ((d), (c), (l))
54
+ #endif
55
+
56
+ #ifndef bstr__memcmp
57
+ #define bstr__memcmp(d,c,l) memcmp ((d), (c), (l))
58
+ #endif
59
+
60
+ #ifndef bstr__memchr
61
+ #define bstr__memchr(s,c,l) memchr ((s), (c), (l))
62
+ #endif
63
+
64
+ /* Just a length safe wrapper for memmove. */
65
+
66
+ #define bBlockCopy(D,S,L) { if ((L) > 0) bstr__memmove ((D),(S),(L)); }
67
+
68
+ /* Compute the snapped size for a given requested size. By snapping to powers
69
+ of 2 like this, repeated reallocations are avoided. */
70
+ static int snapUpSize (int i) {
71
+ if (i < 8) {
72
+ i = 8;
73
+ } else {
74
+ unsigned int j;
75
+ j = (unsigned int) i;
76
+
77
+ j |= (j >> 1);
78
+ j |= (j >> 2);
79
+ j |= (j >> 4);
80
+ j |= (j >> 8); /* Ok, since int >= 16 bits */
81
+ #if (UINT_MAX != 0xffff)
82
+ j |= (j >> 16); /* For 32 bit int systems */
83
+ #if (UINT_MAX > 0xffffffffUL)
84
+ j |= (j >> 32); /* For 64 bit int systems */
85
+ #endif
86
+ #endif
87
+ /* Least power of two greater than i */
88
+ j++;
89
+ if ((int) j >= i) i = (int) j;
90
+ }
91
+ return i;
92
+ }
93
+
94
+ /* int balloc (bstring b, int len)
95
+ *
96
+ * Increase the size of the memory backing the bstring b to at least len.
97
+ */
98
+ int balloc (bstring b, int olen) {
99
+ int len;
100
+ if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen <= 0 ||
101
+ b->mlen < b->slen || olen <= 0) {
102
+ return BSTR_ERR;
103
+ }
104
+
105
+ if (olen >= b->mlen) {
106
+ unsigned char * x;
107
+
108
+ if ((len = snapUpSize (olen)) <= b->mlen) return BSTR_OK;
109
+
110
+ /* Assume probability of a non-moving realloc is 0.125 */
111
+ if (7 * b->mlen < 8 * b->slen) {
112
+
113
+ /* If slen is close to mlen in size then use realloc to reduce
114
+ the memory defragmentation */
115
+
116
+ reallocStrategy:;
117
+
118
+ x = (unsigned char *) bstr__realloc (b->data, (size_t) len);
119
+ if (x == NULL) {
120
+
121
+ /* Since we failed, try allocating the tighest possible
122
+ allocation */
123
+
124
+ if (NULL == (x = (unsigned char *) bstr__realloc (b->data, (size_t) (len = olen)))) {
125
+ return BSTR_ERR;
126
+ }
127
+ }
128
+ } else {
129
+
130
+ /* If slen is not close to mlen then avoid the penalty of copying
131
+ the extra bytes that are allocated, but not considered part of
132
+ the string */
133
+
134
+ if (NULL == (x = (unsigned char *) bstr__alloc ((size_t) len))) {
135
+
136
+ /* Perhaps there is no available memory for the two
137
+ allocations to be in memory at once */
138
+
139
+ goto reallocStrategy;
140
+
141
+ } else {
142
+ if (b->slen) bstr__memcpy ((char *) x, (char *) b->data, (size_t) b->slen);
143
+ bstr__free (b->data);
144
+ }
145
+ }
146
+ b->data = x;
147
+ b->mlen = len;
148
+ b->data[b->slen] = (unsigned char) '\0';
149
+ }
150
+
151
+ return BSTR_OK;
152
+ }
153
+
154
+ /* int ballocmin (bstring b, int len)
155
+ *
156
+ * Set the size of the memory backing the bstring b to len or b->slen+1,
157
+ * whichever is larger. Note that repeated use of this function can degrade
158
+ * performance.
159
+ */
160
+ int ballocmin (bstring b, int len) {
161
+ unsigned char * s;
162
+
163
+ if (b == NULL || b->data == NULL || (b->slen+1) < 0 || b->mlen <= 0 ||
164
+ b->mlen < b->slen || len <= 0) {
165
+ return BSTR_ERR;
166
+ }
167
+
168
+ if (len < b->slen + 1) len = b->slen + 1;
169
+
170
+ if (len != b->mlen) {
171
+ s = (unsigned char *) bstr__realloc (b->data, (size_t) len);
172
+ if (NULL == s) return BSTR_ERR;
173
+ s[b->slen] = (unsigned char) '\0';
174
+ b->data = s;
175
+ b->mlen = len;
176
+ }
177
+
178
+ return BSTR_OK;
179
+ }
180
+
181
+ /* bstring bfromcstr (const char * str)
182
+ *
183
+ * Create a bstring which contains the contents of the '\0' terminated char *
184
+ * buffer str.
185
+ */
186
+ bstring bfromcstr (const char * str) {
187
+ bstring b;
188
+ int i;
189
+ size_t j;
190
+
191
+ if (str == NULL) return NULL;
192
+ j = (strlen) (str);
193
+ i = snapUpSize ((int) (j + (2 - (j != 0))));
194
+ if (i <= (int) j) return NULL;
195
+
196
+ b = (bstring) bstr__alloc (sizeof (struct tagbstring));
197
+ if (NULL == b) return NULL;
198
+ b->slen = (int) j;
199
+ if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) {
200
+ bstr__free (b);
201
+ return NULL;
202
+ }
203
+
204
+ bstr__memcpy (b->data, str, j+1);
205
+ return b;
206
+ }
207
+
208
+ /* bstring bfromcstralloc (int mlen, const char * str)
209
+ *
210
+ * Create a bstring which contains the contents of the '\0' terminated char *
211
+ * buffer str. The memory buffer backing the string is at least len
212
+ * characters in length.
213
+ */
214
+ bstring bfromcstralloc (int mlen, const char * str) {
215
+ bstring b;
216
+ int i;
217
+ size_t j;
218
+
219
+ if (str == NULL) return NULL;
220
+ j = (strlen) (str);
221
+ i = snapUpSize ((int) (j + (2 - (j != 0))));
222
+ if (i <= (int) j) return NULL;
223
+
224
+ b = (bstring) bstr__alloc (sizeof (struct tagbstring));
225
+ if (b == NULL) return NULL;
226
+ b->slen = (int) j;
227
+ if (i < mlen) i = mlen;
228
+
229
+ if (NULL == (b->data = (unsigned char *) bstr__alloc (b->mlen = i))) {
230
+ bstr__free (b);
231
+ return NULL;
232
+ }
233
+
234
+ bstr__memcpy (b->data, str, j+1);
235
+ return b;
236
+ }
237
+
238
+ /* bstring blk2bstr (const void * blk, int len)
239
+ *
240
+ * Create a bstring which contains the content of the block blk of length
241
+ * len.
242
+ */
243
+ bstring blk2bstr (const void * blk, int len) {
244
+ bstring b;
245
+ int i;
246
+
247
+ if (blk == NULL || len < 0) return NULL;
248
+ b = (bstring) bstr__alloc (sizeof (struct tagbstring));
249
+ if (b == NULL) return NULL;
250
+ b->slen = len;
251
+
252
+ i = len + (2 - (len != 0));
253
+ i = snapUpSize (i);
254
+
255
+ b->mlen = i;
256
+
257
+ b->data = (unsigned char *) bstr__alloc ((size_t) b->mlen);
258
+ if (b->data == NULL) {
259
+ bstr__free (b);
260
+ return NULL;
261
+ }
262
+
263
+ if (len > 0) bstr__memcpy (b->data, blk, (size_t) len);
264
+ b->data[len] = (unsigned char) '\0';
265
+
266
+ return b;
267
+ }
268
+
269
+ /* char * bstr2cstr (const_bstring s, char z)
270
+ *
271
+ * Create a '\0' terminated char * buffer which is equal to the contents of
272
+ * the bstring s, except that any contained '\0' characters are converted
273
+ * to the character in z. This returned value should be freed with a
274
+ * bcstrfree () call, by the calling application.
275
+ */
276
+ char * bstr2cstr (const_bstring b, char z) {
277
+ int i, l;
278
+ char * r;
279
+
280
+ if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
281
+ l = b->slen;
282
+ r = (char *) bstr__alloc ((size_t) (l + 1));
283
+ if (r == NULL) return r;
284
+
285
+ for (i=0; i < l; i ++) {
286
+ r[i] = (char) ((b->data[i] == '\0') ? z : (char) (b->data[i]));
287
+ }
288
+
289
+ r[l] = (unsigned char) '\0';
290
+
291
+ return r;
292
+ }
293
+
294
+ /* int bcstrfree (char * s)
295
+ *
296
+ * Frees a C-string generated by bstr2cstr (). This is normally unnecessary
297
+ * since it just wraps a call to bstr__free (), however, if bstr__alloc ()
298
+ * and bstr__free () have been redefined as a macros within the bstrlib
299
+ * module (via defining them in memdbg.h after defining
300
+ * BSTRLIB_MEMORY_DEBUG) with some difference in behaviour from the std
301
+ * library functions, then this allows a correct way of freeing the memory
302
+ * that allows higher level code to be independent from these macro
303
+ * redefinitions.
304
+ */
305
+ int bcstrfree (char * s) {
306
+ if (s) {
307
+ bstr__free (s);
308
+ return BSTR_OK;
309
+ }
310
+ return BSTR_ERR;
311
+ }
312
+
313
+ /* int bconcat (bstring b0, const_bstring b1)
314
+ *
315
+ * Concatenate the bstring b1 to the bstring b0.
316
+ */
317
+ int bconcat (bstring b0, const_bstring b1) {
318
+ int len, d;
319
+ bstring aux = (bstring) b1;
320
+
321
+ if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL) return BSTR_ERR;
322
+
323
+ d = b0->slen;
324
+ len = b1->slen;
325
+ if ((d | (b0->mlen - d) | len) < 0) return BSTR_ERR;
326
+
327
+ if (b0->mlen <= d + len + 1) {
328
+ ptrdiff_t pd;
329
+ if (0 <= (pd = b1->data - b0->data) && pd < b0->mlen) {
330
+ if (NULL == (aux = bstrcpy (b1))) return BSTR_ERR;
331
+ }
332
+ if (balloc (b0, d + len + 1) != BSTR_OK) {
333
+ if (aux != b1) bdestroy (aux);
334
+ return BSTR_ERR;
335
+ }
336
+ }
337
+
338
+ bBlockCopy (&b0->data[d], &aux->data[0], (size_t) len);
339
+ b0->data[d + len] = (unsigned char) '\0';
340
+ b0->slen += len;
341
+ if (aux != b1) bdestroy (aux);
342
+ return BSTR_OK;
343
+ }
344
+
345
+ /* int bconchar (bstring b, char c)
346
+ *
347
+ * Concatenate the single character c to the bstring b.
348
+ */
349
+ int bconchar (bstring b, char c) {
350
+ int d;
351
+
352
+ if (b == NULL) return BSTR_ERR;
353
+ d = b->slen;
354
+ if ((d | (b->mlen - d)) < 0 || balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
355
+ b->data[d] = (unsigned char) c;
356
+ b->data[d + 1] = (unsigned char) '\0';
357
+ b->slen++;
358
+ return BSTR_OK;
359
+ }
360
+
361
+ /* int bcatcstr (bstring b, const char * s)
362
+ *
363
+ * Concatenate a char * string to a bstring.
364
+ */
365
+ int bcatcstr (bstring b, const char * s) {
366
+ char * d;
367
+ int i, l;
368
+
369
+ if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen
370
+ || b->mlen <= 0 || s == NULL) return BSTR_ERR;
371
+
372
+ /* Optimistically concatenate directly */
373
+ l = b->mlen - b->slen;
374
+ d = (char *) &b->data[b->slen];
375
+ for (i=0; i < l; i++) {
376
+ if ((*d++ = *s++) == '\0') {
377
+ b->slen += i;
378
+ return BSTR_OK;
379
+ }
380
+ }
381
+ b->slen += i;
382
+
383
+ /* Need to explicitely resize and concatenate tail */
384
+ return bcatblk (b, (const void *) s, (int) strlen (s));
385
+ }
386
+
387
+ /* int bcatblk (bstring b, const void * s, int len)
388
+ *
389
+ * Concatenate a fixed length buffer to a bstring.
390
+ */
391
+ int bcatblk (bstring b, const void * s, int len) {
392
+ int nl;
393
+
394
+ if (b == NULL || b->data == NULL || b->slen < 0 || b->mlen < b->slen
395
+ || b->mlen <= 0 || s == NULL || len < 0) return BSTR_ERR;
396
+
397
+ if (0 > (nl = b->slen + len)) return BSTR_ERR; /* Overflow? */
398
+ if (b->mlen <= nl && 0 > balloc (b, nl + 1)) return BSTR_ERR;
399
+
400
+ bBlockCopy (&b->data[b->slen], s, (size_t) len);
401
+ b->slen = nl;
402
+ b->data[nl] = (unsigned char) '\0';
403
+ return BSTR_OK;
404
+ }
405
+
406
+ /* bstring bstrcpy (const_bstring b)
407
+ *
408
+ * Create a copy of the bstring b.
409
+ */
410
+ bstring bstrcpy (const_bstring b) {
411
+ bstring b0;
412
+ int i,j;
413
+
414
+ /* Attempted to copy an invalid string? */
415
+ if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
416
+
417
+ b0 = (bstring) bstr__alloc (sizeof (struct tagbstring));
418
+ if (b0 == NULL) {
419
+ /* Unable to allocate memory for string header */
420
+ return NULL;
421
+ }
422
+
423
+ i = b->slen;
424
+ j = snapUpSize (i + 1);
425
+
426
+ b0->data = (unsigned char *) bstr__alloc (j);
427
+ if (b0->data == NULL) {
428
+ j = i + 1;
429
+ b0->data = (unsigned char *) bstr__alloc (j);
430
+ if (b0->data == NULL) {
431
+ /* Unable to allocate memory for string data */
432
+ bstr__free (b0);
433
+ return NULL;
434
+ }
435
+ }
436
+
437
+ b0->mlen = j;
438
+ b0->slen = i;
439
+
440
+ if (i) bstr__memcpy ((char *) b0->data, (char *) b->data, i);
441
+ b0->data[b0->slen] = (unsigned char) '\0';
442
+
443
+ return b0;
444
+ }
445
+
446
+ /* int bassign (bstring a, const_bstring b)
447
+ *
448
+ * Overwrite the string a with the contents of string b.
449
+ */
450
+ int bassign (bstring a, const_bstring b) {
451
+ if (b == NULL || b->data == NULL || b->slen < 0)
452
+ return BSTR_ERR;
453
+ if (b->slen != 0) {
454
+ if (balloc (a, b->slen) != BSTR_OK) return BSTR_ERR;
455
+ bstr__memmove (a->data, b->data, b->slen);
456
+ } else {
457
+ if (a == NULL || a->data == NULL || a->mlen < a->slen ||
458
+ a->slen < 0 || a->mlen == 0)
459
+ return BSTR_ERR;
460
+ }
461
+ a->data[b->slen] = (unsigned char) '\0';
462
+ a->slen = b->slen;
463
+ return BSTR_OK;
464
+ }
465
+
466
+ /* int bassignmidstr (bstring a, const_bstring b, int left, int len)
467
+ *
468
+ * Overwrite the string a with the middle of contents of string b
469
+ * starting from position left and running for a length len. left and
470
+ * len are clamped to the ends of b as with the function bmidstr.
471
+ */
472
+ int bassignmidstr (bstring a, const_bstring b, int left, int len) {
473
+ if (b == NULL || b->data == NULL || b->slen < 0)
474
+ return BSTR_ERR;
475
+
476
+ if (left < 0) {
477
+ len += left;
478
+ left = 0;
479
+ }
480
+
481
+ if (len > b->slen - left) len = b->slen - left;
482
+
483
+ if (a == NULL || a->data == NULL || a->mlen < a->slen ||
484
+ a->slen < 0 || a->mlen == 0)
485
+ return BSTR_ERR;
486
+
487
+ if (len > 0) {
488
+ if (balloc (a, len) != BSTR_OK) return BSTR_ERR;
489
+ bstr__memmove (a->data, b->data + left, len);
490
+ a->slen = len;
491
+ } else {
492
+ a->slen = 0;
493
+ }
494
+ a->data[a->slen] = (unsigned char) '\0';
495
+ return BSTR_OK;
496
+ }
497
+
498
+ /* int bassigncstr (bstring a, const char * str)
499
+ *
500
+ * Overwrite the string a with the contents of char * string str. Note that
501
+ * the bstring a must be a well defined and writable bstring. If an error
502
+ * occurs BSTR_ERR is returned however a may be partially overwritten.
503
+ */
504
+ int bassigncstr (bstring a, const char * str) {
505
+ int i;
506
+ size_t len;
507
+ if (a == NULL || a->data == NULL || a->mlen < a->slen ||
508
+ a->slen < 0 || a->mlen == 0 || NULL == str)
509
+ return BSTR_ERR;
510
+
511
+ for (i=0; i < a->mlen; i++) {
512
+ if ('\0' == (a->data[i] = str[i])) {
513
+ a->slen = i;
514
+ return BSTR_OK;
515
+ }
516
+ }
517
+
518
+ a->slen = i;
519
+ len = strlen (str + i);
520
+ if (len > INT_MAX || i + len + 1 > INT_MAX ||
521
+ 0 > balloc (a, (int) (i + len + 1))) return BSTR_ERR;
522
+ bBlockCopy (a->data + i, str + i, (size_t) len + 1);
523
+ a->slen += (int) len;
524
+ return BSTR_OK;
525
+ }
526
+
527
+ /* int bassignblk (bstring a, const void * s, int len)
528
+ *
529
+ * Overwrite the string a with the contents of the block (s, len). Note that
530
+ * the bstring a must be a well defined and writable bstring. If an error
531
+ * occurs BSTR_ERR is returned and a is not overwritten.
532
+ */
533
+ int bassignblk (bstring a, const void * s, int len) {
534
+ if (a == NULL || a->data == NULL || a->mlen < a->slen ||
535
+ a->slen < 0 || a->mlen == 0 || NULL == s || len + 1 < 1)
536
+ return BSTR_ERR;
537
+ if (len + 1 > a->mlen && 0 > balloc (a, len + 1)) return BSTR_ERR;
538
+ bBlockCopy (a->data, s, (size_t) len);
539
+ a->data[len] = (unsigned char) '\0';
540
+ a->slen = len;
541
+ return BSTR_OK;
542
+ }
543
+
544
+ /* int btrunc (bstring b, int n)
545
+ *
546
+ * Truncate the bstring to at most n characters.
547
+ */
548
+ int btrunc (bstring b, int n) {
549
+ if (n < 0 || b == NULL || b->data == NULL || b->mlen < b->slen ||
550
+ b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
551
+ if (b->slen > n) {
552
+ b->slen = n;
553
+ b->data[n] = (unsigned char) '\0';
554
+ }
555
+ return BSTR_OK;
556
+ }
557
+
558
+ #define upcase(c) (toupper ((unsigned char) c))
559
+ #define downcase(c) (tolower ((unsigned char) c))
560
+ #define wspace(c) (isspace ((unsigned char) c))
561
+
562
+ /* int btoupper (bstring b)
563
+ *
564
+ * Convert contents of bstring to upper case.
565
+ */
566
+ int btoupper (bstring b) {
567
+ int i, len;
568
+ if (b == NULL || b->data == NULL || b->mlen < b->slen ||
569
+ b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
570
+ for (i=0, len = b->slen; i < len; i++) {
571
+ b->data[i] = (unsigned char) upcase (b->data[i]);
572
+ }
573
+ return BSTR_OK;
574
+ }
575
+
576
+ /* int btolower (bstring b)
577
+ *
578
+ * Convert contents of bstring to lower case.
579
+ */
580
+ int btolower (bstring b) {
581
+ int i, len;
582
+ if (b == NULL || b->data == NULL || b->mlen < b->slen ||
583
+ b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
584
+ for (i=0, len = b->slen; i < len; i++) {
585
+ b->data[i] = (unsigned char) downcase (b->data[i]);
586
+ }
587
+ return BSTR_OK;
588
+ }
589
+
590
+ /* int bstricmp (const_bstring b0, const_bstring b1)
591
+ *
592
+ * Compare two strings without differentiating between case. The return
593
+ * value is the difference of the values of the characters where the two
594
+ * strings first differ after lower case transformation, otherwise 0 is
595
+ * returned indicating that the strings are equal. If the lengths are
596
+ * different, then a difference from 0 is given, but if the first extra
597
+ * character is '\0', then it is taken to be the value UCHAR_MAX+1.
598
+ */
599
+ int bstricmp (const_bstring b0, const_bstring b1) {
600
+ int i, v, n;
601
+
602
+ if (bdata (b0) == NULL || b0->slen < 0 ||
603
+ bdata (b1) == NULL || b1->slen < 0) return SHRT_MIN;
604
+ if ((n = b0->slen) > b1->slen) n = b1->slen;
605
+ else if (b0->slen == b1->slen && b0->data == b1->data) return BSTR_OK;
606
+
607
+ for (i = 0; i < n; i ++) {
608
+ v = (char) downcase (b0->data[i])
609
+ - (char) downcase (b1->data[i]);
610
+ if (0 != v) return v;
611
+ }
612
+
613
+ if (b0->slen > n) {
614
+ v = (char) downcase (b0->data[n]);
615
+ if (v) return v;
616
+ return UCHAR_MAX + 1;
617
+ }
618
+ if (b1->slen > n) {
619
+ v = - (char) downcase (b1->data[n]);
620
+ if (v) return v;
621
+ return - (int) (UCHAR_MAX + 1);
622
+ }
623
+ return BSTR_OK;
624
+ }
625
+
626
+ /* int bstrnicmp (const_bstring b0, const_bstring b1, int n)
627
+ *
628
+ * Compare two strings without differentiating between case for at most n
629
+ * characters. If the position where the two strings first differ is
630
+ * before the nth position, the return value is the difference of the values
631
+ * of the characters, otherwise 0 is returned. If the lengths are different
632
+ * and less than n characters, then a difference from 0 is given, but if the
633
+ * first extra character is '\0', then it is taken to be the value
634
+ * UCHAR_MAX+1.
635
+ */
636
+ int bstrnicmp (const_bstring b0, const_bstring b1, int n) {
637
+ int i, v, m;
638
+
639
+ if (bdata (b0) == NULL || b0->slen < 0 ||
640
+ bdata (b1) == NULL || b1->slen < 0 || n < 0) return SHRT_MIN;
641
+ m = n;
642
+ if (m > b0->slen) m = b0->slen;
643
+ if (m > b1->slen) m = b1->slen;
644
+
645
+ if (b0->data != b1->data) {
646
+ for (i = 0; i < m; i ++) {
647
+ v = (char) downcase (b0->data[i]);
648
+ v -= (char) downcase (b1->data[i]);
649
+ if (v != 0) return b0->data[i] - b1->data[i];
650
+ }
651
+ }
652
+
653
+ if (n == m || b0->slen == b1->slen) return BSTR_OK;
654
+
655
+ if (b0->slen > m) {
656
+ v = (char) downcase (b0->data[m]);
657
+ if (v) return v;
658
+ return UCHAR_MAX + 1;
659
+ }
660
+
661
+ v = - (char) downcase (b1->data[m]);
662
+ if (v) return v;
663
+ return - (int) (UCHAR_MAX + 1);
664
+ }
665
+
666
+ /* int biseqcaseless (const_bstring b0, const_bstring b1)
667
+ *
668
+ * Compare two strings for equality without differentiating between case.
669
+ * If the strings differ other than in case, 0 is returned, if the strings
670
+ * are the same, 1 is returned, if there is an error, -1 is returned. If
671
+ * the length of the strings are different, this function is O(1). '\0'
672
+ * termination characters are not treated in any special way.
673
+ */
674
+ int biseqcaseless (const_bstring b0, const_bstring b1) {
675
+ int i, n;
676
+
677
+ if (bdata (b0) == NULL || b0->slen < 0 ||
678
+ bdata (b1) == NULL || b1->slen < 0) return BSTR_ERR;
679
+ if (b0->slen != b1->slen) return BSTR_OK;
680
+ if (b0->data == b1->data || b0->slen == 0) return 1;
681
+ for (i=0, n=b0->slen; i < n; i++) {
682
+ if (b0->data[i] != b1->data[i]) {
683
+ unsigned char c = (unsigned char) downcase (b0->data[i]);
684
+ if (c != (unsigned char) downcase (b1->data[i])) return 0;
685
+ }
686
+ }
687
+ return 1;
688
+ }
689
+
690
+ /* int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len)
691
+ *
692
+ * Compare beginning of string b0 with a block of memory of length len
693
+ * without differentiating between case for equality. If the beginning of b0
694
+ * differs from the memory block other than in case (or if b0 is too short),
695
+ * 0 is returned, if the strings are the same, 1 is returned, if there is an
696
+ * error, -1 is returned. '\0' characters are not treated in any special
697
+ * way.
698
+ */
699
+ int bisstemeqcaselessblk (const_bstring b0, const void * blk, int len) {
700
+ int i;
701
+
702
+ if (bdata (b0) == NULL || b0->slen < 0 || NULL == blk || len < 0)
703
+ return BSTR_ERR;
704
+ if (b0->slen < len) return BSTR_OK;
705
+ if (b0->data == (const unsigned char *) blk || len == 0) return 1;
706
+
707
+ for (i = 0; i < len; i ++) {
708
+ if (b0->data[i] != ((const unsigned char *) blk)[i]) {
709
+ if (downcase (b0->data[i]) !=
710
+ downcase (((const unsigned char *) blk)[i])) return 0;
711
+ }
712
+ }
713
+ return 1;
714
+ }
715
+
716
+ /*
717
+ * int bltrimws (bstring b)
718
+ *
719
+ * Delete whitespace contiguous from the left end of the string.
720
+ */
721
+ int bltrimws (bstring b) {
722
+ int i, len;
723
+
724
+ if (b == NULL || b->data == NULL || b->mlen < b->slen ||
725
+ b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
726
+
727
+ for (len = b->slen, i = 0; i < len; i++) {
728
+ if (!wspace (b->data[i])) {
729
+ return bdelete (b, 0, i);
730
+ }
731
+ }
732
+
733
+ b->data[0] = (unsigned char) '\0';
734
+ b->slen = 0;
735
+ return BSTR_OK;
736
+ }
737
+
738
+ /*
739
+ * int brtrimws (bstring b)
740
+ *
741
+ * Delete whitespace contiguous from the right end of the string.
742
+ */
743
+ int brtrimws (bstring b) {
744
+ int i;
745
+
746
+ if (b == NULL || b->data == NULL || b->mlen < b->slen ||
747
+ b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
748
+
749
+ for (i = b->slen - 1; i >= 0; i--) {
750
+ if (!wspace (b->data[i])) {
751
+ if (b->mlen > i) b->data[i+1] = (unsigned char) '\0';
752
+ b->slen = i + 1;
753
+ return BSTR_OK;
754
+ }
755
+ }
756
+
757
+ b->data[0] = (unsigned char) '\0';
758
+ b->slen = 0;
759
+ return BSTR_OK;
760
+ }
761
+
762
+ /*
763
+ * int btrimws (bstring b)
764
+ *
765
+ * Delete whitespace contiguous from both ends of the string.
766
+ */
767
+ int btrimws (bstring b) {
768
+ int i, j;
769
+
770
+ if (b == NULL || b->data == NULL || b->mlen < b->slen ||
771
+ b->slen < 0 || b->mlen <= 0) return BSTR_ERR;
772
+
773
+ for (i = b->slen - 1; i >= 0; i--) {
774
+ if (!wspace (b->data[i])) {
775
+ if (b->mlen > i) b->data[i+1] = (unsigned char) '\0';
776
+ b->slen = i + 1;
777
+ for (j = 0; wspace (b->data[j]); j++) {}
778
+ return bdelete (b, 0, j);
779
+ }
780
+ }
781
+
782
+ b->data[0] = (unsigned char) '\0';
783
+ b->slen = 0;
784
+ return BSTR_OK;
785
+ }
786
+
787
+ /* int biseq (const_bstring b0, const_bstring b1)
788
+ *
789
+ * Compare the string b0 and b1. If the strings differ, 0 is returned, if
790
+ * the strings are the same, 1 is returned, if there is an error, -1 is
791
+ * returned. If the length of the strings are different, this function is
792
+ * O(1). '\0' termination characters are not treated in any special way.
793
+ */
794
+ int biseq (const_bstring b0, const_bstring b1) {
795
+ if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
796
+ b0->slen < 0 || b1->slen < 0) return BSTR_ERR;
797
+ if (b0->slen != b1->slen) return BSTR_OK;
798
+ if (b0->data == b1->data || b0->slen == 0) return 1;
799
+ return !bstr__memcmp (b0->data, b1->data, b0->slen);
800
+ }
801
+
802
+ /* int bisstemeqblk (const_bstring b0, const void * blk, int len)
803
+ *
804
+ * Compare beginning of string b0 with a block of memory of length len for
805
+ * equality. If the beginning of b0 differs from the memory block (or if b0
806
+ * is too short), 0 is returned, if the strings are the same, 1 is returned,
807
+ * if there is an error, -1 is returned. '\0' characters are not treated in
808
+ * any special way.
809
+ */
810
+ int bisstemeqblk (const_bstring b0, const void * blk, int len) {
811
+ int i;
812
+
813
+ if (bdata (b0) == NULL || b0->slen < 0 || NULL == blk || len < 0)
814
+ return BSTR_ERR;
815
+ if (b0->slen < len) return BSTR_OK;
816
+ if (b0->data == (const unsigned char *) blk || len == 0) return 1;
817
+
818
+ for (i = 0; i < len; i ++) {
819
+ if (b0->data[i] != ((const unsigned char *) blk)[i]) return BSTR_OK;
820
+ }
821
+ return 1;
822
+ }
823
+
824
+ /* int biseqcstr (const_bstring b, const char *s)
825
+ *
826
+ * Compare the bstring b and char * string s. The C string s must be '\0'
827
+ * terminated at exactly the length of the bstring b, and the contents
828
+ * between the two must be identical with the bstring b with no '\0'
829
+ * characters for the two contents to be considered equal. This is
830
+ * equivalent to the condition that their current contents will be always be
831
+ * equal when comparing them in the same format after converting one or the
832
+ * other. If the strings are equal 1 is returned, if they are unequal 0 is
833
+ * returned and if there is a detectable error BSTR_ERR is returned.
834
+ */
835
+ int biseqcstr (const_bstring b, const char * s) {
836
+ int i;
837
+ if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return BSTR_ERR;
838
+ for (i=0; i < b->slen; i++) {
839
+ if (s[i] == '\0' || b->data[i] != (unsigned char) s[i]) return BSTR_OK;
840
+ }
841
+ return s[i] == '\0';
842
+ }
843
+
844
+ /* int biseqcstrcaseless (const_bstring b, const char *s)
845
+ *
846
+ * Compare the bstring b and char * string s. The C string s must be '\0'
847
+ * terminated at exactly the length of the bstring b, and the contents
848
+ * between the two must be identical except for case with the bstring b with
849
+ * no '\0' characters for the two contents to be considered equal. This is
850
+ * equivalent to the condition that their current contents will be always be
851
+ * equal ignoring case when comparing them in the same format after
852
+ * converting one or the other. If the strings are equal, except for case,
853
+ * 1 is returned, if they are unequal regardless of case 0 is returned and
854
+ * if there is a detectable error BSTR_ERR is returned.
855
+ */
856
+ int biseqcstrcaseless (const_bstring b, const char * s) {
857
+ int i;
858
+ if (b == NULL || s == NULL || b->data == NULL || b->slen < 0) return BSTR_ERR;
859
+ for (i=0; i < b->slen; i++) {
860
+ if (s[i] == '\0' ||
861
+ (b->data[i] != (unsigned char) s[i] &&
862
+ downcase (b->data[i]) != (unsigned char) downcase (s[i])))
863
+ return BSTR_OK;
864
+ }
865
+ return s[i] == '\0';
866
+ }
867
+
868
+ /* int bstrcmp (const_bstring b0, const_bstring b1)
869
+ *
870
+ * Compare the string b0 and b1. If there is an error, SHRT_MIN is returned,
871
+ * otherwise a value less than or greater than zero, indicating that the
872
+ * string pointed to by b0 is lexicographically less than or greater than
873
+ * the string pointed to by b1 is returned. If the the string lengths are
874
+ * unequal but the characters up until the length of the shorter are equal
875
+ * then a value less than, or greater than zero, indicating that the string
876
+ * pointed to by b0 is shorter or longer than the string pointed to by b1 is
877
+ * returned. 0 is returned if and only if the two strings are the same. If
878
+ * the length of the strings are different, this function is O(n). Like its
879
+ * standard C library counter part strcmp, the comparison does not proceed
880
+ * past any '\0' termination characters encountered.
881
+ */
882
+ int bstrcmp (const_bstring b0, const_bstring b1) {
883
+ int i, v, n;
884
+
885
+ if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
886
+ b0->slen < 0 || b1->slen < 0) return SHRT_MIN;
887
+ n = b0->slen; if (n > b1->slen) n = b1->slen;
888
+ if (b0->slen == b1->slen && (b0->data == b1->data || b0->slen == 0))
889
+ return BSTR_OK;
890
+
891
+ for (i = 0; i < n; i ++) {
892
+ v = ((char) b0->data[i]) - ((char) b1->data[i]);
893
+ if (v != 0) return v;
894
+ if (b0->data[i] == (unsigned char) '\0') return BSTR_OK;
895
+ }
896
+
897
+ if (b0->slen > n) return 1;
898
+ if (b1->slen > n) return -1;
899
+ return BSTR_OK;
900
+ }
901
+
902
+ /* int bstrncmp (const_bstring b0, const_bstring b1, int n)
903
+ *
904
+ * Compare the string b0 and b1 for at most n characters. If there is an
905
+ * error, SHRT_MIN is returned, otherwise a value is returned as if b0 and
906
+ * b1 were first truncated to at most n characters then bstrcmp was called
907
+ * with these new strings are paremeters. If the length of the strings are
908
+ * different, this function is O(n). Like its standard C library counter
909
+ * part strcmp, the comparison does not proceed past any '\0' termination
910
+ * characters encountered.
911
+ */
912
+ int bstrncmp (const_bstring b0, const_bstring b1, int n) {
913
+ int i, v, m;
914
+
915
+ if (b0 == NULL || b1 == NULL || b0->data == NULL || b1->data == NULL ||
916
+ b0->slen < 0 || b1->slen < 0) return SHRT_MIN;
917
+ m = n;
918
+ if (m > b0->slen) m = b0->slen;
919
+ if (m > b1->slen) m = b1->slen;
920
+
921
+ if (b0->data != b1->data) {
922
+ for (i = 0; i < m; i ++) {
923
+ v = ((char) b0->data[i]) - ((char) b1->data[i]);
924
+ if (v != 0) return v;
925
+ if (b0->data[i] == (unsigned char) '\0') return BSTR_OK;
926
+ }
927
+ }
928
+
929
+ if (n == m || b0->slen == b1->slen) return BSTR_OK;
930
+
931
+ if (b0->slen > m) return 1;
932
+ return -1;
933
+ }
934
+
935
+ /* bstring bmidstr (const_bstring b, int left, int len)
936
+ *
937
+ * Create a bstring which is the substring of b starting from position left
938
+ * and running for a length len (clamped by the end of the bstring b.) If
939
+ * b is detectably invalid, then NULL is returned. The section described
940
+ * by (left, len) is clamped to the boundaries of b.
941
+ */
942
+ bstring bmidstr (const_bstring b, int left, int len) {
943
+
944
+ if (b == NULL || b->slen < 0 || b->data == NULL) return NULL;
945
+
946
+ if (left < 0) {
947
+ len += left;
948
+ left = 0;
949
+ }
950
+
951
+ if (len > b->slen - left) len = b->slen - left;
952
+
953
+ if (len <= 0) return bfromcstr ("");
954
+ return blk2bstr (b->data + left, len);
955
+ }
956
+
957
+ /* int bdelete (bstring b, int pos, int len)
958
+ *
959
+ * Removes characters from pos to pos+len-1 inclusive and shifts the tail of
960
+ * the bstring starting from pos+len to pos. len must be positive for this
961
+ * call to have any effect. The section of the string described by (pos,
962
+ * len) is clamped to boundaries of the bstring b.
963
+ */
964
+ int bdelete (bstring b, int pos, int len) {
965
+ /* Clamp to left side of bstring */
966
+ if (pos < 0) {
967
+ len += pos;
968
+ pos = 0;
969
+ }
970
+
971
+ if (len < 0 || b == NULL || b->data == NULL || b->slen < 0 ||
972
+ b->mlen < b->slen || b->mlen <= 0)
973
+ return BSTR_ERR;
974
+ if (len > 0 && pos < b->slen) {
975
+ if (pos + len >= b->slen) {
976
+ b->slen = pos;
977
+ } else {
978
+ bBlockCopy ((char *) (b->data + pos),
979
+ (char *) (b->data + pos + len),
980
+ b->slen - (pos+len));
981
+ b->slen -= len;
982
+ }
983
+ b->data[b->slen] = (unsigned char) '\0';
984
+ }
985
+ return BSTR_OK;
986
+ }
987
+
988
+ /* int bdestroy (bstring b)
989
+ *
990
+ * Free up the bstring. Note that if b is detectably invalid or not writable
991
+ * then no action is performed and BSTR_ERR is returned. Like a freed memory
992
+ * allocation, dereferences, writes or any other action on b after it has
993
+ * been bdestroyed is undefined.
994
+ */
995
+ int bdestroy (bstring b) {
996
+ if (b == NULL || b->slen < 0 || b->mlen <= 0 || b->mlen < b->slen ||
997
+ b->data == NULL)
998
+ return BSTR_ERR;
999
+
1000
+ bstr__free (b->data);
1001
+
1002
+ /* In case there is any stale usage, there is one more chance to
1003
+ notice this error. */
1004
+
1005
+ b->slen = -1;
1006
+ b->mlen = -__LINE__;
1007
+ b->data = NULL;
1008
+
1009
+ bstr__free (b);
1010
+ return BSTR_OK;
1011
+ }
1012
+
1013
+ /* int binstr (const_bstring b1, int pos, const_bstring b2)
1014
+ *
1015
+ * Search for the bstring b2 in b1 starting from position pos, and searching
1016
+ * forward. If it is found then return with the first position where it is
1017
+ * found, otherwise return BSTR_ERR. Note that this is just a brute force
1018
+ * string searcher that does not attempt clever things like the Boyer-Moore
1019
+ * search algorithm. Because of this there are many degenerate cases where
1020
+ * this can take much longer than it needs to.
1021
+ */
1022
+ int binstr (const_bstring b1, int pos, const_bstring b2) {
1023
+ int j, ii, ll, lf;
1024
+ unsigned char * d0;
1025
+ unsigned char c0;
1026
+ register unsigned char * d1;
1027
+ register unsigned char c1;
1028
+ register int i;
1029
+
1030
+ if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
1031
+ b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
1032
+ if (b1->slen == pos) return (b2->slen == 0)?pos:BSTR_ERR;
1033
+ if (b1->slen < pos || pos < 0) return BSTR_ERR;
1034
+ if (b2->slen == 0) return pos;
1035
+
1036
+ /* No space to find such a string? */
1037
+ if ((lf = b1->slen - b2->slen + 1) <= pos) return BSTR_ERR;
1038
+
1039
+ /* An obvious alias case */
1040
+ if (b1->data == b2->data && pos == 0) return 0;
1041
+
1042
+ i = pos;
1043
+
1044
+ d0 = b2->data;
1045
+ d1 = b1->data;
1046
+ ll = b2->slen;
1047
+
1048
+ /* Peel off the b2->slen == 1 case */
1049
+ c0 = d0[0];
1050
+ if (1 == ll) {
1051
+ for (;i < lf; i++) if (c0 == d1[i]) return i;
1052
+ return BSTR_ERR;
1053
+ }
1054
+
1055
+ c1 = c0;
1056
+ j = 0;
1057
+ lf = b1->slen - 1;
1058
+
1059
+ ii = -1;
1060
+ if (i < lf) do {
1061
+ /* Unrolled current character test */
1062
+ if (c1 != d1[i]) {
1063
+ if (c1 != d1[1+i]) {
1064
+ i += 2;
1065
+ continue;
1066
+ }
1067
+ i++;
1068
+ }
1069
+
1070
+ /* Take note if this is the start of a potential match */
1071
+ if (0 == j) ii = i;
1072
+
1073
+ /* Shift the test character down by one */
1074
+ j++;
1075
+ i++;
1076
+
1077
+ /* If this isn't past the last character continue */
1078
+ if (j < ll) {
1079
+ c1 = d0[j];
1080
+ continue;
1081
+ }
1082
+
1083
+ N0:;
1084
+
1085
+ /* If no characters mismatched, then we matched */
1086
+ if (i == ii+j) return ii;
1087
+
1088
+ /* Shift back to the beginning */
1089
+ i -= j;
1090
+ j = 0;
1091
+ c1 = c0;
1092
+ } while (i < lf);
1093
+
1094
+ /* Deal with last case if unrolling caused a misalignment */
1095
+ if (i == lf && ll == j+1 && c1 == d1[i]) goto N0;
1096
+
1097
+ return BSTR_ERR;
1098
+ }
1099
+
1100
+ /* int binstrr (const_bstring b1, int pos, const_bstring b2)
1101
+ *
1102
+ * Search for the bstring b2 in b1 starting from position pos, and searching
1103
+ * backward. If it is found then return with the first position where it is
1104
+ * found, otherwise return BSTR_ERR. Note that this is just a brute force
1105
+ * string searcher that does not attempt clever things like the Boyer-Moore
1106
+ * search algorithm. Because of this there are many degenerate cases where
1107
+ * this can take much longer than it needs to.
1108
+ */
1109
+ int binstrr (const_bstring b1, int pos, const_bstring b2) {
1110
+ int j, i, l;
1111
+ unsigned char * d0, * d1;
1112
+
1113
+ if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
1114
+ b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
1115
+ if (b1->slen == pos && b2->slen == 0) return pos;
1116
+ if (b1->slen < pos || pos < 0) return BSTR_ERR;
1117
+ if (b2->slen == 0) return pos;
1118
+
1119
+ /* Obvious alias case */
1120
+ if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return 0;
1121
+
1122
+ i = pos;
1123
+ if ((l = b1->slen - b2->slen) < 0) return BSTR_ERR;
1124
+
1125
+ /* If no space to find such a string then snap back */
1126
+ if (l + 1 <= i) i = l;
1127
+ j = 0;
1128
+
1129
+ d0 = b2->data;
1130
+ d1 = b1->data;
1131
+ l = b2->slen;
1132
+
1133
+ for (;;) {
1134
+ if (d0[j] == d1[i + j]) {
1135
+ j ++;
1136
+ if (j >= l) return i;
1137
+ } else {
1138
+ i --;
1139
+ if (i < 0) break;
1140
+ j=0;
1141
+ }
1142
+ }
1143
+
1144
+ return BSTR_ERR;
1145
+ }
1146
+
1147
+ /* int binstrcaseless (const_bstring b1, int pos, const_bstring b2)
1148
+ *
1149
+ * Search for the bstring b2 in b1 starting from position pos, and searching
1150
+ * forward but without regard to case. If it is found then return with the
1151
+ * first position where it is found, otherwise return BSTR_ERR. Note that
1152
+ * this is just a brute force string searcher that does not attempt clever
1153
+ * things like the Boyer-Moore search algorithm. Because of this there are
1154
+ * many degenerate cases where this can take much longer than it needs to.
1155
+ */
1156
+ int binstrcaseless (const_bstring b1, int pos, const_bstring b2) {
1157
+ int j, i, l, ll;
1158
+ unsigned char * d0, * d1;
1159
+
1160
+ if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
1161
+ b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
1162
+ if (b1->slen == pos) return (b2->slen == 0)?pos:BSTR_ERR;
1163
+ if (b1->slen < pos || pos < 0) return BSTR_ERR;
1164
+ if (b2->slen == 0) return pos;
1165
+
1166
+ l = b1->slen - b2->slen + 1;
1167
+
1168
+ /* No space to find such a string? */
1169
+ if (l <= pos) return BSTR_ERR;
1170
+
1171
+ /* An obvious alias case */
1172
+ if (b1->data == b2->data && pos == 0) return BSTR_OK;
1173
+
1174
+ i = pos;
1175
+ j = 0;
1176
+
1177
+ d0 = b2->data;
1178
+ d1 = b1->data;
1179
+ ll = b2->slen;
1180
+
1181
+ for (;;) {
1182
+ if (d0[j] == d1[i + j] || downcase (d0[j]) == downcase (d1[i + j])) {
1183
+ j ++;
1184
+ if (j >= ll) return i;
1185
+ } else {
1186
+ i ++;
1187
+ if (i >= l) break;
1188
+ j=0;
1189
+ }
1190
+ }
1191
+
1192
+ return BSTR_ERR;
1193
+ }
1194
+
1195
+ /* int binstrrcaseless (const_bstring b1, int pos, const_bstring b2)
1196
+ *
1197
+ * Search for the bstring b2 in b1 starting from position pos, and searching
1198
+ * backward but without regard to case. If it is found then return with the
1199
+ * first position where it is found, otherwise return BSTR_ERR. Note that
1200
+ * this is just a brute force string searcher that does not attempt clever
1201
+ * things like the Boyer-Moore search algorithm. Because of this there are
1202
+ * many degenerate cases where this can take much longer than it needs to.
1203
+ */
1204
+ int binstrrcaseless (const_bstring b1, int pos, const_bstring b2) {
1205
+ int j, i, l;
1206
+ unsigned char * d0, * d1;
1207
+
1208
+ if (b1 == NULL || b1->data == NULL || b1->slen < 0 ||
1209
+ b2 == NULL || b2->data == NULL || b2->slen < 0) return BSTR_ERR;
1210
+ if (b1->slen == pos && b2->slen == 0) return pos;
1211
+ if (b1->slen < pos || pos < 0) return BSTR_ERR;
1212
+ if (b2->slen == 0) return pos;
1213
+
1214
+ /* Obvious alias case */
1215
+ if (b1->data == b2->data && pos == 0 && b2->slen <= b1->slen) return BSTR_OK;
1216
+
1217
+ i = pos;
1218
+ if ((l = b1->slen - b2->slen) < 0) return BSTR_ERR;
1219
+
1220
+ /* If no space to find such a string then snap back */
1221
+ if (l + 1 <= i) i = l;
1222
+ j = 0;
1223
+
1224
+ d0 = b2->data;
1225
+ d1 = b1->data;
1226
+ l = b2->slen;
1227
+
1228
+ for (;;) {
1229
+ if (d0[j] == d1[i + j] || downcase (d0[j]) == downcase (d1[i + j])) {
1230
+ j ++;
1231
+ if (j >= l) return i;
1232
+ } else {
1233
+ i --;
1234
+ if (i < 0) break;
1235
+ j=0;
1236
+ }
1237
+ }
1238
+
1239
+ return BSTR_ERR;
1240
+ }
1241
+
1242
+
1243
+ /* int bstrchrp (const_bstring b, int c, int pos)
1244
+ *
1245
+ * Search for the character c in b forwards from the position pos
1246
+ * (inclusive).
1247
+ */
1248
+ int bstrchrp (const_bstring b, int c, int pos) {
1249
+ unsigned char * p;
1250
+
1251
+ if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return BSTR_ERR;
1252
+ p = (unsigned char *) bstr__memchr ((b->data + pos), (unsigned char) c, (b->slen - pos));
1253
+ if (p) return (int) (p - b->data);
1254
+ return BSTR_ERR;
1255
+ }
1256
+
1257
+ /* int bstrrchrp (const_bstring b, int c, int pos)
1258
+ *
1259
+ * Search for the character c in b backwards from the position pos in string
1260
+ * (inclusive).
1261
+ */
1262
+ int bstrrchrp (const_bstring b, int c, int pos) {
1263
+ int i;
1264
+
1265
+ if (b == NULL || b->data == NULL || b->slen <= pos || pos < 0) return BSTR_ERR;
1266
+ for (i=pos; i >= 0; i--) {
1267
+ if (b->data[i] == (unsigned char) c) return i;
1268
+ }
1269
+ return BSTR_ERR;
1270
+ }
1271
+
1272
+ #if !defined (BSTRLIB_AGGRESSIVE_MEMORY_FOR_SPEED_TRADEOFF)
1273
+ #define LONG_LOG_BITS_QTY (3)
1274
+ #define LONG_BITS_QTY (1 << LONG_LOG_BITS_QTY)
1275
+ #define LONG_TYPE unsigned char
1276
+
1277
+ #define CFCLEN ((1 << CHAR_BIT) / LONG_BITS_QTY)
1278
+ struct charField { LONG_TYPE content[CFCLEN]; };
1279
+ #define testInCharField(cf,c) ((cf)->content[(c) >> LONG_LOG_BITS_QTY] & (((long)1) << ((c) & (LONG_BITS_QTY-1))))
1280
+ #define setInCharField(cf,idx) { \
1281
+ unsigned int c = (unsigned int) (idx); \
1282
+ (cf)->content[c >> LONG_LOG_BITS_QTY] |= (LONG_TYPE) (1ul << (c & (LONG_BITS_QTY-1))); \
1283
+ }
1284
+
1285
+ #else
1286
+
1287
+ #define CFCLEN (1 << CHAR_BIT)
1288
+ struct charField { unsigned char content[CFCLEN]; };
1289
+ #define testInCharField(cf,c) ((cf)->content[(unsigned char) (c)])
1290
+ #define setInCharField(cf,idx) (cf)->content[(unsigned int) (idx)] = ~0
1291
+
1292
+ #endif
1293
+
1294
+ /* Convert a bstring to charField */
1295
+ static int buildCharField (struct charField * cf, const_bstring b) {
1296
+ int i;
1297
+ if (b == NULL || b->data == NULL || b->slen <= 0) return BSTR_ERR;
1298
+ memset ((void *) cf->content, 0, sizeof (struct charField));
1299
+ for (i=0; i < b->slen; i++) {
1300
+ setInCharField (cf, b->data[i]);
1301
+ }
1302
+ return BSTR_OK;
1303
+ }
1304
+
1305
+ static void invertCharField (struct charField * cf) {
1306
+ int i;
1307
+ for (i=0; i < CFCLEN; i++) cf->content[i] = ~cf->content[i];
1308
+ }
1309
+
1310
+ /* Inner engine for binchr */
1311
+ static int binchrCF (const unsigned char * data, int len, int pos, const struct charField * cf) {
1312
+ int i;
1313
+ for (i=pos; i < len; i++) {
1314
+ unsigned char c = (unsigned char) data[i];
1315
+ if (testInCharField (cf, c)) return i;
1316
+ }
1317
+ return BSTR_ERR;
1318
+ }
1319
+
1320
+ /* int binchr (const_bstring b0, int pos, const_bstring b1);
1321
+ *
1322
+ * Search for the first position in b0 starting from pos or after, in which
1323
+ * one of the characters in b1 is found and return it. If such a position
1324
+ * does not exist in b0, then BSTR_ERR is returned.
1325
+ */
1326
+ int binchr (const_bstring b0, int pos, const_bstring b1) {
1327
+ struct charField chrs;
1328
+ if (pos < 0 || b0 == NULL || b0->data == NULL ||
1329
+ b0->slen <= pos) return BSTR_ERR;
1330
+ if (1 == b1->slen) return bstrchrp (b0, b1->data[0], pos);
1331
+ if (0 > buildCharField (&chrs, b1)) return BSTR_ERR;
1332
+ return binchrCF (b0->data, b0->slen, pos, &chrs);
1333
+ }
1334
+
1335
+ /* Inner engine for binchrr */
1336
+ static int binchrrCF (const unsigned char * data, int pos, const struct charField * cf) {
1337
+ int i;
1338
+ for (i=pos; i >= 0; i--) {
1339
+ unsigned int c = (unsigned int) data[i];
1340
+ if (testInCharField (cf, c)) return i;
1341
+ }
1342
+ return BSTR_ERR;
1343
+ }
1344
+
1345
+ /* int binchrr (const_bstring b0, int pos, const_bstring b1);
1346
+ *
1347
+ * Search for the last position in b0 no greater than pos, in which one of
1348
+ * the characters in b1 is found and return it. If such a position does not
1349
+ * exist in b0, then BSTR_ERR is returned.
1350
+ */
1351
+ int binchrr (const_bstring b0, int pos, const_bstring b1) {
1352
+ struct charField chrs;
1353
+ if (pos < 0 || b0 == NULL || b0->data == NULL || b1 == NULL ||
1354
+ b0->slen < pos) return BSTR_ERR;
1355
+ if (pos == b0->slen) pos--;
1356
+ if (1 == b1->slen) return bstrrchrp (b0, b1->data[0], pos);
1357
+ if (0 > buildCharField (&chrs, b1)) return BSTR_ERR;
1358
+ return binchrrCF (b0->data, pos, &chrs);
1359
+ }
1360
+
1361
+ /* int bninchr (const_bstring b0, int pos, const_bstring b1);
1362
+ *
1363
+ * Search for the first position in b0 starting from pos or after, in which
1364
+ * none of the characters in b1 is found and return it. If such a position
1365
+ * does not exist in b0, then BSTR_ERR is returned.
1366
+ */
1367
+ int bninchr (const_bstring b0, int pos, const_bstring b1) {
1368
+ struct charField chrs;
1369
+ if (pos < 0 || b0 == NULL || b0->data == NULL ||
1370
+ b0->slen <= pos) return BSTR_ERR;
1371
+ if (buildCharField (&chrs, b1) < 0) return BSTR_ERR;
1372
+ invertCharField (&chrs);
1373
+ return binchrCF (b0->data, b0->slen, pos, &chrs);
1374
+ }
1375
+
1376
+ /* int bninchrr (const_bstring b0, int pos, const_bstring b1);
1377
+ *
1378
+ * Search for the last position in b0 no greater than pos, in which none of
1379
+ * the characters in b1 is found and return it. If such a position does not
1380
+ * exist in b0, then BSTR_ERR is returned.
1381
+ */
1382
+ int bninchrr (const_bstring b0, int pos, const_bstring b1) {
1383
+ struct charField chrs;
1384
+ if (pos < 0 || b0 == NULL || b0->data == NULL ||
1385
+ b0->slen < pos) return BSTR_ERR;
1386
+ if (pos == b0->slen) pos--;
1387
+ if (buildCharField (&chrs, b1) < 0) return BSTR_ERR;
1388
+ invertCharField (&chrs);
1389
+ return binchrrCF (b0->data, pos, &chrs);
1390
+ }
1391
+
1392
+ /* int bsetstr (bstring b0, int pos, bstring b1, unsigned char fill)
1393
+ *
1394
+ * Overwrite the string b0 starting at position pos with the string b1. If
1395
+ * the position pos is past the end of b0, then the character "fill" is
1396
+ * appended as necessary to make up the gap between the end of b0 and pos.
1397
+ * If b1 is NULL, it behaves as if it were a 0-length string.
1398
+ */
1399
+ int bsetstr (bstring b0, int pos, const_bstring b1, unsigned char fill) {
1400
+ int d, newlen;
1401
+ ptrdiff_t pd;
1402
+ bstring aux = (bstring) b1;
1403
+
1404
+ if (pos < 0 || b0 == NULL || b0->slen < 0 || NULL == b0->data ||
1405
+ b0->mlen < b0->slen || b0->mlen <= 0) return BSTR_ERR;
1406
+ if (b1 != NULL && (b1->slen < 0 || b1->data == NULL)) return BSTR_ERR;
1407
+
1408
+ d = pos;
1409
+
1410
+ /* Aliasing case */
1411
+ if (NULL != aux) {
1412
+ if ((pd = (ptrdiff_t) (b1->data - b0->data)) >= 0 && pd < (ptrdiff_t) b0->mlen) {
1413
+ if (NULL == (aux = bstrcpy (b1))) return BSTR_ERR;
1414
+ }
1415
+ d += aux->slen;
1416
+ }
1417
+
1418
+ /* Increase memory size if necessary */
1419
+ if (balloc (b0, d + 1) != BSTR_OK) {
1420
+ if (aux != b1) bdestroy (aux);
1421
+ return BSTR_ERR;
1422
+ }
1423
+
1424
+ newlen = b0->slen;
1425
+
1426
+ /* Fill in "fill" character as necessary */
1427
+ if (pos > newlen) {
1428
+ bstr__memset (b0->data + b0->slen, (int) fill, (size_t) (pos - b0->slen));
1429
+ newlen = pos;
1430
+ }
1431
+
1432
+ /* Copy b1 to position pos in b0. */
1433
+ if (aux != NULL) {
1434
+ bBlockCopy ((char *) (b0->data + pos), (char *) aux->data, aux->slen);
1435
+ if (aux != b1) bdestroy (aux);
1436
+ }
1437
+
1438
+ /* Indicate the potentially increased size of b0 */
1439
+ if (d > newlen) newlen = d;
1440
+
1441
+ b0->slen = newlen;
1442
+ b0->data[newlen] = (unsigned char) '\0';
1443
+
1444
+ return BSTR_OK;
1445
+ }
1446
+
1447
+ /* int binsert (bstring b1, int pos, bstring b2, unsigned char fill)
1448
+ *
1449
+ * Inserts the string b2 into b1 at position pos. If the position pos is
1450
+ * past the end of b1, then the character "fill" is appended as necessary to
1451
+ * make up the gap between the end of b1 and pos. Unlike bsetstr, binsert
1452
+ * does not allow b2 to be NULL.
1453
+ */
1454
+ int binsert (bstring b1, int pos, const_bstring b2, unsigned char fill) {
1455
+ int d, l;
1456
+ ptrdiff_t pd;
1457
+ bstring aux = (bstring) b2;
1458
+
1459
+ if (pos < 0 || b1 == NULL || b2 == NULL || b1->slen < 0 ||
1460
+ b2->slen < 0 || b1->mlen < b1->slen || b1->mlen <= 0) return BSTR_ERR;
1461
+
1462
+ /* Aliasing case */
1463
+ if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->mlen) {
1464
+ if (NULL == (aux = bstrcpy (b2))) return BSTR_ERR;
1465
+ }
1466
+
1467
+ /* Compute the two possible end pointers */
1468
+ d = b1->slen + aux->slen;
1469
+ l = pos + aux->slen;
1470
+ if ((d|l) < 0) return BSTR_ERR;
1471
+
1472
+ if (l > d) {
1473
+ /* Inserting past the end of the string */
1474
+ if (balloc (b1, l + 1) != BSTR_OK) {
1475
+ if (aux != b2) bdestroy (aux);
1476
+ return BSTR_ERR;
1477
+ }
1478
+ bstr__memset (b1->data + b1->slen, (int) fill, (size_t) (pos - b1->slen));
1479
+ b1->slen = l;
1480
+ } else {
1481
+ /* Inserting in the middle of the string */
1482
+ if (balloc (b1, d + 1) != BSTR_OK) {
1483
+ if (aux != b2) bdestroy (aux);
1484
+ return BSTR_ERR;
1485
+ }
1486
+ bBlockCopy (b1->data + l, b1->data + pos, d - l);
1487
+ b1->slen = d;
1488
+ }
1489
+ bBlockCopy (b1->data + pos, aux->data, aux->slen);
1490
+ b1->data[b1->slen] = (unsigned char) '\0';
1491
+ if (aux != b2) bdestroy (aux);
1492
+ return BSTR_OK;
1493
+ }
1494
+
1495
+ /* int breplace (bstring b1, int pos, int len, bstring b2,
1496
+ * unsigned char fill)
1497
+ *
1498
+ * Replace a section of a string from pos for a length len with the string b2.
1499
+ * fill is used is pos > b1->slen.
1500
+ */
1501
+ int breplace (bstring b1, int pos, int len, const_bstring b2,
1502
+ unsigned char fill) {
1503
+ int pl, ret;
1504
+ ptrdiff_t pd;
1505
+ bstring aux = (bstring) b2;
1506
+
1507
+ if (pos < 0 || len < 0 || (pl = pos + len) < 0 || b1 == NULL ||
1508
+ b2 == NULL || b1->data == NULL || b2->data == NULL ||
1509
+ b1->slen < 0 || b2->slen < 0 || b1->mlen < b1->slen ||
1510
+ b1->mlen <= 0) return BSTR_ERR;
1511
+
1512
+ /* Straddles the end? */
1513
+ if (pl >= b1->slen) {
1514
+ if ((ret = bsetstr (b1, pos, b2, fill)) < 0) return ret;
1515
+ if (pos + b2->slen < b1->slen) {
1516
+ b1->slen = pos + b2->slen;
1517
+ b1->data[b1->slen] = (unsigned char) '\0';
1518
+ }
1519
+ return ret;
1520
+ }
1521
+
1522
+ /* Aliasing case */
1523
+ if ((pd = (ptrdiff_t) (b2->data - b1->data)) >= 0 && pd < (ptrdiff_t) b1->slen) {
1524
+ if (NULL == (aux = bstrcpy (b2))) return BSTR_ERR;
1525
+ }
1526
+
1527
+ if (aux->slen > len) {
1528
+ if (balloc (b1, b1->slen + aux->slen - len) != BSTR_OK) {
1529
+ if (aux != b2) bdestroy (aux);
1530
+ return BSTR_ERR;
1531
+ }
1532
+ }
1533
+
1534
+ if (aux->slen != len) bstr__memmove (b1->data + pos + aux->slen, b1->data + pos + len, b1->slen - (pos + len));
1535
+ bstr__memcpy (b1->data + pos, aux->data, aux->slen);
1536
+ b1->slen += aux->slen - len;
1537
+ b1->data[b1->slen] = (unsigned char) '\0';
1538
+ if (aux != b2) bdestroy (aux);
1539
+ return BSTR_OK;
1540
+ }
1541
+
1542
+ /* int bfindreplace (bstring b, const_bstring find, const_bstring repl,
1543
+ * int pos)
1544
+ *
1545
+ * Replace all occurrences of a find string with a replace string after a
1546
+ * given point in a bstring.
1547
+ */
1548
+
1549
+ typedef int (*instr_fnptr) (const_bstring s1, int pos, const_bstring s2);
1550
+
1551
+ static int findreplaceengine (bstring b, const_bstring find, const_bstring repl, int pos, instr_fnptr instr) {
1552
+ int i, ret, slen, mlen, delta, acc;
1553
+ int * d;
1554
+ int static_d[32];
1555
+ ptrdiff_t pd;
1556
+ bstring auxf = (bstring) find;
1557
+ bstring auxr = (bstring) repl;
1558
+
1559
+ if (b == NULL || b->data == NULL || find == NULL ||
1560
+ find->data == NULL || repl == NULL || repl->data == NULL ||
1561
+ pos < 0 || find->slen <= 0 || b->mlen < 0 || b->slen > b->mlen ||
1562
+ b->mlen <= 0 || b->slen < 0 || repl->slen < 0) return BSTR_ERR;
1563
+ if (pos > b->slen - find->slen) return BSTR_OK;
1564
+
1565
+ /* Alias with find string */
1566
+ pd = (ptrdiff_t) (find->data - b->data);
1567
+ if ((ptrdiff_t) (pos - find->slen) < pd && pd < (ptrdiff_t) b->slen) {
1568
+ if (NULL == (auxf = bstrcpy (find))) return BSTR_ERR;
1569
+ }
1570
+
1571
+ /* Alias with repl string */
1572
+ pd = (ptrdiff_t) (repl->data - b->data);
1573
+ if ((ptrdiff_t) (pos - repl->slen) < pd && pd < (ptrdiff_t) b->slen) {
1574
+ if (NULL == (auxr = bstrcpy (repl))) {
1575
+ if (auxf != find) bdestroy (auxf);
1576
+ return BSTR_ERR;
1577
+ }
1578
+ }
1579
+
1580
+ delta = auxf->slen - auxr->slen;
1581
+
1582
+ /* in-place replacement since find and replace strings are of equal
1583
+ length */
1584
+ if (delta == 0) {
1585
+ while ((pos = instr (b, pos, auxf)) >= 0) {
1586
+ bstr__memcpy (b->data + pos, auxr->data, auxr->slen);
1587
+ pos += auxf->slen;
1588
+ }
1589
+ if (auxf != find) bdestroy (auxf);
1590
+ if (auxr != repl) bdestroy (auxr);
1591
+ return BSTR_OK;
1592
+ }
1593
+
1594
+ /* shrinking replacement since auxf->slen > auxr->slen */
1595
+ if (delta > 0) {
1596
+ acc = 0;
1597
+
1598
+ while ((i = instr (b, pos, auxf)) >= 0) {
1599
+ if (acc && i > pos)
1600
+ bstr__memmove (b->data + pos - acc, b->data + pos, i - pos);
1601
+ if (auxr->slen)
1602
+ bstr__memcpy (b->data + i - acc, auxr->data, auxr->slen);
1603
+ acc += delta;
1604
+ pos = i + auxf->slen;
1605
+ }
1606
+
1607
+ if (acc) {
1608
+ i = b->slen;
1609
+ if (i > pos)
1610
+ bstr__memmove (b->data + pos - acc, b->data + pos, i - pos);
1611
+ b->slen -= acc;
1612
+ b->data[b->slen] = (unsigned char) '\0';
1613
+ }
1614
+
1615
+ if (auxf != find) bdestroy (auxf);
1616
+ if (auxr != repl) bdestroy (auxr);
1617
+ return BSTR_OK;
1618
+ }
1619
+
1620
+ /* expanding replacement since find->slen < repl->slen. Its a lot
1621
+ more complicated. */
1622
+
1623
+ mlen = 32;
1624
+ d = (int *) static_d; /* Avoid malloc for trivial cases */
1625
+ acc = slen = 0;
1626
+
1627
+ while ((pos = instr (b, pos, auxf)) >= 0) {
1628
+ if (slen + 1 >= mlen) {
1629
+ int sl;
1630
+ int * t;
1631
+ mlen += mlen;
1632
+ sl = (int)(sizeof (int *) * mlen);
1633
+ if (static_d == d) d = NULL;
1634
+ if (sl < mlen || NULL == (t = (int *) bstr__realloc (d, sl))) {
1635
+ ret = BSTR_ERR;
1636
+ goto done;
1637
+ }
1638
+ if (NULL == d) bstr__memcpy (t, static_d, sizeof (static_d));
1639
+ d = t;
1640
+ }
1641
+ d[slen] = pos;
1642
+ slen++;
1643
+ acc -= delta;
1644
+ pos += auxf->slen;
1645
+ if (pos < 0 || acc < 0) {
1646
+ ret = BSTR_ERR;
1647
+ goto done;
1648
+ }
1649
+ }
1650
+ d[slen] = b->slen;
1651
+
1652
+ if (BSTR_OK == (ret = balloc (b, b->slen + acc + 1))) {
1653
+ b->slen += acc;
1654
+ for (i = slen-1; i >= 0; i--) {
1655
+ int s, l;
1656
+ s = d[i] + auxf->slen;
1657
+ l = d[i+1] - s;
1658
+ if (l) {
1659
+ bstr__memmove (b->data + s + acc, b->data + s, l);
1660
+ }
1661
+ if (auxr->slen) {
1662
+ bstr__memmove (b->data + s + acc - auxr->slen,
1663
+ auxr->data, auxr->slen);
1664
+ }
1665
+ acc += delta;
1666
+ }
1667
+ b->data[b->slen] = (unsigned char) '\0';
1668
+ }
1669
+
1670
+ done:;
1671
+ if (static_d == d) d = NULL;
1672
+ bstr__free (d);
1673
+ if (auxf != find) bdestroy (auxf);
1674
+ if (auxr != repl) bdestroy (auxr);
1675
+ return ret;
1676
+ }
1677
+
1678
+ /* int bfindreplace (bstring b, const_bstring find, const_bstring repl,
1679
+ * int pos)
1680
+ *
1681
+ * Replace all occurrences of a find string with a replace string after a
1682
+ * given point in a bstring.
1683
+ */
1684
+ int bfindreplace (bstring b, const_bstring find, const_bstring repl, int pos) {
1685
+ return findreplaceengine (b, find, repl, pos, binstr);
1686
+ }
1687
+
1688
+ /* int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl,
1689
+ * int pos)
1690
+ *
1691
+ * Replace all occurrences of a find string, ignoring case, with a replace
1692
+ * string after a given point in a bstring.
1693
+ */
1694
+ int bfindreplacecaseless (bstring b, const_bstring find, const_bstring repl, int pos) {
1695
+ return findreplaceengine (b, find, repl, pos, binstrcaseless);
1696
+ }
1697
+
1698
+ /* int binsertch (bstring b, int pos, int len, unsigned char fill)
1699
+ *
1700
+ * Inserts the character fill repeatedly into b at position pos for a
1701
+ * length len. If the position pos is past the end of b, then the
1702
+ * character "fill" is appended as necessary to make up the gap between the
1703
+ * end of b and the position pos + len.
1704
+ */
1705
+ int binsertch (bstring b, int pos, int len, unsigned char fill) {
1706
+ int d, l, i;
1707
+
1708
+ if (pos < 0 || b == NULL || b->slen < 0 || b->mlen < b->slen ||
1709
+ b->mlen <= 0 || len < 0) return BSTR_ERR;
1710
+
1711
+ /* Compute the two possible end pointers */
1712
+ d = b->slen + len;
1713
+ l = pos + len;
1714
+ if ((d|l) < 0) return BSTR_ERR;
1715
+
1716
+ if (l > d) {
1717
+ /* Inserting past the end of the string */
1718
+ if (balloc (b, l + 1) != BSTR_OK) return BSTR_ERR;
1719
+ pos = b->slen;
1720
+ b->slen = l;
1721
+ } else {
1722
+ /* Inserting in the middle of the string */
1723
+ if (balloc (b, d + 1) != BSTR_OK) return BSTR_ERR;
1724
+ for (i = d - 1; i >= l; i--) {
1725
+ b->data[i] = b->data[i - len];
1726
+ }
1727
+ b->slen = d;
1728
+ }
1729
+
1730
+ for (i=pos; i < l; i++) b->data[i] = fill;
1731
+ b->data[b->slen] = (unsigned char) '\0';
1732
+ return BSTR_OK;
1733
+ }
1734
+
1735
+ /* int bpattern (bstring b, int len)
1736
+ *
1737
+ * Replicate the bstring, b in place, end to end repeatedly until it
1738
+ * surpasses len characters, then chop the result to exactly len characters.
1739
+ * This function operates in-place. The function will return with BSTR_ERR
1740
+ * if b is NULL or of length 0, otherwise BSTR_OK is returned.
1741
+ */
1742
+ int bpattern (bstring b, int len) {
1743
+ int i, d;
1744
+
1745
+ d = blength (b);
1746
+ if (d <= 0 || len < 0 || balloc (b, len + 1) != BSTR_OK) return BSTR_ERR;
1747
+ if (len > 0) {
1748
+ if (d == 1) return bsetstr (b, len, NULL, b->data[0]);
1749
+ for (i = d; i < len; i++) b->data[i] = b->data[i - d];
1750
+ }
1751
+ b->data[len] = (unsigned char) '\0';
1752
+ b->slen = len;
1753
+ return BSTR_OK;
1754
+ }
1755
+
1756
+ #define BS_BUFF_SZ (1024)
1757
+
1758
+ /* int breada (bstring b, bNread readPtr, void * parm)
1759
+ *
1760
+ * Use a finite buffer fread-like function readPtr to concatenate to the
1761
+ * bstring b the entire contents of file-like source data in a roughly
1762
+ * efficient way.
1763
+ */
1764
+ int breada (bstring b, bNread readPtr, void * parm) {
1765
+ int i, l, n;
1766
+
1767
+ if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
1768
+ b->mlen <= 0 || readPtr == NULL) return BSTR_ERR;
1769
+
1770
+ i = b->slen;
1771
+ for (n=i+16; ; n += ((n < BS_BUFF_SZ) ? n : BS_BUFF_SZ)) {
1772
+ if (BSTR_OK != balloc (b, n + 1)) return BSTR_ERR;
1773
+ l = (int) readPtr ((void *) (b->data + i), 1, n - i, parm);
1774
+ i += l;
1775
+ b->slen = i;
1776
+ if (i < n) break;
1777
+ }
1778
+
1779
+ b->data[i] = (unsigned char) '\0';
1780
+ return BSTR_OK;
1781
+ }
1782
+
1783
+ /* bstring bread (bNread readPtr, void * parm)
1784
+ *
1785
+ * Use a finite buffer fread-like function readPtr to create a bstring
1786
+ * filled with the entire contents of file-like source data in a roughly
1787
+ * efficient way.
1788
+ */
1789
+ bstring bread (bNread readPtr, void * parm) {
1790
+ int ret;
1791
+ bstring buff;
1792
+
1793
+ if (readPtr == NULL) return NULL;
1794
+ buff = bfromcstr ("");
1795
+ if (buff == NULL) return NULL;
1796
+ ret = breada (buff, readPtr, parm);
1797
+ if (ret < 0) {
1798
+ bdestroy (buff);
1799
+ return NULL;
1800
+ }
1801
+ return buff;
1802
+ }
1803
+
1804
+ /* int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator)
1805
+ *
1806
+ * Use an fgetc-like single character stream reading function (getcPtr) to
1807
+ * obtain a sequence of characters which are concatenated to the end of the
1808
+ * bstring b. The stream read is terminated by the passed in terminator
1809
+ * parameter.
1810
+ *
1811
+ * If getcPtr returns with a negative number, or the terminator character
1812
+ * (which is appended) is read, then the stream reading is halted and the
1813
+ * function returns with a partial result in b. If there is an empty partial
1814
+ * result, 1 is returned. If no characters are read, or there is some other
1815
+ * detectable error, BSTR_ERR is returned.
1816
+ */
1817
+ int bassigngets (bstring b, bNgetc getcPtr, void * parm, char terminator) {
1818
+ int c, d, e;
1819
+
1820
+ if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
1821
+ b->mlen <= 0 || getcPtr == NULL) return BSTR_ERR;
1822
+ d = 0;
1823
+ e = b->mlen - 2;
1824
+
1825
+ while ((c = getcPtr (parm)) >= 0) {
1826
+ if (d > e) {
1827
+ b->slen = d;
1828
+ if (balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
1829
+ e = b->mlen - 2;
1830
+ }
1831
+ b->data[d] = (unsigned char) c;
1832
+ d++;
1833
+ if (c == terminator) break;
1834
+ }
1835
+
1836
+ b->data[d] = (unsigned char) '\0';
1837
+ b->slen = d;
1838
+
1839
+ return d == 0 && c < 0;
1840
+ }
1841
+
1842
+ /* int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator)
1843
+ *
1844
+ * Use an fgetc-like single character stream reading function (getcPtr) to
1845
+ * obtain a sequence of characters which are concatenated to the end of the
1846
+ * bstring b. The stream read is terminated by the passed in terminator
1847
+ * parameter.
1848
+ *
1849
+ * If getcPtr returns with a negative number, or the terminator character
1850
+ * (which is appended) is read, then the stream reading is halted and the
1851
+ * function returns with a partial result concatentated to b. If there is
1852
+ * an empty partial result, 1 is returned. If no characters are read, or
1853
+ * there is some other detectable error, BSTR_ERR is returned.
1854
+ */
1855
+ int bgetsa (bstring b, bNgetc getcPtr, void * parm, char terminator) {
1856
+ int c, d, e;
1857
+
1858
+ if (b == NULL || b->mlen <= 0 || b->slen < 0 || b->mlen < b->slen ||
1859
+ b->mlen <= 0 || getcPtr == NULL) return BSTR_ERR;
1860
+ d = b->slen;
1861
+ e = b->mlen - 2;
1862
+
1863
+ while ((c = getcPtr (parm)) >= 0) {
1864
+ if (d > e) {
1865
+ b->slen = d;
1866
+ if (balloc (b, d + 2) != BSTR_OK) return BSTR_ERR;
1867
+ e = b->mlen - 2;
1868
+ }
1869
+ b->data[d] = (unsigned char) c;
1870
+ d++;
1871
+ if (c == terminator) break;
1872
+ }
1873
+
1874
+ b->data[d] = (unsigned char) '\0';
1875
+ b->slen = d;
1876
+
1877
+ return d == 0 && c < 0;
1878
+ }
1879
+
1880
+ /* bstring bgets (bNgetc getcPtr, void * parm, char terminator)
1881
+ *
1882
+ * Use an fgetc-like single character stream reading function (getcPtr) to
1883
+ * obtain a sequence of characters which are concatenated into a bstring.
1884
+ * The stream read is terminated by the passed in terminator function.
1885
+ *
1886
+ * If getcPtr returns with a negative number, or the terminator character
1887
+ * (which is appended) is read, then the stream reading is halted and the
1888
+ * result obtained thus far is returned. If no characters are read, or
1889
+ * there is some other detectable error, NULL is returned.
1890
+ */
1891
+ bstring bgets (bNgetc getcPtr, void * parm, char terminator) {
1892
+ int ret;
1893
+ bstring buff;
1894
+
1895
+ if (NULL == getcPtr || NULL == (buff = bfromcstr (""))) return NULL;
1896
+
1897
+ ret = bgetsa (buff, getcPtr, parm, terminator);
1898
+ if (ret < 0 || buff->slen <= 0) {
1899
+ bdestroy (buff);
1900
+ buff = NULL;
1901
+ }
1902
+ return buff;
1903
+ }
1904
+
1905
+ struct bStream {
1906
+ bstring buff; /* Buffer for over-reads */
1907
+ void * parm; /* The stream handle for core stream */
1908
+ bNread readFnPtr; /* fread compatible fnptr for core stream */
1909
+ int isEOF; /* track file's EOF state */
1910
+ int maxBuffSz;
1911
+ };
1912
+
1913
+ /* struct bStream * bsopen (bNread readPtr, void * parm)
1914
+ *
1915
+ * Wrap a given open stream (described by a fread compatible function
1916
+ * pointer and stream handle) into an open bStream suitable for the bstring
1917
+ * library streaming functions.
1918
+ */
1919
+ struct bStream * bsopen (bNread readPtr, void * parm) {
1920
+ struct bStream * s;
1921
+
1922
+ if (readPtr == NULL) return NULL;
1923
+ s = (struct bStream *) bstr__alloc (sizeof (struct bStream));
1924
+ if (s == NULL) return NULL;
1925
+ s->parm = parm;
1926
+ s->buff = bfromcstr ("");
1927
+ s->readFnPtr = readPtr;
1928
+ s->maxBuffSz = BS_BUFF_SZ;
1929
+ s->isEOF = 0;
1930
+ return s;
1931
+ }
1932
+
1933
+ /* int bsbufflength (struct bStream * s, int sz)
1934
+ *
1935
+ * Set the length of the buffer used by the bStream. If sz is zero, the
1936
+ * length is not set. This function returns with the previous length.
1937
+ */
1938
+ int bsbufflength (struct bStream * s, int sz) {
1939
+ int oldSz;
1940
+ if (s == NULL || sz < 0) return BSTR_ERR;
1941
+ oldSz = s->maxBuffSz;
1942
+ if (sz > 0) s->maxBuffSz = sz;
1943
+ return oldSz;
1944
+ }
1945
+
1946
+ int bseof (const struct bStream * s) {
1947
+ if (s == NULL || s->readFnPtr == NULL) return BSTR_ERR;
1948
+ return s->isEOF && (s->buff->slen == 0);
1949
+ }
1950
+
1951
+ /* void * bsclose (struct bStream * s)
1952
+ *
1953
+ * Close the bStream, and return the handle to the stream that was originally
1954
+ * used to open the given stream.
1955
+ */
1956
+ void * bsclose (struct bStream * s) {
1957
+ void * parm;
1958
+ if (s == NULL) return NULL;
1959
+ s->readFnPtr = NULL;
1960
+ if (s->buff) bdestroy (s->buff);
1961
+ s->buff = NULL;
1962
+ parm = s->parm;
1963
+ s->parm = NULL;
1964
+ s->isEOF = 1;
1965
+ bstr__free (s);
1966
+ return parm;
1967
+ }
1968
+
1969
+ /* int bsreadlna (bstring r, struct bStream * s, char terminator)
1970
+ *
1971
+ * Read a bstring terminated by the terminator character or the end of the
1972
+ * stream from the bStream (s) and return it into the parameter r. This
1973
+ * function may read additional characters from the core stream that are not
1974
+ * returned, but will be retained for subsequent read operations.
1975
+ */
1976
+ int bsreadlna (bstring r, struct bStream * s, char terminator) {
1977
+ int i, l, ret, rlo;
1978
+ char * b;
1979
+ struct tagbstring x;
1980
+
1981
+ if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0 ||
1982
+ r->slen < 0 || r->mlen < r->slen) return BSTR_ERR;
1983
+ l = s->buff->slen;
1984
+ if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
1985
+ b = (char *) s->buff->data;
1986
+ x.data = (unsigned char *) b;
1987
+
1988
+ /* First check if the current buffer holds the terminator */
1989
+ b[l] = terminator; /* Set sentinel */
1990
+ for (i=0; b[i] != terminator; i++) ;
1991
+ if (i < l) {
1992
+ x.slen = i + 1;
1993
+ ret = bconcat (r, &x);
1994
+ s->buff->slen = l;
1995
+ if (BSTR_OK == ret) bdelete (s->buff, 0, i + 1);
1996
+ return BSTR_OK;
1997
+ }
1998
+
1999
+ rlo = r->slen;
2000
+
2001
+ /* If not then just concatenate the entire buffer to the output */
2002
+ x.slen = l;
2003
+ if (BSTR_OK != bconcat (r, &x)) return BSTR_ERR;
2004
+
2005
+ /* Perform direct in-place reads into the destination to allow for
2006
+ the minimum of data-copies */
2007
+ for (;;) {
2008
+ if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) return BSTR_ERR;
2009
+ b = (char *) (r->data + r->slen);
2010
+ l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm);
2011
+ if (l <= 0) {
2012
+ r->data[r->slen] = (unsigned char) '\0';
2013
+ s->buff->slen = 0;
2014
+ s->isEOF = 1;
2015
+ /* If nothing was read return with an error message */
2016
+ return BSTR_ERR & -(r->slen == rlo);
2017
+ }
2018
+ b[l] = terminator; /* Set sentinel */
2019
+ for (i=0; b[i] != terminator; i++) ;
2020
+ if (i < l) break;
2021
+ r->slen += l;
2022
+ }
2023
+
2024
+ /* Terminator found, push over-read back to buffer */
2025
+ i++;
2026
+ r->slen += i;
2027
+ s->buff->slen = l - i;
2028
+ bstr__memcpy (s->buff->data, b + i, l - i);
2029
+ r->data[r->slen] = (unsigned char) '\0';
2030
+ return BSTR_OK;
2031
+ }
2032
+
2033
+ /* int bsreadlnsa (bstring r, struct bStream * s, bstring term)
2034
+ *
2035
+ * Read a bstring terminated by any character in the term string or the end
2036
+ * of the stream from the bStream (s) and return it into the parameter r.
2037
+ * This function may read additional characters from the core stream that
2038
+ * are not returned, but will be retained for subsequent read operations.
2039
+ */
2040
+ int bsreadlnsa (bstring r, struct bStream * s, const_bstring term) {
2041
+ int i, l, ret, rlo;
2042
+ unsigned char * b;
2043
+ struct tagbstring x;
2044
+ struct charField cf;
2045
+
2046
+ if (s == NULL || s->buff == NULL || r == NULL || term == NULL ||
2047
+ term->data == NULL || r->mlen <= 0 || r->slen < 0 ||
2048
+ r->mlen < r->slen) return BSTR_ERR;
2049
+ if (term->slen == 1) return bsreadlna (r, s, term->data[0]);
2050
+ if (term->slen < 1 || buildCharField (&cf, term)) return BSTR_ERR;
2051
+
2052
+ l = s->buff->slen;
2053
+ if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2054
+ b = (unsigned char *) s->buff->data;
2055
+ x.data = b;
2056
+
2057
+ /* First check if the current buffer holds the terminator */
2058
+ b[l] = term->data[0]; /* Set sentinel */
2059
+ for (i=0; !testInCharField (&cf, b[i]); i++) ;
2060
+ if (i < l) {
2061
+ x.slen = i + 1;
2062
+ ret = bconcat (r, &x);
2063
+ s->buff->slen = l;
2064
+ if (BSTR_OK == ret) bdelete (s->buff, 0, i + 1);
2065
+ return BSTR_OK;
2066
+ }
2067
+
2068
+ rlo = r->slen;
2069
+
2070
+ /* If not then just concatenate the entire buffer to the output */
2071
+ x.slen = l;
2072
+ if (BSTR_OK != bconcat (r, &x)) return BSTR_ERR;
2073
+
2074
+ /* Perform direct in-place reads into the destination to allow for
2075
+ the minimum of data-copies */
2076
+ for (;;) {
2077
+ if (BSTR_OK != balloc (r, r->slen + s->maxBuffSz + 1)) return BSTR_ERR;
2078
+ b = (unsigned char *) (r->data + r->slen);
2079
+ l = (int) s->readFnPtr (b, 1, s->maxBuffSz, s->parm);
2080
+ if (l <= 0) {
2081
+ r->data[r->slen] = (unsigned char) '\0';
2082
+ s->buff->slen = 0;
2083
+ s->isEOF = 1;
2084
+ /* If nothing was read return with an error message */
2085
+ return BSTR_ERR & -(r->slen == rlo);
2086
+ }
2087
+
2088
+ b[l] = term->data[0]; /* Set sentinel */
2089
+ for (i=0; !testInCharField (&cf, b[i]); i++) ;
2090
+ if (i < l) break;
2091
+ r->slen += l;
2092
+ }
2093
+
2094
+ /* Terminator found, push over-read back to buffer */
2095
+ i++;
2096
+ r->slen += i;
2097
+ s->buff->slen = l - i;
2098
+ bstr__memcpy (s->buff->data, b + i, l - i);
2099
+ r->data[r->slen] = (unsigned char) '\0';
2100
+ return BSTR_OK;
2101
+ }
2102
+
2103
+ /* int bsreada (bstring r, struct bStream * s, int n)
2104
+ *
2105
+ * Read a bstring of length n (or, if it is fewer, as many bytes as is
2106
+ * remaining) from the bStream. This function may read additional
2107
+ * characters from the core stream that are not returned, but will be
2108
+ * retained for subsequent read operations. This function will not read
2109
+ * additional characters from the core stream beyond virtual stream pointer.
2110
+ */
2111
+ int bsreada (bstring r, struct bStream * s, int n) {
2112
+ int l, ret, orslen;
2113
+ char * b;
2114
+ struct tagbstring x;
2115
+
2116
+ if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0
2117
+ || r->slen < 0 || r->mlen < r->slen || n <= 0) return BSTR_ERR;
2118
+
2119
+ n += r->slen;
2120
+ if (n <= 0) return BSTR_ERR;
2121
+
2122
+ l = s->buff->slen;
2123
+
2124
+ orslen = r->slen;
2125
+
2126
+ if (0 == l) {
2127
+ if (s->isEOF) return BSTR_ERR;
2128
+ if (r->mlen > n) {
2129
+ l = (int) s->readFnPtr (r->data + r->slen, 1, n - r->slen, s->parm);
2130
+ if (0 >= l || l > n - r->slen) {
2131
+ s->isEOF = 1;
2132
+ return BSTR_ERR;
2133
+ }
2134
+ r->slen += l;
2135
+ r->data[r->slen] = (unsigned char) '\0';
2136
+ return 0;
2137
+ }
2138
+ }
2139
+
2140
+ if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2141
+ b = (char *) s->buff->data;
2142
+ x.data = (unsigned char *) b;
2143
+
2144
+ do {
2145
+ if (l + r->slen >= n) {
2146
+ x.slen = n - r->slen;
2147
+ ret = bconcat (r, &x);
2148
+ s->buff->slen = l;
2149
+ if (BSTR_OK == ret) bdelete (s->buff, 0, x.slen);
2150
+ return BSTR_ERR & -(r->slen == orslen);
2151
+ }
2152
+
2153
+ x.slen = l;
2154
+ if (BSTR_OK != bconcat (r, &x)) break;
2155
+
2156
+ l = n - r->slen;
2157
+ if (l > s->maxBuffSz) l = s->maxBuffSz;
2158
+
2159
+ l = (int) s->readFnPtr (b, 1, l, s->parm);
2160
+
2161
+ } while (l > 0);
2162
+ if (l < 0) l = 0;
2163
+ if (l == 0) s->isEOF = 1;
2164
+ s->buff->slen = l;
2165
+ return BSTR_ERR & -(r->slen == orslen);
2166
+ }
2167
+
2168
+ /* int bsreadln (bstring r, struct bStream * s, char terminator)
2169
+ *
2170
+ * Read a bstring terminated by the terminator character or the end of the
2171
+ * stream from the bStream (s) and return it into the parameter r. This
2172
+ * function may read additional characters from the core stream that are not
2173
+ * returned, but will be retained for subsequent read operations.
2174
+ */
2175
+ int bsreadln (bstring r, struct bStream * s, char terminator) {
2176
+ if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0)
2177
+ return BSTR_ERR;
2178
+ if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2179
+ r->slen = 0;
2180
+ return bsreadlna (r, s, terminator);
2181
+ }
2182
+
2183
+ /* int bsreadlns (bstring r, struct bStream * s, bstring term)
2184
+ *
2185
+ * Read a bstring terminated by any character in the term string or the end
2186
+ * of the stream from the bStream (s) and return it into the parameter r.
2187
+ * This function may read additional characters from the core stream that
2188
+ * are not returned, but will be retained for subsequent read operations.
2189
+ */
2190
+ int bsreadlns (bstring r, struct bStream * s, const_bstring term) {
2191
+ if (s == NULL || s->buff == NULL || r == NULL || term == NULL
2192
+ || term->data == NULL || r->mlen <= 0) return BSTR_ERR;
2193
+ if (term->slen == 1) return bsreadln (r, s, term->data[0]);
2194
+ if (term->slen < 1) return BSTR_ERR;
2195
+ if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2196
+ r->slen = 0;
2197
+ return bsreadlnsa (r, s, term);
2198
+ }
2199
+
2200
+ /* int bsread (bstring r, struct bStream * s, int n)
2201
+ *
2202
+ * Read a bstring of length n (or, if it is fewer, as many bytes as is
2203
+ * remaining) from the bStream. This function may read additional
2204
+ * characters from the core stream that are not returned, but will be
2205
+ * retained for subsequent read operations. This function will not read
2206
+ * additional characters from the core stream beyond virtual stream pointer.
2207
+ */
2208
+ int bsread (bstring r, struct bStream * s, int n) {
2209
+ if (s == NULL || s->buff == NULL || r == NULL || r->mlen <= 0
2210
+ || n <= 0) return BSTR_ERR;
2211
+ if (BSTR_OK != balloc (s->buff, s->maxBuffSz + 1)) return BSTR_ERR;
2212
+ r->slen = 0;
2213
+ return bsreada (r, s, n);
2214
+ }
2215
+
2216
+ /* int bsunread (struct bStream * s, const_bstring b)
2217
+ *
2218
+ * Insert a bstring into the bStream at the current position. These
2219
+ * characters will be read prior to those that actually come from the core
2220
+ * stream.
2221
+ */
2222
+ int bsunread (struct bStream * s, const_bstring b) {
2223
+ if (s == NULL || s->buff == NULL) return BSTR_ERR;
2224
+ return binsert (s->buff, 0, b, (unsigned char) '?');
2225
+ }
2226
+
2227
+ /* int bspeek (bstring r, const struct bStream * s)
2228
+ *
2229
+ * Return the currently buffered characters from the bStream that will be
2230
+ * read prior to reads from the core stream.
2231
+ */
2232
+ int bspeek (bstring r, const struct bStream * s) {
2233
+ if (s == NULL || s->buff == NULL) return BSTR_ERR;
2234
+ return bassign (r, s->buff);
2235
+ }
2236
+
2237
+ /* bstring bjoin (const struct bstrList * bl, const_bstring sep);
2238
+ *
2239
+ * Join the entries of a bstrList into one bstring by sequentially
2240
+ * concatenating them with the sep string in between. If there is an error
2241
+ * NULL is returned, otherwise a bstring with the correct result is returned.
2242
+ */
2243
+ bstring bjoin (const struct bstrList * bl, const_bstring sep) {
2244
+ bstring b;
2245
+ int i, c, v;
2246
+
2247
+ if (bl == NULL || bl->qty < 0) return NULL;
2248
+ if (sep != NULL && (sep->slen < 0 || sep->data == NULL)) return NULL;
2249
+
2250
+ for (i = 0, c = 1; i < bl->qty; i++) {
2251
+ v = bl->entry[i]->slen;
2252
+ if (v < 0) return NULL; /* Invalid input */
2253
+ c += v;
2254
+ if (c < 0) return NULL; /* Wrap around ?? */
2255
+ }
2256
+
2257
+ if (sep != NULL) c += (bl->qty - 1) * sep->slen;
2258
+
2259
+ b = (bstring) bstr__alloc (sizeof (struct tagbstring));
2260
+ if (NULL == b) return NULL; /* Out of memory */
2261
+ b->data = (unsigned char *) bstr__alloc (c);
2262
+ if (b->data == NULL) {
2263
+ bstr__free (b);
2264
+ return NULL;
2265
+ }
2266
+
2267
+ b->mlen = c;
2268
+ b->slen = c-1;
2269
+
2270
+ for (i = 0, c = 0; i < bl->qty; i++) {
2271
+ if (i > 0 && sep != NULL) {
2272
+ bstr__memcpy (b->data + c, sep->data, sep->slen);
2273
+ c += sep->slen;
2274
+ }
2275
+ v = bl->entry[i]->slen;
2276
+ bstr__memcpy (b->data + c, bl->entry[i]->data, v);
2277
+ c += v;
2278
+ }
2279
+ b->data[c] = (unsigned char) '\0';
2280
+ return b;
2281
+ }
2282
+
2283
+ #define BSSSC_BUFF_LEN (256)
2284
+
2285
+ /* int bssplitscb (struct bStream * s, const_bstring splitStr,
2286
+ * int (* cb) (void * parm, int ofs, const_bstring entry), void * parm)
2287
+ *
2288
+ * Iterate the set of disjoint sequential substrings read from a stream
2289
+ * divided by any of the characters in splitStr. An empty splitStr causes
2290
+ * the whole stream to be iterated once.
2291
+ *
2292
+ * Note: At the point of calling the cb function, the bStream pointer is
2293
+ * pointed exactly at the position right after having read the split
2294
+ * character. The cb function can act on the stream by causing the bStream
2295
+ * pointer to move, and bssplitscb will continue by starting the next split
2296
+ * at the position of the pointer after the return from cb.
2297
+ *
2298
+ * However, if the cb causes the bStream s to be destroyed then the cb must
2299
+ * return with a negative value, otherwise bssplitscb will continue in an
2300
+ * undefined manner.
2301
+ */
2302
+ int bssplitscb (struct bStream * s, const_bstring splitStr,
2303
+ int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) {
2304
+ struct charField chrs;
2305
+ bstring buff;
2306
+ int i, p, ret;
2307
+
2308
+ if (cb == NULL || s == NULL || s->readFnPtr == NULL
2309
+ || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
2310
+
2311
+ if (NULL == (buff = bfromcstr (""))) return BSTR_ERR;
2312
+
2313
+ if (splitStr->slen == 0) {
2314
+ while (bsreada (buff, s, BSSSC_BUFF_LEN) >= 0) ;
2315
+ if ((ret = cb (parm, 0, buff)) > 0)
2316
+ ret = 0;
2317
+ } else {
2318
+ buildCharField (&chrs, splitStr);
2319
+ ret = p = i = 0;
2320
+ for (;;) {
2321
+ if (i >= buff->slen) {
2322
+ bsreada (buff, s, BSSSC_BUFF_LEN);
2323
+ if (i >= buff->slen) {
2324
+ if (0 < (ret = cb (parm, p, buff))) ret = 0;
2325
+ break;
2326
+ }
2327
+ }
2328
+ if (testInCharField (&chrs, buff->data[i])) {
2329
+ struct tagbstring t;
2330
+ unsigned char c;
2331
+
2332
+ blk2tbstr (t, buff->data + i + 1, buff->slen - (i + 1));
2333
+ if ((ret = bsunread (s, &t)) < 0) break;
2334
+ buff->slen = i;
2335
+ c = buff->data[i];
2336
+ buff->data[i] = (unsigned char) '\0';
2337
+ if ((ret = cb (parm, p, buff)) < 0) break;
2338
+ buff->data[i] = c;
2339
+ buff->slen = 0;
2340
+ p += i + 1;
2341
+ i = -1;
2342
+ }
2343
+ i++;
2344
+ }
2345
+ }
2346
+
2347
+ bdestroy (buff);
2348
+ return ret;
2349
+ }
2350
+
2351
+ /* int bssplitstrcb (struct bStream * s, const_bstring splitStr,
2352
+ * int (* cb) (void * parm, int ofs, const_bstring entry), void * parm)
2353
+ *
2354
+ * Iterate the set of disjoint sequential substrings read from a stream
2355
+ * divided by the entire substring splitStr. An empty splitStr causes
2356
+ * each character of the stream to be iterated.
2357
+ *
2358
+ * Note: At the point of calling the cb function, the bStream pointer is
2359
+ * pointed exactly at the position right after having read the split
2360
+ * character. The cb function can act on the stream by causing the bStream
2361
+ * pointer to move, and bssplitscb will continue by starting the next split
2362
+ * at the position of the pointer after the return from cb.
2363
+ *
2364
+ * However, if the cb causes the bStream s to be destroyed then the cb must
2365
+ * return with a negative value, otherwise bssplitscb will continue in an
2366
+ * undefined manner.
2367
+ */
2368
+ int bssplitstrcb (struct bStream * s, const_bstring splitStr,
2369
+ int (* cb) (void * parm, int ofs, const_bstring entry), void * parm) {
2370
+ bstring buff;
2371
+ int i, p, ret;
2372
+
2373
+ if (cb == NULL || s == NULL || s->readFnPtr == NULL
2374
+ || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
2375
+
2376
+ if (splitStr->slen == 1) return bssplitscb (s, splitStr, cb, parm);
2377
+
2378
+ if (NULL == (buff = bfromcstr (""))) return BSTR_ERR;
2379
+
2380
+ if (splitStr->slen == 0) {
2381
+ for (i=0; bsreada (buff, s, BSSSC_BUFF_LEN) >= 0; i++) {
2382
+ if ((ret = cb (parm, 0, buff)) < 0) {
2383
+ bdestroy (buff);
2384
+ return ret;
2385
+ }
2386
+ buff->slen = 0;
2387
+ }
2388
+ return BSTR_OK;
2389
+ } else {
2390
+ ret = p = i = 0;
2391
+ for (i=p=0;;) {
2392
+ if ((ret = binstr (buff, 0, splitStr)) >= 0) {
2393
+ struct tagbstring t;
2394
+ blk2tbstr (t, buff->data, ret);
2395
+ i = ret + splitStr->slen;
2396
+ if ((ret = cb (parm, p, &t)) < 0) break;
2397
+ p += i;
2398
+ bdelete (buff, 0, i);
2399
+ } else {
2400
+ bsreada (buff, s, BSSSC_BUFF_LEN);
2401
+ if (bseof (s)) {
2402
+ if ((ret = cb (parm, p, buff)) > 0) ret = 0;
2403
+ break;
2404
+ }
2405
+ }
2406
+ }
2407
+ }
2408
+
2409
+ bdestroy (buff);
2410
+ return ret;
2411
+ }
2412
+
2413
+ /* int bstrListCreate (void)
2414
+ *
2415
+ * Create a bstrList.
2416
+ */
2417
+ struct bstrList * bstrListCreate (void) {
2418
+ struct bstrList * sl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
2419
+ if (sl) {
2420
+ sl->entry = (bstring *) bstr__alloc (1*sizeof (bstring));
2421
+ if (!sl->entry) {
2422
+ bstr__free (sl);
2423
+ sl = NULL;
2424
+ } else {
2425
+ sl->qty = 0;
2426
+ sl->mlen = 1;
2427
+ }
2428
+ }
2429
+ return sl;
2430
+ }
2431
+
2432
+ /* int bstrListDestroy (struct bstrList * sl)
2433
+ *
2434
+ * Destroy a bstrList that has been created by bsplit, bsplits or bstrListCreate.
2435
+ */
2436
+ int bstrListDestroy (struct bstrList * sl) {
2437
+ int i;
2438
+ if (sl == NULL || sl->qty < 0) return BSTR_ERR;
2439
+ for (i=0; i < sl->qty; i++) {
2440
+ if (sl->entry[i]) {
2441
+ bdestroy (sl->entry[i]);
2442
+ sl->entry[i] = NULL;
2443
+ }
2444
+ }
2445
+ sl->qty = -1;
2446
+ sl->mlen = -1;
2447
+ bstr__free (sl->entry);
2448
+ sl->entry = NULL;
2449
+ bstr__free (sl);
2450
+ return BSTR_OK;
2451
+ }
2452
+
2453
+ /* int bsplitcb (const_bstring str, unsigned char splitChar, int pos,
2454
+ * int (* cb) (void * parm, int ofs, int len), void * parm)
2455
+ *
2456
+ * Iterate the set of disjoint sequential substrings over str divided by the
2457
+ * character in splitChar.
2458
+ *
2459
+ * Note: Non-destructive modification of str from within the cb function
2460
+ * while performing this split is not undefined. bsplitcb behaves in
2461
+ * sequential lock step with calls to cb. I.e., after returning from a cb
2462
+ * that return a non-negative integer, bsplitcb continues from the position
2463
+ * 1 character after the last detected split character and it will halt
2464
+ * immediately if the length of str falls below this point. However, if the
2465
+ * cb function destroys str, then it *must* return with a negative value,
2466
+ * otherwise bsplitcb will continue in an undefined manner.
2467
+ */
2468
+ int bsplitcb (const_bstring str, unsigned char splitChar, int pos,
2469
+ int (* cb) (void * parm, int ofs, int len), void * parm) {
2470
+ int i, p, ret;
2471
+
2472
+ if (cb == NULL || str == NULL || pos < 0 || pos > str->slen)
2473
+ return BSTR_ERR;
2474
+
2475
+ p = pos;
2476
+ do {
2477
+ for (i=p; i < str->slen; i++) {
2478
+ if (str->data[i] == splitChar) break;
2479
+ }
2480
+ if ((ret = cb (parm, p, i - p)) < 0) return ret;
2481
+ p = i + 1;
2482
+ } while (p <= str->slen);
2483
+ return BSTR_OK;
2484
+ }
2485
+
2486
+ /* int bsplitscb (const_bstring str, const_bstring splitStr, int pos,
2487
+ * int (* cb) (void * parm, int ofs, int len), void * parm)
2488
+ *
2489
+ * Iterate the set of disjoint sequential substrings over str divided by any
2490
+ * of the characters in splitStr. An empty splitStr causes the whole str to
2491
+ * be iterated once.
2492
+ *
2493
+ * Note: Non-destructive modification of str from within the cb function
2494
+ * while performing this split is not undefined. bsplitscb behaves in
2495
+ * sequential lock step with calls to cb. I.e., after returning from a cb
2496
+ * that return a non-negative integer, bsplitscb continues from the position
2497
+ * 1 character after the last detected split character and it will halt
2498
+ * immediately if the length of str falls below this point. However, if the
2499
+ * cb function destroys str, then it *must* return with a negative value,
2500
+ * otherwise bsplitscb will continue in an undefined manner.
2501
+ */
2502
+ int bsplitscb (const_bstring str, const_bstring splitStr, int pos,
2503
+ int (* cb) (void * parm, int ofs, int len), void * parm) {
2504
+ struct charField chrs;
2505
+ int i, p, ret;
2506
+
2507
+ if (cb == NULL || str == NULL || pos < 0 || pos > str->slen
2508
+ || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
2509
+ if (splitStr->slen == 0) {
2510
+ if ((ret = cb (parm, 0, str->slen)) > 0) ret = 0;
2511
+ return ret;
2512
+ }
2513
+
2514
+ if (splitStr->slen == 1)
2515
+ return bsplitcb (str, splitStr->data[0], pos, cb, parm);
2516
+
2517
+ buildCharField (&chrs, splitStr);
2518
+
2519
+ p = pos;
2520
+ do {
2521
+ for (i=p; i < str->slen; i++) {
2522
+ if (testInCharField (&chrs, str->data[i])) break;
2523
+ }
2524
+ if ((ret = cb (parm, p, i - p)) < 0) return ret;
2525
+ p = i + 1;
2526
+ } while (p <= str->slen);
2527
+ return BSTR_OK;
2528
+ }
2529
+
2530
+ /* int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos,
2531
+ * int (* cb) (void * parm, int ofs, int len), void * parm)
2532
+ *
2533
+ * Iterate the set of disjoint sequential substrings over str divided by the
2534
+ * substring splitStr. An empty splitStr causes the whole str to be
2535
+ * iterated once.
2536
+ *
2537
+ * Note: Non-destructive modification of str from within the cb function
2538
+ * while performing this split is not undefined. bsplitstrcb behaves in
2539
+ * sequential lock step with calls to cb. I.e., after returning from a cb
2540
+ * that return a non-negative integer, bsplitscb continues from the position
2541
+ * 1 character after the last detected split character and it will halt
2542
+ * immediately if the length of str falls below this point. However, if the
2543
+ * cb function destroys str, then it *must* return with a negative value,
2544
+ * otherwise bsplitscb will continue in an undefined manner.
2545
+ */
2546
+ int bsplitstrcb (const_bstring str, const_bstring splitStr, int pos,
2547
+ int (* cb) (void * parm, int ofs, int len), void * parm) {
2548
+ int i, p, ret;
2549
+
2550
+ if (cb == NULL || str == NULL || pos < 0 || pos > str->slen
2551
+ || splitStr == NULL || splitStr->slen < 0) return BSTR_ERR;
2552
+
2553
+ if (0 == splitStr->slen) {
2554
+ for (i=pos; i < str->slen; i++) {
2555
+ if ((ret = cb (parm, i, 1)) < 0) return ret;
2556
+ }
2557
+ return BSTR_OK;
2558
+ }
2559
+
2560
+ if (splitStr->slen == 1)
2561
+ return bsplitcb (str, splitStr->data[0], pos, cb, parm);
2562
+
2563
+ for (i=p=pos; i <= str->slen - splitStr->slen; i++) {
2564
+ if (0 == bstr__memcmp (splitStr->data, str->data + i, splitStr->slen)) {
2565
+ if ((ret = cb (parm, p, i - p)) < 0) return ret;
2566
+ i += splitStr->slen;
2567
+ p = i;
2568
+ }
2569
+ }
2570
+ if ((ret = cb (parm, p, str->slen - p)) < 0) return ret;
2571
+ return BSTR_OK;
2572
+ }
2573
+
2574
+ struct genBstrList {
2575
+ bstring b;
2576
+ struct bstrList * bl;
2577
+ };
2578
+
2579
+ static int bscb (void * parm, int ofs, int len) {
2580
+ struct genBstrList * g = (struct genBstrList *) parm;
2581
+ if (g->bl->qty >= g->bl->mlen) {
2582
+ int mlen = g->bl->mlen * 2;
2583
+ bstring * tbl;
2584
+
2585
+ while (g->bl->qty >= mlen) {
2586
+ if (mlen < g->bl->mlen) return BSTR_ERR;
2587
+ mlen += mlen;
2588
+ }
2589
+
2590
+ tbl = (bstring *) bstr__realloc (g->bl->entry, sizeof (bstring) * mlen);
2591
+ if (tbl == NULL) return BSTR_ERR;
2592
+
2593
+ g->bl->entry = tbl;
2594
+ g->bl->mlen = mlen;
2595
+ }
2596
+
2597
+ g->bl->entry[g->bl->qty] = bmidstr (g->b, ofs, len);
2598
+ g->bl->qty++;
2599
+ return BSTR_OK;
2600
+ }
2601
+
2602
+ /* struct bstrList * bsplit (const_bstring str, unsigned char splitChar)
2603
+ *
2604
+ * Create an array of sequential substrings from str divided by the character
2605
+ * splitChar.
2606
+ */
2607
+ struct bstrList * bsplit (const_bstring str, unsigned char splitChar) {
2608
+ struct genBstrList g;
2609
+
2610
+ if (str == NULL || str->data == NULL || str->slen < 0) return NULL;
2611
+
2612
+ g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
2613
+ if (g.bl == NULL) return NULL;
2614
+ g.bl->mlen = 4;
2615
+ g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
2616
+ if (NULL == g.bl->entry) {
2617
+ bstr__free (g.bl);
2618
+ return NULL;
2619
+ }
2620
+
2621
+ g.b = (bstring) str;
2622
+ g.bl->qty = 0;
2623
+ if (bsplitcb (str, splitChar, 0, bscb, &g) < 0) {
2624
+ bstrListDestroy (g.bl);
2625
+ return NULL;
2626
+ }
2627
+ return g.bl;
2628
+ }
2629
+
2630
+ /* struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr)
2631
+ *
2632
+ * Create an array of sequential substrings from str divided by the entire
2633
+ * substring splitStr.
2634
+ */
2635
+ struct bstrList * bsplitstr (const_bstring str, const_bstring splitStr) {
2636
+ struct genBstrList g;
2637
+
2638
+ if (str == NULL || str->data == NULL || str->slen < 0) return NULL;
2639
+
2640
+ g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
2641
+ if (g.bl == NULL) return NULL;
2642
+ g.bl->mlen = 4;
2643
+ g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
2644
+ if (NULL == g.bl->entry) {
2645
+ bstr__free (g.bl);
2646
+ return NULL;
2647
+ }
2648
+
2649
+ g.b = (bstring) str;
2650
+ g.bl->qty = 0;
2651
+ if (bsplitstrcb (str, splitStr, 0, bscb, &g) < 0) {
2652
+ bstrListDestroy (g.bl);
2653
+ return NULL;
2654
+ }
2655
+ return g.bl;
2656
+ }
2657
+
2658
+ /* struct bstrList * bsplits (const_bstring str, bstring splitStr)
2659
+ *
2660
+ * Create an array of sequential substrings from str divided by any of the
2661
+ * characters in splitStr. An empty splitStr causes a single entry bstrList
2662
+ * containing a copy of str to be returned.
2663
+ */
2664
+ struct bstrList * bsplits (const_bstring str, const_bstring splitStr) {
2665
+ struct genBstrList g;
2666
+
2667
+ if ( str == NULL || str->slen < 0 || str->data == NULL ||
2668
+ splitStr == NULL || splitStr->slen < 0 || splitStr->data == NULL)
2669
+ return NULL;
2670
+
2671
+ g.bl = (struct bstrList *) bstr__alloc (sizeof (struct bstrList));
2672
+ if (g.bl == NULL) return NULL;
2673
+ g.bl->mlen = 4;
2674
+ g.bl->entry = (bstring *) bstr__alloc (g.bl->mlen * sizeof (bstring));
2675
+ if (NULL == g.bl->entry) {
2676
+ bstr__free (g.bl);
2677
+ return NULL;
2678
+ }
2679
+ g.b = (bstring) str;
2680
+ g.bl->qty = 0;
2681
+
2682
+ if (bsplitscb (str, splitStr, 0, bscb, &g) < 0) {
2683
+ bstrListDestroy (g.bl);
2684
+ return NULL;
2685
+ }
2686
+ return g.bl;
2687
+ }