#include "ufk.h"
#include <sys/dir.h>
#include <modes.h>
#include <stat.h>

/*
 *  Get next file in a file group
 */

get_file_spec(firsttime)
char firsttime;
{
   char *wild_file_spec(),
        *status;
   static char my_firsttime;

   if (firsttime)
   {
      filenum = 1;                        /* First time initial values */
      filecount = numprm - 1;
      my_firsttime = TRUE;
   }
   do
   {
      if (rflg != 2)
      {
         status = wild_file_spec(params[filenum], my_firsttime);
         my_firsttime = FALSE;
      }
      else
      {
         status = params[filenum++];      /* Don't parse for 'GET' */
         if (filecount-- == 0)
            break;
      }
      if (status == ERROR)
      {
         prterr(ER_DIROPN);
         break;
      }
      else if (status)                    /* Got valid spec */
      {
         filnam = status;                 /* Setup pointer to spec */
         return TRUE;
      }
      filenum++;                          /* Next parameter */
      my_firsttime = TRUE;                /* Start new directory search */
   }
   while (--filecount > 0);               /* More to do */
   return FALSE;                          /* done */
}

char *wild_file_spec(mask,first)
char mask[], first;
{
   static struct direct *ptr;
   struct direct *diropen();
   static char filename[128];
   char status;

   if (first)
      if ((ptr = diropen(mask)) == ERROR)
         return (ERROR);                  /* Failed to open directory */
   while(TRUE)
   {
      status = dirread(ptr,filename);
      if (status == ERROR)                /* Check for end */
         break;
      if (status != TYPERROR)
         if (mskcmp(filename,mask))       /* Check match if not a directory */
            return(filename);             /* or device type file */
   }
   free(ptr);                             /* Release allocated memory */
   return (FALSE);                        /* No more files */
}

/*
*** Compare against a mask
*
*  This function compares a given string against a mask and returns
*  a 1 for 'compares' or a 0 for 'does not compare'.
*
*  A mask is a concatenation of the following elements:
*
*  c              literal character
*  ?              any character match except endstring null
*  [..]           character class (all of these characters)
*  [^..]          negated character class (all but these characters)
*  ^c             negated character (all but this character)
*  *              zone (match zero or more occurences)
*
*  A character class consists of zero or more of the following
*  surrounded by [ and ]:
*
*  c1-c2          range of ascii characters
*  c1-c2..c1-c3   multiple ranges
*
*/

mskcmp(string,m)
char *string,*m;
{
   int k;
   char *sp,*sav,string2[128];
   char *n,msk[128];

   strcpy(sp = string2,string);
   strcpy(n = msk,m);

   while (*n)
   {
      if (*n == '*')
      {
         sav = sp;
         if (!*++n)
            return (1);
         while (*sp && !mskcmp(sp,n))
            ++sp;
         if (*sp)
            continue;
         sp = sav;
      }
      else
         if (!(k = onecmp(*sp,n)))
            return (0);
         else
            n += k;
      if (*sp)
         ++sp;
   }
   return (!*sp);
}

/*
*** Compare only one character (for mskcmp)
*/

onecmp(s,m)
char s,*m;
{
   char c,setfind,setflag;
   char *mp;

   if ((c = *(mp = m)) == '?' && s);         /* Okay as it is */
   else if (c == '[')
   {
      setfind = setflag = 0;
      if (*++mp == '^')
      {
         setflag = 1;
         ++mp;
      }
      for (;(c = *mp) && c != ']'; ++mp)
         if (*mp == '-' && s >= *(mp - 1) &&
            s <= *(mp + 1) && *(mp - 1) <= *(mp + 1))
         {
            /* skip to trailing ']' */
            while ((c = *(mp + 1)) && c != ']')
               ++mp;
            setfind = 1;
         }
         if (setfind == setflag)
            return (0);
         else
            return (mp - m + 1);
      }
   else if (c == '^' && *(mp + 1) != s)
      return (2);
   else if (c != s)
      return (0);

   return (1);
}

/*
*** Open disk directory
*/

int *dirptr;
char dirspec[128];

struct direct *diropen(name)
char *name;
{
   static struct direct ptr;
   int i, j;

   for (i = strlen(name) - 1; i >= 0; --i)    /* Find filename */
      if (name[i] == '/')
         break;
   for (j = 0; j <= i; j++)                   /* Save directory path */
      dirspec[j] = name[j];
   dirspec[j++] = '.';                        /* Append "." */
   dirspec[j] = '\0';
   if ((dirptr = open(dirspec,0)) == ERROR)   /* Open directory */
      return (ERROR);
   else
      return (&ptr);
}

dirread(ptr,filename)
struct direct *ptr;
char *filename;
{
   int i, j, status;
   struct stat statptr;

   while (TRUE)
   {
      status = read(dirptr,ptr,sizeof(struct direct)); /* Get dir entry */
      if (status == ERROR || status == NULL) /* Stop on EOF or error */
         break;
      if (ptr->d_ino)                        /* If not a deleted file */
      {
         strcpy(filename,dirspec);           /* Copy directory spec */
         strncpy(&filename[strlen(filename)-1],ptr->d_name,DIRSIZ); /* +fnam */
         stat(filename,&statptr);            /* Get file status */
         statptr.st_mode &= S_IFMT;          /* Mask file type bits */
         if ((statptr.st_mode == S_IFDIR) || /* Check if directory */
             (statptr.st_mode == S_IFCHR) || /* or if character device */
             (statptr.st_mode == S_IFBLK))   /* or if block device */
            return(TYPERROR);
         file_size = statptr.st_size;        /* Fill in file size */
         transmit_chr_count = 0;             /* Start new sequence */
         return (TRUE);
      }
   }
   close(dirptr);
   return (ERROR);
}
