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

/* LOADRAM  ramdir diskdir filespec1 [filespec2 ... filespecN]
   where the filespecs can contain a leading or trailing * wildcard
   such as *.c or a* (but not embedded as in a*b)
   All qualified files are copied from the disk directory into the
   ram directory (which is created if it does not exist). Any files
   which match the pattern *.o are copied last so that their file
   date will be later than the corresponding *.c which prevents 'make'
   trying to remake a .o file that is actually up to date.
   This is a fudge, as I am still using 1.2. In 1.3 I think this could
   be fixed up better.
   Pete VE5VA
*/

/*
 *  FYI ... 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;      /* input and output directory locks */
long date[3];
char dirname[100];      /* package the disk dir name */
char ramname[100];      /*          and ram dir name */
char sname[4096];

main(argc,argv)
int argc;
char *argv[];
{
   FILE *fd;
   register char *fp,*cp;
   char *wco[1];
   extern char *filename();
   extern char *AllocMem();
   extern long CreateDir();
   extern long diropen();
   sname[0] = 0;
   if(argc < 3)usage();
   /* copy the disk directory name string and make sure it's not too long */
   for(fp=argv[2],cp=dirname;*fp && (cp < &dirname[99]);)*cp++ = *fp++;
   *cp++ = 0;
   if(cp > &dirname[99]) {
      printf("disk directory name too long\n");
      exit(20);
   }
   /* copy the ram directory name string and make sure it's not too long */
   for(fp=argv[1],cp=ramname;*fp && (cp < &ramname[99]);)*cp++ = *fp++;
   *cp++ = 0;
   if(cp > &ramname[99]) {
      printf("ram directory name too long\n");
      exit(20);
   }
   /* 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(argv[1][0] == 'q') {
      argc--;
      argv++;
      qflag++;
   }
*/
   if((ilock = diropen(argv[1],ifcb)) == 0L) {
      /* Create the ram directory if it isn't already there */
      if((ilock = CreateDir(argv[1])) == 0L) {
         printf("Can't open %s\n",argv[1]);
         done();
      }
   }
   /* Don't need the lock on the ram: directory */
   UnLock(ilock);
   ilock = 0L;
   if((olock = diropen(argv[2],ofcb)) == 0L) {
      printf("Can't open %s\n",argv[2]);
      done();
   }


   /* Look through the directory and copy the relevant files */
   /* set up the *.o wildcard search */
   wco[0] = "*.o";
   fp = &sname[0];
   while(dirnext(ofcb,olock)) {
      /* Does the next filename match any of the wildcard arguments? */
      if(wcm(argc-3,&ofcb->fib_FileName[0],&argv[3])) {
         /* If this matches "*.o" then save the name and copy it after
            everything else is done so that the *.o files have a later
            created date than the *.c files. This way 'make' won't try
            to remake lots of *.o files because they were copied before
            their corresponding *.c file.
         */
         if(wcm(1,&ofcb->fib_FileName[0],&wco[0])) {
            cp = &ofcb->fib_FileName[0];
            while(*cp)*fp++ = *cp++;
            *fp++ = 0;
         }
         else {
            if(copy(argv[2],argv[1],&ofcb->fib_FileName[0])) {
               printf("I/O error in writing %s\n",ofcb->fib_FileName);
               done();
            }
            else
               printf("%s\n",ofcb->fib_FileName);
         }
      }
   }
   olock = 0L;
   /* Now check the sname list for any *.o files and copy them
   */
   *fp++ = 0;
   for(fp=&sname[0];*fp;) {
      if(copy(argv[2],argv[1],fp)) {
         printf("I/O error in writing %s\n",ofcb->fib_FileName);
         done();
      }
      printf("%s\n",fp);
      while(*fp)fp++;
      fp++;
   }

   fp = filename(argv[1],".loadram");
   if((fd = fopen(fp,"w")) == 0) {
      printf("Can't create %s\n",fp);
      done();
   }
   /* write the current date and directory name out and we're done */
   DateStamp(&date[0]);
   fwrite(&date[0],12,1,fd);
   fwrite(dirname,100,1,fd);
   fwrite(ramname,100,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);
}
usage()
{
   printf("usage: loadram ramdir diskdir [filespec1, filespec2 ...]\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) == 0) {
         UnLock(lock);
         return(0);
      }
      /* If it is a directory ignore it */
      if(fcb->fib_DirEntryType >= 0) continue;
      return(1);
   }
}
wcm(n,p,argv)
int n;
char *p;
char *argv[];
{

   if(n <= 0)return(1);
   n--;
   do {
      if(match(p,argv[n]))return(1);
   }while(n--);
   return(0);
}
match(a,b)
char *a,*b;
{
   register char *p,*q;

   p = a;
   q = b;
   if(*q == '*') {
      /* Leading wildcard * in the pattern */
      while(*p)p++;
      while(*q)q++;
      p--;
      q--;
      while(*q != '*') {
         if(*p == *q) {
            p--;
            q--;
            continue;
         }
         break;
      }
      if(*q == '*')return(1);
      return(0);
   }
   while(*p && *q && (*q != '*')) {
      if(*p == *q) {
         p++;
         q++;
         continue;
      }
      break;
   }
   if((*p == 0) && (*q == 0))return(1);
   if(*q == '*')return(1);
   return(0);
}
char iobuf[512];

/* copy file from disk to ram: */
copy(inf,outf,name)
char *inf,*outf,*name;
{
   FILE *fdi,*fdo;
   int n;
   if((fdi = fopen(filename(inf,name),"r")) == NULL) {
      printf("Can't open %s\n",filestr);
      return;
   }
   if((fdo = fopen(filename(outf,name),"w")) == NULL) {
      printf("Can't open %s\n",filestr);
      return;
   }
   while(n = fread(iobuf,1,512,fdi)) {
      if(fwrite(iobuf,1,n,fdo) != n) {
         fclose(fdi);
         fclose(fdo);
         return(1);
      }
   }
   fclose(fdi);
   fclose(fdo);
   return(0);
}
