/*******************************************************************************
 *	BString.cc		Beams String Class
 *				T.Barnaby,	BEAm Ltd,	15/7/92
 *		updated by	D.Korchagin,	CERN AB-BI-SW,	2007-08-31
 *******************************************************************************
 */
#ifndef __Lynx__
#else
#include	<stdarg.h>
#endif
#include	<stdio.h>
#include	<string.h>
#include	<stdlib.h>
#include	<stdarg.h>
#include	<ctype.h>
#include	<BString.h>
#include	<BError.h>

#if TARGET_win32
int vasprintf(char** sptr, const char* fmt, va_list argv){
	int wanted = vsnprintf(*sptr = NULL, 0, fmt, argv);
	if((wanted < 0) || ((*sptr = (char*)malloc( 1 + wanted )) == NULL))
		return -1;

	return vsprintf(*sptr, fmt, argv);
}
#else
#include	<regex.h>
#endif

#ifndef __Lynx__
#else
inline int vasprintf(char **resultp, const char *format, va_list args)
{
	int ret_val;
	int size = 512 * sizeof (char);
	*resultp = (char *) malloc (size);
	while ((((ret_val = vsprintf(*resultp, format, args)) >= size) || (ret_val < 0)) && (*resultp != NULL)) *resultp = (char *) realloc (*resultp, size = (ret_val < 0) ? (2 * size) : (size + sizeof('\0')));
	return ret_val;
}
#endif

# define	STRIP	0x7f
# define	MINUS	'-'

static int gmatch(const char *s, const char *p){
	int	scc;
	char	c;

	if (scc = *s++) {
		if ((scc &= STRIP) == 0)
			scc=0200;
	}
	switch (c = *p++) {
	case '[':
		{
			int	ok;
			int	lc;
			int	notflag = 0;

			ok = 0;
			lc = 077777;
			if (*p == '!') {
				notflag = 1;
				p++;
			}
			while (c = *p++) {
				if (c == ']')
					return(ok ? gmatch(s, p) : 0);
				else if (c == MINUS) {
					if (notflag) {
						if (scc < lc || scc > *(p++))
							ok++;
						else
							return(0);
					}
					else {
						if (lc <= scc && scc <= (*p++))
							ok++;
					}
				}
				else {
					lc = c & STRIP;
					if (notflag) {
						if (scc && scc != lc)
							ok++;
						else
							return(0);
					}
					else {
						if (scc == lc)
							ok++;
					}
				}
			}
			return(0);
		}

	default:
		if ((c & STRIP) != scc)
			return(0);

	case '?':
		return(scc ? gmatch(s, p) : 0);

	case '\\':
		c = *p++;
		if((c & STRIP) != scc)
			return(0);
			
	case '*':
		while (*p == '*')
			p++;

		if (*p == 0)
			return(1);
		--s;
		while (*s) {
			if (gmatch(s++, p))
				return(1);
		}
		return(0);

	case '!':
		return !gmatch(--s, p);
	case 0:
		return(scc == 0);
	}
}

BString::~BString(){
	if(ostr && (ostr->deleteRef() == 0)){
		delete ostr;
	}
	ostr = 0;
}

BString::BString(){
	ostr = 0;
}

BString::BString(const BString& string){
	if(string.ostr)
		ostr = string.ostr->addRef();
	else
		ostr = 0;
}

BString::BString(const char* str){
	if(str && str[0]){
		ostr = new BRefData(strlen(str) + 1);
		strcpy(ostr->data(), str);
	}
	else {
		ostr = 0;
	}
}

BString::BString(const char* str, unsigned int len){
	if(str && len && str[0]){
		ostr = new BRefData(len + 1);
		strncpy(ostr->data(), str, len);
		ostr->data()[len] = '\0';
	}
	else {
		ostr = 0;
	}
}

BString::BString(char ch){
	ostr = new BRefData(2);
	ostr->data()[0] = ch;
	ostr->data()[1] = 0;
}

