#include <shared/typedefs.h>
#include <shared/jblist.h>
#include <mystdlib.h>

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>

#include <clib/exec_protos.h>
#include <clib/alib_protos.h>
#include <clib/dos_protos.h>

#include <stdarg.h>
#include <strings.h>

extern APTR mempool;

void *AllocCleared(ulong size)
{
   void *mem;

   if(!(mem=LibAllocPooled(mempool,size)))
      return(NULL);

   memset(mem,0,size);
   return(mem);
}

/* OBS! Klarar _inte_ Read/Write mode */

struct jbFile *jbOpen(UBYTE *name,UWORD mode,ULONG bufsize)
{
   struct jbFile *jb;

   if(!(jb=(struct jbFile *)AllocCleared(sizeof(struct jbFile))))
   {
      return(NULL);
   }

   if(!(jb->buf=(UBYTE *)LibAllocPooled(mempool,bufsize)))
   {
      LibFreePooled(mempool,jb,sizeof(struct jbFile));
      return(NULL);
   }

   if(!(jb->fh=Open(name,mode)))
   {
      LibFreePooled(mempool,jb->buf,bufsize);
      LibFreePooled(mempool,jb,sizeof(struct jbFile));
      return(NULL);
   }

   jb->mode=mode;
   jb->bufsize=bufsize;

   return(jb);
}

void jbClose(struct jbFile *jb)
{
   if((jb->mode==MODE_NEWFILE || jb->mode==MODE_READWRITE) && jb->pos!=0)
      Write(jb->fh,jb->buf,jb->pos);

   Close(jb->fh);

   LibFreePooled(mempool,jb->buf,jb->bufsize);
   LibFreePooled(mempool,jb,sizeof(struct jbFile));
}

void jbFPrintf(struct jbFile *jb,uchar *fmt,...)
{
   va_list args;

   if((jb->mode==MODE_NEWFILE || jb->mode==MODE_READWRITE) && jb->pos!=0)
      Write(jb->fh,jb->buf,jb->pos);

   jb->pos=0;

   va_start(args,fmt);
   VFPrintf(jb->fh,fmt,args);
   va_end(args);
   Flush(jb->fh);
}

void jbVFPrintf(struct jbFile *jb,uchar *fmt,va_list args)
{
   if((jb->mode==MODE_NEWFILE || jb->mode==MODE_READWRITE) && jb->pos!=0)
      Write(jb->fh,jb->buf,jb->pos);

   jb->pos=0;

   VFPrintf(jb->fh,fmt,args);
   Flush(jb->fh);
}

int jbGetChar(struct jbFile *jb)
{
   if(jb->pos==jb->len)
   {
      jb->pos=0;
      jb->len=Read(jb->fh,jb->buf,jb->bufsize);
      if(jb->len==0) return(-1);
   }
   return(jb->buf[jb->pos++]);
}

ulong jbRead(struct jbFile *jb,void *buf,ULONG bytes)
{
   ULONG toread,copy;

   toread=bytes;
   copy=0;

   while(toread)
   {
      if(jb->pos==jb->len)
      {
         jb->len=Read(jb->fh,jb->buf,jb->bufsize);
         jb->pos=0;
         if(jb->len==0) return(bytes-toread);
      }

      if(toread<jb->len-jb->pos) copy=toread;
      else                       copy=jb->len-jb->pos;

      CopyMem((APTR)&jb->buf[jb->pos],&((UBYTE *)buf)[bytes-toread],copy);
      toread-=copy;
      jb->pos+=copy;
   }

   return(bytes);
}

void jbPutChar(struct jbFile *jb, UBYTE ch)
{
   if(jb->pos==jb->bufsize)
   {
      Write(jb->fh,jb->buf,jb->pos);
      jb->pos=0;

      if(IoErr()!=0)
      {
         return;
      }
   }

   jb->buf[jb->pos]=ch;
   jb->pos++;
   jb->len++;
}

