/*  004  20-Apr-87  scantree.c

        Copyright (c) 1987 by Blue Sky Software.  All rights reserved.
*/

#include "strmem.h"
#include "dosfile.h"

#ifndef NULL
#define NULL (0)
#endif

static char *scanpath;
static int (*scanfunc)(), scanattr, firstime;

struct scanent { struct scanent *next; char *name; };

char *strrchr(), *strupr();
struct search_block *nxtfile();

/******************************************************************************
                               S C A N T R E E
 *****************************************************************************/

scantree(dir,pathbuf,attrib,func)  /* scan the specified dir tree */
char *dir, *pathbuf;
int attrib, (*func)();
{
   /* caller must initialize pathbuf - put in the drive spec, e.g. "C:"
      if starting at the root and dir names are going to be processed */

   scanfunc = func;                    /* ptr to function called with names */
   scanattr = attrib;                  /* attributes to scan for */
   scanpath = pathbuf;                 /* dir name work buffer */

   walk(dir);                          /* walk the dir tree */
}

/******************************************************************************
                                   W A L K
 *****************************************************************************/

walk(dirname)          /* walk the dir tree */
char *dirname;
{
   int pathlen;
   struct scanent *subdirs = NULL;
   register struct search_block *sbp;
   register struct scanent *nsub = (struct scanent *) &subdirs;

   /* build the pathname of the dir to scan */

   pathlen = strlen(scanpath);         /* remember callers length */
   if (strcmp(dirname,"\\") != 0) {    /* special case if root dir */
      strcat(scanpath,dirname);        /* add name of dir to scan */
      strcat(scanpath,"\\");
   } else                              /* starting at root */
      strcat(scanpath,dirname);        /* add root to scanpath */

   /* tell users routine what dir is about to be scanned, only scan it if
      users routine returns a NZ value - skip this one if 0 - note that the
      dir names all have trailing \'s when passed to user */

   if ((*scanfunc)(NULL,scanpath)) {   /* tell user what dir it is (has \) */

      strcat(scanpath,"*.*");          /* add wildcard string */

      /* scan all files in directory, call scanfunc to process each file entry,
         stack the names of any subdirectories so we can then scan them later */

      firstime = 1;

      while (sbp = nxtfile(scanpath,scanattr,&firstime)) {

         if ((*scanfunc)(sbp,NULL) == 0)  /* let somebody else see it */
            break;                        /* skip the rest if they say stop */

         /* if this is a subdir to also scan, build a scanent for it */

         if (sbp->attrib & 0x10 && *sbp->fn != '.')
            if (nsub->next = (struct scanent *) Malloc(sizeof(struct scanent))) {
               nsub = nsub->next;
               nsub->next = NULL;
               nsub->name = Strdup(sbp->fn);
            }
      }
   }

   /* if any subdirectories were found, scan 'em.  This isn't done
      earlier so the file search isn't complicated by the directory
      switches. */

   if (nsub = subdirs) {                       /* NULL if no sub's found */
      scanpath[strlen(scanpath)-3] = '\0';     /* remove *.* for next level */
      do {
         walk(nsub->name);             /* call ourselves to scan this subtree */
         free(nsub->name);             /* release sub dir name space   */
         subdirs = nsub;               /* eat our own tail as we crawl */
         nsub = nsub->next;            /*   down the list of subdirs   */
         free((char *)subdirs);        /*   you can't go home again    */
      } while (nsub);                  /* do all the subs found above  */
   }

   scanpath[pathlen] = '\0';           /* restore dir pathname for caller */
}


