/*
 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Yokogawa Electric Corporation,
 * YDC Corporation, IPA (Information-technology Promotion Agency, Japan).
 * All rights reserved.
 * 
 * Redistribution and use of this software in source and binary forms, with 
 * or without modification, are permitted provided that the following 
 * conditions and disclaimer are agreed and accepted by the user:
 * 
 * 1. Redistributions of source code must retain the above copyright 
 * notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the following disclaimer in the 
 * documentation and/or other materials provided with the distribution.
 * 
 * 3. Neither the names of the copyrighters, the name of the project which 
 * is related to this software (hereinafter referred to as "project") nor 
 * the names of the contributors may be used to endorse or promote products 
 * derived from this software without specific prior written permission.
 * 
 * 4. No merchantable use may be permitted without prior written 
 * notification to the copyrighters. However, using this software for the 
 * purpose of testing or evaluating any products including merchantable 
 * products may be permitted without any notification to the copyrighters.
 * 
 * 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHTERS, THE PROJECT AND 
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING 
 * BUT NOT LIMITED THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.  IN NO EVENT SHALL THE 
 * COPYRIGHTERS, THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT,STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $TAHI: v6eval/lib/Cm/CmString.cc,v 1.12 2001/10/12 04:56:14 tanaka Exp $
 */
#include "CmString.h"
//IMPLEMENTATION
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "CmTypes.h"
#if !defined(__FreeBSD__) && !defined(__bsdi__)
#include <alloca.h>
#endif

void CmString::set(CSTR s,long l) {
	data_=s;
	length_=l;
}

CmString::CmString():data_(0),length_(0) {
}

CmString::CmString(CSTR s) {
	set(s,s!=0?strlen(s):0);
}

CmString::CmString(CSTR s, long n) {
	set(s,n);
}

CmString::CmString(const CmString& s) {
	set(s.string(),s.length());
}

CmString::~CmString() {}

CmString& CmString::operator=(const CmString& s) {
	if(this!=&s) {
		set(s.string(),s.length());}
	return *this;
}

CmString& CmString::operator=(CSTR s) {
	set(s,s!=0?strlen(s):0);
	return *this;
}

uint32_t CmString::hash() const {
	int32_t l=length();
	CSTR s=string();
	return basicHash(s,l<0?strlen(s):l);}

int CmString::compare(CSTR s) const {
	CSTR ms=string();
	int r=0;
	/**/ if(ms!=0&&s!=0) {r=strcmp(ms,s);}
	else if(ms==0&&s==0) {r=0;}
	else if(ms!=0&&s==0) {r=1;}
	else if(ms==0&&s!=0) {r=-1;}
	return r;}

int CmString::compare(const CmString& s) const {
	return compare(s.string());}

bool CmString::operator==(CSTR s) const {
	return compare(s)==0;}

bool CmString::operator==(const CmString& s) const {
	return operator==(s.string());}

bool CmString::like(CSTR s) const {
	CSTR ms=string();
	return (ms!=0&&s!=0)?(strncmp(ms,s,length())==0):(ms==s);}

bool CmString::case_insensitive_equal(const CmString& s) const {
	long l=length();
	if(l!=s.length()) {
		return false;}
	CSTR p = string();
	CSTR q = s.string();
	CSTR e = p+l;
	for (; p < e; p++, q++) {
		long c1 = *p;
		long c2 = *q;
		if (c1 != c2 && tolower(c1) != tolower(c2)) {
			return false;
		}
	}
	return true;
}

bool CmString::case_insensitive_equal(CSTR s) const {
	return case_insensitive_equal(CmString(s));
}

/*
* A negative value for start initializes the position at the end
* of the string before indexing.  Any negative length makes
* the substring extend to the end of the string.
*/

CmString CmString::substr(long start,long len) const {
	long l=length();
	if (start >= l || start < -l) {
		/* should raise exception */
		return *this;
	}
	long pos = (start >= 0) ? start : (l + start);
	if (pos + len > l) {
		/* should raise exception */
		return *this;
	}
	long nl=(len>=0)?len:(l-pos);
	return CmString(data_+pos,nl);
}

void CmString::set_to_substr(long start,long len) {
	long l=length();
	if (start >= l || start < -l) {
		/* should raise exception */
		return;
	}
	long pos = (start >= 0) ? start : (l + start);
	if (pos + len > l) {
		/* should raise exception */
		return;
	}
	long nl = (len >= 0) ? len : (l - pos);
	set(data_+pos,nl);
}

/*
* A negative value for start initializes the position to the end
* of the string before indexing and searches right-to-left.
*/

long CmString::search(long start, char c) const {
	long l=length();
	if (start >= l || start < -l) {
		/* should raise exception */
		return -1;
	}
	CSTR s=string();
	CSTR p=s+(0<=start?start:0);
	CSTR e=s+l+(start<0?start:0);
	long pos=-1;
	long len;
	for(; p<e; p+=len){
		len=mblen(p,2);
		if(*p==c){
			pos=p-s;
			if(start>=0) break;}}
	return pos;
}

/*
* Convert a string to binary value.
*/

bool CmString::convert(int& value) const {
	CSTR s = string();
	STR ptr;
	value = s!=0?strtol(s, &ptr, 0):0;
	return ptr != s;
}

bool CmString::convert(long& value) const {
	CSTR s = string();
	STR ptr;
	value = s!=0?strtol(s, &ptr, 0):0;
	return ptr != s;
}

bool CmString::convert(float& value) const {
	CSTR s = string();
	STR ptr;
	value = s!=0?(float)strtod(s, &ptr):0.;
	return ptr != s;
}

bool CmString::convert(double& value) const {
	CSTR s = string();
	STR ptr;
	value = s!=0?strtod(s, &ptr):0.;
	return ptr != s;
}

/* class CmCString */

CmCString::CmCString():CmString(),allocated_(0) {}

CmCString::CmCString(CSTR s):CmString(),allocated_(0) {
	set(s,s!=0?strlen(s):0);
}

CmCString::CmCString(CSTR s, long length):CmString(),allocated_(0) {
	set(s, length);
}

CmCString::CmCString(const CmString& s):CmString(),allocated_(0) {
	set(s.string(), s.length());
}

CmCString::CmCString(const CmCString& s):CmString(),allocated_(0) {
	set(s.string(), s.length());
}

CmCString::~CmCString() {
	free();
}

/*
* Guarantee null-terminated string for compatibility with prlongf et al.
*/

void CmCString::set(CSTR s,long l) {
	long nl=l+1;
	STR ns=(STR)string();
	if(allocated_<nl) {
		free();
		nl=round8(nl);
		ns=new char[allocated_=nl];}
	if(l>0) {strncpy(ns,s,l);}
	ns[l]='\0';
	CmString::set(ns,l);
}

void CmString::free() {
	delete [] data_;
	CmString::set(0,0);
}

void CmCString::free() {
	CmString::free();
	allocated_=0;
}

CmCString& CmCString::operator+=(CSTR as) {
	long ml=length();
	long al=as!=0?strlen(as):0;
	long l=ml+al;
	STR ns=(STR)alloca(l+1);
	CSTR ms=string();
	CSTR e;
	STR t=ns;
	for(e=ms+ml;ms<e;ms++,t++) {
		*t=*ms;}
	for(e=as+al;as<e;as++,t++) {
		*t=*as;}
	*t=0;
	set(ns,l);
	return *this;}

implementCmSet(StringSet, CmString);
implementCmList(StringList, CmString);
implementCmList(CStringList, CmCString);


syntax highlighted by Code2HTML, v. 0.9.1