1/* ----------------------------------------------------------------------------- 2 * string.c 3 * 4 * Implements a string object that supports both sequence operations and 5 * file semantics. 6 * 7 * Author(s) : David Beazley (beazley@cs.uchicago.edu) 8 * 9 * Copyright (C) 1999-2000. The University of Chicago 10 * See the file LICENSE for information on usage and redistribution. 11 * ----------------------------------------------------------------------------- */ 12 13char cvsroot_string_c[] = "$Id: string.c 10926 2008-11-11 22:17:40Z wsfulton $"; 14 15#include "dohint.h" 16 17extern DohObjInfo DohStringType; 18 19typedef struct String { 20 DOH *file; 21 int line; 22 int maxsize; /* Max size allocated */ 23 int len; /* Current length */ 24 int hashkey; /* Hash key value */ 25 int sp; /* Current position */ 26 char *str; /* String data */ 27} String; 28 29/* ----------------------------------------------------------------------------- 30 * void *String_data() - Return as a 'void *' 31 * ----------------------------------------------------------------------------- */ 32 33static void *String_data(DOH *so) { 34 String *s = (String *) ObjData(so); 35 s->str[s->len] = 0; 36 return (void *) s->str; 37} 38 39/* static char *String_char(DOH *so) { 40 return (char *) String_data(so); 41} 42*/ 43 44/* ----------------------------------------------------------------------------- 45 * int String_dump() - Serialize a string onto out 46 * ----------------------------------------------------------------------------- */ 47 48static int String_dump(DOH *so, DOH *out) { 49 int nsent; 50 int ret; 51 String *s = (String *) ObjData(so); 52 nsent = 0; 53 while (nsent < s->len) { 54 ret = Write(out, s->str + nsent, (s->len - nsent)); 55 if (ret < 0) 56 return ret; 57 nsent += ret; 58 } 59 return nsent; 60} 61 62/* ----------------------------------------------------------------------------- 63 * CopyString() - Copy a string 64 * ----------------------------------------------------------------------------- */ 65 66static DOH *CopyString(DOH *so) { 67 String *str; 68 String *s = (String *) ObjData(so); 69 str = (String *) DohMalloc(sizeof(String)); 70 str->hashkey = s->hashkey; 71 str->sp = s->sp; 72 str->line = s->line; 73 str->file = s->file; 74 if (str->file) 75 Incref(str->file); 76 str->str = (char *) DohMalloc(s->len + 1); 77 memcpy(str->str, s->str, s->len); 78 str->maxsize = s->len; 79 str->len = s->len; 80 str->str[str->len] = 0; 81 82 return DohObjMalloc(&DohStringType, str); 83} 84 85/* ----------------------------------------------------------------------------- 86 * DelString() - Delete a string 87 * ----------------------------------------------------------------------------- */ 88 89static void DelString(DOH *so) { 90 String *s = (String *) ObjData(so); 91 DohFree(s->str); 92 DohFree(s); 93} 94 95/* ----------------------------------------------------------------------------- 96 * DohString_len() - Length of a string 97 * ----------------------------------------------------------------------------- */ 98 99static int String_len(DOH *so) { 100 String *s = (String *) ObjData(so); 101 return s->len; 102} 103 104 105/* ----------------------------------------------------------------------------- 106 * int String_cmp() - Compare two strings 107 * ----------------------------------------------------------------------------- */ 108 109static int String_cmp(DOH *so1, DOH *so2) { 110 String *s1, *s2; 111 char *c1, *c2; 112 int maxlen, i; 113 s1 = (String *) ObjData(so1); 114 s2 = (String *) ObjData(so2); 115 maxlen = s1->len; 116 if (s2->len < maxlen) 117 maxlen = s2->len; 118 c1 = s1->str; 119 c2 = s2->str; 120 for (i = maxlen; i; --i, c1++, c2++) { 121 if (*c1 != *c2) 122 break; 123 } 124 if (i != 0) { 125 if (*c1 < *c2) 126 return -1; 127 else 128 return 1; 129 } 130 if (s1->len == s2->len) 131 return 0; 132 if (s1->len > s2->len) 133 return 1; 134 return -1; 135} 136 137/* ----------------------------------------------------------------------------- 138 * int String_equal() - Say if two string are equal 139 * ----------------------------------------------------------------------------- */ 140 141static int String_equal(DOH *so1, DOH *so2) { 142 String *s1 = (String *) ObjData(so1); 143 String *s2 = (String *) ObjData(so2); 144 register int len = s1->len; 145 if (len != s2->len) { 146 return 0; 147 } else { 148 register char *c1 = s1->str; 149 register char *c2 = s2->str; 150#if 0 151 register int mlen = len >> 2; 152 register int i = mlen; 153 for (; i; --i) { 154 if (*(c1++) != *(c2++)) 155 return 0; 156 if (*(c1++) != *(c2++)) 157 return 0; 158 if (*(c1++) != *(c2++)) 159 return 0; 160 if (*(c1++) != *(c2++)) 161 return 0; 162 } 163 for (i = len - (mlen << 2); i; --i) { 164 if (*(c1++) != *(c2++)) 165 return 0; 166 } 167 return 1; 168#else 169 return memcmp(c1, c2, len) == 0; 170#endif 171 } 172} 173 174/* ----------------------------------------------------------------------------- 175 * int String_hash() - Compute string hash value 176 * ----------------------------------------------------------------------------- */ 177 178static int String_hash(DOH *so) { 179 String *s = (String *) ObjData(so); 180 if (s->hashkey >= 0) { 181 return s->hashkey; 182 } else { 183 register char *c = s->str; 184 register int len = s->len > 50 ? 50 : s->len; 185 register int h = 0; 186 register int mlen = len >> 2; 187 register int i = mlen; 188 for (; i; --i) { 189 h = (h << 5) + *(c++); 190 h = (h << 5) + *(c++); 191 h = (h << 5) + *(c++); 192 h = (h << 5) + *(c++); 193 } 194 for (i = len - (mlen << 2); i; --i) { 195 h = (h << 5) + *(c++); 196 } 197 h &= 0x7fffffff; 198 s->hashkey = h; 199 return h; 200 } 201} 202 203/* ----------------------------------------------------------------------------- 204 * DohString_append(String *s, const char *newstr) - Append to s 205 * ----------------------------------------------------------------------------- */ 206 207void DohString_append(DOH *so, DOH *str) { 208 int oldlen, newlen, newmaxsize, l, sp; 209 char *tc; 210 String *s = (String *) ObjData(so); 211 char *newstr = 0; 212 213 if (DohCheck(str)) { 214 String *ss = (String *) ObjData(str); 215 newstr = (char *) String_data((DOH *) str); 216 l = ss->len; 217 } else { 218 newstr = (char *) (str); 219 l = (int) strlen(newstr); 220 } 221 if (!newstr) 222 return; 223 s->hashkey = -1; 224 225 oldlen = s->len; 226 newlen = oldlen + l + 1; 227 if (newlen >= s->maxsize - 1) { 228 newmaxsize = 2 * s->maxsize; 229 if (newlen >= newmaxsize - 1) 230 newmaxsize = newlen + 1; 231 s->str = (char *) DohRealloc(s->str, newmaxsize); 232 assert(s->str); 233 s->maxsize = newmaxsize; 234 } 235 tc = s->str; 236 memcpy(tc + oldlen, newstr, l + 1); 237 sp = s->sp; 238 if (sp >= oldlen) { 239 int i = oldlen + l - sp; 240 tc += sp; 241 for (; i; --i) { 242 if (*(tc++) == '\n') 243 s->line++; 244 } 245 s->sp = oldlen + l; 246 } 247 s->len += l; 248} 249 250 251/* ----------------------------------------------------------------------------- 252 * void String_clear() - Clear a string 253 * ----------------------------------------------------------------------------- */ 254 255static void String_clear(DOH *so) { 256 String *s = (String *) ObjData(so); 257 s->hashkey = -1; 258 s->len = 0; 259 *(s->str) = 0; 260 s->sp = 0; 261 s->line = 1; 262} 263 264/* ----------------------------------------------------------------------------- 265 * void String_insert() - Insert a string 266 * ----------------------------------------------------------------------------- */ 267 268static int String_insert(DOH *so, int pos, DOH *str) { 269 String *s; 270 char *nstr; 271 int len; 272 char *data; 273 274 if (pos == DOH_END) { 275 DohString_append(so, str); 276 return 0; 277 } 278 279 280 s = (String *) ObjData(so); 281 s->hashkey = -1; 282 if (DohCheck(str)) { 283 String *ss = (String *) ObjData(str); 284 data = (char *) String_data(str); 285 len = ss->len; 286 } else { 287 data = (char *) (str); 288 len = (int) strlen(data); 289 } 290 nstr = s->str; 291 292 if (pos < 0) 293 pos = 0; 294 else if (pos > s->len) 295 pos = s->len; 296 297 /* See if there is room to insert the new data */ 298 while (s->maxsize <= s->len + len) { 299 int newsize = 2 * s->maxsize; 300 s->str = (char *) DohRealloc(s->str, newsize); 301 assert(s->str); 302 s->maxsize = newsize; 303 } 304 memmove(s->str + pos + len, s->str + pos, (s->len - pos)); 305 memcpy(s->str + pos, data, len); 306 if (s->sp >= pos) { 307 int i; 308 309 for (i = 0; i < len; i++) { 310 if (data[i] == '\n') 311 s->line++; 312 } 313 s->sp += len; 314 } 315 s->len += len; 316 s->str[s->len] = 0; 317 return 0; 318} 319 320/* ----------------------------------------------------------------------------- 321 * int String_delitem() - Delete a character 322 * ----------------------------------------------------------------------------- */ 323 324static int String_delitem(DOH *so, int pos) { 325 String *s = (String *) ObjData(so); 326 s->hashkey = -1; 327 if (pos == DOH_END) 328 pos = s->len - 1; 329 if (pos == DOH_BEGIN) 330 pos = 0; 331 if (s->len == 0) 332 return 0; 333 334 if (s->sp > pos) { 335 s->sp--; 336 assert(s->sp >= 0); 337 if (s->str[pos] == '\n') 338 s->line--; 339 } 340 memmove(s->str + pos, s->str + pos + 1, ((s->len - 1) - pos)); 341 s->len--; 342 s->str[s->len] = 0; 343 return 0; 344} 345 346/* ----------------------------------------------------------------------------- 347 * int String_delslice() - Delete a range 348 * ----------------------------------------------------------------------------- */ 349 350static int String_delslice(DOH *so, int sindex, int eindex) { 351 String *s = (String *) ObjData(so); 352 int size; 353 if (s->len == 0) 354 return 0; 355 s->hashkey = -1; 356 if (eindex == DOH_END) 357 eindex = s->len; 358 if (sindex == DOH_BEGIN) 359 sindex = 0; 360 361 size = eindex - sindex; 362 if (s->sp > sindex) { 363 /* Adjust the file pointer and line count */ 364 int i, end; 365 if (s->sp > eindex) { 366 end = eindex; 367 s->sp -= size; 368 } else { 369 end = s->sp; 370 s->sp = sindex; 371 } 372 for (i = sindex; i < end; i++) { 373 if (s->str[i] == '\n') 374 s->line--; 375 } 376 assert(s->sp >= 0); 377 } 378 memmove(s->str + sindex, s->str + eindex, s->len - eindex); 379 s->len -= size; 380 s->str[s->len] = 0; 381 return 0; 382} 383 384/* ----------------------------------------------------------------------------- 385 * DOH *String_str() - Returns a string (used by printing commands) 386 * ----------------------------------------------------------------------------- */ 387 388static DOH *String_str(DOH *so) { 389 String *s = (String *) ObjData(so); 390 s->str[s->len] = 0; 391 return NewString(s->str); 392} 393 394/* ----------------------------------------------------------------------------- 395 * int String_read() - Read data from a string 396 * ----------------------------------------------------------------------------- */ 397 398static int String_read(DOH *so, void *buffer, int len) { 399 int reallen, retlen; 400 char *cb; 401 String *s = (String *) ObjData(so); 402 if ((s->sp + len) > s->len) 403 reallen = (s->len - s->sp); 404 else 405 reallen = len; 406 407 cb = (char *) buffer; 408 retlen = reallen; 409 410 if (reallen > 0) { 411 memmove(cb, s->str + s->sp, reallen); 412 s->sp += reallen; 413 } 414 return retlen; 415} 416 417/* ----------------------------------------------------------------------------- 418 * int String_write() - Write data to a string 419 * ----------------------------------------------------------------------------- */ 420static int String_write(DOH *so, void *buffer, int len) { 421 int newlen; 422 String *s = (String *) ObjData(so); 423 s->hashkey = -1; 424 if (s->sp > s->len) 425 s->sp = s->len; 426 newlen = s->sp + len + 1; 427 if (newlen > s->maxsize) { 428 s->str = (char *) DohRealloc(s->str, newlen); 429 assert(s->str); 430 s->maxsize = newlen; 431 s->len = s->sp + len; 432 } 433 if ((s->sp + len) > s->len) 434 s->len = s->sp + len; 435 memmove(s->str + s->sp, buffer, len); 436 s->sp += len; 437 s->str[s->len] = 0; 438 return len; 439} 440 441/* ----------------------------------------------------------------------------- 442 * int String_seek() - Seek to a new position 443 * ----------------------------------------------------------------------------- */ 444 445static int String_seek(DOH *so, long offset, int whence) { 446 int pos, nsp, inc; 447 String *s = (String *) ObjData(so); 448 if (whence == SEEK_SET) 449 pos = 0; 450 else if (whence == SEEK_CUR) 451 pos = s->sp; 452 else if (whence == SEEK_END) { 453 pos = s->len; 454 offset = -offset; 455 } else 456 pos = s->sp; 457 458 nsp = pos + offset; 459 if (nsp < 0) 460 nsp = 0; 461 if (s->len > 0 && nsp > s->len) 462 nsp = s->len; 463 464 inc = (nsp > s->sp) ? 1 : -1; 465 466 { 467#if 0 468 register int sp = s->sp; 469 register char *tc = s->str; 470 register int len = s->len; 471 while (sp != nsp) { 472 int prev = sp + inc; 473 if (prev >= 0 && prev <= len && tc[prev] == '\n') 474 s->line += inc; 475 sp += inc; 476 } 477#else 478 register int sp = s->sp; 479 register char *tc = s->str; 480 if (inc > 0) { 481 while (sp != nsp) { 482 if (tc[++sp] == '\n') 483 ++s->line; 484 } 485 } else { 486 while (sp != nsp) { 487 if (tc[--sp] == '\n') 488 --s->line; 489 } 490 } 491#endif 492 s->sp = sp; 493 } 494 assert(s->sp >= 0); 495 return 0; 496} 497 498/* ----------------------------------------------------------------------------- 499 * long String_tell() - Return current position 500 * ----------------------------------------------------------------------------- */ 501 502static long String_tell(DOH *so) { 503 String *s = (String *) ObjData(so); 504 return (long) (s->sp); 505} 506 507/* ----------------------------------------------------------------------------- 508 * int String_putc() 509 * ----------------------------------------------------------------------------- */ 510 511static int String_putc(DOH *so, int ch) { 512 String *s = (String *) ObjData(so); 513 register int len = s->len; 514 register int sp = s->sp; 515 s->hashkey = -1; 516 if (sp >= len) { 517 register int maxsize = s->maxsize; 518 register char *tc = s->str; 519 if (len > (maxsize - 2)) { 520 maxsize *= 2; 521 tc = (char *) DohRealloc(tc, maxsize); 522 assert(tc); 523 s->maxsize = (int) maxsize; 524 s->str = tc; 525 } 526 tc += sp; 527 *tc = (char) ch; 528 *(++tc) = 0; 529 s->len = s->sp = sp + 1; 530 } else { 531 s->str[s->sp++] = (char) ch; 532 } 533 if (ch == '\n') 534 s->line++; 535 return ch; 536} 537 538/* ----------------------------------------------------------------------------- 539 * int String_getc() 540 * ----------------------------------------------------------------------------- */ 541 542static int String_getc(DOH *so) { 543 int c; 544 String *s = (String *) ObjData(so); 545 if (s->sp >= s->len) 546 c = EOF; 547 else 548 c = (int)(unsigned char) s->str[s->sp++]; 549 if (c == '\n') 550 s->line++; 551 return c; 552} 553 554/* ----------------------------------------------------------------------------- 555 * int String_ungetc() 556 * ----------------------------------------------------------------------------- */ 557 558static int String_ungetc(DOH *so, int ch) { 559 String *s = (String *) ObjData(so); 560 if (ch == EOF) 561 return ch; 562 if (s->sp <= 0) 563 return EOF; 564 s->sp--; 565 if (ch == '\n') 566 s->line--; 567 return ch; 568} 569 570/* ----------------------------------------------------------------------------- 571 * replace_simple(String *str, char *token, char *rep, int flags, int count) 572 * 573 * Replaces count non-overlapping occurrences of token with rep in a string. 574 * ----------------------------------------------------------------------------- */ 575 576static char *end_quote(char *s) { 577 char *qs; 578 char qc; 579 char *q; 580 char *nl; 581 qc = *s; 582 qs = s; 583 while (1) { 584 q = strpbrk(s + 1, "\"\'"); 585 nl = strchr(s + 1, '\n'); 586 if (nl && (nl < q)) { 587 /* A new line appears before the end of the string */ 588 if (*(nl - 1) == '\\') { 589 s = nl + 1; 590 continue; 591 } 592 /* String was terminated by a newline. Wing it */ 593 return qs; 594 } 595 if (!q && nl) { 596 return qs; 597 } 598 if (!q) 599 return 0; 600 if ((*q == qc) && (*(q - 1) != '\\')) 601 return q; 602 s = q; 603 } 604} 605 606static char *match_simple(char *base, char *s, char *token, int tokenlen) { 607 (void) base; 608 (void) tokenlen; 609 return strstr(s, token); 610} 611 612static char *match_identifier(char *base, char *s, char *token, int tokenlen) { 613 while (s) { 614 s = strstr(s, token); 615 if (!s) 616 return 0; 617 if ((s > base) && (isalnum((int) *(s - 1)) || (*(s - 1) == '_'))) { 618 s += tokenlen; 619 continue; 620 } 621 if (isalnum((int) *(s + tokenlen)) || (*(s + tokenlen) == '_')) { 622 s += tokenlen; 623 continue; 624 } 625 return s; 626 } 627 return 0; 628} 629 630 631static char *match_identifier_begin(char *base, char *s, char *token, int tokenlen) { 632 while (s) { 633 s = strstr(s, token); 634 if (!s) 635 return 0; 636 if ((s > base) && (isalnum((int) *(s - 1)) || (*(s - 1) == '_'))) { 637 s += tokenlen; 638 continue; 639 } 640 return s; 641 } 642 return 0; 643} 644 645static char *match_identifier_end(char *base, char *s, char *token, int tokenlen) { 646 (void) base; 647 while (s) { 648 s = strstr(s, token); 649 if (!s) 650 return 0; 651 if (isalnum((int) *(s + tokenlen)) || (*(s + tokenlen) == '_')) { 652 s += tokenlen; 653 continue; 654 } 655 return s; 656 } 657 return 0; 658} 659 660static int replace_simple(String *str, char *token, char *rep, int flags, int count, char *(*match) (char *, char *, char *, int)) { 661 int tokenlen; /* Length of the token */ 662 int replen; /* Length of the replacement */ 663 int delta, expand = 0; 664 int ic; 665 int rcount = 0; 666 int noquote = 0; 667 char *c, *s, *t, *first; 668 char *q, *q2; 669 register char *base; 670 int i; 671 672 /* Figure out if anything gets replaced */ 673 if (!strlen(token)) 674 return 0; 675 676 base = str->str; 677 tokenlen = strlen(token); 678 s = (*match) (base, base, token, tokenlen); 679 680 if (!s) 681 return 0; /* No matches. Who cares */ 682 683 str->hashkey = -1; 684 685 if (flags & DOH_REPLACE_NOQUOTE) 686 noquote = 1; 687 688 /* If we are not replacing inside quotes, we need to do a little extra work */ 689 if (noquote) { 690 q = strpbrk(base, "\"\'"); 691 if (!q) { 692 noquote = 0; /* Well, no quotes to worry about. Oh well */ 693 } else { 694 while (q && (q < s)) { 695 /* First match was found inside a quote. Try to find another match */ 696 q2 = end_quote(q); 697 if (!q2) { 698 return 0; 699 } 700 if (q2 > s) { 701 /* Find next match */ 702 s = (*match) (base, q2 + 1, token, tokenlen); 703 } 704 if (!s) 705 return 0; /* Oh well, no matches */ 706 q = strpbrk(q2 + 1, "\"\'"); 707 if (!q) 708 noquote = 0; /* No more quotes */ 709 } 710 } 711 } 712 713 first = s; 714 replen = strlen(rep); 715 716 delta = (replen - tokenlen); 717 718 if (delta <= 0) { 719 /* String is either shrinking or staying the same size */ 720 /* In this case, we do the replacement in place without memory reallocation */ 721 ic = count; 722 t = s; /* Target of memory copies */ 723 while (ic && s) { 724 if (replen) { 725 memcpy(t, rep, replen); 726 t += replen; 727 } 728 rcount++; 729 expand += delta; 730 /* Find the next location */ 731 s += tokenlen; 732 if (ic == 1) 733 break; 734 c = (*match) (base, s, token, tokenlen); 735 736 if (noquote) { 737 q = strpbrk(s, "\"\'"); 738 if (!q) { 739 noquote = 0; 740 } else { 741 while (q && (q < c)) { 742 /* First match was found inside a quote. Try to find another match */ 743 q2 = end_quote(q); 744 if (!q2) { 745 c = 0; 746 break; 747 } 748 if (q2 > c) 749 c = (*match) (base, q2 + 1, token, tokenlen); 750 if (!c) 751 break; 752 q = strpbrk(q2 + 1, "\"\'"); 753 if (!q) 754 noquote = 0; /* No more quotes */ 755 } 756 } 757 } 758 if (delta) { 759 if (c) { 760 memmove(t, s, c - s); 761 t += (c - s); 762 } else { 763 memmove(t, s, (str->str + str->len) - s + 1); 764 } 765 } else { 766 t += (c - s); 767 } 768 s = c; 769 ic--; 770 } 771 if (s && delta) { 772 memmove(t, s, (str->str + str->len) - s + 1); 773 } 774 str->len += expand; 775 str->str[str->len] = 0; 776 if (str->sp >= str->len) 777 str->sp += expand; /* Fix the end of file pointer */ 778 return rcount; 779 } 780 /* The string is expanding as a result of the replacement */ 781 /* Figure out how much expansion is going to occur and allocate a new string */ 782 { 783 char *ns; 784 int newsize; 785 786 rcount++; 787 ic = count - 1; 788 s += tokenlen; 789 while (ic && (c = (*match) (base, s, token, tokenlen))) { 790 if (noquote) { 791 q = strpbrk(s, "\"\'"); 792 if (!q) { 793 break; 794 } else { 795 while (q && (q < c)) { 796 /* First match was found inside a quote. Try to find another match */ 797 q2 = end_quote(q); 798 if (!q2) { 799 c = 0; 800 break; 801 } 802 if (q2 > c) { 803 c = (*match) (base, q2 + 1, token, tokenlen); 804 if (!c) 805 break; 806 } 807 q = strpbrk(q2 + 1, "\"\'"); 808 if (!q) 809 noquote = 0; 810 } 811 } 812 } 813 if (c) { 814 rcount++; 815 ic--; 816 s = c + tokenlen; 817 } else { 818 break; 819 } 820 } 821 822 expand = delta * rcount; /* Total amount of expansion for the replacement */ 823 newsize = str->maxsize; 824 while ((str->len + expand) >= newsize) 825 newsize *= 2; 826 827 ns = (char *) DohMalloc(newsize); 828 assert(ns); 829 t = ns; 830 s = first; 831 832 /* Copy the first part of the string */ 833 if (first > str->str) { 834 memcpy(t, str->str, (first - str->str)); 835 t += (first - str->str); 836 } 837 for (i = 0; i < rcount; i++) { 838 memcpy(t, rep, replen); 839 t += replen; 840 s += tokenlen; 841 c = (*match) (base, s, token, tokenlen); 842 if (noquote) { 843 q = strpbrk(s, "\"\'"); 844 if (!q) { 845 noquote = 0; 846 } else { 847 while (q && (q < c)) { 848 /* First match was found inside a quote. Try to find another match */ 849 q2 = end_quote(q); 850 if (!q2) { 851 c = 0; 852 break; 853 } 854 if (q2 > c) { 855 c = (*match) (base, q2 + 1, token, tokenlen); 856 if (!c) 857 break; 858 } 859 q = strpbrk(q2 + 1, "\"\'"); 860 if (!q) 861 noquote = 0; /* No more quotes */ 862 } 863 } 864 } 865 if (i < (rcount - 1)) { 866 memcpy(t, s, c - s); 867 t += (c - s); 868 } else { 869 memcpy(t, s, (str->str + str->len) - s + 1); 870 } 871 s = c; 872 } 873 c = str->str; 874 str->str = ns; 875 if (str->sp >= str->len) 876 str->sp += expand; 877 str->len += expand; 878 str->str[str->len] = 0; 879 str->maxsize = newsize; 880 DohFree(c); 881 return rcount; 882 } 883} 884 885/* ----------------------------------------------------------------------------- 886 * int String_replace() 887 * ----------------------------------------------------------------------------- */ 888 889static int String_replace(DOH *stro, DOH *token, DOH *rep, int flags) { 890 int count = -1; 891 String *str = (String *) ObjData(stro); 892 893 if (flags & DOH_REPLACE_FIRST) 894 count = 1; 895 896 if (flags & DOH_REPLACE_ID_END) { 897 return replace_simple(str, Char(token), Char(rep), flags, count, match_identifier_end); 898 } else if (flags & DOH_REPLACE_ID_BEGIN) { 899 return replace_simple(str, Char(token), Char(rep), flags, count, match_identifier_begin); 900 } else if (flags & DOH_REPLACE_ID) { 901 return replace_simple(str, Char(token), Char(rep), flags, count, match_identifier); 902 } else { 903 return replace_simple(str, Char(token), Char(rep), flags, count, match_simple); 904 } 905} 906 907/* ----------------------------------------------------------------------------- 908 * void String_chop(DOH *str) 909 * ----------------------------------------------------------------------------- */ 910 911static void String_chop(DOH *so) { 912 char *c; 913 String *str = (String *) ObjData(so); 914 /* Replace trailing whitespace */ 915 c = str->str + str->len - 1; 916 while ((str->len > 0) && (isspace((int) *c))) { 917 if (str->sp >= str->len) { 918 str->sp--; 919 if (*c == '\n') 920 str->line--; 921 } 922 str->len--; 923 c--; 924 } 925 str->str[str->len] = 0; 926 assert(str->sp >= 0); 927 str->hashkey = -1; 928} 929 930static void String_setfile(DOH *so, DOH *file) { 931 DOH *fo; 932 String *str = (String *) ObjData(so); 933 934 if (!DohCheck(file)) { 935 fo = NewString(file); 936 Decref(fo); 937 } else 938 fo = file; 939 Incref(fo); 940 Delete(str->file); 941 str->file = fo; 942} 943 944static DOH *String_getfile(DOH *so) { 945 String *str = (String *) ObjData(so); 946 return str->file; 947} 948 949static void String_setline(DOH *so, int line) { 950 String *str = (String *) ObjData(so); 951 str->line = line; 952} 953 954static int String_getline(DOH *so) { 955 String *str = (String *) ObjData(so); 956 return str->line; 957} 958 959static DohListMethods StringListMethods = { 960 0, /* doh_getitem */ 961 0, /* doh_setitem */ 962 String_delitem, /* doh_delitem */ 963 String_insert, /* doh_insitem */ 964 String_delslice, /* doh_delslice */ 965}; 966 967static DohFileMethods StringFileMethods = { 968 String_read, 969 String_write, 970 String_putc, 971 String_getc, 972 String_ungetc, 973 String_seek, 974 String_tell, 975 0, /* close */ 976}; 977 978static DohStringMethods StringStringMethods = { 979 String_replace, 980 String_chop, 981}; 982 983DohObjInfo DohStringType = { 984 "String", /* objname */ 985 DelString, /* doh_del */ 986 CopyString, /* doh_copy */ 987 String_clear, /* doh_clear */ 988 String_str, /* doh_str */ 989 String_data, /* doh_data */ 990 String_dump, /* doh_dump */ 991 String_len, /* doh_len */ 992 String_hash, /* doh_hash */ 993 String_cmp, /* doh_cmp */ 994 String_equal, /* doh_equal */ 995 0, /* doh_first */ 996 0, /* doh_next */ 997 String_setfile, /* doh_setfile */ 998 String_getfile, /* doh_getfile */ 999 String_setline, /* doh_setline */ 1000 String_getline, /* doh_getline */ 1001 0, /* doh_mapping */ 1002 &StringListMethods, /* doh_sequence */ 1003 &StringFileMethods, /* doh_file */ 1004 &StringStringMethods, /* doh_string */ 1005 0, /* doh_position */ 1006 0 1007}; 1008 1009 1010#define INIT_MAXSIZE 16 1011 1012/* ----------------------------------------------------------------------------- 1013 * NewString(const char *c) - Create a new string 1014 * ----------------------------------------------------------------------------- */ 1015 1016DOHString *DohNewString(const DOH *so) { 1017 int l = 0, max; 1018 String *str; 1019 char *s; 1020 int hashkey = -1; 1021 if (DohCheck(so)) { 1022 str = (String *) ObjData(so); 1023 s = (char *) String_data((String *) so); 1024 l = s ? str->len : 0; 1025 hashkey = str->hashkey; 1026 } else { 1027 s = (char *) so; 1028 l = s ? (int) strlen(s) : 0; 1029 } 1030 1031 str = (String *) DohMalloc(sizeof(String)); 1032 str->hashkey = hashkey; 1033 str->sp = 0; 1034 str->line = 1; 1035 str->file = 0; 1036 max = INIT_MAXSIZE; 1037 if (s) { 1038 if ((l + 1) > max) 1039 max = l + 1; 1040 } 1041 str->str = (char *) DohMalloc(max); 1042 str->maxsize = max; 1043 if (s) { 1044 strcpy(str->str, s); 1045 str->len = l; 1046 str->sp = l; 1047 } else { 1048 str->str[0] = 0; 1049 str->len = 0; 1050 } 1051 return DohObjMalloc(&DohStringType, str); 1052} 1053 1054 1055/* ----------------------------------------------------------------------------- 1056 * NewStringEmpty() - Create a new string 1057 * ----------------------------------------------------------------------------- */ 1058 1059DOHString *DohNewStringEmpty(void) { 1060 int max = INIT_MAXSIZE; 1061 String *str = (String *) DohMalloc(sizeof(String)); 1062 str->hashkey = 0; 1063 str->sp = 0; 1064 str->line = 1; 1065 str->file = 0; 1066 str->str = (char *) DohMalloc(max); 1067 str->maxsize = max; 1068 str->str[0] = 0; 1069 str->len = 0; 1070 return DohObjMalloc(&DohStringType, str); 1071} 1072 1073/* ----------------------------------------------------------------------------- 1074 * NewStringWithSize(const char *c, int len) - Create a new string 1075 * ----------------------------------------------------------------------------- */ 1076 1077DOHString *DohNewStringWithSize(const DOH *so, int len) { 1078 int l = 0, max; 1079 String *str; 1080 char *s; 1081 if (DohCheck(so)) { 1082 s = (char *) String_data((String *) so); 1083 } else { 1084 s = (char *) so; 1085 } 1086 1087 str = (String *) DohMalloc(sizeof(String)); 1088 str->hashkey = -1; 1089 str->sp = 0; 1090 str->line = 1; 1091 str->file = 0; 1092 max = INIT_MAXSIZE; 1093 if (s) { 1094 l = (int) len; 1095 if ((l + 1) > max) 1096 max = l + 1; 1097 } 1098 str->str = (char *) DohMalloc(max); 1099 str->maxsize = max; 1100 if (s) { 1101 strncpy(str->str, s, len); 1102 str->len = l; 1103 str->sp = l; 1104 } else { 1105 str->str[0] = 0; 1106 str->len = 0; 1107 } 1108 return DohObjMalloc(&DohStringType, str); 1109} 1110 1111/* ----------------------------------------------------------------------------- 1112 * NewStringf(DOH *fmt, ...) 1113 * 1114 * Create a new string from a list of objects. 1115 * ----------------------------------------------------------------------------- */ 1116 1117DOHString *DohNewStringf(const DOH *fmt, ...) { 1118 va_list ap; 1119 DOH *r; 1120 va_start(ap, fmt); 1121 r = NewStringEmpty(); 1122 DohvPrintf(r, Char(fmt), ap); 1123 va_end(ap); 1124 return (DOHString *) r; 1125} 1126 1127/* ----------------------------------------------------------------------------- 1128 * Strcmp() 1129 * Strncmp() 1130 * Strstr() 1131 * Strchr() 1132 * 1133 * Some utility functions. 1134 * ----------------------------------------------------------------------------- */ 1135 1136int DohStrcmp(const DOHString_or_char *s1, const DOHString_or_char *s2) { 1137 const char *c1 = Char(s1); 1138 const char *c2 = Char(s2); 1139 if (c1 && c2) { 1140 return strcmp(c1, c2); 1141 } else { 1142 return c1 < c2; 1143 } 1144} 1145 1146int DohStrncmp(const DOHString_or_char *s1, const DOHString_or_char *s2, int n) { 1147 return strncmp(Char(s1), Char(s2), n); 1148} 1149 1150char *DohStrstr(const DOHString_or_char *s1, const DOHString_or_char *s2) { 1151 char *p1 = Char(s1); 1152 char *p2 = Char(s2); 1153 return p1 == 0 || p2 == 0 || *p2 == '\0' ? p1 : strstr(p1, p2); 1154} 1155 1156char *DohStrchr(const DOHString_or_char *s1, int ch) { 1157 return strchr(Char(s1), ch); 1158} 1159