PageRenderTime 61ms CodeModel.GetById 24ms app.highlight 31ms RepoModel.GetById 0ms app.codeStats 0ms

/tags/rel-1-3-25/SWIG/Source/DOH/string.c

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