BString::BString(BInt value){
	char	buf[32];

	sprintf(buf, "%d", value);
	ostr = new BRefData(strlen(buf) + 1);
	strcpy(ostr->data(), buf);
}

BString::BString(BUInt value){
	char	buf[32];

	sprintf(buf, "%u", value);
	ostr = new BRefData(strlen(buf) + 1);
	strcpy(ostr->data(), buf);
}

BString::BString(BUInt64 value){
	char	buf[32];

#if __WORDSIZE == 64
	sprintf(buf, "%ld", value);
#else
	sprintf(buf, "%lld", value);
#endif
	ostr = new BRefData(strlen(buf) + 1);
	strcpy(ostr->data(), buf);
}

BString::BString(double value){
	char	buf[32];

	sprintf(buf, "%f", value);
	ostr = new BRefData(strlen(buf) + 1);
	strcpy(ostr->data(), buf);
}

void BString::init(const char* str) {
	if(str && str[0]){
		ostr = new BRefData(strlen(str) + 1);
		strcpy(ostr->data(), str);
	}
	else {
		ostr = 0;
	}
}

BString BString::convert(char value){
	char	buf[128];

	sprintf(buf, "%c", value);
	return buf;
}

BString BString::convert(BInt value){
	char	buf[128];

	sprintf(buf, "%d", value);
	return buf;
}

BString BString::convert(BUInt value){
	char	buf[128];

	sprintf(buf, "%u", value);
	return buf;
}

BString BString::convert(double value, int eFormat){
	char	buf[128];

	if(eFormat)
		sprintf(buf, "%e", value);
	else
		sprintf(buf, "%f", value);

	return buf;
}

BString BString::convert(BUInt64 value){
	char	buf[128];

#if __WORDSIZE == 64
	sprintf(buf, "%ld", value);
#else
	sprintf(buf, "%lld", value);
#endif
	return buf;
}

BString BString::convertHex(BInt value){
	char	buf[128];

	sprintf(buf, "0x%x", value);
	return buf;
}

BString BString::convertHex(BUInt value){
	char	buf[128];

	sprintf(buf, "0x%x", value);
	return buf;
}

BString BString::copy() const {
	BString	s;

	s = retStr();
	return s;
}

int BString::len() const {
	int	l = 0;
	
	if(ostr && ostr->len())
		l = ostr->len() - 1;
	return l;
}

BString& BString::truncate(int l) {
	if(ostr){
		ostr = ostr->copy();
		if(l < len()){
			ostr->setLen(l + 1);
			ostr->data()[l] = '\0';
		}
	}
	return *this;
}

void BString::clear(){
	if(ostr && (ostr->deleteRef() == 0)){
		delete ostr;
	}
	ostr = 0;
}

BString& BString::pad(int l) {
	if(ostr){
		ostr = ostr->copy();
	}
	while(l > len()){
		*this = *this + " ";
	}
	return *this;
}

BString& BString::toUpper(){
	char*	s;

	if(ostr){
		ostr = ostr->copy();
		for(s = ostr->data(); *s; s++)
			*s = toupper(*s);
	}
	return *this;
}

BString& BString::toLower(){
	char*	s;

	if(ostr){
		ostr = ostr->copy();
		for(s = ostr->data(); *s; s++)
			*s = tolower(*s);
	}
	return *this;
}

BString BString::lowerFirst(){
	BString	s;

	if(ostr && len()){
		s = retStr();
		s[0] = tolower(s[0]);
	}
	return s;
}

void BString::removeNL(){
	if(ostr){
		ostr = ostr->copy();
		if((len() > 1) && (ostr->data()[len() - 1] == '\n') && (ostr->data()[len() - 2] == '\r'))
			truncate(len() - 2);
		else if(len() && (ostr->data()[len() - 1] == '\n'))
			truncate(len() - 1);
	}
}

