#pragma implementation

#include "Str.h"

extern "C" {

	#include <stdio.h>
	#include <float.h>
	#include <ctype.h>
	
#ifdef SYSV
	#include <string.h>
	#define bcopy(from, to, len) (memcpy((to), (from), (len)))
#else
	#include <strings.h>
#endif

}

#include "set_error.h"

const char Str::empty_string = 0;

void Str::clear(void) {
	if (alloc_len) {
		if (alloc_len >= 16*1024) {
			delete [] adr;
			adr = (char *)&empty_string;
			alloc_len = 0;  
			fail = 0;
			return;
		} else {
			*adr = 0;
		}
		
		len = 0;
	}
	return;
};


void Str::expand(void) {
	
	unsigned long newlen = alloc_len * 2;
	if (newlen == 0) newlen = 31;
	if (alloc_len >= 64*1024) newlen = alloc_len + 64*1024;
	
	char * nadr = new char[newlen+1];
	if (nadr == 0) {
		fail = -1;
		set_error("Str::expand ","unable to allocate more memory");
		return;
	}
	
	bcopy(adr, nadr, len+1);
	if (alloc_len) delete [] adr;
	adr = nadr;
	alloc_len = newlen;
}

void Str::fill(char fill) {	
	if (len) {
		char * d = adr;
		unsigned long l = len-1;
		do {
			*d++ = fill;
		} while (l--);
	}
}

Str::Str (unsigned long int length) {
	
	if (length == 0) {
		adr = ((char *)&empty_string);
		len = 0;
		fail = 0;
		alloc_len = 0;
		return;
	}
	
	adr = new char[length+1];
	if (adr) {
		*(adr) = 0;
		*(adr+length) = 0;
		fail = 0;
		len = length;
		alloc_len = length;
	} else {
		fail = -1;
		len = 0;
		alloc_len = 0;
	}
}


Str::Str(const char * text) {

	alloc_len = 31;
	adr = new char[31+1];
	len = 0;
	fail = 0;
	
	for (;;) {
		if (adr == 0) {
			fail = -1;
			len = 0;
			alloc_len = 0;
		}

		char * dst = adr+len;		
		unsigned long cnt = alloc_len - len;
		while (cnt) {
			char c = *text++;
			*dst++ = c;
			
			if (c == 0) {
				return;
			}
			
			len++;
			cnt--;
		}
		
		expand();
	}
}

Str::Str(const char * text, unsigned long length) {
	if (length == 0) {
		adr = ((char *)&empty_string);
		len = 0;
		fail = 0;
		alloc_len = 0;
		return;
	}
	
	adr = new char[length+1];
	if (adr == 0) {
		set_error("Str: ","unable to construct string");
		fail = -1;
		len = 0;
		alloc_len = 0;
		return;
	}
	
	len = length;
	alloc_len = length;
	bcopy(text, adr, len);
	*(adr+len) = 0;
	fail = 0;
}

Str::Str(const Str & rv) {

	if (rv.len == 0) {
		adr = ((char *)&empty_string);
		len = 0;
		fail = 0;
		alloc_len = 0;
		return;
	}
	
	adr = new char[rv.len+1];
	if (adr == 0) {
		set_error("Str: ","unable to copy-construct string");
		fail = -1;
		len = 0;
		alloc_len = 0;
		return;
	}
	
	len = rv.len;
	alloc_len = rv.len;
	bcopy(rv.adr, adr, len+1);
	fail = 0;
}

const Str & Str::operator=(const Str & rv) {	

	if (rv.len == 0) {
		if (alloc_len < 16*1024) {
			len = 0;
			if (alloc_len) *adr = 0;
			fail = 0;
			return *this;
		} else {
			delete [] adr;
			adr = ((char *)&empty_string);
			len = 0;
			fail = 0;
			alloc_len = 0;
			return *this;
		}
	}

	if ( (rv.len <= alloc_len) && (alloc_len - rv.len < 16*1024) ) {
		// we don't need to allocate new memory, just copy
		// the string and adjust len
		
		bcopy (rv.adr, adr, rv.len+1);
		len = rv.len;
		return *this;
	}
		 
	if (alloc_len) delete [] adr;
	
	adr = new char[rv.len+1];
	if (adr == 0) {
		set_error("Str::operator= ","unable to copy-construct string");
		fail = -1;
		len = 0;
		alloc_len = 0;
		return *this;
	}
	
	len = rv.len;
	alloc_len = rv.len;
	bcopy(rv.adr, adr, len+1);
	fail = 0;
	return *this;
}

