//
// Copyright (C) 1999-2004 Toshikaz Hirabayashi
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// TOSHIKAZ HIRABAYASHI BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Except as contained in this notice, the name of Toshikaz Hirabayashi shall
// not be used in advertising or otherwise to promote the sale, use or other
// dealings in this Software without prior written authorization from
// Toshikaz Hirabayashi.

#include <WScom.h>
#include <WSCstring.h>
#include <WSClistData.h>
#include <WSClocaleSet.h>

long WSCstring::getLines(){
  return getWords("\n");
}
void WSCstring::clear(){
  if (_str != NULL){
//WSMFtrace("WSCstring::clear #%s# deleted=0x%x\n",_str,_str);
    _str[0] = 0;
    delete[] _str;
    _str = NULL;
  }
  _seek_pt = 0;
  _encoding = WS_EN_DEFAULT;
  _clear_list();
}
void WSCstring::_clear_list(){
//printf("WSCstring::_clear_list()...this=0x%x\n",this);
  long i;
  long num = _tmp_list.getNum();
  for(i=0; i<num; i++){
    char* str = (char*)_tmp_list[i];
    str[0] = 0;
    delete str;
//WSMFtrace("WSCstring::_clear_list deleted=0x%x\n",str);
  }
  _tmp_list.clear();
  _tmp_encode.clear();
  _chars = -1;
}

WSCstring::WSCstring(){
//printf("WSCstring::WSCstring() this=0x%x\n",this);
  _str = NULL;
  _encoding = WS_EN_DEFAULT;
  _seek_pt = 0;
  _chars = -1;
}

WSCstring::WSCstring(const char* str,long encode){
//printf("WSCstring::WSCstring(char* str) this=0x%x\n",this);
  _encoding = encode;
  if (str != NULL){
    _str = WSGFstrdup(str);
  }else{
    _str = NULL;
  }
//printf("WSCstring::WSCstring(char*) enc=%d str=0x%x #%s#\n",_encoding,str,_str);
  _seek_pt = 0;
  _chars = -1;
}
WSCstring::WSCstring(WSCstring& str){
//printf("WSCstring::WSCstring(WSCstirng& str) this=0x%x\n",this);
  _encoding = str._encoding;
  if (str._str != NULL){
    _str = WSGFstrdup(str._str);
  }else{
    _str = NULL;
  }
//printf("WSCstring::WSCstring(WSCstring&) enc=%d #%s#\n",_encoding,_str);
  _seek_pt = 0;
  _chars = str._chars;
}

WSCstring::WSCstring(const WSCstring& str){
//printf("WSCstring::WSCstring(WSCstirng& str) this=0x%x\n",this);
  _encoding = str._encoding;
  if (str._str != NULL){
    _str = WSGFstrdup(str._str);
  }else{
    _str = NULL;
  }
//printf("WSCstring::WSCstring(WSCstring&) enc=%d #%s#\n",_encoding,_str);
  _seek_pt = 0;
  _chars = str._chars;
}

WSCstring::WSCstring(WSCvariant& str,long encode){
  _encoding = encode;
  _str = WSGFstrdup(str.getCharPtr());
//printf("WSCstring::WSCstring(WSCvariant) enc=%d #%s#\n",_encoding,_str);
  _seek_pt = 0;
  _chars = -1;
}


WSCstring::WSCstring(const WSCvariant& str,long encode){
  _encoding = encode;
  WSCvariant tmp(str);
  _str = WSGFstrdup(tmp.getCharPtr());
//printf("WSCstring::WSCstring(WSCvariant) enc=%d #%s#\n",_encoding,_str);
  _seek_pt = 0;
  _chars = -1;
}
  
long WSCstring::operator ==(const WSCstring& src){
  WSCstring tmp;
  tmp = src;
  if (!strcmp(getString(),tmp.getString())){
    return 1;
  }
  return 0;
}


