#include "efile.h"

#define _WIN32_WCE 0x0400

#include "logger.h"
#include "esystem.h"
//#include "eregexp.h"

#include <sys/types.h>
#include <sys/stat.h>

#include <stdio.h>

#ifndef __MINGW32CE__
#include <errno.h>
#endif

#ifndef _MSC_VER
 #include <unistd.h>
#include <libgen.h>
#else
 #include <direct.h>
#endif

#ifdef _WIN32
 #include <windows.h>
 #include <windowsx.h>
 #include <io.h>
 #define dup2 _dup2
 #define pclose _pclose
#endif

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>

#ifdef EUTILS_HAVE_ZLIB_H
 #include <zlib.h>
#endif


#include "edistcomp.h"

#undef basename
#undef dirname

ebasefile::~ebasefile() {}

eufile::eufile(): bfile(0x00) {}

bool eufile::open(FILE *fstream,const estr& mode)
{
  close();
  efile *tfile=new efile();
  bfile=tfile;
  return(tfile->open(fstream,mode));
}

bool eufile::open(const estr& filename,const estr& mode)
{
  close();
  efile *tfile=new efile();
  bfile=tfile;
  return(tfile->open(filename,mode));
}

bool eufile::open(const estr& hostname,const estr& filename,const estr& mode)
{
  close();
  edcfile *tfile=new edcfile();
  bfile=tfile;
  return(tfile->open(hostname,filename,mode));
}

void eufile::close() const
{
  if (bfile) bfile->close();
  delete bfile;
  bfile=0x00;
}

void eufile::flush() const
{
  if (bfile)
    bfile->flush();
}

bool eufile::eof() const
{
  if (bfile)
    return(bfile->eof());
  return(true);
}

int eufile::write(const estr& str) const
{
  if (bfile)
    return(bfile->write(str));
  return(-1);
}

int eufile::read(estr& str,long int len) const
{
  if (bfile)
    return(bfile->read(str,len));
  return(-1);
}

bool eufile::readln(estr& str) const
{
  if (bfile)
    return(bfile->readln(str));
  return(false);
}

bool eufile::readarr(estrarray& arr,const estr& sep) const
{
  if (bfile)
    return(bfile->readarr(arr,sep));
  return(false);
}

bool eufile::readarr(estr& line,estrarray& arr,const estr& sep) const
{
  if (bfile)
    return(bfile->readarr(line,arr,sep));
  return(false);
}

bool eufile::readbuffer(estrbuffer& buffer) const
{
  if (bfile)
    return(bfile->readbuffer(buffer));
  return(false);
}




bool edcfile::open(const estr& hostname,const estr& filename,const estr& mode)
{
  return(getDistComp().fileOpen(*this));
}

void edcfile::close() const
{
  getDistComp().fileClose(*this);
}

void edcfile::flush() const
{
  getDistComp().fileFlush(*this);
}

bool edcfile::eof() const
{
  return(getDistComp().fileEOF(*this));
}

int edcfile::write(const estr& str) const
{
  return(getDistComp().fileWrite(*this,str));
}

int  edcfile::read(estr& str,long int len) const
{
  return(getDistComp().fileRead(*this,str,len));
}

bool edcfile::readln(estr& str) const
{
  return(getDistComp().fileReadLn(*this,str));
}

bool edcfile::readarr(estrarray& arr,const estr& sep) const
{
  ldie("not coded yet");
//  return(getDistComp().fileReadLn(*this,str));
  return(false);
}

bool edcfile::readarr(estr& line,estrarray& arr,const estr& sep) const
{
  ldie("not coded yet");
//  return(getDistComp().fileReadLn(*this,str));
  return(false);
}

bool edcfile::readbuffer(estrbuffer& buffer) const
{
  ldie("not coded yet");
  estr str;
  int len;
  return(getDistComp().fileRead(*this,str,len));
}



#ifdef EUTILS_HAVE_ZLIB_H
egzfile::egzfile(): f(0x00),opened(false){}
egzfile::egzfile(const estr& _name,const estr& _mode): name(_name),mode(_mode) {}
egzfile::~egzfile()
{
// close();
}