BString BString::justify(int leftMargin, int width){
	BString	r;
	char*	s;
	int	x = 0;

	if(ostr){	
		for(s = ostr->data(); *s; s++){
			if(x > width){
				r = r + "\n";
				x = 0;
			}
			if(x == 0){
				while(x < leftMargin){
					r = r + " ";
					x++;
				}
			}

			if(*s == '\n'){
				r = r + *s;
				x = 0;
			}
			else if((x > (7 * width) / 8) && isspace(*s)){
				r = r + "\n";
				x = 0;
			}
			else {
				r = r + *s;
				x++;
			}
		}
	}

	return r;
}

BString BString::fixedLen(int length, int rightJustify){
	BString	str;
	int	l;
	int	ls = length;
	int	p = 0;
	
	str.ostr = new BRefData(length + 1);
	str.ostr->data()[length] = '\0';

	if(len() < ls)
		ls = len();
		
	if(rightJustify){
		l = length - len();
		while(l-- > 0)
			str.ostr->data()[p++] = ' ';
	}

	for(l = 0; l < ls; l++){
		str.ostr->data()[p++] = get(l);
	}
		
	if(!rightJustify){
		while(l++ < length)
			str.ostr->data()[p++] = ' ';
	}
	
	return str;
}

BString BString::firstLine(){
	return subString(0, find('\n'));
}

BString BString::translateChar(char ch, BString replace){
	BString	s;
	char	c;
	int	i;
	
	for(i = 0; i < len(); i++){
		c = get(i);
		if(c == ch)
			s += replace;
		else
			s += c;
	}
	
	return s;
}

BString BString::csvEncode() const {
	BString	s;
	char	c;
	int	i;
	
	for(i = 0; i < len(); i++){
		c = get(i);
		if(c == ',')
			s += "\\,";
		else if(c == '\n')
			s += "\\n";
		else
			s += c;
	}
	
	return s;
}

BString& BString::csvDecode(const BString str){
	char	c;
	int	i;
	
	clear();
	for(i = 0; i < str.len(); i++){
		c = str[i];
		if((c == '\\') && (i < (len() - 2)))
			*this += get(++i);
		else
			*this += c;
	}
	
	return *this;
}

// Base64 functions
BString BString::base64Encode() const {
	const char	base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	const BUInt8*	data = (const BUInt8*)retStr();
	BUInt		resultIndex = 0;
	int		x;
	BUInt32		n = 0;
	int		padCount = len() % 3;
	BUInt8		n0, n1, n2, n3;
	BString		str;

	for(x = 0; x < len(); x += 3){
		n = ((uint32_t)data[x]) << 16;

		if((x + 1) < len())
			n += ((BUInt32)data[x + 1]) << 8;

		if((x + 2) < len())
			n += data[x + 2];

		/* This 24-bit number gets separated into four 6-bit numbers */
		n0 = (BUInt8)(n >> 18) & 63;
		n1 = (BUInt8)(n >> 12) & 63;
		n2 = (BUInt8)(n >> 6) & 63;
		n3 = (BUInt8)n & 63;

		str += char(base64chars[n0]);
		str += char(base64chars[n1]);
	
		if((x + 1) < len()){
			str += char(base64chars[n2]);
		}

		if((x + 2) < len()){
			str += char(base64chars[n3]);
		}
	}  

	if(padCount > 0){
		for(; padCount < 3; padCount++){
			str += '=';
		} 
	}
	return str;
}

static const BUInt8 base64_decode_table[] = {
	66,66,66,66,66,66,66,66,66,66,64,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
	66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,62,66,66,66,63,52,53,
	54,55,56,57,58,59,60,61,66,66,66,65,66,66,66, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
	10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,66,66,66,66,66,66,26,27,28,
	29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,66,66,
	66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
	66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
	66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
	66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
	66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,
	66,66,66,66,66,66
};

