/*
** Part 2
*/

#include <stdio.h>
#include <functions.h>
#include <exec/exec.h>
#include <libraries/dos.h>

extern void *malloc (), *calloc ();
extern char gifname [], iffname [];
extern int update;

/* ADT for list */
struct listentry {
   struct listentry *next;
   char *gifname, *iffname;
};

struct listentry *list = NULL;

/* Initalize list */
initlist ()
{
   list = NULL;
}

/* Add entry to list. Process update flag */
addlist (gifname, iffname)
char *gifname, *iffname;
{
   struct listentry *new;

   if (update) {
      if (existsfile (iffname))
         return;
   }

   new = malloc (sizeof (struct listentry));
   if (!new)
      fatalerr ("Out of memory");
   new->next = list;
   new->gifname = calloc (strlen (gifname) + 1, sizeof (char));
   if (!new->gifname)
      fatalerr ("Out of memory");
   new->iffname = calloc (strlen (iffname) + 1, sizeof (char));
   if (!new->iffname)
      fatalerr ("Out of memory");
   strcpy (new->gifname, gifname);
   strcpy (new->iffname, iffname);
   list = new;
}

/* Get and delete entry from list. Returns 0 if no more */
getlist (gifname, iffname)
char *gifname, *iffname;
{
   struct listentry *old = list;

   if (list == NULL)
      return (0);
   strcpy (gifname, list->gifname);
   strcpy (iffname, list->iffname);
   list = list->next;
   free (old->gifname);
   free (old->iffname);
   free (old);
   return (-1);
}

/* Free memory occupied by list */
freelist ()
{
   while (getlist (gifname, iffname));
}

/* Check if given file exists */
existsfile (filename)
char *filename;
{
   struct Lock *lock;

   lock = Lock (filename, ACCESS_READ);
   if (!lock)
      return (0);
   UnLock (lock);
   return (-1);
}

/* Add files matching template in gifname [] to list */
getwild ()
{
   struct Lock *lock;
   struct FileInfoBlock *fib;
   int success, i;
   long ioerr;
   char dirname [120], template [120];

   for (i = 0; i < strlen (gifname); i++)
      if (gifname [i] == '*')
         goto wild;
   addlist (gifname, iffname);   /* No wildcards */
   return;

wild:
   dirname [0] = '\0';
   strcpy (template, gifname);
   for (i = strlen (gifname) - 1; i >= 0; i--)
      if ((gifname [i] == ':') || (gifname [i] == '/')) {
         strncpy (dirname, gifname, i+1);
         dirname [i+1] = '\0';
         strcpy (template, &gifname [i+1]);
         break;
      }
   lock = Lock (dirname, ACCESS_READ);
   if (!lock)
      fatalerr ("Lock failed");
   fib = AllocMem ((long) sizeof (struct FileInfoBlock), 0L);
   if (!fib) {
      UnLock (lock);
      fatalerr ("Out of memory");
   }
   success = Examine (lock, fib);
   if (!success) {
      FreeMem (fib, (long) sizeof (struct FileInfoBlock));
      UnLock (lock);
      fatalerr ("Can't examine directory");
   }
   if (fib->fib_DirEntryType < 0) {
      FreeMem (fib, (long) sizeof (struct FileInfoBlock));
      UnLock (lock);
      fatalerr ("Not a directory");
   }
   while (success = ExNext (lock, fib)) {
      if (fib->fib_DirEntryType < 0)
         fillwild (dirname, fib->fib_FileName, template, iffname);
   }
   ioerr = IoErr ();
   FreeMem (fib, (long) sizeof (struct FileInfoBlock));
   UnLock (lock);
   if (ioerr != ERROR_NO_MORE_ENTRIES)
      fatalerr ("Unexpected error while reading directory");
}

/* Match and fill in wildcards and add to list */
fillwild (dirname, input, gifname, iffname)
char *dirname, *input, *gifname, *iffname;
{
   char tos (), pop ();
   char gifname2 [120], iffname2 [120];
   int i, j;

   initstack ();
   if (match (input, gifname)) {
      j = 0;
      for (i = 0; i < strlen (iffname); i++) {
         if ((iffname [i] == '*') && (!emptystack ())) {
            while (tos () != 0)
               iffname2 [j++] = pop ();
            pop ();
         }
         else
            iffname2 [j++] = iffname [i];
      }
      iffname2 [j] = '\0';
      strcpy (gifname2, dirname);
      strcat (gifname2, input);
      addlist (gifname2, iffname2);
   }
}

match (input, template)
char *input, *template;
{
   int success;
   char temp = *template;
   char inp = *input;

   switch (temp) {
   case '\0' :
      return (inp == '\0');
   case '*' :
      success = match (input, template + 1);
      if (success)
         push (0);
      else {
         if (inp == '\0')
            success = (*(template + 1) == '\0');
         else {
            success = match (input + 1, template);
            if (success)
               push (inp);
         }
      }
      return (success);
   default:
      if (inp == '\0')
         return (temp == '\0');
      if (inp != temp)
         return (0);
      return (match (input + 1, template + 1));
   }
}

char stack [256];
int sp = 0;

initstack ()
{
   for (sp = 0; sp < 256; sp++)
      stack [sp] = 0;
   sp = 0;
}

push (ch)
char ch;
{
   stack [sp++] = ch;
}

char pop ()
{
   return (stack [--sp]);
}

char tos ()
{
   return (stack [sp-1]);
}

emptystack ()
{
   return (sp == 0);
}