void egzfile::close() const
{
  if (f && opened)
    gzclose(f);
  f=0x00;
  opened=false;
}
bool egzfile::open() const
{
  lerrorifr(name.len()==0 || mode.len()==0,"no filename specified",(false));

  opened=true;
  f=gzopen(name._str,mode._str);
  if (f==0x00){
    opened=false;
    lwarn("efile: unable to open file \""+name+"\"");
    return(false);
  }
  return(true);
//  return(open(name,mode));
}

bool egzfile::eof() const
{
  if (f==0x00){ lerror("file handle is null"); return(-1); }
  return(gzeof(f));
}

bool egzfile::open(FILE *fs,const estr& _mode)
{
//  int nfd=dup(fileno(fs));
  mode=_mode;
  f=gzdopen(fileno(fs),_mode._str);
  opened=true;
  if (f==0x00){
    opened=false;
    lwarn("efile: unable to open file \""+name+"\"");
    return(false);
  }
  return(true);
}

bool egzfile::open(const estr& _name,const estr& _mode)
{
  ldinfo("openning gzfile: "+_name+" mode: "+_mode);
//  close();

  name=_name;
  mode=_mode;

  opened=true;
  f=gzopen(name._str,mode._str);
  if (f==0x00){
    opened=false;
    lwarn("efile: unable to open file \""+name+"\"");
    return(false);
  }
  return(true);
}

int egzfile::write(const estr& str) const
{
  if (f==0x00 && !open()) return(-1);
  return(gzwrite(f,str._str,str.len()));
}

int egzfile::read(estr& str,long int len) const
{
  if (f==0x00 && !open()) return(-1);

  if (len==-1){
    long int olen=str.len();
    while (!eof() && read(str,1<<16)>0);
    return(str.len()-olen);
  }

  str.reserve(str.len()+len);
  len=gzread(f,&str._str[str.len()],len);
  if (len>=0){
    str._strlen+=len;
    str._str[str._strlen]=0x00;
    return(len);
  }
  return(len);

/*
  if (len==-1){
    len=0;
    long int tmplen;
    do {
      str.reserve(len+1024);
      tmplen=gzread(f,&str._str[len],1024);
      if (tmplen<=0) break;
      len+=tmplen;
    } while (tmplen>0);
  }else{
    str.reserve(len);
    len=gzread(f,str._str,len);
  }
  if (len){
    str._strlen=len;
    str._str[len]=0x00;
    return(true);
  }
  str._str[0]=0x00;
  str._strlen=0;
  return(false);
*/
}
void egzfile::flush() const
{
  gzflush(f,Z_SYNC_FLUSH);
}

bool egzfile::readarr(estr& line,estrarray& arr,const estr& sep) const
{
  if (f==0x00){
    mode="r";
    if (!open()) return(false);
  }

  long int len;
  char *res;
  int p;

  len=1024;

  arr.clear();
  line.clear();

  estr& str(line);
   
  str.reserve(len);
  str._str[0]=0x00;
  str._strlen=0;

  p=0;
  do {
    str.reserve(len);
    res=gzgets(f,&str._str[p],len-p);
    p=strlen(str._str);
    if (!res) {
      if (eof())
        return(false);
      str._str[0]=0x00;
      str._strlen=0;
      arr.clear();
      return(false);
    }

    str._strlen=strlen(str._str);
    if (str._strlen>=2 && str[str._strlen-2]=='\r' && str[str._strlen-1]=='\n')
      { str[str._strlen-2]=0x00; str._strlen-=2; break; }
    else if (str._strlen>=1 && str[str._strlen-1]=='\n')
      { str[str._strlen-1]=0x00; --str._strlen; break; }
    else if (str._strlen>0 && eof())
      { break; }
    len=len*2;
  }while (1);

  
  int i0=str.findchr(sep);
  if (i0==-1){
    arr.add(str);
    return(true);
  }
  arr.add(str.substr(0,i0));
  int i,e;
  for (i=i0; i!=-1; i=e){
    e=str.findchr(sep,i+1);
    if (e!=-1)
      arr.add(str.substr(i+1,e-i-1));
    else
      arr.add(str.substr(i+1));
  }
//  str.del(i0);
  return(true);
}

