/* -*-C-*-
*******************************************************************************
*
* File:         SimpleString.m
* RCS:          /usr/local/sources/CVS/EnhanceMail/SimpleString.m,v 1.6 1997/11/15 16:56:40 tom Exp
* Description:  
* Author:       Carl Edman
* Created:      Tue Oct 17 23:45:45 1995
* Modified:     Sat Jun 22 19:10:45 1996 (Carl Edman) cedman@capitalist.princeton.edu
* Language:     C
* Package:      N/A
* Status:       Experimental (Do Not Distribute)
*
* (C) Copyright 1995, but otherwise this file is perfect freeware.
*
*******************************************************************************
*/

#import "SimpleString.h"
#import "EnhanceMail.h"

#define START 64

#define BYTE_LENGTH(self)  (self->cur - self->data)
#define MUSTGROW(self,len) (self->cur+(len)>=self->data+malloc_size(self->data))


@implementation SimpleString

- init
{
   [super init];
   cur=data=NXZoneMalloc([self zone],START);
   *cur='\0';
   return self;
}

- free
{
   free(data);
   return [super free];
}

- grow:(int)by
{
   int pos = cur-data;
   int size = malloc_size(data);

   do { size *= 2; } while (pos+by >= size);
   data=NXZoneRealloc([self zone],data,size);
   cur=data+pos;
   return self;
}

- grow
{
   return [self grow:0];
}

- (char *)string
{
   return data;
}

- (int)length
{
   return BYTE_LENGTH(self);
}

#define iskanji(c) (c & 0x80)

- (int)textLength
{
   if (EnhanceUseKanji())
   {
      char *c=data;
      int length=0;
      const int byte_per_mbchar=2;

      while (c<cur)
      {
	    if (iskanji(*c)) c+=byte_per_mbchar; else c++;
	    length++;
      }
      return length;
   }
   return BYTE_LENGTH(self);
}

- empty
{
   cur=data;
   *cur='\0';
   return self;
}

- (int)appendChar:(char)c
{
   if (MUSTGROW(self,1)) [self grow:1];
   *cur++=c;
   *cur='\0';
   return cur-data;
}

- (int)appendString:(const char *)str
{
   return [self appendString:str length:strlen(str)];
}

- (int)appendString:(const char *)str length:(int)len
{
   if (MUSTGROW(self,len)) [self grow:len];
   while(len>0) { *cur++=*str++; len--; }
   *cur='\0';
   return cur-data;
}

- (int)appendStream:(NXStream *)s
{
   int c;
   
   while ((c=NXRead(s,cur,data+malloc_size(data)-cur))>0)
   {
      cur+=c;
      if (MUSTGROW(self,0)) [self grow];
   }
   
   *cur='\0';
   return cur-data;
}

- (int)appendFile:(int)fd
{
   int c;
   
   while ((c=read(fd,cur,data+malloc_size(data)-cur))>0)
   {
      cur+=c;
      if (MUSTGROW(self,0)) [self grow];
   }
   
   *cur='\0';
   return cur-data;
}

- (int)writeFile:(int)fd
{
   char *pos;
   int c;

   for(pos=data;pos<cur;)
   {
      c=write(fd,pos,cur-pos);
      if (c<0) return c;
      pos+=c;
   }
   
   return cur-data;
}

- (int)appendSimpleString:(id)sstr
{
   return [self appendString:[sstr string] length:[sstr length]];
}

- (int)appendAndFreeSimpleString:(id)sstr
{
   int ret = [self appendSimpleString:sstr];
   [sstr free];
   return ret;
}

- (int)insertString:(const char *)str
{
   return [self insertString:str length:strlen(str) at:0];
}

- (int)insertString:(const char *)str length:(int)len
{
   return [self insertString:str length:len at:0];
}

- (int)insertString:(const char *)str length:(int)len at:(int)pos
{
   char *p, *d;
   const char *s;

   if (MUSTGROW(self,len)) [self grow:len];
   if (pos < 0) p = data;
   else if (pos > cur-data) p = cur;
   else p = data + pos;
   cur += len;
   // shift tail (including terminating '\0'):
   for (d = cur + 1, s = d - len;  s > p; ) *--d = *--s;
   // insert string:
   for (s = str, d = p;  --len >= 0; ) *d++ = *s++;
   return cur-data;
}

- (int)lastChar
{
   return (cur>data) ? *(cur-1) : -1;
}

@end // SimpleString