unsigned long Str::val(void) const {
	
	unsigned long int v = 0;
	unsigned long int i;
	const char * a;
	char c;
	
	if (len > 2 && left(2) == "0x") {
		for (a=adr+2, i=len-2; i!=0; i--) {
			c = *a++;
			if ( (c >= '0') && (c <= '9') ) {
				v <<= 4;
				v += c-'0';
			} else if ( (c >= 'a') && (c <= 'f') ) {
				v <<= 4;
				v += c-('a'-10);
			} else if ( (c >= 'A') && (c <= 'F') ) {
				v <<= 4;
				v += c-('A'-10);
			} else break;
		}
	} else if ( len > 2 && left(2) == "0b" ) {
		for (a=adr+2, i=len-2; i!=0; i--) {
            c = *a++;
			if ( c == '0' ) {
				v <<= 1;
			} else if ( c == '1' ) {
				v <<= 1;
				v++;
			} else break;
                }
	} else {
		for (a=adr, i=len; i!=0; i--) {
			c = *a++;
			if ( (c < '0') || (c > '9') ) break;
			v *= 10;
			v += (unsigned long int) (c-'0');
		}
	}
	
	return v;
}

unsigned long long Str::vall(void) const {
	
	unsigned long long v = 0;
	unsigned long i;
	const char * a;
	char c;
	
	if (len > 2 && left(2) == "0x") {
		for (a=adr+2, i=len-2; i!=0; i--) {
			c = *a++;
			if ( (c >= '0') && (c <= '9') ) {
				v <<= 4;
				v += c-'0';
			} else if ( (c >= 'a') && (c <= 'f') ) {
				v <<= 4;
				v += c-('a'-10);
			} else if ( (c >= 'A') && (c <= 'F') ) {
				v <<= 4;
				v += c-('A'-10);
			} else break;
		}
	} else if ( len > 2 && left(2) == "0b" ) {
		for (a=adr+2, i=len-2; i!=0; i--) {
            c = *a++;
			if ( c == '0' ) {
				v <<= 1;
			} else if ( c == '1' ) {
				v <<= 1;
				v++;
			} else break;
		}
	} else {
		for (a=adr, i=len; i!=0; i--) {
			c = *a++;
			if ( (c < '0') || (c > '9') ) break;
			v *= 10;
			v += (unsigned long long) (c-'0');
		}
	}
	
	return v;
}

long Str::sval(void) const {
	
	if (len == 0) return 0;
	if (*adr == '-') {
		long v = (long) right(len-1).val();
		return -v;
	}
	else {
		return val();
	}
}

long long Str::svall(void) const {
	
	if (len == 0) return 0;
	if (*adr == '-') {
		long long v = (long long) right(len-1).vall();
		return -v;
	}
	else {
		return vall();
	}
}

Str Str::next_word(void) {
	
	Str res;
	char c;
	unsigned long i;
	unsigned long j;
	
	for (i = 0; i<len; i++) {
		c=*(adr+i);
		if ((c != 0x20 ) && (c != 9)) break;
	}
	
	if (i==len) {
		len = 0;
		return Str();
	}
	
	char qflag = 0;
	
	for (j = i; j<len; j++) {
		c = *(adr+j);
		if (!qflag) {
			if ((c==0x20 ) || (c==9)) break;
			if (c==0x22) qflag = -1;
		}
		else {
			if (c==0x22) qflag = 0;
		}
	}
	
	if ( (*(adr+i) == 0x22) && (*(adr+j-1) == 0x22) ) {
		res = Str((adr+i+1),(j-i)-2);
	}
	else {
		res = Str((adr+i),j-i);
	}
	
	if (j==len) {
		len = 0;
		*adr = 0;
	}
	else {
		bcopy(adr+j, adr, 1+len-j);
		len = len-j;
	}
	
	return res;
}

Str Str::next_line(void) {
	
	Str res;
	unsigned long i = index(0x0a);
	
	if (i == (unsigned long)~0) {
		res = Str(*this);
		len = 0;
		*adr = 0;
		return res;
	}
	
	res = before(i);
	
	if (len > i+1) {
		bcopy((adr+i+1), adr, 1+len-(i+1));
	}
	
	len -= i+1;
	return res;
}

