#include <ctype.h>
#include <libraries/dos.h>
#include <exec/memory.h>
#include <time.h>
#include <stdio.h>

/* SAVERAM  [-q] [ramdir] [diskdir]
*/
/* There's a problem with the Rename function. It does not change the
   file date if you rename a file. So if a file in the ram: directory
   is renamed and then you do a saveram, the saveram program won't
   detect that a change has been made to the file.
   RATS

   28-jul-89 Modified so that it only gets a lock on the output directory
             if it actually needs to save a file (see the 'nothing' variable)
*/

/*
 *  A directory item looks like this
struct FileInfoBlock {
   LONG fib_DiskKey;
   LONG fib_DirEntryType;
   char fib_FileName[108];
   LONG fib_Protection;
   LONG fib_EntryType;
   LONG fib_Size;
   LONG fib_NumBlocks;
   struct DateStamp fib_Date;
   char fib_Comment[80];
   char padding[36];
};
*/

typedef struct FileInfoBlock FCB;
FCB *ifcb = 0,*ofcb = 0;
static int olddta;
long ilock = 0L,olock = 0L;
long date[3];
short qflag = 0;
char dirname[100];
char ramname[100];
char loadname[30];
short nothing = 1;
main(argc,argv)
int argc;
char *argv[];
{
   FILE *fd;
   char *fp,*cp,*rp;
   extern char *filename();
   extern char *AllocMem();
   extern long diropen();
   /* This allocates the memory on a longword boundary */
   ifcb = (FCB *)AllocMem((long)sizeof(*ifcb),
                                   (long)MEMF_PUBLIC|MEMF_CLEAR);
   ofcb = (FCB *)AllocMem((long)sizeof(*ofcb),
                                   (long)MEMF_PUBLIC|MEMF_CLEAR);
   if(argc > 1) {
      if(argv[1][0] == '-') {
         if(argv[1][1] == 'q') {
            qflag++;
         }
         argc--;
         argv++;
      }
   }
   if(argc > 3)usage();
   if(argc < 2)
      rp = ".loadram";
   else
      rp = filename(argv[1],".loadram");
   for(cp=&loadname[0];*rp;)*cp++ = *rp++;
   *cp++ = 0;
   if((fd = fopen(&loadname[0],"r")) == 0) {
      printf("Can't find %s\n",&loadname[0]);
      done();
   }
   /* read the date from the file  */
   fread(&date[0],12,1,fd);
   /* and the target directory */
   fread(&dirname[0],100,1,fd);
   /* and the ram directory */
   fread(&ramname[0],100,1,fd);
   fclose(fd);
   /* now override the disk directory if it's been specified as an arg */
   if(argc > 2) {
      for(fp=dirname,cp=argv[2];*cp;)*fp++ = *cp++;
      *fp++ = 0;
   }
   if((ilock = diropen(&ramname[0],ifcb)) == 0L) {
      printf("Can't open %s\n",&ramname[0]);
      done();
   }
   UnLock(olock);
   olock = 0L;
   /* Look through the directory and copy anything that's changed */
   while(dirnext(ifcb,ilock)) {
      if(later(&ifcb->fib_Date,&date[0])) {
         if(nothing && ((olock = diropen(&dirname[0],ofcb)) == 0L)) {
            printf("Can't open %s\n",&dirname[0]);
            done();
         }
         nothing = 0;
         copy(&ramname[0],&dirname[0]);
         if(!qflag)printf("%s\n",ifcb->fib_FileName);
      }
   }
   ilock = 0L;
   if((fd = fopen(&loadname[0],"r+")) == 0) {
      printf("Can't find %s\n",loadname);
      done();
   }
   /* write the current date in the file and we're done */
   DateStamp(&date[0]);
   fwrite(&date[0],12,1,fd);
   fclose(fd);
   done();
}
done()
{
   freefcb();
   if(ilock)UnLock(ilock);
   if(olock)UnLock(olock);
   exit(0);
}
static char filestr[200];
/* append string b to a to create a filename */
char *filename(a,b)
char *a,*b;
{
   register char *p,*q;
   p = filestr;
   q = a;
   while(*q)*p++ = *q++;
   q--;
   if(*q != ':')*p++ = '/';
   q = b;
   while(*q)*p++ = *q++;
   *p = 0;
   return(&filestr[0]);
}
usage()
{
   printf("usage: saveram [[[-q] ramdir] diskdir]\n");
   printf("-q   don't print filenames\n");
   freefcb();
}

/*
 *  Open directory and return a Lock or zero, if it fails the lock is
 *  unlocked
 */
extern long Lock(),Examine(),ExNext();
long diropen(cp,fcb)
char   *cp;
FCB *fcb;
{
   long  result,lock;
   /* Get the lock on the directory */
   lock = Lock(cp,ACCESS_READ);
   if(lock == 0L) {
      return (0L);
   }
   /* Examine the lock and if that fails or if this is not a directory
      then give up
   */
   result = Examine(lock,fcb);
   if((result == 0L) || (fcb->fib_DirEntryType < 0)) {
      UnLock(lock);
      return(0L);
   }
   /* Looks good */
   return(lock);
}
freefcb()
{
   if(ifcb)FreeMem(ifcb,(long)sizeof(*ifcb));
   if(ofcb)FreeMem(ofcb,(long)sizeof(*ofcb));
}
/*
 *  Return next file entry, ignore directories and when the lock
 *  is exhausted Unlock it.
 */

dirnext(fcb,lock)
FCB *fcb;
long lock;
{
   /* search for next file */
   while(1) {
      if(ExNext(lock,fcb) == 0L) {
         UnLock(lock);
         return(0);
      }
      /* If it is a directory ignore it */
      if(fcb->fib_DirEntryType >= 0) continue;
      /* If it is the .loadram file bypass it */
      if(match(".loadram",&fcb->fib_FileName[0]))continue;
      return(1);
   }
}
/* copy fib_FileName from inf to outf */
char iobuf[512];
copy(inf,outf)
char *inf,*outf;
{
   FILE *fdi,*fdo;
   int n;
   if((fdi = fopen(filename(inf,&ifcb->fib_FileName),"r")) == NULL) {
      printf("Can't open %s\n",filestr);
      return;
   }
   if((fdo = fopen(filename(outf,&ifcb->fib_FileName),"w")) == NULL) {
      printf("Can't open %s\n",filestr);
      return;
   }
   while(n = fread(iobuf,1,512,fdi)) {
      fwrite(iobuf,n,1,fdo);
   }
   fclose(fdi);
   fclose(fdo);
}
later(d1,d2)
long d1[],d2[];
{
   if(d1[0] > d2[0])return(1);
   if(d1[0] < d2[0])return(0);
   if(d1[1] > d2[1])return(1);
   if(d1[1] < d2[1])return(0);
   if(d1[2] > d2[2])return(1);
   return(0);
}
match(a,b)
char *a,*b;
{
   register char *p,*q;

   p = a;
   q = b;
   while(*p && *q && (*q != '*')) {
      if(*p == *q) {
         p++;
         q++;
         continue;
      }
      break;
   }
   if((*p == 0) && (*q == 0))return(1);
   if(*q == '*')return(1);
   return(0);
}
