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