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

#include <string.h>

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

#include <libraries/dos.h>
#include <libraries/dosextens.h>

#include <link/io.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/dlg.h>

#include <pragmas/dlg.h>

#define COPYBUFSIZE 1024
char **libgetlang(void);

LONG  __saveds __asm LIBStricmp(register __a0 char *,  register __a1 char *);
LONG  __saveds __asm LIBStrnicmp(register __a0 char *, register __a1 char *, register __d0 USHORT);
void  __saveds __asm LIBUpper(register __a0 char *);

void  __saveds __asm LIBMDate(register __a0 char *);

extern char            nline;

/// FileSize
LONG __saveds __asm LIBFileSize(register __a0 char  *filename,
                                register __a1 ULONG *size)

{__aligned struct FileInfoBlock FileInfo;
 BPTR             lock;

 if (!(lock = Lock(filename, ACCESS_READ)))  return(-1);
 Examine(lock, &FileInfo);

 *size = FileInfo.fib_Size;
 UnLock(lock);

 return(0);
}
//-

/// GetComment
LONG __saveds __asm LIBGetComment(register __a0 char *filename,
                                  register __a1 char *string)

{__aligned struct FileInfoBlock FileInfo;
 BPTR             lock;

 if (!(lock = Lock(filename, ACCESS_READ)))  return(-1);
 Examine(lock, &FileInfo);

 strcpy(string, FileInfo.fib_Comment);
 UnLock(lock);

 return(0);
}
//-

/// GetFileDate
BOOL __saveds __asm LIBGetFileDate(register __a0 char *filename,
                                   register __a1 long *secs)

{__aligned struct  FileInfoBlock FileInfo;
 BPTR              lock;
 struct DateStamp *ds = &FileInfo.fib_Date;

 if (!(lock = Lock(filename, ACCESS_READ)))  return(FALSE);
 Examine(lock, &FileInfo);

 *secs = (ds->ds_Days * 86400L) + (ds->ds_Minute * 60L) + (ds->ds_Tick / 50L);
 UnLock(lock);

 return(TRUE);
}
//-

/// CD
BOOL __saveds __asm LIBCD(register __a0 char *dirname)

{BPTR lock;

 if (!(lock = Lock(dirname, ACCESS_READ)))  return(FALSE);

 UnLock(CurrentDir(lock));
 return(TRUE);
}
//-

/// Exists
BOOL __saveds __asm LIBExists(register __a0 char *filename)

{BPTR lock;

 if (!(lock = Lock(filename, ACCESS_READ)))  return(FALSE);

 UnLock(lock);
 return(TRUE);
}
//-

/// AppendFile
LONG __saveds __asm LIBAppendFile(register __a0 char *filename,
                                  register __a1 char *buffer)

{BPTR fh;
 char date[21];

 if (!(fh = Open(filename, MODE_READWRITE)))
       if (!(fh = Open(filename, MODE_NEWFILE)))
             return(-1);

 Seek (fh, 0, OFFSET_END);
 LIBMDate(date);
 Write(fh,  date,   19);
 Write(fh, ": ",     2);
 Write(fh,  buffer, strlen(buffer));
 Write(fh, &nline,   1);

 Close(fh);
 return(0);
}
//-

/// DelDir
BOOL __saveds __asm LIBDelDir(register __a0 char             *dir,
                              register __a1 struct USER_DATA *User)