WSCstring& WSCstring::operator =(const WSCstring& src){
//printf("WSCstring operator =WSCstring&\n");
  if (&src != this){
    if (_str != NULL){
      delete _str;
      _str = NULL;
    }
    if (src._str != NULL){ 
      _str = WSGFstrdup(src._str);
    }
    _encoding = src._encoding;
    _seek_pt = 0;
    _clear_list();
    _chars = src._chars;
  }
  return *this;
}
WSCstring& WSCstring::operator =(const char* src){
//printf("WSCstring operator =char*\n");
  setString(src);
  return *this;
}
WSCstring& WSCstring::operator =(const WSCvariant& src){
  WSCvariant tmp = src;
  setString(tmp.getCharPtr());
  return *this;
}
WSCstring WSCstring::operator +(const WSCstring& str1){
  WSCstring _ret(*this);
  _ret.addString(str1);
  return _ret;
}
WSCstring WSCstring::operator +(const char* str1){
  WSCstring _ret(*this);
  _ret.addString(str1);
  return _ret;
}
WSCstring WSCstring::operator +(const WSCvariant& str1){
  WSCstring _ret(*this);
  WSCvariant tmp = str1;
  _ret.addString(tmp.getCharPtr());
  return _ret;
}
WSCstring& WSCstring::operator +=(const WSCstring& str1){
  addString(str1);
  return *this;
}
WSCstring& WSCstring::operator +=(const WSCvariant& str1){
  WSCvariant tmp = str1;
  addString(tmp.getCharPtr());
  return *this;
}
WSCstring& WSCstring::operator +=(const char* str1){
  addString(str1);
  return *this;
}
WSCstring& WSCstring::operator <<(const WSCstring& str1){
  addString(str1);
  return *this;
}
WSCstring& WSCstring::operator <<(const WSCvariant& str1){
  WSCvariant tmp = str1;
  addString(tmp.getCharPtr());
  return *this;
}
WSCstring& WSCstring::operator <<(const char* str1){
  addString(str1);
  return *this;
}
WSCstring& WSCstring::operator <<(long val){
  addString(WSGFltoa(val));
  return *this;
}
WSCstring& WSCstring::operator <<(WSCulong val){
  addString(WSGFultoa(val));
  return *this;
}
WSCstring& WSCstring::operator <<(int val){
  addString(WSGFltoa(val));
  return *this;
}
WSCstring& WSCstring::operator <<(WSCuint val){
  addString(WSGFultoa(val));
  return *this;
}
WSCstring& WSCstring::operator <<(double val){
  addString(WSGFlftoa(val));
  return *this;
}
WSCstring& WSCstring::operator <<(float val){
  addString(WSGFftoa(val));
  return *this;
}

WSCstring::operator char* (){
//printf("WSCstring::operator char* ret=0x%x #%s#\n",getString(),getString());
  return getString();
}
WSCstring::operator WSCvariant(){
  WSCvariant var;
  var = getString();
  return var;
}

WSCstring::~WSCstring(){
  clear();
}
long WSCstring::_get_encoding() const{
  long encoding = _encoding;
  if (encoding == WS_EN_DEFAULT){
    encoding = WSGIappLocaleSet()->getDefaultEncoding();
  }
  if (encoding == WS_EN_LOCALE){
    encoding = WSGIappLocaleSet()->getSystemLocaleEncoding();
  } 
  return encoding;
}
void WSCstring::delLineFeed(){
  if (_str != NULL){
    long cnt =0;
    long max = strlen(_str);
    long i;
    for(i=0; i < max; i++){
      if (_str[i] != '\n'){
        _str[cnt] = _str[i];
        cnt++;
      }
    }
    _str[cnt] = 0;
    _clear_list();
    _chars = -1;
    return;
  }
}

char* WSCstring::_get_utf8_string(char* str,long encode){
  if (encode == WS_EN_DEFAULT){
    encode = WSGIappLocaleSet()->getDefaultEncoding();
  } 
  if (encode == WS_EN_LOCALE){
    encode = WSGIappLocaleSet()->getSystemLocaleEncoding();
  } 
  int len = WSGIappCodeConvert()->codeConvert(NULL,0,WS_EN_UTF8,str,-1,encode);
  char* ret = new char[len+1];
  WSGIappCodeConvert()->codeConvert(ret,len+1,WS_EN_UTF8,str,-1,encode);
  return ret;
}
char* WSCstring::_get_mb_string(char* str,long encode){
  if (encode == WS_EN_DEFAULT){
    encode = WSGIappLocaleSet()->getDefaultEncoding();
  } 
  if (encode == WS_EN_LOCALE){
    encode = WSGIappLocaleSet()->getSystemLocaleEncoding();
  } 
  int len = WSGIappCodeConvert()->codeConvert(NULL,0,encode,str,-1,WS_EN_UTF8);
  char* ret = new char[len+1];
  WSGIappCodeConvert()->codeConvert(ret,len+1,encode,str,-1,WS_EN_UTF8);
  return ret;
}
char* WSCstring::_convert_string(const char* str,long from_encode,long to_encode){
  if (to_encode == WS_EN_DEFAULT){
    to_encode = WSGIappLocaleSet()->getDefaultEncoding();
  } 
  if (to_encode == WS_EN_LOCALE){
    to_encode = WSGIappLocaleSet()->getSystemLocaleEncoding();
  } 
  if (from_encode == WS_EN_DEFAULT){
    from_encode = WSGIappLocaleSet()->getDefaultEncoding();
  } 
  if (from_encode == WS_EN_LOCALE){
    from_encode = WSGIappLocaleSet()->getSystemLocaleEncoding();
  } 
  int len = WSGIappCodeConvert()->codeConvert(NULL,0,to_encode,str,-1,from_encode);
  char* ret = new char[len+1];
  WSGIappCodeConvert()->codeConvert(ret,len+1,to_encode,str,-1,from_encode);
  return ret;
}