bool egzfile::readarr(estrarray& arr,const estr& sep) const
{
  if (f==0x00){
    mode="r";
    if (!open()) return(false);
  }

  long int len;
  char *res;
  int p;

  len=1024;

  arr.clear();
  arr.add(estr());

  estr& str(arr[0]);
   
  str.reserve(len);
  str._str[0]=0x00;
  str._strlen=0;

  p=0;
  do {
    str.reserve(len);
    res=gzgets(f,&str._str[p],len-p);
    p=strlen(str._str);
    if (!res) {
      if (eof())
        return(false);
      str._str[0]=0x00;
      str._strlen=0;
      arr.clear();
      return(false);
    }

    str._strlen=strlen(str._str);
    if (str._strlen>=2 && str[str._strlen-2]=='\r' && str[str._strlen-1]=='\n')
      { str[str._strlen-2]=0x00; str._strlen-=2; break; }
    else if (str._strlen>=1 && str[str._strlen-1]=='\n')
      { str[str._strlen-1]=0x00; --str._strlen; break; }
    else if (str._strlen>0 && eof())
      { break; }
    len=len*2;
  }while (1);

  int i0=str.findchr(sep);
  if (i0==-1) return(true);
  int i,e;
  for (i=i0; i!=-1; i=e){
    e=str.findchr(sep,i+1);
    if (e!=-1)
      arr.add(str.substr(i+1,e-i-1));
    else
      arr.add(str.substr(i+1));
  }
  str.del(i0);

  return(true);
}

bool egzfile::readln(estr& str) const
{
  if (f==0x00 && !open()) return(false);

  long int len;
  int p;
  char *res;
  len=1024;

/*
  if (!blocking && fileno(f) == fileno(stdin)){
#ifdef _MSC_VER
    getSystem().wait(GetStdHandle(STD_INPUT_HANDLE));
#else
    getSystem().wait(fileno(stdin));
#endif
  }
*/

  str.reserve(len);
  str._str[0]=0x00;
  str._strlen=0;

  p=0;
  do {
    str.reserve(len);
//    linfo("getting string");
    res=gzgets(f,&str._str[p],len-p);
    p=strlen(str._str);
//    linfo("got string");
    if (!res) {
      if (gzeof(f))
        return(false);
      str._str[0]=0x00;
      str._strlen=0;
      return(false);
    }

    str._strlen=strlen(str._str);
    if (str._strlen>=2 && str[str._strlen-2]=='\r' && str[str._strlen-1]=='\n')
      { str[str._strlen-2]=0x00; str._strlen-=2; return(true); }
    else if (str._strlen>=1 && str[str._strlen-1]=='\n')
      { str[str._strlen-1]=0x00; --str._strlen; return(true); }
    else if (str._strlen>0 && gzeof(f))
      { return(true); }
    len=len*2;
  }while (1);
  return(false);
}

bool egzfile::readbuffer(estrbuffer& buffer) const
{
  if (f==0x00 && !open()) return(false);
//  if (f==0x00){
//    mode="r";
//    if (!open()) return(false);
//  }

  if (buffer.free()==0) return(false);

  int len;
  len=gzread(f,&buffer._str[buffer.epos],buffer.freecontig());
  if (len<=0)
    return(false);

  buffer.add(len);
  return(true);
}
#endif



ostream& operator<<(ostream& stream,const efile& file)
{
  if (file.f!=0x00)
    stream << "[efile name: "<<file.name<<" fd: " << file.fileno() << "]";
  else
    stream << "[efile name: "<<file.name<<"]";
  return(stream);
}


efile::~efile()
{
//  close();
}


efile::efile(const efile& file): opened(file.opened),f(file.f),blocking(file.blocking),name(file.name),mode(file.mode) {}

efile::efile(): f(0x00),opened(false),blocking(false) {}
efile::efile(const estr& _name): f(0x00),opened(false),name(_name),mode("r"),blocking(false) {}
efile::efile(const char* _name): f(0x00),opened(false),name(_name),mode("r"),blocking(false) {}
efile::efile(char* _name): f(0x00),opened(false),name(_name),mode("r"),blocking(false) {}
efile::efile(const estr& _name,const estr& _mode): f(0x00),opened(false),name(_name),mode(_mode),blocking(false) {}
efile::efile(int fd,const estr& mode): blocking(false)
{
  open(fd,mode);
//  fcntl(fileno(file),F_SETFL,O_NONBLOCK);
}

efile::efile(FILE* file): f(file),opened(true),blocking(false)
{
//  fcntl(fileno(file),F_SETFL,O_NONBLOCK);
}