BError BString::base64Decode(BString& str) const {
	BError		err;
	const char*	in = retStr();
	const char*	end = in + len();
	char		iter = 0;
	uint32_t	buf = 0;
	size_t		len = 0;

	while(in < end){
		BUInt8 c = base64_decode_table[int(*in++)];

		switch(c){
		case 64:
			// Skip whitespace
			continue;
		case 66:
			// Error
			return err.set(1);
		case 65:
			// Pad character, end of data
			in = end;
			continue;
		default:
			buf = buf << 6 | c;
			iter++;
			
			if(iter == 4){
				str += char((buf >> 16) & 255);
				str += char((buf >> 8) & 255);
				str += char(buf & 255);
				buf = 0;
				iter = 0;
			}   
		}
	}

	if(iter == 3){
		str += char((buf >> 10) & 255);
		str += char((buf >> 2) & 255);
	}
	else if(iter == 2) {
		str += char((buf >> 4) & 255);
	}

	return err;
}


BString BString::reverse() const {
	BString	s = copy();
	int	f;
	int	t;

	if(ostr){
		for(t = 0, f = len() - 1; t < len(); t++, f--)
			s.ostr->data()[t] = ostr->data()[f];
	}
	return s;
}

BString BString::subString(int start, int l) const {
	BString	s;

	if(ostr && inString(start) && len()){
		if(l >= 0){
			if(l > (len() - start))
				l = len() - start;
			s = BString(&ostr->data()[start], l);
		}
		else {
			s = &ostr->data()[start];
		}
	}
	return s;
}

int BString::inString(int pos) const {
	int	r = 0;

	if((pos >= 0) && (pos <= len()))
		r = 1;
	return r;
}

int BString::del(int start, int l){
	char*	d;
	char*	s;
	int	r = 0;

	if(ostr){
		ostr = ostr->copy();
		if(inString(start) && len()){
			if(l > (len() - start))
				l = len() - start;
			d = &ostr->data()[start];
			s = &ostr->data()[start + l];
			while(*d++ = *s++);
			ostr->setLen(ostr->len() - l);
			r = 1;
		}
	}
	return r;
}

int BString::insert(int start, BString str){
	BString	s;
	int	r = 0;

	if(inString(start)){
		if(start)
			s = subString(0, start);
		s = s + str;
		s = s + subString(start, -1);
		*this = s;
		r = 1;
	}
	return r;
}

BString& BString::printf(const char* fmt, ...)
{
	va_list	ap;
	int	l;
	char*	s = 0;

	if(ostr && ostr->deleteRef() == 0)
		delete ostr;
	ostr = 0;

	va_start(ap, fmt);
	l = vasprintf(&s, fmt, ap);
	va_end(ap);
	if(l >= 0){
		*this = s;
		free(s);
	}
	return *this;
}

int BString::find(char ch) const
{
	char*	a;
	int	p = -1;

	if(ostr && (a = strchr(ostr->data(), ch)))
		p = a - ostr->data();
	return p;
}

int BString::find(BString str) const {
	char*	a;
	int	p = -1;

	if(ostr && (a = strstr(ostr->data(), str)))
		p = a - ostr->data();
	return p;
}

int BString::findReverse(char ch) const
{
	char*	a;
	int	p = -1;

	if(ostr && (a = strrchr(ostr->data(), ch)))
		p = a - ostr->data();
	
	return p;
}

int BString::isSpace(char ch) const {
	return ((ch == ',') || (ch == ' ') || (ch == '\t') || (ch == '\n')
		|| (ch == '\r'));
}

