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