bool efile::eof() const
{
  if (f==0x00){ lerror("file handle is null"); return(-1); }
  return(::feof(f));
}

int efile::fileno() const
{
  if (f==0x00){ lerror("file handle is null"); return(-1); }
  return(::fileno(f));
}

estr efile::extension() const
{
  int i;
  for (i=name.len()-1; i>=0; --i){
    if (name[i]=='.') break;
  }
  if (i<=0) return("");
  return(name.substr(i+1));
}
estr efile::basename() const
{
  estr tmpname(name);
  if (tmpname.len()==0 || tmpname[tmpname.len()-1]=='/') return(estr());
  return(::basename(tmpname._str));
}
estr efile::dirname() const
{
  estr tmpname(name);
  if (tmpname.len()==0) return(estr());
  if (tmpname[tmpname.len()-1]=='/') return(tmpname);
  return(::dirname(tmpname._str));
}

void efile::disableBuffer() const
{
  setvbuf(f,0x00,_IONBF,0);
}

void efile::close() const
{
  if (f && opened)
    fclose(f);
  f=0x00;
  opened=false;
}

bool efile::open(FILE *_file)
{
  ldinfo("openning file descritor");
//  close();
  opened=true;
  f=_file;
  if (f==0x00){
    opened=false;
    lwarn("efile: invalid file handle");
    return(false);
  }
  return(true);
}

bool efile::open(int fd,const estr& mode)
{
  ldinfo("openning file descritor");
  opened=true;
  f=fdopen(fd,mode._str);
  if (f==0x00){
    opened=false;
    lwarn("efile: invalid file handle");
    return(false);
  }
  return(true); 
}

bool efile::open() const
{
  lerrorifr(name.len()==0 || mode.len()==0,"no filename specified",(false));
#ifdef _MSC_VER
  _set_fmode(_O_BINARY);
#endif

  f=fopen(name._str,mode._str);
  if (f==0x00){
    lwarn("efile: unable to open file \""+name+"\"");
    return(false);
  }
  opened=true;
  return(true);
}

bool efile::open(const estr& _name,const estr& _mode)
{
  ldinfo("opening file: "+_name+" mode: "+_mode);
//  close();

  name=_name;
  mode=_mode;

  return(open());
}

bool efile::create() const
{
  bool res;
  mode="w";
  res=open();
  if (res){
    close();
    return(true);
  }
  return(false);
}

/*
bool efile::open(const estr& mode)
{
  ldinfo("openning file: "+name+" mode: "+mode);
  close();

  f=fopen(name._str,mode._str);
  if (f==0x00){
    lwarn("efile: unable to open file \""+name+"\"");
    return(false);
  }
  return(true);
}
*/
bool efile::exists() const
{
#ifdef _MSC_VER
//    GetFileAttributes(name._str); // from winbase.h
    wchar_t *wsz=0x00;
    wstr(&wsz,name);
    if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(wsz) && GetLastError() == ERROR_FILE_NOT_FOUND) {
        free(wsz);
        return(false);
    }
    free(wsz);
    return(true);
#else
  struct stat sb;
  long int r;

  r=stat(name._str,&sb);

  if (!r) return(true);
#ifdef _MSC_VER
  switch (errno)
  {
    case ENOENT:
      printf("File %s not found.\n", name._str);
      break;
  case EINVAL:
      printf("Invalid parameter to _stat.\n");
      break;
  default:
      /* Should never be reached. */
      printf("Unexpected error in _stat.\n");
  }
#endif
  return(false);
#endif
}

long int efile::tell() const
{
  return(ftell(f));
}

int efile::seek(long int p)
{
  return(fseek(f,p,SEEK_SET));
}

long int efile::size() const
{
  struct stat sb;
  long int r;

  if (name.len()==0) return(-1);

  r=stat(name._str,&sb);
  if (r==0) return(sb.st_size);

  return(-1);
}

void efile::flush() const
{
  fflush(f);
}

estrarray efile::grep(const estr& str,const estr& sep) const
{
  return(data().grep(str,sep));
}

estrarray efile::egrep(const estr& re,const estr& sep) const
{
  return(data().egrep(re,sep));
}

estrarray efile::egrepo(const estr& re,const estr& sep) const
{
  return(data().egrepo(re,sep));
}