BString BString::field(int field) const {
	char*	ps;
	char*	pe;
	BString	s;

	if(ostr){
		ps = ostr->data();
		while(field && ps && *ps){
			while(*ps && !isSpace(*ps)){
				if(*ps == '"'){
					ps++;
					while(*ps && (*ps != '"'))
						ps++;
				}
				else if(*ps == '('){
					ps++;
					while(*ps && (*ps != ')'))
						ps++;
				}
				ps++;
			}
			while(*ps && isSpace(*ps))
				ps++;
			field--;
		}

		pe = ps;
		while(*pe && !isSpace(*pe)){
			if(*pe == '"'){
				pe++;
				while(*pe && (*pe != '"'))
					pe++;
			}
			else if(*pe == '('){
				pe++;
				while(*pe && (*pe != ')'))
					pe++;
			}
			pe++;
		}
		if(*ps == '"'){
			ps++;
			pe--;
		}
		s = ps;
		s.truncate(pe - ps);
	}
	return s;
}

char** BString::fields(){
	BString	a;
	char**	r;
	char**	o;
	int	f;

	o = r = new char* [64 + 1];

	for(f = 0; f < 64; f++){
		a = field(f);
		if(a != ""){
			*o = new char [a.len() + 1];
			strcpy(*o, a.retStr());
		}
		else {
			break;
		}
		o++;
	}
	*o = 0;
	return r;
}

BList<BString> BString::getTokenList(BString separators){
	BList<BString>	list;
	BString		s = *this;
	BString		t;

	while((t = s.pullToken(separators)) != ""){
		list.append(t.removeSeparators(separators));
	}
	return list;
}

BList<BString> BString::getTokenList(char separator){
	BList<BString>	list;
	int		s = 0;
	int		e = s;

	while(s < len()){
		e = s;
		while((e < len()) && (ostr->data()[e] != separator)){
			e++;
		}
		list.append(subString(s, e - s));

		s = ++e;
	}
	return list;
}

BString BString::pullToken(BString terminators){
	char*		p = 0;
	int		s;
	int		e;
	int		n;
	BString		ret;

	if(ostr){
		p = ostr->data();
		s = 0;

		while(*p && strchr(terminators, *p)){
			s++;
			p++;
		}
		e = s;
		while(*p && !strchr(terminators, *p)){
			e++;
			p++;
		}
		n = e;
		while(*p && strchr(terminators, *p)){
			n++;
			p++;
		}

		ret = subString(s, e - s);
		*this = subString(n, -1);
	}
	return ret;
}

BString BString::removeSeparators(BString separators){
	char*		p = 0;
	int		s;
	int		e;
	BString		r;

	if(ostr){
		p = ostr->data();
		s = 0;
		while(*p && strchr(separators, *p)){
			s++;
			p++;
		}
		e = len() - 1;
		if(e > 0){
			p = ostr->data() + len() - 1;
			while(*p && strchr(separators, *p)){
				e--;
				p--;
			}
		}
		r =subString(s, e - s + 1);
	}
	return r;
}

BString BString::pullSeparators(BString separators){
	char*		p = 0;
	int		e;
	BString		ret;

	if(ostr){
		p = ostr->data();
		e = 0;
		while(*p && strchr(separators, *p)){
			e++;
			p++;
		}

		ret = subString(0, e);
		*this = subString(e, -1);
	}
	return ret;
}

BString BString::pullWord(){
	return pullToken(" \t\n");
}


BString	BString::pullLine(){
	return pullToken("\n");
}

BList<BString> BString::split(char splitChar){
	BList<BString>	list;
	int		s = 0;
	int		e = 0;
	char		c = 0;
	
	while(s < len()){
		e = s;
		while((e < len()) && ((c = get(e)) != splitChar))
			e++;
			
		list.append(subString(s, e - s));
		s = e + 1;
	}
	
	if(c == splitChar)
		list.append("");

	return list;
}

int BString::compare(const BString& string) const {
	int	r;
	
	r = strcmp(retStr(), string.retStr());
	return r;
}

int BString::compareWild(const BString& string) const {
	int	r;
	
	r = gmatch(retStr(), string.retStr());
	return r;
}