void jbWrite(struct jbFile *jb,const void *buf, ULONG bytes)
{
   ULONG towrite,copy;

   towrite=bytes;
   copy=0;

   while(towrite)
   {
      if(jb->pos==jb->bufsize)
      {
         Write(jb->fh,jb->buf,jb->pos);
         jb->pos=0;

         if(IoErr()!=0)
         {
            return;
         }
      }

      if(towrite<jb->bufsize-jb->pos) copy=towrite;
      else                            copy=jb->bufsize-jb->pos;

      CopyMem(&((UBYTE *)buf)[bytes-towrite],(APTR)&jb->buf[jb->pos],copy);
      towrite-=copy;
      jb->pos+=copy;
      jb->len+=copy;
   }
}

void jbPuts(struct jbFile *jb, UBYTE *str)
{
   jbWrite(jb,str,strlen(str));
}

short jbFGets(struct jbFile *jb,UBYTE *str,ULONG max)
{
   short d;

   d=0;

   if(max==0)
      return(0);

   for(;;)
   {
      if(d==max-1)
      {
         str[d]=0;
         return(d);
      }

      if(jb->pos==jb->len)
      {
         jb->len=Read(jb->fh,jb->buf,jb->bufsize);
         jb->pos=0;

         if(jb->len==0)
         {
            str[d]=0;
            return(d);
         }
      }

      str[d]=jb->buf[jb->pos];

      if(str[d]==10 || str[d]==13)
      {
         d++;
         jb->pos++;
         str[d]=0;

         return(d);
      }

      d++;
      jb->pos++;
   }
}

long jbcpos;

short jbstrcpy(char *dest,char *src,long maxlen)
{
   long d=0;
   char stopchar1,stopchar2;

   while(src[jbcpos]==32 || src[jbcpos]==9) jbcpos++;

   if(src[jbcpos]=='"')
   {
      jbcpos++;
      stopchar1='"';
      stopchar2=0;
   }
   else
   {
   	stopchar1=' ';
   	stopchar2=9;
   }

   while(src[jbcpos]!=stopchar1 && src[jbcpos]!=stopchar2 && src[jbcpos]!=10 && src[jbcpos]!=0 && d<maxlen-1)
   {
      if(src[jbcpos]=='\\' && src[jbcpos+1]!=0 && src[jbcpos+1]!=10)
      {
         jbcpos++;
         dest[d++]=src[jbcpos++];
      }

      else
         dest[d++]=src[jbcpos++];
   }
   dest[d]=0;
   if(src[jbcpos]==9 || src[jbcpos]==' ' || src[jbcpos]=='"') jbcpos++;

   if(d!=0 || stopchar1=='"') return(TRUE);

   return(FALSE);
}

short jbReadDir(uchar *dir,struct jbList *filelist,int (*acceptfunc)(uchar *filename))
{
   BPTR l;
   struct FileInfoBlock *fib;
   struct FileEntry *tmp;

   jbNewList(filelist);

   if(!(fib=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR)))
   {
      return(FALSE);
   }

   if(!(l=Lock(dir,SHARED_LOCK)))
   {
      FreeMem(fib,sizeof(struct FileInfoBlock));
      return(FALSE);
   }

   if(!Examine(l,fib))
   {
      UnLock(l);
      FreeMem(fib,sizeof(struct FileInfoBlock));
      return(FALSE);
   }

   if(fib->fib_DirEntryType <= 0)
   {
      UnLock(l);
      FreeMem(fib,sizeof(struct FileInfoBlock));
      return(FALSE);
   }

   while(ExNext(l,fib))
   {
      BOOL add;

      if(!acceptfunc)   add=TRUE;
      else              add=acceptfunc(fib->fib_FileName);

      if(add)
      {
         if(!(tmp=(struct FileEntry *)AllocCleared(sizeof(struct FileEntry))))
         {
            jbFreeList(filelist,sizeof(struct FileEntry));
            UnLock(l);
            FreeMem(fib,sizeof(struct FileInfoBlock));
            return(FALSE);
         }

         strncpy(tmp->Name,fib->fib_FileName,40);
         tmp->Name[39]=0;
         strcpy(tmp->Comment,fib->fib_Comment);
         tmp->Size=fib->fib_Size;
         CopyMem(&fib->fib_Date,&tmp->Date,sizeof(struct DateStamp));

         jbAddNode(filelist,(struct jbNode *)tmp);
      }
   }

   UnLock(l);
   FreeMem(fib,sizeof(struct FileInfoBlock));

   return(TRUE);
}

