/* LookFor the file whose name|pattern matches that passed as first argument.
 * Print the filename and its path to the screen
 */
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <exec/types.h>
#include <libraries/dosextens.h>
#include <proto/exec.h>
#include <proto/dos.h>
#define LONGEST_PATH_NAME  130
#define LONGEST_NAME  32
#define MAXDEV        30

/*
 *                 F U N C T I O N     D E C L A R A T I O N S
 */
extern BPTR Lock(char *,long);

BOOL ifoundit;
void chkabort(void);
int breakout(void);
void close_things (void);
void scan_directory (char *,char *);
char * adddir (char *);
void do_usage(void);
void do_searchfile(char *);
void do_devname(char *);
void usage_exit(void);
void getdisks(struct List *);
void freedisks(struct List *);
int MakeDevArray(char *);
int searchforcommas(char *);
int searchforALL(char *);
/*
 *                  E X T E R N A L S
 */
int notANY,notON,alive;
char devname[LONGEST_NAME][MAXDEV];
char searchfile[LONGEST_NAME];
/*
 *                  B R E A K   O U T    O F    S E A R C H
 */
int breakout()
{
printf("LookFor .......... terminated with \033[2mBREAK\033[0m.\n");
close_things();
alive = 0;
return(alive);       /* we return 0 so that we can clean up memory */
}

/*
 *                  M A I N     P R O G R A M     M O D U L E
 */
void
main( argc,argv)
int argc;
char * argv[];
{
        void scan_directory ();
        void UnLock ();
        void usage_exit();
        void do_usage();

        char path[130];           /* hold volume name */
        int ndev,i,dummy;

        notANY = notON = 1;
        switch(argc)
        {
        case 2:    /*
                    *     LookFor filename
                    */
            if (!(strcmp(argv[1],"?"))) usage_exit();
            devname[0][0] = '\0';
            do_searchfile(argv[1]);
            break;

        case 3:    /*  argv[]     0     1          2
                    *          LookFor ANY      filename
                    *          LookFor filename devname
                    */
            do_searchfile(argv[2]);
            devname[0][0] = '\0';
            notANY = stricmp(argv[1],"ANY");
            if (notANY)
                {
                    do_devname(argv[2]);
                    do_searchfile(argv[1]);
                }
            break;

        case 4:    /*  argv[]     0     1          2         3
                    *          LookFor ANY      filename  devname
                    *          LookFor filename    ON     devname
                    */
            do_devname(argv[3]);
            do_searchfile(argv[2]);
            if(notANY = stricmp(argv[1],"ANY"))
                {
                    if( notON = stricmp(argv[2],"ON")) usage_exit();
                    do_searchfile(argv[1]);
                }
            else do_searchfile(argv[2]);
            break;
        case 5:    /*  argv[]     0     1      2      3      4
                    *          LookFor ANY  filename  ON  devname
                    */
            notANY = stricmp(argv[1],"ANY");
            notON  = stricmp(argv[3],"ON");
            if(notANY || notON) usage_exit();
            do_devname(argv[4]);
            do_searchfile(argv[2]);
            break;
        default:
            usage_exit();
            break;
        }                    /* end of switch */

        ifoundit = FALSE;
        dummy = onbreak(&breakout);     /*  Set break trap */
        alive = 1;            /*  alive is 0 when we've been aborted */
        if (notON)
            {
               strcpy (path, devname[0]);
               /* Find it */
               scan_directory (searchfile,path);
               close_things ();
               exit(0);
            }
        if ( (ndev = MakeDevArray(devname[0])) < 0 ) close_things();
        for ( i = 0 ; i <= ndev; i++)
            {
              strcpy (path,devname[i]);
              printf("Checking %s\n",path);
              scan_directory(searchfile,path);
            }
        close_things ();
        exit(0);
} /* end main */

int MakeDevArray(devices)
char * devices;
{
    int ndev;
    if(stricmp(devices,"ALL"))  /* if notALL search for commas */
        {
        ndev = searchforcommas(devices);
        return(ndev);
        }
    /*  ALL keyword used, therefore */
    ndev = searchforALL(devices);
    return(ndev);
}
/********************************************************************/
int searchforALL(all)
char * all;
{
   struct List disks;
   struct Node *disk;
   static char Name_Disk[LONGEST_NAME] ;
   extern void getdisks(),freedisks();
   int count;

   count = 0;
   NewList(&disks);         /* Macro in exec ( ROM Kernel)  */
   getdisks(&disks);

 for ( disk = disks.lh_Head;disk->ln_Succ;disk=disk->ln_Succ)
     {
        strcpy(Name_Disk, disk->ln_Name) ;
        strcat(Name_Disk, ":");
        strcpy(devname[count++],Name_Disk);
        if (count > (int)MAXDEV) break;
     }
   freedisks(&disks);
   return(--count);
}

int searchforcommas(strofCommas)
char * strofCommas;
{
    char * dummy;
    char * token;
    int count;

    count = -1;
    dummy = strofCommas;
    token = strtok(dummy,",");
    while ( (token != NULL) && (count <= (int)MAXDEV) )
        {
           strcpy(devname[++count],token);
           token = strtok(NULL,",");
        }
    return(count);
}

/********************************************************************/
/*
Do whatever final clean up is needed to leave the program.
*/
void
close_things()
{
        if (!ifoundit)
                printf ("File not found.\n");
        return;
} /* end close_things */