estr efile::data() const
{
  estr tmpstr;
  read(tmpstr);
  return(tmpstr);
}


evar efile::readvar() const
{
  if (f==0x00){
    mode="r";
    if (!open()) return(evar());
  }
  evar var;

  char tmpsz[4];
  int l=fread(tmpsz,sizeof(char),4,f);
  int i;

  if (l<4) {
    for (i=l-1; i>=0; --l)
      ungetc(tmpsz[i],f);
    return(evar());
  }

  estr data;
  int size=*(uint32_t*)tmpsz;
  l=read(data,size);
  if (l!=size) { lerror("reading variable: expected length: "+estr(size)+" got: "+estr(l)); return(evar()); }
//  evar var;
  var.unserial(data);
  return(var);
}

bool efile::readvar(evar& var) const
{
  if (f==0x00){
    mode="r";
    if (!open()) return(false);
  }

  char tmpsz[4];
  int l=fread(tmpsz,sizeof(char),4,f);
  int i;

  if (l<4) {
    for (i=l-1; i>=0; --l)
      ungetc(tmpsz[i],f);
    return(false);
  }

  estr data;
  int size=*(uint32_t*)tmpsz;
  l=read(data,size);
  if (l!=size) { lerror("reading variable: expected length: "+estr(size)+" got: "+estr(l)); return(false); }
//  evar var;
  var.unserial(data);
  return(true);
}

int efile::writevar(const evar& var) const
{
  estr data;
  // reserving space for unsigned int length specifier
  data.reserve(4);
  data._strlen=4;

  var.serial(data); 
  *(uint32_t*)data._str=(data.len()-sizeof(uint32_t)); // data packet length
  return(write(data));
}

int efile::write(const estr& str) const
{
  if (f==0x00){
    mode="w";
    if (!open()) return(0);
  }

  int len=fwrite(str._str,sizeof(char),str.len(),f);
  return(len);
}

int efile::write(const char *str,int slen) const
{
  if (f==0x00){
    mode="w";
    if (!open()) return(0);
  }

  long len=fwrite(str,sizeof(char),slen,f);
  return(len);
}

int efile::read(char *str,int slen) const
{
  if (f==0x00){
    mode="r";
    if (!open()) return(0);
  }
  long rlen = fread(str, sizeof(char), slen, f);
  return(rlen);
}


int efile::read(estr& str) const
{
  if (f==0x00){
    mode="r";
    if (!open()) return(-1);
  }

  int rlen,olen,len;
  olen=str.len();
  if (name.len()==0){ // pipe with no filename
    while (!eof() && read(str,1<<16)>0);
    return(str.len()-olen);
  }

  len=size();
  while (!eof()) {
    str.reserve(str.len()+len);
    rlen=fread(&str._str[str.len()],sizeof(char),len,f);
    if (rlen>0){
      str._strlen+=rlen;
      str._str[str._strlen]=0x00;
    } else
      return(str.len()-olen);
  }

  return(str.len()-olen);
}

int efile::read(estr& str,long int len) const
{
  if (f==0x00){
    mode="r";
    if (!open()) return(false);
  }

  str.reserve(str.len()+len);
  len=fread(&str._str[str.len()],sizeof(char),len,f);
  if (len>=0){
    str._strlen+=len;
    str._str[str._strlen]=0x00;
    return(len);
  }
  return(-1);
}

/*
bool efile::readstr(estr& str,const estr& limit)
{
  if (f==0x00 && !open("r")) return(false);

  int len;

  char *res;
  len=1023;
   
  str.reserve(len);
  res=fgets(str._str,len,f);
  if (res){
    str._strlen=strlen(str._str);
    if (str.len()>1 && str[str.len()-1]=='\n')
      { str[str.len()-1]=0x00; --str._strlen; }
    else if (str.len()>2 && str[str.len()-2]=='\r' && str[str.len()-1]=='\n')
      { str[str.len()-2]=0x00; str._strlen-=2; }
    return(true);
  }
  str._str[0]=0x00;
  str._strlen=0;
  return(false);
}
*/

/*
extern BOOL GetStdioPathW(
  int id,
  wchar_t *pwszBuf,
  DWORD *lpdwLen
);
*/