Str Str::operator+(const Str & rv) const {
	Str res(len+rv.len);
	if (len) bcopy(adr, res.adr, len);
	if (rv.len) bcopy(rv.adr, res.adr+len, rv.len);
	return res;
}

Str Str::operator+(char rv) const {
	Str res(len+1);
	if (len) bcopy(adr, res.adr, len);
	*(res.adr+len) = rv;
	return res;
}

Str Str::operator+=(const Str & rv) {
	if (! rv.len) return *this;
	if (len+rv.len <= alloc_len) {
		bcopy(rv.adr, adr+len, rv.len);
		len += rv.len;
		*(adr+len) = 0;
	} else {
		if (rv.len < 64*1024 && rv.len < len) {
			expand();
			if (alloc_len >= len+rv.len) {
				bcopy(rv.adr, adr+len, rv.len);
				len += rv.len;
				*(adr+len) = 0; 
			} else {
				fail = -1;
				set_error("Str::operator+ ","unable to allocate more memory");
			}
		} else {
			char * nadr = new char[len+rv.len+1];
			if (nadr == 0) {
				fail = -1;
				set_error("Str::operator+ ","unable to allocate more memory");
				return *this;
			}
			
			bcopy(adr, nadr, len);
			bcopy(rv.adr, nadr+len, rv.len);
			if (alloc_len) delete [] adr;
			adr = nadr;
			len += rv.len;
			*(adr+len) = 0;
			alloc_len = len;
			
		}
	}
	return *this;
}

int Str::operator==(const char * p) const {
	
	const char * a = adr;
	unsigned long cnt = 0;
	
	for (;;) {
		char c = *p++;
		if (cnt == len) {
			if (c == 0) return -1;
			return 0;
		}
		if (c == 0) return 0;
		if (c != *a++) return 0;
		cnt++;
	}
	return 0;
}

int Str::operator==(const Str & rv) const {
	
	if (len != rv.len) return 0;
	if (len == 0) return -1;
	
	const char * a = adr;
	const char * b = rv.adr;
	unsigned long cnt = len-1;
	do {
		if (*a++ != *b++) return 0;
	} while (cnt--);
	return -1;
}

int Str::operator<(const char * p) const {

	const char * a = adr;
	unsigned long cnt = 0;

	for (;;) {
		char c = *p++;
		if (len == cnt) {
			if (c == 0)
				return 0;
			return -1;
		}
		if (c == 0)
			return 0;
		if (c != *a)
			return (*a < c);
		a++; cnt++;
	}
}

int Str::operator<(const Str & rv) const {
	
	unsigned long p = (rv.len < len)? rv.len : len;
	const char * a = adr;
	const char * b = rv.adr;
	
	if (len && rv.len) {
		
		for (; p!=0; p--) {
			if (*a != *b) break;
			a++;
			b++;
		}
		
		if (p) {
			if (*a < *b) return -1;
			else return 0;
		}
		else {
			return (len < rv.len);
		}
	}
	else {
		if (len == rv.len) return 0;
		if (len == 0) return -1;
		else return 0;
	}
}

int Str::compare (const Str & rv) const {
	
	unsigned long p = (rv.len < len)? rv.len : len;
	const char * a = adr;
	const char * b = rv.adr;
	
	if (len && rv.len) {
		
		for (; p!=0; p--) {
			if (*a != *b) break;
			a++;
			b++;
		}
		
		if (p) {
			if (*a < *b) return -1;
			else return 1;
		}
		else {
			if (len == rv.len) return 0;
			if (len < rv.len) return -1;
			return 1;
		}
	}
	else {
		if (len == rv.len) return 0;
		if (len == 0) return -1;
		else return 1;
	}
}

int Str::operator>(const Str & rv) const {
	
	unsigned long p = (rv.len < len)? rv.len : len;
	const char * a = adr;
	const char * b = rv.adr;
	
	if (len && rv.len) {
		
		for (; p!=0; p--) {
			if (*a != *b) break;
			a++;
			b++;
		}
		
		if (p) {
			if (*a > *b) return -1;
			else return 0;
		}
		else {
			return (len > rv.len);
		}
	}
	else {
		if (len == rv.len) return 0;
		if (len == 0) return 0;
		else return -1;
	}
}

Str Str::sub(unsigned long from, unsigned long to) const {
	if (to > len) to = len;
	if (from >= to) return Str((unsigned long) 0);
	return Str(adr+from, to-from);
};

