#import <RCString.h>
/*
    Copyright (C) 1992. Bruce Ediger.

      This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU Library General Public License.
*/

//
// implementation of "insertion" methods
//

@implementation RCString (Insertion)

// all of the other Insertion category methods are
// wrappers around this one.  No doubt it would be
// very wise if this method did not modify anAsciiString.
- insertString:  (char *)anAsciiString at:(int)index
{
	int iLength, iSumTotal;
	char *bpTmp;

	// Simple checks before expending further effort.
	if (anAsciiString == p->s)
		return self;  // try to avoid some weird recursion
	else if (anAsciiString == NULL)
		return self;
	else if ((iLength = strlen(anAsciiString)) <= 0)
		return self;
	else if (index < 0)
		return self;

	if (index > p->l - 1)
		index = p->l - 1;  // silently trim insertion point to fit

	// Something's going to happen for sure.  Copy the reference.
	if (p->n > 1)
		[self copyReference];

	iSumTotal = p->l + iLength;  // p->l includes 1 for trailing null
	bpTmp = malloc(iSumTotal);
	if (bpTmp) {
		if (index == 0) {
			// insert at beginning of internal string
			bcopy(anAsciiString, bpTmp, iLength);
			if (p->s && p->l > 1)
				bcopy(p->s, &bpTmp[iLength], p->l);
		} else if (index == p->l - 1) {
			// insert at end of internal string
			if (p->s && p->l > 1)
				bcopy(p->s, bpTmp, p->l - 1);
			bcopy(anAsciiString, &bpTmp[p->l - 1], iLength);
		} else {
			// insert at arbitrary location
			if (p->s && p->l > 1) {
				bcopy(p->s, bpTmp, index);
				bcopy(&p->s[index], &bpTmp[index + iLength], p->l - index);
			}
			bcopy(anAsciiString, &bpTmp[index], iLength);
		}
		bpTmp[iSumTotal - 1] = '\0';
		if (p->s)
			free(p->s);
		p->s = bpTmp;
		p->l = iSumTotal;
	}

	return self;
}

// -appendString: and -prependString: can be special
// cases of -insertString:at:.  But they don't have to
// be.  They may be faster as special case implementations.

- appendString:(char *)anAsciiString
{
	return [self insertString:anAsciiString at:p->l - 1];
}

- prependString:(char *)anAsciiString
{
	return [self insertString:anAsciiString at:0];
}

// *Object methods are just wrappers around the insertString:at:
// method.  There may be a better way.

- appendObject:  (RCString *)anotherObject
{
	if (anotherObject) {
		return [self insertString:[anotherObject data] at:0];
	}
	return self;
}

- prependObject: (RCString *)anotherObject
{
	if (anotherObject) {
		return [self insertString:[anotherObject data] at:p->l - 1];
	}
	return self;
}

- insertObject:  (RCString *)anotherObject at:(int)index
{
	if (anotherObject && index >= 0) {
		return [self insertString:[anotherObject data] at:index];
	}
	return self;
}

// These final two are not wrappers around -insertString:at:
// I just can't think of a better category to put it in.

// There's some internal dependencies: this method is used by the
// regular expression stuff in another category.
- replaceStringAt:(int)index extent:(int)length with:(char *)aString
{
	int iLength;

	if (length >= 0 && aString != NULL && (iLength = strlen(aString)) > 0
		&& index >=0 && index <= p->l)
	{
		char *bpTmp;

		if((bpTmp = malloc(p->l + iLength)) != NULL)
		{
			bcopy(p->s, bpTmp, index);
			bcopy(aString, &(bpTmp[index]), iLength);
			bcopy(&(p->s[index + length]), &(bpTmp[index + iLength]),
				p->l - index - length);

			if (p->n == 1)
			{
				if (p->s) free(p->s); // this is the only reference
				p->s = bpTmp;
				p->l = p->l + iLength;
			} else {
				struct srep *spOld = p;

				// Decrement ref count on old internal rep, 
				// conjure up new internal ref.
				--p->n;
				p = (struct srep *)malloc(sizeof(struct srep));
				p->s = bpTmp;
				p->l = spOld->l + iLength;
				p->n = 1;
			}
		}
	}
	return self;
}

- replaceStringAt:(int)index extent:(int)replength with:(char *)aString extent:(int)strlength
{
	if (replength >= 0 && aString != NULL && strlength > 0
		&& index >=0 && index <= p->l)
	{
		char *bpTmp;

		// allocate memory for a new asciiz string
		if((bpTmp = malloc(p->l + strlength)) != NULL)
		{
			bcopy(p->s, bpTmp, index);
			bcopy(aString, &(bpTmp[index]), strlength);
			bcopy(&(p->s[index + replength]), &(bpTmp[index + strlength]),
				p->l - index - replength);

			if (p->n == 1)
			{
				if (p->s) free(p->s); // this is the only reference
				p->s = bpTmp;
				p->l = p->l + strlength;
			} else {
				struct srep *spOld = p;

				// Decrement ref count on old internal rep, 
				// conjure up new internal ref.
				--p->n;
				p = (struct srep *)malloc(sizeof(struct srep));
				p->s = bpTmp;
				p->l = spOld->l + strlength;
				p->n = 1;
			}
		}
	}
	return self;
}

@end
