/* needed.c */
/*
Copyright (C) 1986 Rahul Dhesi -- All rights reserved
*/
#include "options.h"
/* Accepts a filename from an archive and returns 1 if a command-line
   argument filename matches it.  Otherwise returns 0. Returns
   1 if no arguments were supplied (so by default, all files will
   be extracted */

#include "zoo.h"

#ifdef NEEDCTYP
#include <ctype.h>              /* for tolower() */
#endif

#include <stdio.h>               /* solely to define NULL */
#include "various.h"
#include "zoofns.h"
#include "debug.h"

extern int next_arg;          /* filenames start at this position */
extern int arg_count;         /* count of arguments supplied to program */
extern char **arg_vector;     /* vector of arguments supplied to program */
/* Uses FIRST_ARG in zoo.h, so must be recompiled when switching
   between Ooz and Zoo */

int needed(pathname)
char *pathname;
{
   register int i;
   register char *arg;
   char *justname;

   if (arg_count <= FIRST_ARG)         /* no filenames supplied */
      return (1);                   /* so all files are needed */
   /* count backwards and stop if '+' is encountered */
   for (i = arg_count-1;  i >= next_arg; i--) {
      arg = arg_vector[i];
#ifdef FOLD
      strlwr(pathname); strlwr(arg);
#endif
      if (strcmp(arg,"+") == 0)
         return (0);

      /* If the argument contains a slash, the match fails if the
         path prefixes don't match */
      if (strchr(arg, *PATH_CH) != NULL) {      /* found slash */
         char *p;
         char arg_prefix[PATHSIZE];
         char path_prefix[PATHSIZE];
         strcpy(arg_prefix,arg);
         strcpy(path_prefix,pathname);

         p = findlast(arg_prefix, PATH_CH);
         if (p != NULL)
            *p = '\0';

         p = findlast(path_prefix, PATH_CH);
         if (p != NULL)
            *p = '\0';

#ifdef DEBUG
      printf("match:  prefix compare between [%s] and [%s]\n",
                  path_prefix, arg_prefix);
#endif

         if (!match_half(path_prefix, arg_prefix)) {
#ifdef DEBUG
      printf ("match:  prefix match failed\n");
#endif
            continue;                     /* no match this time in loop */
         }


      }

      /*
      We reach here either if the pattern had no slashes, or if it
      had a slash but the path prefixes matched.  Now we test to see 
      if the filename parts match.
      */

      if (match (pathname, arg))       /* match with dot special */
         return (1);
      /* 
      if supplied pattern contains "**", then do a full match also 
      */
      if (index(arg,"**") != -1 && match_half(nameptr(pathname),arg))
         return (1);

#ifdef DEBUG
      printf("needed:  matching [%s] and [%s]\n", arg, pathname);
#endif

      /* try for a character range */
      justname = nameptr(pathname);
      if (match_half (arg, "?-?")) { /* character range given */
         if (arg[0] <= *justname && arg[2] >= *justname)
            return (1);
      }
   }
   return (0);

} /* needed */

/********************/
/*
match() compares a name with a pattern, with EXT_CH treated specially.
EXT_CH is assumed to separate a filename from its extension.  Both are
matched separately.
*/
int match(name, pattern)            /* compare names including * and ? */
register char *name, *pattern;
{
   /* will hold half the name */
   char half1[LFNAMESIZE], half2[LFNAMESIZE]; 
   rootname (name, half1);          /* get root name minus extension */
   rootname (pattern, half2);

   debug ((printf ("match:  root names are [%s] and [%s].\n", half1, half2)))

   if (!match_half (half1, half2))     /* if roots don't match */
      return (0);                      /* ... then names don't match */

   extension (name, half1);            /* get extension */
   extension (pattern, half2);

   debug((printf ("match:  extensions are [%s] and [%s].\n", half1, half2)))

   /* if name's extension is null, we force it to also match pattern if 
   pattern's extension contains only "*" characters.  Thus "*.*" will
   match filenames without extensions too */
   if (*half1 == '\0')  {              /* if null extension */
      char *p = half2;
      debug((printf ("match:  extension is null.\n")))
      while (*p == '*')
         p++;
      if (*p == '\0')               /* if pattern is only *, success */
         return (1);
   }

   debug((printf ("name's extension = [%s].\n", half1)))
   debug((printf ("pattern's extension = [%s].\n", half2)))
   return (match_half (half1, half2));
}

/***********************/
/*
match_half() compares a pattern with a string.  Wildcards accepted in
the pattern are:  "*" for zero or more arbitrary characters;  "?"
for any one characters.  Unlike the MS-DOS wildcard match, "*" is
correctly handled even if it isn't at the end of the pattern. ".'
is not special.

Originally written by Jeff Damens of Columbia University Center for
Computing Activities.  Taken from the source code for C-Kermit version
4C.
*/

int match_half (string, pattern) 
register char *string, *pattern;
{
   char *psave,*ssave;        /* back up pointers for failure */
   psave = ssave = NULL;
   while (1) {
#ifdef IGNORECASE
      for (; 
         tolower(*pattern) == tolower(*string); 
         pattern++,string++                        )  /* skip first */
#else
      for (; *pattern == *string; pattern++,string++)  /* skip first */
#endif /* IGNORECASE */

         if (*string == '\0') 
            return(1);                          /* end of strings, succeed */
      if (*string != '\0' && *pattern == '?') {
         pattern++;                             /* '?', let it match */
         string++;
      } else if (*pattern == '*') {             /* '*' ... */
         psave = ++pattern;                     /* remember where we saw it */
         ssave = string;                        /* let it match 0 chars */
      } else if (ssave != NULL && *ssave != '\0') {   /* if not at end  */
         /* ...have seen a star */
         string = ++ssave;                      /* skip 1 char from string */
         pattern = psave;                       /* and back up pattern */
      } else 
         return(0);                             /* otherwise just fail */
   }
}