bool efile::readarr(estr& line,estrarray& arr,const estr& sep) const
{
  if (f==0x00){
    mode="r";
    if (!open()) return(false);
  }

  long int len;
  char *res;
  int p;

  len=1024;

  line.clear();
  arr.clear();

  estr& str(line);
   
  str.reserve(len);
  str._str[0]=0x00;
  str._strlen=0;

  p=0;
  do {
    str.reserve(len);
    if (!blocking && fileno() == ::fileno(stdin)){
      #ifdef _MSC_VER
       getSystem().wait(GetStdHandle(STD_INPUT_HANDLE));
      #else
       getSystem().wait(::fileno(stdin));
      #endif
    }
    res=fgets(&str._str[p],len-p,f);
    p=strlen(str._str);
    if (!res) {
      if (eof())
        return(false);
      str._str[0]=0x00;
      str._strlen=0;
      arr.clear();
      return(false);
    }

    str._strlen=strlen(str._str);
    if (str._strlen>=2 && str[str._strlen-2]=='\r' && str[str._strlen-1]=='\n')
      { str[str._strlen-2]=0x00; str._strlen-=2; break; }
    else if (str._strlen>=1 && str[str._strlen-1]=='\n')
      { str[str._strlen-1]=0x00; --str._strlen; break; }
    else if (str._strlen>0 && feof(f))
      { break; }
    len=len*2;
  }while (1);

  int i0=str.findchr(sep);
  if (i0==-1){
    arr.add(str);
    return(true);
  }
  arr.add(str.substr(0,i0));
  int i,e;
  for (i=i0; i!=-1; i=e){
    e=str.findchr(sep,i+1);
    if (e!=-1)
      arr.add(str.substr(i+1,e-i-1));
    else
      arr.add(str.substr(i+1));
  }
  return(true);
}

bool efile::readarr(estrarray& arr,const estr& sep) const
{
  if (f==0x00){
    mode="r";
    if (!open()) return(false);
  }

  long int len;
  char *res;
  int p;

  len=1024;

  arr.clear();
  arr.add(estr());

  estr& str(arr[0]);
   
  str.reserve(len);
  str._str[0]=0x00;
  str._strlen=0;

  p=0;
  do {
    str.reserve(len);
    if (!blocking && fileno() == ::fileno(stdin)){
      #ifdef _MSC_VER
       getSystem().wait(GetStdHandle(STD_INPUT_HANDLE));
      #else
       getSystem().wait(::fileno(stdin));
      #endif
    }
    res=fgets(&str._str[p],len-p,f);
    p=strlen(str._str);
    if (!res) {
      if (eof())
        return(false);
      str._str[0]=0x00;
      str._strlen=0;
      arr.clear();
      return(false);
    }

    str._strlen=strlen(str._str);
    if (str._strlen>=2 && str[str._strlen-2]=='\r' && str[str._strlen-1]=='\n')
      { str[str._strlen-2]=0x00; str._strlen-=2; break; }
    else if (str._strlen>=1 && str[str._strlen-1]=='\n')
      { str[str._strlen-1]=0x00; --str._strlen; break; }
    else if (str._strlen>0 && feof(f))
      { break; }
    len=len*2;
  }while (1);

  int i0=str.findchr(sep);
  if (i0==-1) return(true);
  int i,e;
  for (i=i0; i!=-1; i=e){
    e=str.findchr(sep,i+1);
    if (e!=-1)
      arr.add(str.substr(i+1,e-i-1));
    else
      arr.add(str.substr(i+1));
  }
  str.del(i0);

  return(true);
}

bool efile::readln(estr& str) const
{
  if (f==0x00){
    mode="r";
    if (!open()) return(false);
  }

  long int len;
  char *res;
  int p;

  len=1024;
   
  str.reserve(len);
  str._str[0]=0x00;
  str._strlen=0;

  p=0;
  do {
    str.reserve(len);
    if (!blocking && fileno() == ::fileno(stdin)){
      #ifdef _MSC_VER
       getSystem().wait(GetStdHandle(STD_INPUT_HANDLE));
      #else
       getSystem().wait(::fileno(stdin));
      #endif
    }
    res=fgets(&str._str[p],len-p,f);
    p=strlen(str._str);
    if (!res) {
      if (feof(f))
        return(false);
      str._str[0]=0x00;
      str._strlen=0;
      return(false);
    }

    str._strlen=strlen(str._str);
    if (str._strlen>=2 && str[str._strlen-2]=='\r' && str[str._strlen-1]=='\n')
      { str[str._strlen-2]=0x00; str._strlen-=2; return(true); }
    else if (str._strlen>=1 && str[str._strlen-1]=='\n')
      { str[str._strlen-1]=0x00; --str._strlen; return(true); }
    else if (str._strlen>0 && feof(f))
      { return(true); }
    len=len*2;
  }while (1);

  return(false);
}