void WSCstring::addString(const char* string,long encode){
  if (string == NULL){
    return;
  }
  if (_str == NULL){
    setString(string,encode);
    return;
  }
  if (encode == WS_EN_DEFAULT){
    encode = WSGIappLocaleSet()->getDefaultEncoding();
  }
  if (encode == WS_EN_LOCALE){
    encode = WSGIappLocaleSet()->getSystemLocaleEncoding();
  } 
  if (encode == _get_encoding()){
    long len = strlen(_str) + strlen(string);
    char* new_str = new char[len+1];
    strcpy(new_str,_str);
    strcat(new_str,string);
    setString(new_str,encode);
    delete new_str;
    return;
  }else{
    char* org = _convert_string(_str,_get_encoding(),WS_EN_UTF8);
    char* string2 = _convert_string(string,encode,WS_EN_UTF8);
    setString(org,WS_EN_UTF8);
    addString(string2,WS_EN_UTF8);
    delete org;
    delete string2;
    return;
  }
}
void WSCstring::addString(const WSCstring& src){
  addString(src._str,src._get_encoding());
}
void WSCstring::addString(const WSCvariant& src,long encode){
  WSCvariant tmp = src;
  addString( tmp.getCharPtr(),encode);
}

char* WSCstring::getString(long encode){
  if (_str == NULL){
    return "";
  }
  if (encode == WS_EN_DEFAULT){
    encode = WSGIappLocaleSet()->getDefaultEncoding();
  } 
  if (encode == WS_EN_LOCALE){
    encode = WSGIappLocaleSet()->getSystemLocaleEncoding();
  } 
  if (encode == WS_EN_NONE){
    return _str;
  }
  long encoding = _get_encoding();
  if (encode == encoding){
//printf("WSCstring::getString encode=%d(same) return _str=%s\n",encode,_str);
    return _str;
  }else{
    char* ret = _get_string_from_list(encode);
    if (ret != NULL){
      return ret;
    }
    ret = _convert_string(_str,encoding,encode);
    _add_string_to_list(ret,encode);
//printf("WSCstring::getString encode=%d->%d  _str=#%s# _ret=0x%x _ret=#%s#\n",encoding,encode,_str,ret,ret);
    return ret;
  }
}

void WSCstring::cutString(WSCulong char_pos){
  if (_str == NULL){
    return;
  }
  char* str = _str;
  long encoding = _get_encoding();
  if (encoding != WS_EN_UTF8){
    str = _convert_string(_str,encoding,WS_EN_UTF8);
  }
  long len = strlen(str);

  char* ptr = str;
  WSCulong cnt = 0;
  int next_diff;
  while(1){
    if (len < 1){
      break;
    }
    if (cnt == char_pos){
      *ptr = 0;
      break;
    }
    next_diff = WSGIappCodeConvert()->utf8CharLen(ptr,len);
    cnt++;
    ptr += next_diff;
    len -= next_diff;
  }
  if (encoding != WS_EN_UTF8){
    char* new_str = _convert_string(str,WS_EN_UTF8,encoding);
    setString(new_str,encoding);
    delete new_str;
    delete str;
  }
  _clear_list();
}

long WSCstring::_seek_next_line(){
  if (_str == NULL){
     _seek_pt = 0;
    return 0;
  }
  long encoding = _get_encoding();
  long ptr = _seek_pt;
  if (_str[_seek_pt] == 0){
    return 0;
  }
//  long val1 = 0;
//  if (ptr > 0){
//    char* org = new char[ptr+1];
//    strncpy(org,_str,ptr);
//    org[ptr] = 0;
//    WSCushort* ustr1 = WSGFgetUCS2(org,encoding);
//    val1 = WSGFstrlenUCS2(ustr1);
//    delete ustr1;
//    delete org;
//  } 

  while( _str[ptr] != '\n' && _str[ptr] != 0 ) ptr++;
  char* ret = new char[ptr - _seek_pt +1];
  strncpy(ret,&(_str[_seek_pt]),(ptr - _seek_pt));
  ret[ptr-_seek_pt] = 0;
  _seek_pt = ptr;
  if (_str[_seek_pt] == '\n'){
     _seek_pt++;
  }
  WSCushort* ustr = WSGFgetUCS2(ret,encoding);
  long val = WSGFstrlenUCS2(ustr);
  delete ustr;
  delete ret;
  return val;
#if 0
  char* str = getString(WS_EN_EUCJP);
  long i = _seek_pt;

  if (str[i] == 0){
    return 0;
  }

  long k = 0;
  while(str[i] != 0){
    if (str[i] == '\n'){
      i++;
      break;
    }
    if(str[i] & 0x80){         //not ascii
      if (str[i] == (char)0x8e){       //Hankaku 2byte
        i++;
      }else if (str[i] == (char)0x8f){ //Gaiji 3byte
        i++;
        i++;
      }else{         //Kanji 2byte
        i++;
      }
    }
    k++;
    i++;
  }
  _seek_pt = i;
  return k;
#endif
}
long WSCstring::getChars(){
  if (_str == NULL){
    return 0;
  }
  if (_chars != -1){
    return _chars;
  }
  char* str = getString(WS_EN_UTF8);
  long len = strlen(str);
  int cnt = 0;
  int next_diff;
  while(1){
    if (len < 1){
      break;
    }
    next_diff = WSGIappCodeConvert()->utf8CharLen(str,len);
    cnt++;
    str += next_diff;
    len -= next_diff;
  }
  _chars = cnt;
  return cnt;
}

