/******************************************************************************
*
* Copyright (c) 2014 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer.
*
* 2. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR 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.
*
*
* StringT.h
*
*****************************************************************************/
#pragma once
#include <oz++/CommonObject.h>
#include <oz++/Exception.h>
namespace OZ {
template <class T> class StringT :public CommonObject {
private:
int length;
T* text;
private:
bool copy(const T* string)
{
assert(string);
bool rc = false;
int len = __strlen(string);
T* temp = new T[len+1];
if(temp) {
__strcpy(temp, string);
if(this->text != string && this->text !=NULL) {
delete [] this->text;
}
this->text = temp;
this->length = len;
rc = true;
} else {
Exception("Memory allocation error.").display();
assert(temp == NULL);
}
return rc;
}
public:
/**
*/
StringT()
:length(0),
text(NULL)
{
}
public:
StringT(T* array, int len)
:length(0),
text(NULL)
{
assert(array);
assert(len>0);
deepCopy(array, len);
}
public:
StringT(const T* string, bool deepCopy=true)
:length(0),
text(NULL)
{
//2016/04/23
if (string) {
//assert(string);
if (deepCopy) {
copy(string);
} else {
shallowCopy((T*)string);
}
}
}
public:
StringT(const StringT* string)
:length(0),
text(NULL)
{
assert(string);
const T* str = string->getContents();
assert(str);
copy(str);
}
public:
StringT(const StringT& string)
:length(0),
text(NULL)
{
const T* str = string.getContents();
if (str) {
copy(str);
}
}
public:
~StringT()
{
clear();
}
private:
void clear()
{
if (this->text) {
delete [] this->text;
}
this->text =NULL;
this->length = 0;
}
public:
T* getContents() const
{
return this->text;
}
public:
int getLength() const
{
return this->length;
}
public:
bool isEmpty()
{
bool rc = false;
if (this->length>0 && this->text !=NULL) {
rc = true;
}
return rc;
}
public:
operator T*() const
{
return this->text;
}
public:
operator const T*() const
{
return this->text;
}
public:
StringT& operator=(const T* string)
{
if (string != NULL) {
if(copy(string) == false) {
throw Exception("Failed to substitue a string");
}
}
return *this;
}
public:
// The string parameter can be non-NULL terminated.
void deepCopy(T* string, int length)
{
if (string != NULL && length>0) {
if (this->text != string) {
clear();
}
int len = length;
T* temp = new T[len+1];
__memcpy(temp, string, len);
temp[len] = ZERO; //Put a NULL char at this len position to make a NULL terminated string
this->text = temp;
this->length = len;
} else {
clear();
this->text = NULL;
this->length = 0;
}
}
public:
void shallowCopy(T* string)
{
// Accept a string of NULL
if (string) {
if (this->text != string) {
clear();
}
this->text = string;
this->length = __strlen(string);
}
else {
clear();
this->text = string; //NULL
this->length = 0;
}
}
public:
StringT& operator=(const StringT& string)
{
//this->length = string.getLength();
T* str = string.getContents();
if (str) {
if (copy(str) == false) {
throw Exception("Failed to substitue a string");
}
} else {
//str = NULL;
clear();
this->text = str;
this->length = 0;
}
return *this;
}
public:
int operator==(const T* string)
{
int rc = 0;
if (this->text == NULL && string ==NULL) {
rc = 1;
}
//2008/07/08
if (this->text != NULL && string != NULL) {
if(__strcmp(this->text, string) == 0) {
rc = 1;
}
}
return rc;
}
//int operator==(String& string)
public:
int operator==(StringT& string)
{
int rc = 0;
const T* str = (const T*)string;
if (this->text == NULL && str ==NULL) {
rc = 1;
}
if (this->text != NULL && str != NULL) {
if(__strcmp(this->text, str) == 0) {
rc = 1;
}
}
return rc;
}
public:
StringT& operator+(const T* string)
{
if(string == NULL) {
return *this;
}
size_t orglen = this->length;
this->length += strlen(string);
T* temp = new T[this->length+1];
__memset(temp, (T)0, length+1);
__memcpy(temp, this->text, orglen);
__memcpy(temp+orglen, string, strlen(string));
if(this->text != string) {
delete [] text;
}
text = temp;
return *this;
}
public:
int compare(CommonObject* object)
{
int rc = 0;
if (object==NULL) {
return rc;
}
StringT* string = (StringT*)object;
const T* p1 = this->text;
const T* p2 = (const T*)(*string);
if (p1 == NULL && p2 == NULL) {
rc = 1;
}
if (p1 != NULL && p2 != NULL) {
rc = __strcmp(p1, p2);
}
return rc;
}
public:
const T* find(const T* string)
{
const T* ptr = NULL;
if (this->text && string) {
ptr = __strstr(this->text, string);
}
return ptr;
}
public:
int replace(T oc, T nc)
{
int n = 0;
if (this->text) {
for (int i = 0; i<this->length; i++) {
if (text[i] == oc) {
text[i] = nc;
n++;
}
}
}
return n;
}
public:
StringT substring(int position, int size)
{
if (this->text) {
if (position>=0 && position<this->length) {
if ((position+size)>=this->length) {
size = this->length - position;
}
return StringT(&text[position], size);
}
}
return StringT(NULL, 0);
}
public:
StringT& operator+(T ch)
{
T string[2];
string[0] = ch;
string[1] = (T)0;//Zero;
return StringT::operator+(string);
}
private:
StringT& appendFormat(T* format,...)
{
T buffer[128];
memset(buffer, (T)0, 128);
va_list pos;
va_start(pos, format);
__vsprintf(buffer, format, pos);
va_end(pos);
return StringT::operator+(buffer);
}
public:
StringT& operator+(int num)
{
T format[3] ={(T)'%',(T)'d', (T)0};
return appendFormat(format, num);
}
public:
StringT& operator+(float num)
{
T format[3] ={(T)'%',(T)'f', (T)0};
return appendFormat(format, num);
}
public:
StringT& operator+(double num)
{
T format[3] ={(T)'%',(T)'f', (T)0};
return appendFormat(format, num);
}
public:
bool equals(const T* str) {
bool rc = false;
if(this->text != NULL && str != NULL) {
if(__strcmp(this->text, str) == 0) {
rc = true;
}
}
return rc;
}
public:
bool equals(const StringT& str) {
return equals((const T*)str);
}
public:
bool equalsIgnoreCase(const T* str) {
bool rc = false;
if(this->text != NULL && str != NULL) {
//strcmpi -> stricmp
if(__strcasecmp(this->text, str) == 0) {
rc = true;
}
}
return rc;
}
public:
bool equalsIgnoreCase(const StringT& str) {
return equalsIgnoreCase((const T*)str);
}
public:
void trim()
{
T* rt = StringT::trim(this->text);
if (rt) {
clear();
//Shallow copy
this->text = rt;
this->length = __strlen(rt);
}
}
public:
void trimOnNewLine() {
if (this->text) {
T newLine[1] = { (T)'\n'};
T* ptr = (T*)__strstr(this->text, newLine);
if (ptr) {
//Terminate this text on this ptr position by putting '\0';
*ptr = '\0';
this->length = __strlen(this->text);
}
}
}
public:
/**
*/
bool startsWith(const T* start) {
return StringT::startsWith(this->text, start);
}
public:
/**
*/
bool startsWithIgnoreCase(const T* start) {
return StringT::startsWithIgnoreCase(this->text, start);
}
public:
/**
*/
bool endsWith(const T* end) {
return StringT::endsWith(this->text, end);
}
public:
/**
*/
bool endsWithIgnoreCase(const T* end) {
return StringT::endsWithIgnoreCase(this->text, end);
}
public:
//2009/11/12
const T* findLast(const T* string)
{
return StringT::findLast(this->text, string);
}
public:
//2009/11/12
static const T* findLast(const T* text, const T* string)
{
const T* ptr = NULL;
if (text && string) {
int tlen = __strlen(text);
int slen = __strlen(string);
if (tlen < slen) {
return ptr;
} else {
for(int i = tlen - slen; i>=0; i--) {
int n= __strncmp(text + i, string, slen);
if (n == 0) {
ptr = text + i;
break;
}
}
}
}
return ptr;
}
public:
const T* findFirst(const T* string) {
return StringT::findFirst(this->text, string);
}
public:
static const T* findFirst(const T* text, const T* string) {
const T* ptr = NULL;
if (text && string) {
ptr = __strstr(text, string);
}
return ptr;
}
public:
T& operator[](int n)
{
if (this->text == NULL) {
throw Exception("String::operator[] - Text is NULL");
}
if (n <=0 || n>this->length) {
throw Exception("String::operator[] - Index is out of range");
}
//
return text[n];
}
//////////////////////////////////////////////////////////////////////
/// static methods.
public:
static T* trim(T* string) {
if (string == NULL) {
return string;
}
size_t slen = __strlen(string)+1;
T* temp = new T[slen];
__strcpy(temp, string);
T* p = temp;
while (*p == (T)' ' || *p == (T)'\t' || *p ==(T)'\r' || *p==(T)'\n') {
p++;
}
T* t = p + strlen(p) -1;
while (*t == (T)' ' || *t == (T)'\t' || *t ==(T)'\r' || *t==(T)'\n') {
if (p == t) break;
*t = (T)'\0';
t--;
}
size_t plen = __strlen(p)+1;
T* rt = new T[plen];
__strcpy(rt, plen, p);
delete [] temp;
return rt;
}
public:
/**
*
* @param string
* @param start
* @return bool
*
*/
static bool startsWith(const T* string, const T* start) {
bool rc = false;
if (string != NULL && start != NULL) {
if (__strncmp(string, start, __strlen(start)) ==0) {
rc = true;
}
}
return rc;
}
public:
/**
*
* @param string
* @param start
* @return bool
*/
static bool startsWithIgnoreCase(const T* string, const T* start) {
bool rc = false;
if (string != NULL && start != NULL) {
if (__strncasecmp(string, start, __strlen(start)) ==0) {
rc = true;
}
}
return rc;
}
public:
/**
*
* @param string
* @param end
* @return bool
*/
static bool endsWith(const T* string, const T* end) {
bool rc = false;
if (string != NULL && end != NULL) {
size_t tlen = __strlen(string);
size_t slen = __strlen(end);
if (tlen >= slen) {
if (__strncmp(string+tlen-slen, end, slen) ==0) {
rc = true;
}
}
}
return rc;
}
public:
/**
*
* @param string
* @param end
* @return bool
*/
static bool endsWithIgnoreCase(const T* string, const T* end) {
bool rc = false;
if (string != NULL && end != NULL) {
size_t tlen = __strlen(string);
size_t slen = __strlen(end);
if (tlen >= slen) {
if (strncasecmp(string+tlen-slen, end, slen) ==0) {
rc = true;
}
}
}
return rc;
}
//2014/12/21 Printf a string without a new line
virtual void write()
{
int mode = fwide(stdout, 0);
if (sizeof(T) == sizeof(char)) {
if (mode == 0) {
printf("%s", (const char*)this->text);
} else {
fwide(stdout, 0);
wprintf(L"%s", (const char*)this->text);
}
}
if (sizeof(T) == sizeof(wchar_t)) {
fwide(stdout, 1);
wprintf(L"%ls", (const wchar_t*)this->text);
}
}
/* virtual const T* toString()
{
return text;
}
*/
void display()
{
int mode = fwide(stdout, 0);
if (sizeof(T) == sizeof(char)) {
if (mode == 0) {
printf("%s\n", (const char*)this->text);
} else {
//fwide(stdout, 1);
wprintf(L"%s\n", (const char*)this->text);
}
}
if (sizeof(T) == sizeof(wchar_t)) {
fwide(stdout, 1);
wprintf(L"%ls\n", (const wchar_t*)this->text);
}
}
};
}