/* Implementation of TLMutableString class.
   This file is part of TL, Tiggr's Library.
   Written by Tiggr <tiggr@es.ele.tue.nl>
   Copyright (C) 1995, 1996 Pieter J. Schoenmakers
   TL is distributed WITHOUT ANY WARRANTY.
   See the file LICENSE in the TL distribution for details.

   $Id: TLMutableString.m,v 1.3 1998/05/12 20:03:32 tiggr Exp $  */

#import "tl/support.h"
#import "tl/TLMutableString.h"
#import "tl/TLVector.h"
#import "tl/TLStringStream.h"
#import "tl/TLPatchedRoots.h"
#import "tl/TLNumber.h"
#import <string.h>

#define GROW(NEEDED)  \
  do									\
    {									\
      if (cap < len + (NEEDED) + 1)					\
	{								\
	  cap = len + (NEEDED) + 1;					\
	  c_string = xrealloc (c_string, cap * sizeof (*c_string));	\
	}								\
    } while (0)

@implementation TLMutableString

+(TLMutableString *) mutableString
{
  return ([[self gcAlloc] init]);
} /* +mutableString */

+(TLMutableString *) mutableStringWithCapacity: (int) c
{
  return [[self gcAlloc] initWithCapacity: c];
} /* +mutableStringWithCapacity: */

+(TLMutableString *) mutableStringWithFormatVector: (TLVector *) vector
{
  return ([[self gcAlloc] initWithFormatVector: vector]);
} /* +mutableStringWithFormatVector: */

-(int) _appendByReading: (int) max fromStream: (id <TLInputStream>) stream
{
  int n;

  GROW (max + 1);

  n = [stream readBytes: max intoBuffer: c_string + len];
  if (n > 0)
    {
      len += n;
      c_string[len] = 0;
    }
  return (n);
} /* -_appendByReading:fromStream: */

-(id <TLNumber>) appendByReading: (id <TLNumber>) max
 fromStream: (id <TLInputStream>) stream
{
  int n = [self _appendByReading: [max integerPIntValue] fromStream: stream];
  return (n >= 0 ? [CO_TLNumber numberWithInt: n] : nil);
} /* -appendByReading:fromStream: */

-(int) appendCChar: (int) c
{
  GROW (1);
  c_string[len++] = c;
  c_string[len] = 0;
  return (1);
} /* -appendCChar: */

-(int) appendCString: (const char *) s
{
  return ([self appendCString: s length: strlen (s)]);
} /* -appendCString: */

-(int) appendCString: (const char *) s length: (int) l
{
  GROW (l);
  memcpy (c_string + len, s, l);
  len += l;
  c_string[len] = 0;
  return (l);
} /* -appendCString:length: */

-appendFormatVector: (TLVector *) v
{
  id <TLString> format = [v _elementAtIndex: 0];
  va_list ap;
  memset (&ap, 0, sizeof (ap));
  [v removeElementsFromIndex: 0 range: 1];
  llvformac (self, format, ap, v);
  return (self);
}

-initWithCapacity: (int) c
{
  GROW (c - 1);
  return self;
} /* -initWithCapacity: */

-initWithFormatVector: (TLVector *) v
{
  [self appendFormatVector: v];
  return (self);
} /* -initWithFormatVector: */

-(id <TLMutableStream>) mutableStream
{
  return ([TLStringStream mutableStreamWithString: self]);
} /* -stream */

-(id) removeRange: (id <TLRange>) r
{
  int start, length;

  start = [r _start];

  /* XXX Is this a good idea?  */
  if (start < 0)
    start = len + start;

  if (start > len)
    return (nil);

  length = [r length];
  if (length < 0)
    length = len - start;

  if (start < 0)
    length += start, start = 0;
  if (start + length > len)
    length = len - start;

  if (start + length == len)
    len = start;
  else
    {
      memmove (c_string + start, c_string + start + length, len - length);
      len -= length;
    }
  return (self);
} /* -removeRange: */

/******************** TLStream ********************/

-close
{
  return (self);
} /* -close */

-(int) fileDescriptor
{
  return (-1);
} /* -fileDescriptor */

-streamp
{
  return (self);
} /* -streamp */

/******************** TLOutputStream ********************/

-flushOutput
{
  /* Don't do this.  It causes invocations of realloc which we do not
     desire.  */
#if 0
  if (c_string)
    {
      /* Leave room for the trailing `\0'.  */
      cap = len + 1;
      /* Is this desirable?  */
      c_string = xrealloc (c_string, cap);
    }
#endif
  return (self);
} /* -flushOutput */

-(int) writeByte: (char) c
{
  GROW (1);
  c_string[len++] = c;
  c_string[len] = 0;
  return (1);
} /* -writeByte: */

-(int) writeBytes: (int) l fromBuffer: (const char *) s
{
  GROW (l);
  memcpy (c_string + len, s, l);
  len += l;
  c_string[len] = 0;
  return (l);
} /* -writeBytes:fromBuffer: */

@end