long WSCstring::getWordCharPos(long wd,const char* sep,long encode){
  if (sep == NULL){
    return getWordCharPos(wd);
  }
  
  if (wd < 0){
//printf("WSCstring::getWordCharPos wd=%d -1\n",wd);
//fflush(stdout);
    return -1;
  }
  if (encode == WS_EN_DEFAULT){
    encode = WSGIappLocaleSet()->getDefaultEncoding();
  }
  if (encode == WS_EN_LOCALE){
    encode = WSGIappLocaleSet()->getSystemLocaleEncoding();
  } 
  long encoding = _get_encoding();

  char* str = _str;
  if (str == NULL){
    str = "";
  } 
  WSCushort* sep1 = WSGFgetUCS2(sep,encode);
  long seplen = WSGFstrlenUCS2(sep1);
  if (seplen < 1){
    delete sep1;
//printf("WSCstring::getWordCharPos1 wd=%d 0\n",wd);
//fflush(stdout);
    return 0;
  }
  WSCushort* str1 = WSGFgetUCS2(str,encoding);
  long len = WSGFstrlenUCS2(str1);
//printf("str=#%s# en=%d\n",str,encoding);

  long i;
  long cnt = 0;
  if (seplen > 1){
    for(i=0; i < len +1; i++){
      if ( str1[i] == sep1[0] && !memcmp(&str1[i],sep1,seplen*sizeof(WSCushort))){
        cnt++;
        i += seplen-1;
      }
      if (cnt == wd){
        delete sep1;
        delete str1;
        if (cnt == 0){
//printf("WSCstring::getWordCharPos2 wd=%d 0\n",wd);
//fflush(stdout);
          return 0;
        }else{
//printf("WSCstring::getWordCharPos3 wd=%d %d\n",wd,i+1);
//fflush(stdout);
          return i+1;
        }
      }
    }
  }else{
//printf("WSCstring::getWordCharPos len=%d wd=%d 0\n",len,wd);
//fflush(stdout);
    for(i=0; i < len +1; i++){
//printf("WSCstring::getWordCharPos cnt=%d hit str1[i]=0x%x,sep1[0]=0x%x\n",cnt,str1[i],sep1[0]);
//fflush(stdout);
      if ( str1[i] == sep1[0]){
//printf("WSCstring::getWordCharPos cnt=%d hit sep1[0]=0x%x\n",cnt,sep1[0]);
//fflush(stdout);
        cnt++;
      }
      if (cnt == wd){
        delete sep1;
        delete str1;
        if (cnt == 0){
//printf("WSCstring::getWordCharPos4 wd=%d 0\n",wd);
//fflush(stdout);
          return 0;
        }else{
//printf("WSCstring::getWordCharPos5 wd=%d %d\n",wd,i+1);
//fflush(stdout);
          return i+1;
        }
      }
    }
  }
//printf("WSCstring::getWordCharPos6 wd=%d -1\n",wd);
//fflush(stdout);
  return -1;
}

long WSCstring::getWords(const char* sep,long encode){
  if (sep == NULL){
    return 1;
  }
  if (encode == WS_EN_DEFAULT){
    encode = WSGIappLocaleSet()->getDefaultEncoding();
  }
  if (encode == WS_EN_LOCALE){
    encode = WSGIappLocaleSet()->getSystemLocaleEncoding();
  } 
  long encoding = _get_encoding();
  if (encode != encoding){
    sep = _convert_string(sep,encode,encoding);
  }

  char* str = _str;

  if (str == NULL){
    return 0;
  }

  long len = strlen(str);
  long seplen = strlen(sep);
  if (seplen < 1){
    if (encode != encoding){
      delete sep;
    }
    return 1;
  }
  long i;
  long cnt = 1; //words

  for(i=0; i < len +1; i++){
    if ( str[i] == sep[0] && !strncmp(&str[i],sep,(size_t)seplen) ){
      cnt++;
      i += seplen-1;
    }
  }
  if (encode != encoding){
    delete sep;
  }
  return cnt;
}

