/* makelist.c */
/*
Copyright (C) 1986 Rahul Dhesi -- All rights reserved
*/

#include "options.h"
#include "portable.h"

/* for low-level I/O */
#ifdef NOFCNTL
#include <file.h>
#else
#include <fcntl.h>
#endif

#ifdef FLAT
#include <types.h>
#include <stat.h>
#else
#include <sys/types.h>
#include <sys/stat.h>
#endif

#include "zoo.h"
#include <stdio.h>
#include "various.h"

#include "zoofns.h"
#include "assert.h"
#include "debug.h"

#ifdef LINT_ARGS
char *nameptr (char *);
#else
char *nameptr();
#endif

/*******************/
/*
makelist() gets all pathnames corresponding to a set of filespecs and
adds them to a list.  Not more than "flistsize" pathnames are added.
Into `longest' it returns the length of the longest name added, or
zero if none added.
*/

void makelist (argc, argv, flist, flistsize, ignore1, ignore2, ignore3, longest)
int argc;               /* number of filespec supplied */
char *argv[];           /* array of pointers to supplied filespecs */
register char *flist[]; /* array of pointers to filenames we will add */
int flistsize;          /* home many names we can use */
char *ignore1, *ignore2, *ignore3; /* files to exclude from list */
int *longest;        /* length of longest name in list */
{
   char *this_path;        /* current pathname */
   int fptr;               /* pointer to within flist */
   register int i, j;      /* loop counters */
   char *pat_name;         /* filename part of pattern */
   int range;              /* testing character range? */
   int gap;                /* for Shell sort */
   
   flistsize--;            /* allow for one terminating NULL entry */
   fptr = *longest = 0;

   assert(argc > 0);

   while (argc > 0) {
      char *this_arg = *argv;
#ifndef PORTABLE
      char *temp = lastptr (this_arg);
      char lastch = *temp;
#endif
      assert(*lastptr (this_arg) != NULL);
#ifdef PORTABLE
      /* nothing */
#else
      if (strchr(PATH_SEP, lastch) != NULL)
         this_arg = newcat (this_arg, "*.*");
#endif

      debug((printf ("makelist:  this_arg = [%s].\n", this_arg)))

      /* initialize fileset 0.  If char range specified, select all
      files -- match_half will filter out the ones wanted */
#ifdef FOLD
      strlwr (this_arg);
#endif
      pat_name = strdup (nameptr (this_arg));

#ifdef PORTABLE
      /* nothing */
#else
      if (range = match_half (pat_name, "?-?")) {  /* "=" intentional */
         strcpy (nameptr (this_arg), "*.*"); /* change "?-?" to "*.*" */
      }
      /* note: when this_arg goes from "?-?" to "*.*", pat_name remains
      unchanged. */
#endif

      nextfile (0, this_arg, 0);
      while (fptr < flistsize && 
            (this_path = nextfile(1, NULL, 0)) != NULL) {
         char *this_name = nameptr (this_path);
#ifdef FOLD
         strlwr (this_path);
#endif

#ifdef FORCESLASH
   fixslash (this_path);               /* convert backslashes to slashes */
#endif

         debug((printf ("makelist:  this_path=[%s] this_name=[%s] pat_name=[%s].\n", 
                                    this_path, this_name, pat_name)))

#ifdef IGNORECASE
         if (!strcmpi(this_name,ignore1)  ||    /* exclude ignored files */
             !strcmpi(this_name,ignore2)  ||
             !strcmpi(this_name,ignore3))
            continue;
#else
         if (!strcmp(this_name,ignore1)  ||    /* exclude ignored files */
             !strcmp(this_name,ignore2)  ||
             !strcmp(this_name,ignore3))
            continue;
#endif

#ifdef CHEKDIR
      {
         int skip, han;  
         han=OPEN(this_name, F_READ);
         skip = isadir(han);  close(han);
         if (skip)
            continue;
      }
#endif
      
#ifdef CHEKUDIR
         if (isuadir(this_name))
            continue;
#endif

         if (match (this_name,pat_name) || range && 
               *this_name >= *pat_name && *this_name <= pat_name[2]) {
            flist[fptr++] = strdup (this_path);
         if (*longest < strlen(this_path))
            *longest = strlen(this_path);
            debug((printf ("makelist:  [%s] added to list.\n", this_path)))
         }

      }
      argc--;
      argv++;
   }
   /* fptr is now 1 + index of last item in array */

   if (this_path != NULL && fptr >= flistsize)
      prterror ('w', "Some filenames ignored -- can only handle %d.\n",
                                                   flistsize);
#ifndef  DONT_SORT
   /* Shell sort -- K&R p. 58 */
   for (gap = fptr/2; gap > 0; gap /= 2)
      for (i = gap; i < fptr; i++)
         for (j = i - gap; j >= 0 && 
            strcmp(flist[j],flist[j+gap]) > 0; j -= gap) {
/* strcmp(nameptr(flist[j]),nameptr(flist[j+gap])) > 0; j -= gap) */
            char *t = flist[j]; flist[j] = flist[j+gap]; flist[j+gap] = t;
         }
#endif /* DONT_SORT */

   fptr--;     /* fptr is now index of last item in array */

   /* Remove duplicates */
   for (i = 0; i < fptr; i++) {
      debug((printf ("duplicate test:  [%s] and [%s].\n",
                        nameptr(flist[i]), nameptr(flist[i+1]))))
#ifdef IGNORECASE
/* while (i<fptr && strcmpi (nameptr(flist[i]),nameptr(flist[i+1])) == 0) */
      while (i<fptr && strcmpi (flist[i],flist[i+1]) == 0) {
#else
/* while (i<fptr && strcmp  (nameptr(flist[i]),nameptr(flist[i+1])) == 0) */
      while (i<fptr && strcmp (flist[i],flist[i+1]) == 0) {
#endif
         for (j = i; j < fptr; j++)
            flist[j] = flist[j+1];
         fptr--;
      }
   }

   flist[++fptr] = NULL;      /* NULL entry terminates list */
}