{__aligned struct FileInfoBlock finfo;
 BPTR             sout;
 BPTR             dlock;
 long             i;
 char            *s;
 char           **SA;
 char             dfile[256];

 sout = Output();
 if (User)  SA = libgetlang();

 s = stpcpy(dfile, dir);
 s--;
 if (*s != '/'  &&  *s != ':')
    {s++;
    *s = '/';
     s++;
    }

 if ((dlock = Lock(dir, ACCESS_READ)))
    {Examine(dlock, &finfo);

     while((i = ExNext(dlock, &finfo)))
          {strcpy(s, finfo.fib_FileName);

           if (finfo.fib_DirEntryType > 0)
              {if (User)  AFPrintf(NULL, sout, "\n");
               LIBDelDir(dfile, User);
               continue;
              }

           if (User)  AFPrintf(User, sout, SA[3659], finfo.fib_FileName);
           if (DeleteFile(dfile))
               if (User)  AFPrintf(User, sout, SA[3660]);
             else
               if (User)  AFPrintf(User, sout, SA[3661]);
          }

     UnLock(dlock);
    }

 if (User)  AFPrintf(User, sout, SA[3662], dir);
 if (DeleteFile(dir))
    {if (User)
        {AFPrintf(User, sout, SA[3660]);
         AFPrintf(NULL, sout, "\n");
        }
     return(TRUE);
    }
   else
    {if (User)
        {AFPrintf(User, sout, SA[3661]);
         AFPrintf(NULL, sout, "\n");
        }
    }

 return(FALSE);
}
//-

/// DirSize
LONG __saveds __asm LIBDirSize(register __a0 char *dir)

{__aligned struct FileInfoBlock finfo;
 BPTR             dlock;

 long             i;
 long             size;

 char            *s;
 char             dfile[256];


 size = 0;
 s    = stpcpy(dfile, dir);
 s--;
 if (*s != '/'  &&  *s != ':')
    {s++;
    *s = '/';
     s++;
    }

 if ((dlock = Lock(dir, ACCESS_READ)))
    {Examine(dlock, &finfo);

     while((i = ExNext(dlock, &finfo)))
          {size += 512;

           if (finfo.fib_DirEntryType > 0)
              {strcpy(s, finfo.fib_FileName);
               size += LIBDirSize(dfile);
               continue;
              }

           size += finfo.fib_Size;
          }

     UnLock(dlock);
    }

 return(size);
}
//-

/// BinPos
LONG __saveds __asm LIBBinPos(register __a0 BPTR   fh,
                              register __d0 ULONG  filesize,
                              register __a1 char  *structptr,
                              register __d1 USHORT structsize,
                              register __d2 USHORT fieldsize,
                              register __a2 ULONG *returnptr)

{__aligned struct FileInfoBlock finfo;
 ULONG     index;
 ULONG     high;
 ULONG     low;
 ULONG     tot;
 LONG      cmpres;
 char     *buf;

 buf  =  AllocMem(fieldsize, MEMF_PUBLIC);
 low  =  0;
 tot  = (filesize / (ULONG)structsize) - 1;
 high =  tot;

 /* Kludge to Fix BinPos() Case Insensistivity */
 ExamineFH(fh, &finfo);
 if (!LIBStricmp("User.Msg",  finfo.fib_FileName))  LIBUpper(structptr);
 if (!LIBStricmp("User.File", finfo.fib_FileName))  LIBUpper(structptr);

 while(high > low)
      {index = (low + high) / 2;
       Seek(fh, index*(ULONG)structsize, OFFSET_BEGINNING);
       Read(fh, buf,                    (ULONG)fieldsize);
       cmpres = strncmp(structptr, buf, fieldsize);
       if (cmpres < 0)
           high = index;
         else
           if (cmpres > 0)
               low = index+1;
             else
               {high = index;
                low  = index;
               }
      }

 index = low;
 if (index > tot) index--;

 *returnptr = index * (ULONG)structsize;

 Seek(fh,*returnptr,OFFSET_BEGINNING);
 Read(fh,buf,(ULONG)fieldsize);

 cmpres = strncmp(structptr,buf,fieldsize);

 FreeMem(buf, fieldsize);
 return(cmpres);
}
//-

/// FileCopy
LONG __saveds __asm LIBFileCopy(register __a0 BPTR  ifh,
                                register __a1 BPTR  ofh,
                                register __d0 ULONG iofs,
                                register __d1 ULONG oofs,
                                register __d2 ULONG size)