WSCstring WSCstring::getWord(long pos,const char* sep,long encode){
  WSCstring _return_tmp;
  if (sep == NULL){
    sep = "";
  }
  if (encode == WS_EN_DEFAULT){
    encode = WSGIappLocaleSet()->getDefaultEncoding();
  }
  if (encode == WS_EN_LOCALE){
    encode = WSGIappLocaleSet()->getSystemLocaleEncoding();
  } 
  long encoding = _get_encoding();
  if (encode != encoding){
    sep = _convert_string(sep,encode,encoding);
  }

  char* str = _str;
  if (str == NULL){
    return _return_tmp;
  }
  long len = strlen(str);
  long seplen = strlen(sep);
  if (seplen < 1){
    _return_tmp.setString("",encoding);
    if (encode != encoding){
      delete sep;
    } 
    return _return_tmp;
  }

  long i;
  long cnt = 0;
  long hit_point=0;
  for(i=0; i < len +1; i++){
    if (str[i] == sep[0] && !strncmp(&str[i],sep,(size_t)seplen)  ){
      if (cnt == pos){
        long length = i +1 -hit_point;
        char* tmp = new char[length];
        strncpy(tmp,&str[hit_point],(size_t)(i-hit_point));
        tmp[i-hit_point] = 0;
        _return_tmp.setString(tmp,encoding);
        delete tmp;
        if (encode != encoding){
          delete sep;
        } 
        return _return_tmp;
      }
      cnt++;
      hit_point = i + seplen;
      i += seplen -1;
    }
  }

  if ( cnt == pos ){
    long length = len +1 -hit_point;
    char* tmp = new char[length];
    strcpy(tmp,&str[hit_point]);

    _return_tmp.setString(tmp,encoding);
    delete tmp;
    if (encode != encoding){
      delete sep;
    } 
    return _return_tmp;
  }
  _return_tmp.setString("",encoding);
  if (encode != encoding){
    delete sep;
  } 
  return _return_tmp;
}

long WSCstring::getWordCharPos(long wd){
  if (wd < 0){
    return -1;
  }
  char* str = _str;
  if (str == NULL){
    return -1;
  }
  long encoding = _get_encoding();

  WSCushort* str1 = WSGFgetUCS2(str,encoding);
  long len = WSGFstrlenUCS2(str1);
  long i;
  long cnt = -1;
  WSCbool flag = False;

  for(i=0; i < len +1; i++){
    if (flag == False && str[i] != ' ' && str[i] != '\t' && str[i] != '\n' && str[i] != 0){
      cnt++;
      flag = True;
    }else if (flag != False && (str[i] == ' ' || str[i] == '\t' || str[i] == '\n' || str[i] == 0) ){
      flag = False;
    }
    if (cnt == wd){
      delete str1;
      return i;
    }
  }
  delete str1;
  return -1;
}

long WSCstring::getWords(){
  char* str = _str;
  if (_str == NULL){
    return 0;
  }
  long len = strlen(str);
  long i;
  long cnt = 0; //words

  WSCbool flag = False;

  for(i=0; i < len +1; i++){
    if (flag == False && str[i] != ' ' && str[i] != '\t' && str[i] != '\n' && str[i] != 0){
      cnt++;
      flag = True;
    }else if (flag != False && (str[i] == ' ' || str[i] == '\t' || str[i] == '\n' || str[i] == 0) ){
      flag = False;
    }
  }
  return cnt;
}

WSCstring WSCstring::getWord(long pos){
  WSCstring _return_tmp;
  char* str = _str;
  if (_str == NULL){
    return _return_tmp;
  }
  long len = strlen(str);
  long i;
  long cnt = 0;

  WSCbool flag = False;
  WSCbool hit = False;
  long    hit_point=0;
  long encoding = _get_encoding();
  
  for(i=0; i < len +1; i++){
    if (flag == False && str[i] != ' ' && str[i] != '\t' && str[i] != '\n'){
      flag = True;
      if (cnt == pos){
        hit = True;
        hit_point = i;
      }
      cnt++;
    }else if (flag != False && (str[i] == ' ' || str[i] == '\t' ||
              str[i] == '\n' || str[i] == 0) ){
      flag = False;
      if (hit != False){
        long length = i +1 -hit_point;
        char* tmp = new char[length];
        strncpy(tmp,&str[hit_point],(size_t)(i-hit_point));
        tmp[i-hit_point] = 0;
        _return_tmp.setString(tmp,encoding);
        delete tmp;
        return _return_tmp;
      }
    }
  }
  _return_tmp.setString("");
  return _return_tmp;
}