ulong hextodec(UBYTE *hex)
{
   UBYTE *hextab="0123456789abcdef";
   UWORD c=0,c2=0;
   ULONG result=0;

   while(hex[c] && hex[c]!='.')
   {
      hex[c]|=32;

      for(c2=0;c2<16;c2++)
      {
         if(hex[c] == hextab[c2])
         {
            result *= 16;
            result += c2;
         }
      }
      c++;
   }
   return(result);
}

long jbGetSize(uchar *file)
{
   BPTR l;
   struct FileInfoBlock *fib;
   long size;
   if(!(fib=(struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock),MEMF_CLEAR)))
   {
      return(-1);
   }

   if(!(l=Lock(file,SHARED_LOCK)))
   {
      FreeMem(fib,sizeof(struct FileInfoBlock));
      return(-1);
   }

   if(!Examine(l,fib))
   {
      UnLock(l);
      FreeMem(fib,sizeof(struct FileInfoBlock));
      return(-1);
   }

   size=fib->fib_Size;

   UnLock(l);
   FreeMem(fib,sizeof(struct FileInfoBlock));

   return(size);
}

#define COPYBUFSIZE  10000

short MoveFile(uchar *file,uchar *newfile)
{
   BPTR ifh,ofh;
   ULONG len,err;
   uchar *copybuf;
   BOOL stop;
   
   if(Rename(file,newfile))
      return(TRUE);

   if(!(copybuf=AllocMem(COPYBUFSIZE,MEMF_ANY)))
   {
      return(FALSE);
   }

   if(!(ifh=Open(file,MODE_OLDFILE)))
   {
      FreeMem(copybuf,COPYBUFSIZE);
      return(FALSE);
   }

   if(!(ofh=Open(newfile,MODE_NEWFILE)))
   {
      FreeMem(copybuf,COPYBUFSIZE);
      Close(ifh);
      return(FALSE);
   }

   stop=FALSE;

   while((len=Read(ifh,copybuf,COPYBUFSIZE)) && !stop)
   {
      if(len == -1)
      {
         stop=TRUE;
      }
      else
      {
         len=Write(ofh,copybuf,len);
         if(len == -1) stop=TRUE;
      }
   }

   err=IoErr();

   FreeMem(copybuf,COPYBUFSIZE);
   Close(ofh);
   Close(ifh);

   if(err==0)
   {
      DeleteFile(file);
      SetIoErr(err);
      return(TRUE);
   }
   else
   {
      DeleteFile(newfile);
      SetIoErr(err);
      return(FALSE);
   }
}

short CopyFile(uchar *file,uchar *newfile)
{
   BPTR ifh,ofh;
   ULONG len,err;
   uchar *copybuf;
   BOOL stop;

   if(!(copybuf=AllocMem(COPYBUFSIZE,MEMF_ANY)))
   {
      return(FALSE);
   }

   if(!(ifh=Open(file,MODE_OLDFILE)))
   {
      FreeMem(copybuf,COPYBUFSIZE);
      return(FALSE);
   }

   if(!(ofh=Open(newfile,MODE_NEWFILE)))
   {
      FreeMem(copybuf,COPYBUFSIZE);
      Close(ifh);
      return(FALSE);
   }

   stop=FALSE;

   while((len=Read(ifh,copybuf,COPYBUFSIZE)) && !stop)
   {
      if(len == -1)
      {
         stop=TRUE;
      }
      else
      {
         len=Write(ofh,copybuf,len);
         if(len == -1) stop=TRUE;
      }
   }

   err=IoErr();

   FreeMem(copybuf,COPYBUFSIZE);
   Close(ofh);
   Close(ifh);

   if(err==0)
   {
      return(TRUE);
   }
   else
   {
      DeleteFile(newfile);
      SetIoErr(err);
      return(FALSE);
   }
}

void mystrncpy(uchar *dest,uchar *src,ulong len)
{
   strncpy(dest,src,len-1);
   dest[len-1]=0;
}