int BString::compareWildExpression(const BString& string) const {
	BString	e;
	int	n;
	int	r = 0;
	
	for(n = 0; (e = string.field(n)) != ""; n++){
		if(e[0] == '!'){
			if(gmatch(retStr(), e.retStr() + 1)){
				r = 0;
				break;
			}
		}
		else {
			if(gmatch(retStr(), e.retStr())){
				r = 1;
				break;
			}
		}
	}
	return r;
}

#if !TARGET_win32
int BString::compareRegex(const BString& pattern, int ignoreCase) const {
	int	r = 0;
	regex_t	re;
	int	reFlags = REG_EXTENDED | REG_NOSUB;

	if(ignoreCase)
		reFlags |= REG_ICASE;

	if(regcomp(&re, pattern, reFlags) != 0)
	        return 0;

	if(regexec(&re, retStr(), 0, NULL, 0) == 0)
	 	r = 1;

	regfree(&re);

	return r;
}
#endif

const char* BString::retStr() const {
	static char z[] = "";
	char*	r = z;

	if(ostr)
		r = ostr->data();
	return r;
}

char* BString::retStrDup() const {
	char*	r;
	
	if(ostr)
		r = strdup(ostr->data());
	else
		r = strdup("");
	return r;
}

int BString::retInt() const {
	int	r = 0;
	
	if(ostr)
		r = strtol(ostr->data(), NULL, 0);
	return r;
}

unsigned int BString::retUInt() const {
	unsigned int	r = 0;
	
	if(ostr)
		r = strtoul(ostr->data(), NULL, 0);
	return r;
}

double BString::retDouble() const {
	double	r = 0;
	
	if(ostr)
		r = strtod(ostr->data(), NULL);
	return r;
}

int BString::append(const BString& string) {
	if(ostr){
		if(string.ostr){
			ostr = ostr->copy();
			ostr->setLen(len() + string.len() + 1);
			strcat(ostr->data(), string.ostr->data());
		}
	}
	else {
		if(string.ostr){
			ostr = string.ostr->addRef();
		}
	}
	return 0;
}

BString BString::add(const BString& string) const {
	BString	s;

	if(ostr || string.ostr){
		s.ostr = new BRefData(len() + string.len() + 1);
		s.ostr->data()[0] = '\0';
		if(ostr)
			strcat(s.ostr->data(), ostr->data());
		if(string.ostr)
			strcat(s.ostr->data(), string.ostr->data());
	}
	return s;
}

BString& BString::operator=(const BString& string) {
	if(this != &string){
		if(ostr && (ostr->deleteRef() == 0))
			delete ostr;
		if(string.ostr)
			ostr = string.ostr->addRef();
		else
			ostr = 0;
	}
	return *this;
}

char& BString::get(int pos){
	char*	p = (char*)"";

	if(ostr){
		p = &ostr->data()[pos];
	}
	else {
		fprintf(stderr, "BString: array operator out of range\n");
		exit(1);
	}
	return *p;
}

const char& BString::get(int pos) const{
	char*		p = (char*)"";

	if(ostr){
		p = &ostr->data()[pos];
	}
	else {
		fprintf(stderr, "BString: array operator out of range\n");
		exit(1);
	}
	return *p;
}

char& BString::operator[](int pos){
	char*		p = (char*)"";

	if(ostr){
		p = &ostr->data()[pos];
	}
	else {
		fprintf(stderr, "BString: array operator out of range\n");
		exit(1);
	}
	return *p;
}

BString BString::dirname(){
	BString	r;
	int	e;

	if((e = findReverse('/')) >= 0){
		r = subString(0, e);
	}
	
	return r;
}

BString	BString::basename(){
	int	s;
	int	e;

	if((s = findReverse('/')) >= 0)
		s = s + 1;
	else
		s = 0;

	if((e = findReverse('.')) >= 0)
		e = e - s;
	
	return subString(s, e);
}

BString	BString::extension(){
	BString	r;
	int	s;

	if((s = findReverse('.')) >= 0)
		r = subString(s + 1, -1);
	
	return r;
}