void WSCstring::insertString(WSCulong char_pos,WSCstring& src){
  if ( _str == NULL ){
    setString(src);
    return;
  }
  char* str = _str;
  long encoding = _get_encoding();
  if (encoding != WS_EN_UTF8){
    str = _convert_string(_str,encoding,WS_EN_UTF8);
  }
  long len = strlen(str);
  long pos = 0;
  WSCulong cnt = 0;
  int next_diff;
  while(1){
    if (len < 1){
      break;
    }
    if (cnt == char_pos){
      break;
    }
    next_diff = WSGIappCodeConvert()->utf8CharLen(&str[pos],len);
    cnt++;
    pos += next_diff;
    len -= next_diff;
  }
  char* insert = src.getString(WS_EN_UTF8);
  long slen = strlen(insert);

  char* new_str = new char[ strlen(str) +slen +1 + 32];
  strncpy(new_str, str, (size_t)pos );
  strncpy(&new_str[pos],insert,(size_t)slen);
  strcpy(&new_str[pos + slen],&str[pos]);

  if (encoding != WS_EN_UTF8){
    delete _str;
    _str = _convert_string(new_str,WS_EN_UTF8,encoding);
    delete new_str;
    _chars = -1;
  }else{
    delete _str;
    _str = new_str;
  }
  _clear_list();
}

long WSCstring::isExist(const char* str,long encode){
  if (str == NULL || str[0] == 0){
    return -1;
  }
  if (_str == NULL){
    if (str[0] == 0){
      return 0;
    }
    return -1;
  }
  if (encode == WS_EN_DEFAULT){
    encode = WSGIappLocaleSet()->getDefaultEncoding();
  }
  if (encode == WS_EN_LOCALE){
    encode = WSGIappLocaleSet()->getSystemLocaleEncoding();
  } 
  long encoding = _get_encoding();
  if (encoding != encode){
    str = _convert_string(str,encode,encoding);
  }

  long i;
  long slen = strlen(str);
  char* text = _str;
  long len = strlen(text) - slen +1;
  if (len < 1){
    if (encoding != encode){
      delete str;
    }
    return -1;
  }

  for(i = 0; i < len; i++){
    if (text[i] == str[0]){
      if ( !strncmp(&text[i],str,(size_t)slen) ){
        if (encoding != encode){
          delete str;
        }
        if (i == 0){
          return 0;
        }
        char* tmp = WSGFstrdup(text);
        tmp[i] = 0;
        WSCushort* tmp2 = WSGFgetUCS2(tmp,encoding);
        long ret = WSGFstrlenUCS2(tmp2);
        delete tmp;
        delete tmp2;
        return ret;
      }
    }
  }
  if (encoding != encode){
    delete str;
  }
  return -1;

}

void WSCstring::delString(const char* str,long num){
  replaceString(str,"",num);
}
void WSCstring::delString(const char* str,long num,long encode){
  replaceString(str,"",num,encode);
}

void WSCstring::deleteChar(WSCulong char_pos){
  if ( _str == NULL ){
    return;
  }
  char* str = _str;
  long encoding = _get_encoding();
  if (encoding != WS_EN_UTF8){
    str = _convert_string(_str,encoding,WS_EN_UTF8);
  }
  long len = strlen(str);
  long pos = 0;
  WSCulong cnt = 0;
  int next_diff = 0;
  while(1){
    if (len < 1){
      if (encoding != WS_EN_UTF8){
        delete str;
      }
      return;
    }
    if (cnt == char_pos){
      next_diff = WSGIappCodeConvert()->utf8CharLen(&str[pos],len);
      memcpy(&str[pos],&str[pos+next_diff],len - next_diff+1);
      if (encoding != WS_EN_UTF8){
        delete _str;
        _str = _convert_string(str,WS_EN_UTF8,encoding);
        delete str;
        _chars = -1;
      }
      _clear_list();
      return;
    }
    next_diff = WSGIappCodeConvert()->utf8CharLen(&str[pos],len);
    cnt++;
    pos += next_diff;
    len -= next_diff;
  }
}