/******************************
       scan_directory
*******************************/
void
scan_directory (searchfile,path)
char * searchfile;
char * path;
        {
        char * strcpy ();
        void UnLock ();
        register BPTR dir;
        struct FileInfoBlock * fb;
        char * adddir ();

#       define MAXSUB 50
        char subdir [LONGEST_NAME][MAXSUB]; /* Pointer area for Sub-Directories */
        char pathname[LONGEST_PATH_NAME]; /* Pointers to AmigaDOS sub-directories */
        register UBYTE countdir,indexdir,i;
        int thistest;
        char testname[LONGEST_NAME];
        char * ch;
        char * match;

        /* Get Lock on this directory */
        alive = 1;
        if ( (dir = Lock (path,ACCESS_READ)) == NULL)
                {
                printf ("Couldn't get %s\n",path);
                close_things ();
                exit (4);
                }

        /* Examine lock and obtain FileInfoBlock */
        fb=(struct FileInfoBlock *) AllocMem(sizeof(struct FileInfoBlock),0);
        if (!Examine (dir,fb))
                {
                printf ("Couldn't Examine files on lock\n");
                FreeMem ((char *)fb, sizeof (struct FileInfoBlock));
                UnLock (dir);
                close_things ();
                exit (4);
                }
        /* we now have dir and fb set up,
         * scan all files at this level
         * (remembering subdirectories)
         */
        countdir = 0;
        while ((ExNext(dir,fb) || IoErr() != ERROR_NO_MORE_ENTRIES)
                && (countdir <= MAXSUB)
                )
                {
                chkabort();
                if (!alive) goto abortMem;
                if (fb->fib_DirEntryType > 0)
                        {
                        /* we have a subdirectory here... */
                        if (countdir < MAXSUB) strcpy(subdir[countdir],fb->fib_FileName);
                        else printf ("Too many subdirectories for LookFor\n");
                        countdir++;
                        }
                else
                        {
                        /* compare fb->filename with searchfile  */
                        for (i=0;i<32;i++)
                                testname[i] = '\0';
                        strncpy (testname,fb->fib_FileName, 32);
                        testname[31] = '\0';
                        for (i = 0,ch=testname; (ch != '\0')&&(i<32);
                                i++,ch++)
                                *ch = toupper (*ch);
/******                 printf ("%s =?= %s\n",testname, searchfile); *****/

                        thistest = ( (notANY) ? stcpma(testname,searchfile) : stcpm(testname,searchfile,&match) );
                        if (thistest)
                                {
                                /*   printf("\033[2m%-20s\033[0m",fb->fib_FileName);  */
                                /*   printf ("  \033[2m%s/\033[0m%-30s   %9d bytes\n",path,fb->fib_FileName,fb->fib_Size); */
                                /*   printf ("  \033[2m%s/\033[0m%s\t%9d bytes\n",path,fb->fib_FileName,fb->fib_Size);     */
                                printf ("  %s/%s\t%9d bytes\n",path,fb->fib_FileName,fb->fib_Size);
                                ifoundit = TRUE;
                                }
                        }
                } /* end while */
        /* return these now, we're done, thank you. */
        FreeMem ((char *)fb, sizeof (struct FileInfoBlock));
        UnLock (dir);

        /* finished with this level, try one level down */
        indexdir = 0;
        while (indexdir < countdir)
                {
                chkabort();
                if (!alive) goto abortMem;
                strcpy (pathname,path); /*  , LONGEST_PATH_NAME - strlen(pathname) - 1);  */
                /* if no path delimiter, add one */
                if (       (path[strlen(path)-1] != ':')
                        && (path[strlen(path)-1] != '/')
                        && (strlen(path) > 0))
                        strcat (pathname,"/");
                strcat (pathname,subdir[indexdir]);  /*  , LONGEST_PATH_NAME - strlen(pathname) - 1);  */
                scan_directory (searchfile,pathname);
                indexdir++;
                }

        return;   /* normal end of scan_directory  */

abortMem: /* we've been aborted so attempt to clean up */
   if(fb)  FreeMem ((char *)fb, sizeof (struct FileInfoBlock));
   if(dir) UnLock (dir);
   exit(0);
}       /* end scan_directory */


void do_searchfile(string)
char *string;
{
    char * ch;

    strcpy (searchfile,string);
    for (ch=searchfile; *ch != '\0'; ch++)
        *ch = toupper (*ch);
    return;
}

void do_devname(string)
char *string;
{
    int i;

    for (i=0;i<32;i++)
        devname[i][0] = '\0';
    strncpy (devname[0],string,31);
    return;
}

void do_usage()
{
   printf ("\nLookFor by\033[2m Mark Schretlen\033[0m 88-12\n\n");
   printf ("usage: LookFor <ANY> <filename> <ON> <drive(s)|ALL>\n\n");
   printf ("patterns: (filename only)\n?  any single character ( LookFor ? gives this help message)\n*  zero or more occurrences \n+  one or more occurrences\n\\  override the above patterns\n\n");
   printf ("keywords: (optional)\nANY looks for the pattern anywhere within the filename (unanchored).\nON must be specified for a multi-drive search (separate drives with commas).\nON ALL looks for the file on all drives.\n\n");
   printf ("\nLookFor is a \033[2mpublic domain \033[0mprogram. Please distribute freely.\n\n");
   return;
}

void usage_exit()
{
    do_usage();
    exit(0);
    return;
}