BUInt32 BString::hash() const {
	BUInt32	hash = 0;
	char*	p = 0;
	int	c;

	if(ostr && (p = ostr->data())){
		hash = 5381;
		while(c = *p++){
			hash = ((hash << 5) + hash) + c;	// hash * 33 + c
		}
	}
	
	return hash;
}

#ifdef ZAP
BString operator+(const char* a1, BString& a2) {
	return (BString)a1 + a2;
}
#endif

std::ostream& operator<<(std::ostream& o, BString& s){
	o << s.retStr();
	return o;
}

std::istream& operator>>(std::istream& i, BString& s){
	char	buf[1024];

	i >> buf;
	s = (BString)buf;
	return i;
}

int bstringListinList(BStringList& list, BString s){
	BIter	i;
	int	r = 0;
	
	for(list.start(i); !list.isEnd(i); list.next(i)){
		if(list[i] == s)
			return 1;
	}
	
	return r;
}

BString blistToString(const BStringList& list){
	BString	s;
	BIter	i;
	
	for(list.start(i); !list.isEnd(i); list.next(i)){
		if(s.len())
			s += ",";
		s = s + list[i];
	}
	
	return s;
}

BStringList bstringToList(BString str, int stripSpaces){
	BList<BString>	list;
	int		s = 0;
	int		e = 0;
	int		em = 0;
	char		c = 0;
	
	while(s < str.len()){
		e = s;
		while((e < str.len()) && ((c = str[e]) != ','))
			e++;

		em = e;
		if(stripSpaces){
			while((s < em) && isspace(str[s]))
				s++;
			
			while((em > s) && isspace(str[em - 1]))
				em--;
		}
		list.append(str.subString(s, em - s));
		s = e + 1;
	}
	if(c == ',')
		list.append("");

	return list;
}

BStringList charToList(const char** str){
	BList<BString>	list;

	while(*str){
		list.append(*str);
		str++;
	}
	return list;
}

BString barrayToString(const BStringArray& list){
	BString	s;
	BUInt	i;
	
	for(i = 0; i < list.size(); i++){
		if(s.len())
			s += ",";
		s = s + list[i];
	}
	
	return s;
}

BStringArray bstringToArray(BString str, int stripSpaces){
	BStringArray	list;
	int		s = 0;
	int		e = 0;
	int		em = 0;
	char		c = 0;
	
	while(s < str.len()){
		e = s;
		while((e < str.len()) && ((c = str[e]) != ','))
			e++;

		em = e;
		if(stripSpaces){
			while((s < em) && isspace(str[s]))
				s++;
			
			while((em > s) && isspace(str[em - 1]))
				em--;
		}
		list.append(str.subString(s, em - s));
		s = e + 1;
	}

	if(c == ',')
		list.append("");
	
	return list;
}

BStringArray charToArray(const char** str){
	BStringArray	list;

	while(*str){
		list.append(*str);
		str++;
	}
	return list;
}


// String conversion functions
void toBString(BString& v, BString& s){
	s = v;
}

void toBString(BStringList& v, BString& s){
	s = blistToString(v);
}

void toBString(BInt32& v, BString& s){
	s = BString::convert(v);
}

void toBString(BUInt32& v, BString& s){
	s = BString::convert(v);
}

void toBString(BUInt64& v, BString& s){
	s.printf("%lld", v);
}

void toBString(BFloat64& v, BString& s){
	s.printf("%.8e", v);
}


void fromBString(BString& s, BString& v){
	v = s;
}

void fromBString(BString& s, BStringList& v){
	v = bstringToList(s);
}

void fromBString(BString& s, BInt32& v){
	v = s.retInt();
}

void fromBString(BString& s, BUInt32& v){
	v = s.retUInt();
}

void fromBString(BString& s, BUInt64& v){
	v = strtoull(s.retStr(), NULL, 0);
}

void fromBString(BString& s, BFloat64& v){
	v = s.retDouble();
}