void WSCstring::_add_string_to_list(char* pstr,long encode){
  long i;
  long num = _tmp_list.getNum();
  for(i=0; i<num; i++){
    long encode1 = (long)_tmp_encode[i];
    if (encode1 == encode){
      char* str1 = (char*)_tmp_list[i];
      delete str1;
      _tmp_list.setData(i,pstr);
      return;
    }
  }
  _tmp_list.add((void*)pstr);
  _tmp_encode.add((void*)encode);
}
char* WSCstring::_get_string_from_list(long encode){
  long i;
  long num = _tmp_list.getNum();
  for(i=0; i<num; i++){
    long encode1 = (long)_tmp_encode[i];
    if (encode1 == encode){
      char* str = (char*)_tmp_list[i];
      return str;
    }
  }
  return NULL;
}
void WSCstring::setString(const char* str,long encode){
  if (encode == WS_EN_DEFAULT){
    encode = WSGIappLocaleSet()->getDefaultEncoding();
  } 
  if (encode == WS_EN_LOCALE){
    encode = WSGIappLocaleSet()->getSystemLocaleEncoding();
  } 
  if (_str != NULL){
    delete _str;
    _str = NULL;
  }
  _encoding = encode;
  _str = WSGFstrdup(str);
  _chars = -1;
  _clear_list();
  _seek_pt = 0;
}

long WSCstring::tell(){
  return _seek_pt;
}

long WSCstring::seek(long pos){
  if (_str == NULL){
    _seek_pt = 0;
    return 0;
  }
  long len = strlen( _str );
  if ( pos > len ){
    pos = len; 
  }
  if (pos == -1){
    pos = len;
  }
  if  (pos < 0){
    pos = 0;
  }
  _seek_pt = pos;
  return _seek_pt;
}
long WSCstring::eof(){
  if (_str == NULL){
    return 1;
  }
  long len = strlen( _str );
  if (len == _seek_pt){
    return 1;
  }
  return 0;
}
long WSCstring::seekEnd(){
  return seek(-1);
}

WSCstring WSCstring::gets(){
  long encoding = _get_encoding();
  WSCstring _ret_tmp;
  if (_str == NULL){
    return _ret_tmp;
  }
  long ptr = _seek_pt;
  if (_str[_seek_pt] == 0){
    _ret_tmp.setString("",encoding);
    return _ret_tmp;
  }
  while( _str[ptr] != '\n' && _str[ptr] != 0 ) ptr++;
  char* ret = new char[ptr - _seek_pt +1];
  strncpy(ret,&(_str[_seek_pt]),(ptr - _seek_pt));
  if (ptr-_seek_pt > 0 && ret[ptr-_seek_pt -1] == 13){ //0x0d ms line feed
    ret[ptr-_seek_pt-1] = 0;
  }
  ret[ptr-_seek_pt] = 0;
  _seek_pt = ptr;
  if (_str[_seek_pt] == '\n'){
     _seek_pt++;
  }
  
  _ret_tmp.setString(ret,encoding);
  delete ret;
  return _ret_tmp;
}

long WSCstring::replaceString(const char* srcchar,const char* destchar,long num,long encode){
  if (srcchar == NULL){
    return 0;
  }
  if (destchar == NULL){
    destchar = "";
  }
  long encoding = _get_encoding();
  if (encode == WS_EN_DEFAULT){
    encode = WSGIappLocaleSet()->getDefaultEncoding();
  }
  if (encode == WS_EN_LOCALE){
    encode = WSGIappLocaleSet()->getSystemLocaleEncoding();
  } 
  if (encoding == WS_EN_SJIS && srcchar[0] == '\\'){
    WSCstring ustr;
    ustr.setString(getString(WS_EN_UTF8),WS_EN_UTF8);
    long ret = ustr.replaceString(srcchar,destchar,num,encode);
    setString(ustr.getString(WS_EN_SJIS),WS_EN_SJIS);
    return ret;
  }
  if (encoding != encode && encoding == WS_EN_NONE){
    char* src2 = _convert_string(srcchar,encode,encoding);
    char* dest2 = _convert_string(destchar,encode,encoding);
    long ret = replaceString(src2,dest2,num,encoding);
    delete src2;
    delete dest2;
    return ret;
  }
  if (_str == NULL){
    return 0;
  }
  long len = strlen(_str);
  long slen = strlen(srcchar);
  long dlen = strlen(destchar);
  if (slen == 0){
    return 0;
  }
  if (num < 1){
     num = 65535*32767;
  }

  long i;
  long cnum = 0;
  WSCbool fl = False;
  for(i=0; i < len  ; i++){
    if (cnum < num && _str[i] == srcchar[0] && !strncmp(&_str[i],srcchar,(size_t)slen)){
      cnum ++;
      if (cnum <= num){
        fl = True;
        i += slen -1;
      }
    }
  }
  if (fl == False){
    return 0;
  }
  long newlen = len+1 + cnum * (dlen - slen);
  if (newlen < 0){
    newlen = 1;
  }
  char* new_str = new char[newlen];
  cnum = 0;
  long cnt = 0;
  long count = 0;
  for(i=0; i < len  ; i++){
    if (cnum < num && _str[i] == srcchar[0] && !strncmp(&_str[i],srcchar,(size_t)slen)){
      cnum ++;
      if (cnum <= num){
        strncpy(&new_str[cnt],destchar,(size_t)dlen);
        cnt += dlen;
        i += slen -1;
        count++;
      }
    }else{
      new_str[cnt] = _str[i];
      cnt++;
    }
  }
  new_str[cnt] = 0;
  delete _str;
  _str = new_str; 
  _chars = -1;
  _clear_list();
  return count;
}

