PageRenderTime 79ms CodeModel.GetById 17ms app.highlight 53ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/Source/DOH/string.c

#
C | 1175 lines | 924 code | 120 blank | 131 comment | 252 complexity | e62fcf78d11ca6968a9bd310f10b971b MD5 | raw file
   1/* -----------------------------------------------------------------------------
   2 * This file is part of SWIG, which is licensed as a whole under version 3 
   3 * (or any later version) of the GNU General Public License. Some additional
   4 * terms also apply to certain portions of SWIG. The full details of the SWIG
   5 * license and copyrights can be found in the LICENSE and COPYRIGHT files
   6 * included with the SWIG source code as distributed by the SWIG developers
   7 * and at http://www.swig.org/legal.html.
   8 *
   9 * string.c
  10 *
  11 *     Implements a string object that supports both sequence operations and
  12 *     file semantics.
  13 * ----------------------------------------------------------------------------- */
  14
  15char cvsroot_string_c[] = "$Id: string.c 12849 2011-11-28 19:35:44Z wsfulton $";
  16
  17#include "dohint.h"
  18
  19extern DohObjInfo DohStringType;
  20
  21typedef struct String {
  22  DOH *file;
  23  int line;
  24  int maxsize;			/* Max size allocated */
  25  int len;			/* Current length     */
  26  int hashkey;			/* Hash key value     */
  27  int sp;			/* Current position   */
  28  char *str;			/* String data        */
  29} String;
  30
  31/* -----------------------------------------------------------------------------
  32 * String_data() - Return as a 'void *'
  33 * ----------------------------------------------------------------------------- */
  34
  35static void *String_data(DOH *so) {
  36  String *s = (String *) ObjData(so);
  37  s->str[s->len] = 0;
  38  return (void *) s->str;
  39}
  40
  41/* static char *String_char(DOH *so) {
  42  return (char *) String_data(so);
  43}
  44*/
  45
  46/* -----------------------------------------------------------------------------
  47 * String_dump() - Serialize a string onto out
  48 * ----------------------------------------------------------------------------- */
  49
  50static int String_dump(DOH *so, DOH *out) {
  51  int nsent;
  52  int ret;
  53  String *s = (String *) ObjData(so);
  54  nsent = 0;
  55  while (nsent < s->len) {
  56    ret = Write(out, s->str + nsent, (s->len - nsent));
  57    if (ret < 0)
  58      return ret;
  59    nsent += ret;
  60  }
  61  return nsent;
  62}
  63
  64/* -----------------------------------------------------------------------------
  65 * CopyString() - Copy a string
  66 * ----------------------------------------------------------------------------- */
  67
  68static DOH *CopyString(DOH *so) {
  69  String *str;
  70  String *s = (String *) ObjData(so);
  71  str = (String *) DohMalloc(sizeof(String));
  72  str->hashkey = s->hashkey;
  73  str->sp = s->sp;
  74  str->line = s->line;
  75  str->file = s->file;
  76  if (str->file)
  77    Incref(str->file);
  78  str->str = (char *) DohMalloc(s->len + 1);
  79  memcpy(str->str, s->str, s->len);
  80  str->maxsize = s->len;
  81  str->len = s->len;
  82  str->str[str->len] = 0;
  83
  84  return DohObjMalloc(&DohStringType, str);
  85}
  86
  87/* -----------------------------------------------------------------------------
  88 * DelString() - Delete a string
  89 * ----------------------------------------------------------------------------- */
  90
  91static void DelString(DOH *so) {
  92  String *s = (String *) ObjData(so);
  93  DohFree(s->str);
  94  DohFree(s);
  95}
  96
  97/* -----------------------------------------------------------------------------
  98 * DohString_len() - Length of a string
  99 * ----------------------------------------------------------------------------- */
 100
 101static int String_len(DOH *so) {
 102  String *s = (String *) ObjData(so);
 103  return s->len;
 104}
 105
 106
 107/* -----------------------------------------------------------------------------
 108 * String_cmp() - Compare two strings
 109 * ----------------------------------------------------------------------------- */
 110
 111static int String_cmp(DOH *so1, DOH *so2) {
 112  String *s1, *s2;
 113  char *c1, *c2;
 114  int maxlen, i;
 115  s1 = (String *) ObjData(so1);
 116  s2 = (String *) ObjData(so2);
 117  maxlen = s1->len;
 118  if (s2->len < maxlen)
 119    maxlen = s2->len;
 120  c1 = s1->str;
 121  c2 = s2->str;
 122  for (i = maxlen; i; --i, c1++, c2++) {
 123    if (*c1 != *c2)
 124      break;
 125  }
 126  if (i != 0) {
 127    if (*c1 < *c2)
 128      return -1;
 129    else
 130      return 1;
 131  }
 132  if (s1->len == s2->len)
 133    return 0;
 134  if (s1->len > s2->len)
 135    return 1;
 136  return -1;
 137}
 138
 139/* -----------------------------------------------------------------------------
 140 * String_equal() - Say if two string are equal
 141 * ----------------------------------------------------------------------------- */
 142
 143static int String_equal(DOH *so1, DOH *so2) {
 144  String *s1 = (String *) ObjData(so1);
 145  String *s2 = (String *) ObjData(so2);
 146  register int len = s1->len;
 147  if (len != s2->len) {
 148    return 0;
 149  } else {
 150    register char *c1 = s1->str;
 151    register char *c2 = s2->str;
 152#if 0
 153    register int mlen = len >> 2;
 154    register int i = mlen;
 155    for (; i; --i) {
 156      if (*(c1++) != *(c2++))
 157	return 0;
 158      if (*(c1++) != *(c2++))
 159	return 0;
 160      if (*(c1++) != *(c2++))
 161	return 0;
 162      if (*(c1++) != *(c2++))
 163	return 0;
 164    }
 165    for (i = len - (mlen << 2); i; --i) {
 166      if (*(c1++) != *(c2++))
 167	return 0;
 168    }
 169    return 1;
 170#else
 171    return memcmp(c1, c2, len) == 0;
 172#endif
 173  }
 174}
 175
 176/* -----------------------------------------------------------------------------
 177 * String_hash() - Compute string hash value
 178 * ----------------------------------------------------------------------------- */
 179
 180static int String_hash(DOH *so) {
 181  String *s = (String *) ObjData(so);
 182  if (s->hashkey >= 0) {
 183    return s->hashkey;
 184  } else {
 185    register char *c = s->str;
 186    register int len = s->len > 50 ? 50 : s->len;
 187    register int h = 0;
 188    register int mlen = len >> 2;
 189    register int i = mlen;
 190    for (; i; --i) {
 191      h = (h << 5) + *(c++);
 192      h = (h << 5) + *(c++);
 193      h = (h << 5) + *(c++);
 194      h = (h << 5) + *(c++);
 195    }
 196    for (i = len - (mlen << 2); i; --i) {
 197      h = (h << 5) + *(c++);
 198    }
 199    h &= 0x7fffffff;
 200    s->hashkey = h;
 201    return h;
 202  }
 203}
 204
 205/* -----------------------------------------------------------------------------
 206 * DohString_append() - Append to s
 207 * ----------------------------------------------------------------------------- */
 208
 209static void DohString_append(DOH *so, const DOHString_or_char *str) {
 210  int oldlen, newlen, newmaxsize, l, sp;
 211  char *tc;
 212  String *s = (String *) ObjData(so);
 213  char *newstr = 0;
 214
 215  if (DohCheck(str)) {
 216    String *ss = (String *) ObjData(str);
 217    newstr = (char *) String_data((DOH *) str);
 218    l = ss->len;
 219  } else {
 220    newstr = (char *) (str);
 221    l = (int) strlen(newstr);
 222  }
 223  if (!newstr)
 224    return;
 225  s->hashkey = -1;
 226
 227  oldlen = s->len;
 228  newlen = oldlen + l + 1;
 229  if (newlen >= s->maxsize - 1) {
 230    newmaxsize = 2 * s->maxsize;
 231    if (newlen >= newmaxsize - 1)
 232      newmaxsize = newlen + 1;
 233    s->str = (char *) DohRealloc(s->str, newmaxsize);
 234    assert(s->str);
 235    s->maxsize = newmaxsize;
 236  }
 237  tc = s->str;
 238  memcpy(tc + oldlen, newstr, l + 1);
 239  sp = s->sp;
 240  if (sp >= oldlen) {
 241    int i = oldlen + l - sp;
 242    tc += sp;
 243    for (; i; --i) {
 244      if (*(tc++) == '\n')
 245	s->line++;
 246    }
 247    s->sp = oldlen + l;
 248  }
 249  s->len += l;
 250}
 251
 252
 253/* -----------------------------------------------------------------------------
 254 * String_clear() - Clear a string
 255 * ----------------------------------------------------------------------------- */
 256
 257static void String_clear(DOH *so) {
 258  String *s = (String *) ObjData(so);
 259  s->hashkey = -1;
 260  s->len = 0;
 261  *(s->str) = 0;
 262  s->sp = 0;
 263  s->line = 1;
 264}
 265
 266/* -----------------------------------------------------------------------------
 267 * String_insert() - Insert a string
 268 * ----------------------------------------------------------------------------- */
 269
 270static int String_insert(DOH *so, int pos, DOH *str) {
 271  String *s;
 272  int len;
 273  char *data;
 274
 275  if (pos == DOH_END) {
 276    DohString_append(so, str);
 277    return 0;
 278  }
 279
 280
 281  s = (String *) ObjData(so);
 282  s->hashkey = -1;
 283  if (DohCheck(str)) {
 284    String *ss = (String *) ObjData(str);
 285    data = (char *) String_data(str);
 286    len = ss->len;
 287  } else {
 288    data = (char *) (str);
 289    len = (int) strlen(data);
 290  }
 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 * 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 * 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 * 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 * 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 * String_write() - Write data to a string
 419 * ----------------------------------------------------------------------------- */
 420static int String_write(DOH *so, const 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 * 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 * 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 * 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 * 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 * 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
 570static char *end_quote(char *s) {
 571  char *qs;
 572  char qc;
 573  char *q;
 574  char *nl;
 575  qc = *s;
 576  qs = s;
 577  while (1) {
 578    q = strpbrk(s + 1, "\"\'");
 579    nl = strchr(s + 1, '\n');
 580    if (nl && (nl < q)) {
 581      /* A new line appears before the end of the string */
 582      if (*(nl - 1) == '\\') {
 583	s = nl + 1;
 584	continue;
 585      }
 586      /* String was terminated by a newline.  Wing it */
 587      return qs;
 588    }
 589    if (!q && nl) {
 590      return qs;
 591    }
 592    if (!q)
 593      return 0;
 594    if ((*q == qc) && (*(q - 1) != '\\'))
 595      return q;
 596    s = q;
 597  }
 598}
 599
 600static char *match_simple(char *base, char *s, char *token, int tokenlen) {
 601  (void) base;
 602  (void) tokenlen;
 603  return strstr(s, token);
 604}
 605
 606static char *match_identifier(char *base, char *s, char *token, int tokenlen) {
 607  while (s) {
 608    s = strstr(s, token);
 609    if (!s)
 610      return 0;
 611    if ((s > base) && (isalnum((int) *(s - 1)) || (*(s - 1) == '_'))) {
 612      s += tokenlen;
 613      continue;
 614    }
 615    if (isalnum((int) *(s + tokenlen)) || (*(s + tokenlen) == '_')) {
 616      s += tokenlen;
 617      continue;
 618    }
 619    return s;
 620  }
 621  return 0;
 622}
 623
 624
 625static char *match_identifier_begin(char *base, char *s, char *token, int tokenlen) {
 626  while (s) {
 627    s = strstr(s, token);
 628    if (!s)
 629      return 0;
 630    if ((s > base) && (isalnum((int) *(s - 1)) || (*(s - 1) == '_'))) {
 631      s += tokenlen;
 632      continue;
 633    }
 634    return s;
 635  }
 636  return 0;
 637}
 638
 639static char *match_identifier_end(char *base, char *s, char *token, int tokenlen) {
 640  (void) base;
 641  while (s) {
 642    s = strstr(s, token);
 643    if (!s)
 644      return 0;
 645    if (isalnum((int) *(s + tokenlen)) || (*(s + tokenlen) == '_')) {
 646      s += tokenlen;
 647      continue;
 648    }
 649    return s;
 650  }
 651  return 0;
 652}
 653
 654static char *match_number_end(char *base, char *s, char *token, int tokenlen) {
 655  (void) base;
 656  while (s) {
 657    s = strstr(s, token);
 658    if (!s)
 659      return 0;
 660    if (isdigit((int) *(s + tokenlen))) {
 661      s += tokenlen;
 662      continue;
 663    }
 664    return s;
 665  }
 666  return 0;
 667}
 668
 669/* -----------------------------------------------------------------------------
 670 * replace_simple()
 671 *
 672 * Replaces count non-overlapping occurrences of token with rep in a string.   
 673 * ----------------------------------------------------------------------------- */
 674
 675static int replace_simple(String *str, char *token, char *rep, int flags, int count, char *(*match) (char *, char *, char *, int)) {
 676  int tokenlen;			/* Length of the token */
 677  int replen;			/* Length of the replacement */
 678  int delta, expand = 0;
 679  int ic;
 680  int rcount = 0;
 681  int noquote = 0;
 682  char *c, *s, *t, *first;
 683  char *q, *q2;
 684  register char *base;
 685  int i;
 686
 687  /* Figure out if anything gets replaced */
 688  if (!strlen(token))
 689    return 0;
 690
 691  base = str->str;
 692  tokenlen = strlen(token);
 693  s = (*match) (base, base, token, tokenlen);
 694
 695  if (!s)
 696    return 0;			/* No matches.  Who cares */
 697
 698  str->hashkey = -1;
 699
 700  if (flags & DOH_REPLACE_NOQUOTE)
 701    noquote = 1;
 702
 703  /* If we are not replacing inside quotes, we need to do a little extra work */
 704  if (noquote) {
 705    q = strpbrk(base, "\"\'");
 706    if (!q) {
 707      noquote = 0;		/* Well, no quotes to worry about. Oh well */
 708    } else {
 709      while (q && (q < s)) {
 710	/* First match was found inside a quote.  Try to find another match */
 711	q2 = end_quote(q);
 712	if (!q2) {
 713	  return 0;
 714	}
 715	if (q2 > s) {
 716	  /* Find next match */
 717	  s = (*match) (base, q2 + 1, token, tokenlen);
 718	}
 719	if (!s)
 720	  return 0;		/* Oh well, no matches */
 721	q = strpbrk(q2 + 1, "\"\'");
 722	if (!q)
 723	  noquote = 0;		/* No more quotes */
 724      }
 725    }
 726  }
 727
 728  first = s;
 729  replen = strlen(rep);
 730
 731  delta = (replen - tokenlen);
 732
 733  if (delta <= 0) {
 734    /* String is either shrinking or staying the same size */
 735    /* In this case, we do the replacement in place without memory reallocation */
 736    ic = count;
 737    t = s;			/* Target of memory copies */
 738    while (ic && s) {
 739      if (replen) {
 740	memcpy(t, rep, replen);
 741	t += replen;
 742      }
 743      rcount++;
 744      expand += delta;
 745      /* Find the next location */
 746      s += tokenlen;
 747      if (ic == 1)
 748	break;
 749      c = (*match) (base, s, token, tokenlen);
 750
 751      if (noquote) {
 752	q = strpbrk(s, "\"\'");
 753	if (!q) {
 754	  noquote = 0;
 755	} else {
 756	  while (q && (q < c)) {
 757	    /* First match was found inside a quote.  Try to find another match */
 758	    q2 = end_quote(q);
 759	    if (!q2) {
 760	      c = 0;
 761	      break;
 762	    }
 763	    if (q2 > c)
 764	      c = (*match) (base, q2 + 1, token, tokenlen);
 765	    if (!c)
 766	      break;
 767	    q = strpbrk(q2 + 1, "\"\'");
 768	    if (!q)
 769	      noquote = 0;	/* No more quotes */
 770	  }
 771	}
 772      }
 773      if (delta) {
 774	if (c) {
 775	  memmove(t, s, c - s);
 776	  t += (c - s);
 777	} else {
 778	  memmove(t, s, (str->str + str->len) - s + 1);
 779	}
 780      } else {
 781	t += (c - s);
 782      }
 783      s = c;
 784      ic--;
 785    }
 786    if (s && delta) {
 787      memmove(t, s, (str->str + str->len) - s + 1);
 788    }
 789    str->len += expand;
 790    str->str[str->len] = 0;
 791    if (str->sp >= str->len)
 792      str->sp += expand;	/* Fix the end of file pointer */
 793    return rcount;
 794  }
 795  /* The string is expanding as a result of the replacement */
 796  /* Figure out how much expansion is going to occur and allocate a new string */
 797  {
 798    char *ns;
 799    int newsize;
 800
 801    rcount++;
 802    ic = count - 1;
 803    s += tokenlen;
 804    while (ic && (c = (*match) (base, s, token, tokenlen))) {
 805      if (noquote) {
 806	q = strpbrk(s, "\"\'");
 807	if (!q) {
 808	  break;
 809	} else {
 810	  while (q && (q < c)) {
 811	    /* First match was found inside a quote.  Try to find another match */
 812	    q2 = end_quote(q);
 813	    if (!q2) {
 814	      c = 0;
 815	      break;
 816	    }
 817	    if (q2 > c) {
 818	      c = (*match) (base, q2 + 1, token, tokenlen);
 819	      if (!c)
 820		break;
 821	    }
 822	    q = strpbrk(q2 + 1, "\"\'");
 823	    if (!q)
 824	      noquote = 0;
 825	  }
 826	}
 827      }
 828      if (c) {
 829	rcount++;
 830	ic--;
 831	s = c + tokenlen;
 832      } else {
 833	break;
 834      }
 835    }
 836
 837    expand = delta * rcount;	/* Total amount of expansion for the replacement */
 838    newsize = str->maxsize;
 839    while ((str->len + expand) >= newsize)
 840      newsize *= 2;
 841
 842    ns = (char *) DohMalloc(newsize);
 843    assert(ns);
 844    t = ns;
 845    s = first;
 846
 847    /* Copy the first part of the string */
 848    if (first > str->str) {
 849      memcpy(t, str->str, (first - str->str));
 850      t += (first - str->str);
 851    }
 852    for (i = 0; i < rcount; i++) {
 853      memcpy(t, rep, replen);
 854      t += replen;
 855      s += tokenlen;
 856      c = (*match) (base, s, token, tokenlen);
 857      if (noquote) {
 858	q = strpbrk(s, "\"\'");
 859	if (!q) {
 860	  noquote = 0;
 861	} else {
 862	  while (q && (q < c)) {
 863	    /* First match was found inside a quote.  Try to find another match */
 864	    q2 = end_quote(q);
 865	    if (!q2) {
 866	      c = 0;
 867	      break;
 868	    }
 869	    if (q2 > c) {
 870	      c = (*match) (base, q2 + 1, token, tokenlen);
 871	      if (!c)
 872		break;
 873	    }
 874	    q = strpbrk(q2 + 1, "\"\'");
 875	    if (!q)
 876	      noquote = 0;	/* No more quotes */
 877	  }
 878	}
 879      }
 880      if (i < (rcount - 1)) {
 881	memcpy(t, s, c - s);
 882	t += (c - s);
 883      } else {
 884	memcpy(t, s, (str->str + str->len) - s + 1);
 885      }
 886      s = c;
 887    }
 888    c = str->str;
 889    str->str = ns;
 890    if (str->sp >= str->len)
 891      str->sp += expand;
 892    str->len += expand;
 893    str->str[str->len] = 0;
 894    str->maxsize = newsize;
 895    DohFree(c);
 896    return rcount;
 897  }
 898}
 899
 900/* -----------------------------------------------------------------------------
 901 * String_replace()
 902 * ----------------------------------------------------------------------------- */
 903
 904static int String_replace(DOH *stro, const DOHString_or_char *token, const DOHString_or_char *rep, int flags) {
 905  int count = -1;
 906  String *str = (String *) ObjData(stro);
 907
 908  if (flags & DOH_REPLACE_FIRST)
 909    count = 1;
 910
 911  if (flags & DOH_REPLACE_ID_END) {
 912    return replace_simple(str, Char(token), Char(rep), flags, count, match_identifier_end);
 913  } else if (flags & DOH_REPLACE_ID_BEGIN) {
 914    return replace_simple(str, Char(token), Char(rep), flags, count, match_identifier_begin);
 915  } else if (flags & DOH_REPLACE_ID) {
 916    return replace_simple(str, Char(token), Char(rep), flags, count, match_identifier);
 917  } else if (flags & DOH_REPLACE_NUMBER_END) {
 918    return replace_simple(str, Char(token), Char(rep), flags, count, match_number_end);
 919  } else {
 920    return replace_simple(str, Char(token), Char(rep), flags, count, match_simple);
 921  }
 922}
 923
 924/* -----------------------------------------------------------------------------
 925 * String_chop()
 926 * ----------------------------------------------------------------------------- */
 927
 928static void String_chop(DOH *so) {
 929  char *c;
 930  String *str = (String *) ObjData(so);
 931  /* Replace trailing whitespace */
 932  c = str->str + str->len - 1;
 933  while ((str->len > 0) && (isspace((int) *c))) {
 934    if (str->sp >= str->len) {
 935      str->sp--;
 936      if (*c == '\n')
 937	str->line--;
 938    }
 939    str->len--;
 940    c--;
 941  }
 942  str->str[str->len] = 0;
 943  assert(str->sp >= 0);
 944  str->hashkey = -1;
 945}
 946
 947static void String_setfile(DOH *so, DOH *file) {
 948  DOH *fo;
 949  String *str = (String *) ObjData(so);
 950
 951  if (!DohCheck(file)) {
 952    fo = NewString(file);
 953    Decref(fo);
 954  } else
 955    fo = file;
 956  Incref(fo);
 957  Delete(str->file);
 958  str->file = fo;
 959}
 960
 961static DOH *String_getfile(DOH *so) {
 962  String *str = (String *) ObjData(so);
 963  return str->file;
 964}
 965
 966static void String_setline(DOH *so, int line) {
 967  String *str = (String *) ObjData(so);
 968  str->line = line;
 969}
 970
 971static int String_getline(DOH *so) {
 972  String *str = (String *) ObjData(so);
 973  return str->line;
 974}
 975
 976static DohListMethods StringListMethods = {
 977  0,				/* doh_getitem */
 978  0,				/* doh_setitem */
 979  String_delitem,		/* doh_delitem */
 980  String_insert,		/* doh_insitem */
 981  String_delslice,		/* doh_delslice */
 982};
 983
 984static DohFileMethods StringFileMethods = {
 985  String_read,
 986  String_write,
 987  String_putc,
 988  String_getc,
 989  String_ungetc,
 990  String_seek,
 991  String_tell,
 992  0,				/* close */
 993};
 994
 995static DohStringMethods StringStringMethods = {
 996  String_replace,
 997  String_chop,
 998};
 999
1000DohObjInfo DohStringType = {
1001  "String",			/* objname */
1002  DelString,			/* doh_del */
1003  CopyString,			/* doh_copy */
1004  String_clear,			/* doh_clear */
1005  String_str,			/* doh_str */
1006  String_data,			/* doh_data */
1007  String_dump,			/* doh_dump */
1008  String_len,	    	        /* doh_len */
1009  String_hash,			/* doh_hash    */
1010  String_cmp,			/* doh_cmp */
1011  String_equal,	    	        /* doh_equal */
1012  0,				/* doh_first    */
1013  0,				/* doh_next     */
1014  String_setfile,		/* doh_setfile */
1015  String_getfile,		/* doh_getfile */
1016  String_setline,		/* doh_setline */
1017  String_getline,		/* doh_getline */
1018  0,				/* doh_mapping */
1019  &StringListMethods,		/* doh_sequence */
1020  &StringFileMethods,		/* doh_file */
1021  &StringStringMethods,		/* doh_string */
1022  0,				/* doh_position */
1023  0
1024};
1025
1026
1027#define INIT_MAXSIZE  16
1028
1029/* -----------------------------------------------------------------------------
1030 * NewString() - Create a new string
1031 * ----------------------------------------------------------------------------- */
1032
1033DOHString *DohNewString(const DOHString_or_char *so) {
1034  int l = 0, max;
1035  String *str;
1036  char *s;
1037  int hashkey = -1;
1038  if (DohCheck(so)) {
1039    str = (String *) ObjData(so);
1040    s = (char *) String_data((String *) so);
1041    l = s ? str->len : 0;
1042    hashkey = str->hashkey;
1043  } else {
1044    s = (char *) so;
1045    l = s ? (int) strlen(s) : 0;
1046  }
1047
1048  str = (String *) DohMalloc(sizeof(String));
1049  str->hashkey = hashkey;
1050  str->sp = 0;
1051  str->line = 1;
1052  str->file = 0;
1053  max = INIT_MAXSIZE;
1054  if (s) {
1055    if ((l + 1) > max)
1056      max = l + 1;
1057  }
1058  str->str = (char *) DohMalloc(max);
1059  str->maxsize = max;
1060  if (s) {
1061    strcpy(str->str, s);
1062    str->len = l;
1063    str->sp = l;
1064  } else {
1065    str->str[0] = 0;
1066    str->len = 0;
1067  }
1068  return DohObjMalloc(&DohStringType, str);
1069}
1070
1071
1072/* -----------------------------------------------------------------------------
1073 * NewStringEmpty() - Create a new string
1074 * ----------------------------------------------------------------------------- */
1075
1076DOHString *DohNewStringEmpty(void) {
1077  int max = INIT_MAXSIZE;
1078  String *str = (String *) DohMalloc(sizeof(String));
1079  str->hashkey = 0;
1080  str->sp = 0;
1081  str->line = 1;
1082  str->file = 0;
1083  str->str = (char *) DohMalloc(max);
1084  str->maxsize = max;
1085  str->str[0] = 0;
1086  str->len = 0;
1087  return DohObjMalloc(&DohStringType, str);
1088}
1089
1090/* -----------------------------------------------------------------------------
1091 * NewStringWithSize() - Create a new string
1092 * ----------------------------------------------------------------------------- */
1093
1094DOHString *DohNewStringWithSize(const DOHString_or_char *so, int len) {
1095  int l = 0, max;
1096  String *str;
1097  char *s;
1098  if (DohCheck(so)) {
1099    s = (char *) String_data((String *) so);
1100  } else {
1101    s = (char *) so;
1102  }
1103
1104  str = (String *) DohMalloc(sizeof(String));
1105  str->hashkey = -1;
1106  str->sp = 0;
1107  str->line = 1;
1108  str->file = 0;
1109  max = INIT_MAXSIZE;
1110  if (s) {
1111    l = (int) len;
1112    if ((l + 1) > max)
1113      max = l + 1;
1114  }
1115  str->str = (char *) DohMalloc(max);
1116  str->maxsize = max;
1117  if (s) {
1118    strncpy(str->str, s, len);
1119    str->len = l;
1120    str->sp = l;
1121  } else {
1122    str->str[0] = 0;
1123    str->len = 0;
1124  }
1125  return DohObjMalloc(&DohStringType, str);
1126}
1127
1128/* -----------------------------------------------------------------------------
1129 * NewStringf()
1130 *
1131 * Create a new string from a list of objects.
1132 * ----------------------------------------------------------------------------- */
1133
1134DOHString *DohNewStringf(const DOHString_or_char *fmt, ...) {
1135  va_list ap;
1136  DOH *r;
1137  va_start(ap, fmt);
1138  r = NewStringEmpty();
1139  DohvPrintf(r, Char(fmt), ap);
1140  va_end(ap);
1141  return (DOHString *) r;
1142}
1143
1144/* -----------------------------------------------------------------------------
1145 * Strcmp()
1146 * Strncmp()
1147 * Strstr()
1148 * Strchr()
1149 *
1150 * Some utility functions.
1151 * ----------------------------------------------------------------------------- */
1152
1153int DohStrcmp(const DOHString_or_char *s1, const DOHString_or_char *s2) {
1154  const char *c1 = Char(s1);
1155  const char *c2 = Char(s2);
1156  if (c1 && c2) {
1157    return strcmp(c1, c2);
1158  } else {
1159    return c1 < c2;
1160  }
1161}
1162
1163int DohStrncmp(const DOHString_or_char *s1, const DOHString_or_char *s2, int n) {
1164  return strncmp(Char(s1), Char(s2), n);
1165}
1166
1167char *DohStrstr(const DOHString_or_char *s1, const DOHString_or_char *s2) {
1168  char *p1 = Char(s1);
1169  char *p2 = Char(s2);
1170  return p1 == 0 || p2 == 0 || *p2 == '\0' ? p1 : strstr(p1, p2);
1171}
1172
1173char *DohStrchr(const DOHString_or_char *s1, int ch) {
1174  return strchr(Char(s1), ch);
1175}