unsigned long Str::index(const Str & match, unsigned long offset) const {

	if (match.len == 0) return 0;

	const char * m = match.adr;
	char c = *m++; // erstes zeichen
	const char * o = adr+offset;
	 
	for (; offset+match.length() <= len; offset++) {
		if (*o++ == c) {
			if (match.len == 1) return offset;
			
			const char * a = m;
			const char * b = o;
			unsigned long l = match.len - 2;
			do {
				if ( *a++ != *b++ ) break;
			} while (l--);
			if (l == (unsigned long)~0) return offset;
		}
	}
	return (unsigned long)~0;
}

unsigned long Str::index(char match, unsigned long offset) const {
	
	if (offset >= len) return ~(unsigned long)0;
	
	const char * a = adr+offset;
	
	for (; offset < len; offset++) {
		if ((*a++) == match) break;
	}
	
	if (offset < len) return offset;
	else return ~(unsigned long)0;
}

unsigned long Str::rindex(char match, unsigned long offset) const {
	
	if (offset >= len) return ~(unsigned long)0;
	
	const char * a = adr+len-offset;
	unsigned long i = (len-offset)-1;
	
	for (; i != ~(unsigned long)0; i--) {
		if ((*(--a)) == match) break;
	}
	
	return i;
}

Str NtoStr(unsigned long val, short int width) {
	
	char vbuf[20];
	
	register short p = 1;
	register char * a = vbuf+20;
	
	for (;; p++) {
		*(--a) = (char)'0'+(val % 10);
		val /= 10;
		if (val == 0) break;
	}
	
	Str res=Str(vbuf+(20-p),p);
	
	if (width) {
		
		if ((unsigned long)width > res.length()) {
			Str tmp(width-res.length());
			tmp.fill();
			return tmp+res;
		}
		else {
			return res.sub(res.length()-width,res.length());
		}
	}
	else{
		return res;
	}
}

Str SNtoStr(long val, short int width) {
	
	if (val >= 0) {
		return NtoStr(val, width);
	}
	else {
		if (width > 1) width--;
		val = -val;
		return Str("-")+NtoStr((unsigned long)val, width);
	}
}

static char HexTab[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };

static char HexBuf[8];

Str NtoHex(unsigned long val, unsigned short width) {
	
	if (width > 8) width = 8;
	
	{
		short x = 7;
		char * c = HexBuf;
		do {
			*c++ = '0';
		} while (x--);
	}
	
	char * c = &HexBuf[8];
	short cnt = 0;
	
	do {
		
		cnt++;
		*(--c) = HexTab[val & 0xf];
		val >>= 4;
		
	} while (val != 0);
	
	if (width) return Str(&(HexBuf[8-width]), width);
	return Str(&(HexBuf[8-cnt]), cnt);
	
}

Str & Str::to_upper(void) {
	
	char * a = adr;
	for (unsigned long i = 0; i < len; i++) {
		*a = upper(*a);
		a++;
	}
	
	return *this;
}

Str & Str::to_lower(void) {
	
	char * a = adr;
	for (unsigned long i = 0; i < len; i++) {
		*a = lower(*a);
		a++;
	}
	
	return *this;
}


Str LtoStr(long num) {
	
	Str res(4);
	
	// if (res.fail) return Str();
	
	char * c = (char *)res;
	
	*c++ = (num & 0xff000000) >> 24;
	*c++ = (num & 0xff0000) >> 16;
	*c++ = (num & 0xff00) >> 8;
	*c++ = (num & 0xff);
	
	return res;
}

Str operator+(const char * lv, const Str & rv) {
	return Str(lv)+rv;
}

Str FtoStr(double val) {
	Str res;
	static char buf[40];
	sprintf(buf,"%1.*g",DBL_DIG,val);
	res = Str(buf);
	return res;
}

void Str::implode_escape_sequences(void) {

    char *i,*o;
    i = o = adr;
    int n = len;

    while(n--) {
	if(*i == '\\' &&
	   isdigit(i[1]) &&
	   isdigit(i[2]) &&
	   isdigit(i[3])) {
	    int c;
	    sscanf(i+1, "%3o", &c);
	    *o++ = c;
	    i += 4;
	    len -= 3;
	    n -= 3;
	}
	else {
	    *o++ = *i++;
	}
    }
}	


syntax highlighted by Code2HTML, v. 0.9.1