{char  buf[COPYBUFSIZE];
 ULONG bytescopied = 0;
 ULONG toread      = COPYBUFSIZE;

 Seek(ifh,iofs,OFFSET_BEGINNING);
 Seek(ofh,oofs,OFFSET_BEGINNING);

 while(bytescopied < size)
      {if ((size-bytescopied) < COPYBUFSIZE)  toread = size - bytescopied;
       Read(ifh,  &buf, toread);
       if (Write(ofh, &buf, toread) != toread)  return(-1);

       bytescopied += toread;
      }

 return(0);
}
//-

/// Copy
LONG __saveds __asm LIBCopy(register __a0 char *source,
                            register __a1 char *dest)

{BPTR  ifh;
 BPTR  ofh;
 ULONG size;
 char  exestr[256];


 if (LIBFileSize(source, &size) == -1)     return(1);
 if (!(ifh = Open(source, MODE_OLDFILE)))  return(1);

 if ((ofh = Open(dest, MODE_NEWFILE)))
    {LIBFileCopy(ifh, ofh, 0, 0, size);
     Close(ofh);
    }
 Close(ifh);

 if (IoErr() == ERROR_DISK_FULL)
     if (LIBExists("DLGConfig:Batch/DriveIsFull.batch"))
        {ASPrintf(NULL, exestr, "Execute DLGConfig:Batch/DriveIsFull.batch \"%s\" \"%s\"", source, dest);
         Execute(exestr, 0, 0);
         return(-1);
        }

 if (!ofh)  return(2);
 return(0);
}
//-

/// Cat
LONG __saveds __asm LIBCat(register __a0 char *file1,
                           register __a1 char *file2,
                           register __a2 char *joiner)

{BPTR  f1;
 BPTR  f2;

 ULONG size;
 ULONG copied = 0;
 long  toread = COPYBUFSIZE;
 long  count  = 0;
 char  buf[COPYBUFSIZE];


 if (LIBFileSize(file2, &size) == -1)    return(0);
 if (!(f1 = Open(file1, MODE_OLDFILE)))
     if (!(f1 = Open(file1, MODE_NEWFILE)))
           return(0);
 Seek(f1, 0, OFFSET_END);

 if (!(f2 = Open(file2, MODE_OLDFILE)))
    {Close(f1);
     return(0);
    }

 if (joiner)
    {count = strlen(joiner);
     if (count)  Write(f1, joiner, count);
    }
 while(copied < size)
      {if ((size-copied) < COPYBUFSIZE)  toread = size - copied;
       Read(f2,  &buf, toread);
       if (Write(f1, &buf, toread) != toread)  return(FALSE);

       copied += toread;
      }

 Close(f1);
 Close(f2);
 return((long)(copied+count));
}
//-

/// SmartRename
LONG __saveds __asm LIBSmartRename(register __a0 char *source,
                                   register __a1 char *dest)

{if (LIBExists(dest))        return(-1);
 if (Rename(source, dest))   return(0);
 if (LIBCopy(source, dest))  return(-2);

 DeleteFile(source);
 return(0);
}
//-

/// AddStruct
LONG __saveds __asm LIBAddStruct(register __a0 char   *filename,
                                 register __a1 char   *structptr,
                                 register __d0 ULONG   structsize,
                                 register __d1 USHORT  fieldsize)

