/*
** StringStorage.m,v 1.5 1992/09/24 03:34:31 nwc Exp
**
** Copyright (c) 1991 Ronin Consulting, Inc.
*/


#import "StringStorage.h"
#import <limits.h>
#import <string.h>
#import <stdlib.h>
#import<appkit/nextstd.h>

static char EOS = (char)0;

@implementation StringStorage

- init
{
   [self init: ""];
   return self;
}

- init: (const char *) str
{
   [super init];
   
   [self initCount: 0 elementSize: sizeof(char) description: "c"];
   [self setStringValue: str];
   return self;
}

- setStringValue: (const char *) str;
{
   int len;

   if(!str)
       str = "";			     /* avoid nil strings */

   len = strlen(str);			     /* get length - no reason to do it twice */
   [self setNumSlots: len + 1];		     /* use setNumSlots vs setAvailCapacity since it sets count */

					     /* bcopy is far faster than strcpy if the length is known */
   bcopy(str, (char *)dataPtr, len); 
   [self replaceElementAt: len with: (char *)&EOS];
   return self;
}

- setFStringValue: (const char *)format,...
{
   NXStream *stream;
   long len;
   va_list params;

   va_start(params,format);
   stream = NXOpenMemory(NULL, 0, NX_READWRITE);
   NXVPrintf(stream, format, params);
   NXFlush(stream);
   NXSeek(stream, 0, NX_FROMEND);
   len = NXTell(stream);
   NXSeek(stream, 0, NX_FROMSTART);

   [self setNumSlots: len + 1];
   NXRead(stream, (char *)dataPtr, len);
   [self replaceElementAt: len with: (char *)&EOS];
   NXCloseMemory(stream, NX_FREEBUFFER);
   return self;
}

- (const char *) stringValue
{
   return dataPtr;
}

- appendStringValue: (const char *)str
{
   int oldCount = [self count];
   int len;

   if(!str || !*str)			     /* nothing to append */
       return self;
   
   len = strlen(str);			     
   [self setNumSlots: oldCount + len];
   bcopy(str, (char *)[self elementAt: oldCount - 1], len);
   [self replaceElementAt: oldCount + len - 1 with: (char *)&EOS ];
   return self;
}

- appendFStringValue: (const char *)format,...
{
   int oldCount = [self count];
   NXStream *stream;
   long len;
   va_list params;

   va_start(params,format);
   stream = NXOpenMemory(NULL, 0, NX_READWRITE);
   NXVPrintf(stream, format, params);
   NXFlush(stream);
   NXSeek(stream, 0, NX_FROMEND);
   len = NXTell(stream);
   NXSeek(stream, 0, NX_FROMSTART);

   [self setNumSlots: oldCount + len];
   NXRead(stream, ((char *)dataPtr) + (oldCount - 1), len);
   [self replaceElementAt: oldCount + len - 1 with: (char *)&EOS ];
   NXCloseMemory(stream, NX_FREEBUFFER);
   return self;
}

- appendCharValue: (char) c
{
   char buf[2];
   
   buf[0] = c;
   buf[1] = (char)0;

   [self appendStringValue: buf];

   return self;
}

- empty					     /* override to ensure null termination */
{
   [super empty];
   [self setStringValue: ""];
   return self;
}

- (int) strlen				     /* just (count - 1)...but nicer */
{
   return [self count] - 1;
}

- (int) matchSubstring: (const char *)str
{
   int x, cnt;

   if(!str)
       return -1;

   for (x = 0, cnt = [self strlen]; x <  cnt; x++)
       if(((char *)dataPtr)[x] == *str && !strncmp(str,(char *)dataPtr + x, strlen(str)))
	   return x;

   return -1;
}

- (char *) getSubstring: (const char *)str
{
   int offset;

   offset = [self matchSubstring: str];
   if(offset != -1)
       return dataPtr + offset;
   else
       return (char*)0;
}

- replaceSubstring: (const char *)str with: (const char *)str2
{
   int offset, len1, len2;
   char *buf;

   if(!(str && str2))
       return nil;

   offset = [self matchSubstring: str];
   if(offset == -1)
       return nil;

   len1 = strlen(str);
   len2 = strlen(str2);

   NX_MALLOC(buf,char,([self count] + len2));
   buf[[self count] + len2 - len1 - 1] = (char)0;

   bcopy((char *)dataPtr, buf, offset);
   bcopy(str2, buf + offset, len2);
   bcopy(((char *)dataPtr) + offset + len1, buf + offset + len2, [self count] - offset - len1 - 1);
   
   [self setStringValue: buf];
   NX_FREE(buf);

   return self;
}

- (unsigned int)hash
{
   unsigned int x = 0;
   int y, cnt;

   for(y = 0, cnt = [self strlen]; y < cnt; y++)
       x += ((char *)(dataPtr))[y];

   return x;
}

@end