void WSCstring::delHeadSpace(){
  if (_str == NULL){
    return;
  }
  char* new_str = new char[strlen(_str)+32];

  strcpy(new_str,_str);
  long len = strlen(_str);
  long i;

  for(i=0; i < len; i++){
    if (new_str[i] != ' '){
      break;
    }
  }
  strcpy(_str,&new_str[i]);
  delete new_str;
  _clear_list();
  _chars = -1;
  return;
}

void WSCstring::delTailSpace(){
  if (_str == NULL){
    return;
  }
  char* new_str = new char[strlen(_str)+32];

  strcpy(new_str,_str);
  long i;
  long len = strlen(_str);
  for(i=len; i > -1; i--){
    if (new_str[i] != ' ' && new_str[i] != '\n' && new_str[i] != 0){
      break;
    }
  }
  new_str[i+1] = 0;
  delete _str;
  _str = new_str;
  _clear_list();
  _chars = -1;
  return; 
}
void WSCstring::to_upper(){
  long i;
  if (_str != NULL){
    long len = strlen(_str);
    for(i=0;i<len; i++){
      if (_str[i] > 'a'-1 && _str[i] < 'z'+1){
        _str[i] = _str[i] - 'a' + 'A';
      }
    }
  }
  _clear_list();
}
void WSCstring::to_lower(){
  long i;
  if (_str != NULL){
    long len = strlen(_str);
    for(i=0;i<len; i++){
      if (_str[i] > 'A'-1 && _str[i] < 'Z'+1){
        _str[i] = _str[i] - 'A' + 'a';
      }
    }
  }
  _clear_list();
}
void WSCstring::deleteChars(WSCulong char_pos,WSCulong len){
  if ( _str == NULL ){
    return;
  }
  char* str = _str;
  long encoding = _get_encoding();
  if (encoding != WS_EN_UTF8){
    str = _convert_string(_str,encoding,WS_EN_UTF8);
  }
//printf("WSCstring::... encoding=%d\n",encoding);
//printf("WSCstring::... start=#%s#\n",_str);
//fflush(stdout);
  long len2 = strlen(str);
  long len3 = len2;
  long pos = 0;
  WSCulong cnt = 0;
  int next_diff = 0;
  while(1){
    if (len2 < 1){
      if (encoding != WS_EN_UTF8){
        delete str;
      }
      return;
    }
    if (cnt == char_pos){
      next_diff = pos;
      WSCulong cnt2 = 0;
      while(1){
        if (cnt2 == len){
          break;
        }
//printf("WSCstring::... len=%d cnt2=%d next_diff=%d str[i]=0x%x\n",len,cnt2,next_diff,str[next_diff]);
//fflush(stdout);
        next_diff += WSGIappCodeConvert()->utf8CharLen(&str[next_diff],len2);
        cnt2++;
      }
//printf("WSCstring::... len=%d len2=%d next_diff=%d slen=%d\n",len,len2,next_diff,len3+1 - next_diff);
//fflush(stdout);
      memcpy(&str[pos],&str[next_diff],len3+1 - next_diff);
//printf("WSCstring::... 0x%x 0x%x 0x%x\n",str[next_diff -1],str[next_diff],str[next_diff+1]);
//fflush(stdout);
      if (encoding != WS_EN_UTF8){
        delete _str;
        _str = _convert_string(str,WS_EN_UTF8,encoding);
        delete str;
//printf("WSCstring::... result=#%s#\n",_str);
//printf("WSCstring::... result=#%s#\n",_convert_string(_str,encoding,WS_EN_EUCJP));
//fflush(stdout);
        _chars = -1;
      }
      return;
    }
    next_diff = WSGIappCodeConvert()->utf8CharLen(&str[pos],len2);
    cnt++;
    pos += next_diff;
    len2 -= next_diff;
  }
}
long WSCstring::getEncoding(){
  return _get_encoding();
}
long WSCstring::setEncoding(long enc){
  long encoding = enc;
  if (encoding == WS_EN_DEFAULT){
    encoding = WSGIappLocaleSet()->getDefaultEncoding();
  }
  if (encoding == WS_EN_LOCALE){
    encoding = WSGIappLocaleSet()->getSystemLocaleEncoding();
  } 
  long encoding_bak = getEncoding();
  if (encoding_bak == encoding){
    return encoding;
  }
  char* new_str = _convert_string(_str,encoding_bak,encoding);
  setString(new_str,encoding);
  delete new_str;
  return encoding_bak;
}