{ULONG myptr;
 BPTR  sfh;
 LONG  binresult;
 ULONG size;

 size = 0;
 if (LIBFileSize(filename, &size) == -1)
     sfh = Open(filename, MODE_NEWFILE);
   else
     sfh = Open(filename, MODE_READWRITE);
 if (!sfh)  return(FALSE);

 if (!size)
    {/* Kludge to Fix BinPos() Case Insensistivity */
     char *s;

     s = FilePart(filename);

     if (!LIBStricmp("User.Msg",  s))  LIBUpper(structptr);
     if (!LIBStricmp("User.File", s))  LIBUpper(structptr);

     Write(sfh,structptr,(long)structsize);
     Close(sfh);
     return(0);
    }

 binresult = LIBBinPos(sfh,size,structptr,structsize,fieldsize,&myptr);

 if (binresult < 0)
    {BPTR  ofh;
     char *temp;
     char  tempfile[512];

     temp = stpcpy(tempfile, filename);
            strcpy(temp,    ".tmp");

     if (!(ofh = Open(tempfile,MODE_NEWFILE)))
        {Close(sfh);
         return(-1);
        }

     LIBFileCopy(sfh, ofh, 0, 0, myptr);
     Write(ofh, structptr, structsize);
     LIBFileCopy(sfh, ofh, myptr, myptr+structsize, size-myptr);

     Close(ofh);
     Close(sfh);

     DeleteFile(filename);
     Rename(tempfile,filename);
     DeleteFile(tempfile);
     return(0);
    }
  else
    if (binresult==0)
       {Seek(sfh,myptr,OFFSET_BEGINNING);
        Write(sfh,structptr,(ULONG)structsize);
       }
     else
       {Seek(sfh,myptr+(ULONG)structsize,OFFSET_BEGINNING);
        Write(sfh,structptr,(ULONG)structsize);
       }

 Close(sfh);
 return(binresult==0);
}
//-

/// DeleteStruct
LONG __saveds __asm LIBDeleteStruct(register __a0 char  *filename,
                                    register __a1 char  *structptr,
                                    register __d0 ULONG  structsize,
                                    register __d1 USHORT fieldsize)
{char *temp;
 char  tempfile[512];

 BPTR  sfh;
 BPTR  ofh;

 ULONG myptr;
 ULONG size;

 if (LIBFileSize(filename,&size)==-1)       return(-1);
 if (!size)                                 return(-1);
 if (!(sfh = Open(filename,MODE_OLDFILE)))  return(-1);

 if (!LIBBinPos(sfh,size,structptr,structsize,fieldsize,&myptr))
    {size -= structsize;
     if (!size)
        {Close(sfh);
         DeleteFile(filename);
         return(0);
        }

     temp = stpcpy(tempfile, filename);
            strcpy(temp,    ".tmp");

     if (!(ofh = Open(tempfile,MODE_NEWFILE)))
        {Close(sfh);
         return(-1);
        }

     LIBFileCopy(sfh,ofh,0,0,myptr);
     LIBFileCopy(sfh,ofh,myptr+(ULONG)structsize,myptr,size-myptr);

     Close(ofh);
     Close(sfh);

     DeleteFile(filename);
     Rename(tempfile,filename);
     DeleteFile(tempfile);
     return(0);
    }

 Close(sfh);
 return(-1);
}
//-

/// GetStruct
LONG __saveds __asm LIBGetStruct(register __a0 char  *filename,
                                 register __a1 char  *structptr,
                                 register __d0 ULONG  structsize,
                                 register __d1 USHORT fieldsize)

{ULONG myptr;
 BPTR  sfh;
 ULONG size;


 if (LIBFileSize(filename,&size)==-1)       return(-1);
 if (!size)                                 return(-1);
 if (!(sfh = Open(filename,MODE_OLDFILE)))  return(-1);

 if (!LIBBinPos(sfh,size,structptr,structsize,fieldsize,&myptr))
    {Seek(sfh,myptr,OFFSET_BEGINNING);
     Read(sfh,structptr,structsize);
     Close(sfh);
     return(0);
    }

 Close(sfh);
 return(-1);
}
//-

/// GetFirstStruct
LONG __saveds __asm LIBGetFirstStruct(register __a0 char *filename,
                                      register __a1 char *structptr,
                                      register __d0 ULONG structsize)

{BPTR  sfh;
 ULONG size;

 if (LIBFileSize(filename,&size)==-1)        return(-1);
 if (!size)                                  return(-1);
 if (!(sfh = Open(filename, MODE_OLDFILE)))  return(-1);

 Read(sfh, structptr, structsize);
 Close(sfh);
 return(0);
}
//-