bool efile::readbuffer(estrbuffer& buffer) const
{
  if (f==0x00){
    mode="r";
    if (!open()) return(false);
  }

  if (buffer.free()==0) return(false);

  if (!blocking && fileno() == ::fileno(stdin)){
    #ifdef _MSC_VER
    getSystem().wait(GetStdHandle(STD_INPUT_HANDLE));
    #else
    getSystem().wait(::fileno(stdin));
    #endif
  }
  int len;
  len=fread(&buffer._str[buffer.epos],1,buffer.freecontig(),f);
  buffer.add(len);
  if (!len)
    return(false);

  return(true);
}

void efile::setNonBlocking() const
{
#ifndef _WIN32
  fcntl(fileno(),F_SETFL,O_NONBLOCK);
#endif
}

void efile::wait() const
{
#ifndef _WIN32
  getSystem().wait(fileno());
#endif
}


void efile::serial(estr& data) const
{
  name.serial(data);
}

size_t efile::unserial(const estr& data,size_t i)
{
  i=name.unserial(data,i);
  return(i);
}

void efile::serial(const efile& f) const
{
  name.serial(f);
}

bool efile::unserial(const efile& f)
{
  if (!name.unserial(f)) return(false);
  return(true);
}








efile popen(const estr& cmd)
{
#ifdef _WIN32
  FILE* res=::_popen(cmd._str,"r"); // r+ not supported in linux, must be unidirectional pipe, use popen2 for bidirectional
#else
  FILE* res = ::popen(cmd._str, "r"); // r+ not supported in linux, must be unidirectional pipe, use popen2 for bidirectional
#endif
  lwarnif(res==0x00,"error in popen command: "+cmd+": "+estr(errno)+" :: "+strerror(errno));
  return(res);
}

void pclose(efile& file)
{
  pclose(file.f);
}

int system(const estr& cmd)
{
  return(system(cmd._str));
}

#define READ 0
#define WRITE 1

#ifndef _WIN32
void showless(const estr& data)
{
  int p_stdin[2];
  pid_t pid;

  const char * cmd[]={ "less", 0x00 };

  if (pipe(p_stdin) != 0)
    return;

  pid = fork();

  if (pid < 0)
    return;
  else if (pid == 0) {
    close(p_stdin[WRITE]);
    dup2(p_stdin[READ], READ);

    execvp(*cmd, (char * const *)cmd);
    perror("execvp");
    exit(1);
  }

  write(p_stdin[WRITE],data._str,data._strlen);
  close(p_stdin[WRITE]);
}

int popen2(const estr& cmd, int& infp,int& outfp)
{
  const char *commands[4];
  commands[0]="/bin/bash";
  commands[1]="-c";
  commands[2]=cmd._str;
  commands[3]=0x00;

  int p_stdin[2], p_stdout[2];
  pid_t pid;

  if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
    return(-1);

  pid = fork();

  if (pid < 0)
    return(pid);
  else if (pid == 0) {
    close(p_stdin[WRITE]);
    dup2(p_stdin[READ], READ);
    close(p_stdout[READ]);
    dup2(p_stdout[WRITE], WRITE);

    execvp(*commands, (char * const *)commands);
    perror("execvp");
    exit(1);
  }

//  if (infp == NULL)
//    close(p_stdin[WRITE]);
//  else
  infp = p_stdin[WRITE];

//  if (outfp == NULL)
//    close(p_stdout[READ]);
//  else
  outfp = p_stdout[READ];

  return(pid);
}
#else
void showless(const estr& data)
{
	ldie("not implemented");
}

int popen2(const estr& cmd, int& infp, int& outfp)
{
	ldie("not implemented");
}
#endif

estr dirname(const estr& file)
{
#ifdef _MSC_VER
  estr tmp(file);
  if (tmp.find("/") == -1) return(".");

  estrarray arr(tmp.explode("/"));
  tmp.clear();
  tmp = arr[0];
  for (int i = 1; i < arr.size() - 1; ++i)
	  tmp += "/" + arr[i];
  return(tmp);
#else
  return(::dirname(file._str));
#endif
}

estr basename(const estr& file)
{
  estr tmp(file);
  return(::basename(file._str));
}








/*
int efile_size(const estr &filename)
{
  struct stat sb;
  int r;

  r=stat(filename._str,&sb);

  if (!r) return(sb.st_size);
  return(-1);
}

bool efile_exists(const estr &filename)
{
  struct stat sb;
  int r;

  r=stat(filename._str,&sb);

  if (!r) return(true);
  return(false);
}


estr efile_load(const estr &filename)
{
  estr data;
  ldtip("efile_load(filename,result) is the recommended way to load all data from a file");
  efile_load(filename,data);
  return(data);
}

int efile_load(const estr& filename, estr& buffer)
{
  FILE *f;

//  if (filename == "-")
//    return(load_pipe(stdin,buffer));

  int len;
  int szlen;
  
  len=efile_size(filename);

  f=fopen(filename._str,"r");

  dieif(f==0x00,"error: unable to open file: "+filename);
  
  buffer._checkNewSize(len+1);
  buffer._strlen = len;
  buffer._str[len]=0x00;

  szlen = fread(buffer._str,sizeof(char),len,f);

  dieif(szlen!=len,"load_file: size mismatch reading file");

  fclose(f);

  return(szlen);
}

void efile_save(const estr& filename,const estr& buffer)
{
  FILE *f;

  int szlen;
  
  f=fopen(filename._str,"w");

  dieif(f==0x00,"error: unable to open file: "+filename);
  
  szlen = fwrite(buffer._str,sizeof(char),buffer.len(),f);

  dieif(szlen!=buffer.len(),"efile_save: size mismatch writing file");

  fclose(f);
}

void efile_read(FILE *f,estr& buffer)
{
  int len;
  int szlen;

  len=1023;
  buffer._checkNewSize(len+1);

  szlen = fread(buffer._str,sizeof(char),len,f);

  buffer._strlen = szlen;
  buffer._str[szlen]=0x00;
}

void efile_gets(FILE *f,estr& buffer)
{
  int len;
  char* szres;

  len=1023;
  buffer._checkNewSize(len+1);

  szres = fgets(buffer._str,len,f);

  if (szres){
    buffer._strlen = strlen(buffer._str);
    return;
  }

  buffer._str[0]=0x00;
  buffer._strlen = 0;
}
*/




/*

eafileptr::eafileptr(): fd(0),buffer(0x00),bi(0),be(0),bsize(0)
{
}

eafileptr::eafileptr(estr filename)
{
  open(filename);
}

#ifndef O_LARGEFILE
#define O_LARGEFILE 0x00
#endif

void eafileptr::open(estr filename)
{
  fd=::open(filename._str,O_RDONLY | O_LARGEFILE);
  buffer=new char[BUFFER_SIZE];
  bsize =BUFFER_SIZE;
  bi    =READ_SIZE;
  be    =READ_SIZE;    
  _eof  =false;

  int rlen;

  rlen = read(fd,buffer + bi,READ_SIZE);
  if (rlen > 0) be=(bi+rlen)%bsize;
  else if (rlen==0) _eof=true;
  ldieif(rlen < 0,"eafileptr, error reading first bytes of file");
}

eafileptr::~eafileptr()
{
  close(fd);
  delete buffer;
}

bool eafileptr::operator++()
{
  int rlen;

  ++bi;
  bi=bi%bsize;
  if (bi==be){
    rlen = read(fd,buffer+bi,READ_SIZE);
    if (rlen > 0) be=(bi+rlen)%bsize; else if (rlen==0) {_eof=true;return(false);}
    ldieif(be != 0 && be != READ_SIZE && read(fd,buffer+bi,1),"eafileptr::operator++, \"be\" out of bounds");
    return(true);
  }
  return(true);  
}

estr eafileptr::getline()
{
  estr tmp;

  while (!eof() && 0x0A != *(*this) && 0x0D != *(*this) )
    { tmp+=*(*this); ++(*this); }

  if (!eof() && *(*this) == 0x0D) ++(*this);
  if (!eof() && *(*this) == 0x0A) ++(*this);

  return(tmp); 
}

*/
