;/*
; *************************************************************************
; * List Comment                   Created: August 11, 1991               *
; * ©1991  John Bianchi            Bianchi Computer Systems               *
; *************************************************************************
; *              Execute me to compile under SAS/C 5.10a                  *
; *************************************************************************

if NOT exists PatMatch.o
   lc -tr PatMatch.c
endif
lc -tr ListCom.c 
blink FROM LIB:c.o+"ListCom.o"+"PatMatch.o" TO "ListCom" LIB LIB:lc.lib LIB:amiga.lib
quit

*/

#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <string.h>

#define PROGRAM    "ListCom" 
#define VERS       "1.33"
#define RELEASE    "18.10.1991"
#define COPYRIGHT  "©1991 John Bianchi  All Rights Reserved." 

/* 2.0 compatable Version Tag String                                    */
UBYTE *version      = "\0$VER: List Comments " VERS "   (17.10.91) ";

UBYTE *Usage        = "\
[1mLIST COMMENTS[0;33m   Version: " VERS "   " COPYRIGHT "[0m\n\
\n\
[32mUsage:[0m\n   [1m" PROGRAM " [0m <Path> <Comment> <-options>\n\
\n\
[32mWith:[0m\n\
   Path    : the path and/or file(s) you want to list\n\
   Comment : the comment(s) you want to match\n\n\
[32mOptions:[0m\n\
   -M = Match  : stop on first found match\n\
   -F = NoForm : don't format the output listing\n\
   -H = NoHead : do not show header line\n\
   -S = NoSize : don't show file size(s)\n\
   -C = NoCom  : don't show file comment(s)\n\
   -Q = Quiet  : (-H -S -C -F) only show the file name(s)\n\
   -N = NoLine : don't do a line feed (-m)\n\
\n";

struct FileInfoBlock *f_info;

int  ListCom();          /* Parses and does directory type stuff         */
int  showfileinfo();     /* shows a file info block in special format(s) */
BOOL isapat();           /* checks for pattern characters                */
BOOL patternmatch();     /* calls PatMatch.c funcs, returns TRUE/FALSE   */


char err_msg[80];        /* My error messages                            */
int  return_value;       /* depends upon return of ListCom() routine     */
char Pat[128];           /* here for PatMatch.c stuff written/translated */
char Str[128];           /* by Jeff Lydiatt                              */
WORD Aux[128];           /* See  PatMatch.c  source for more info        */

/* flags for the argument switches                                       */
BOOL match,nohead,noform,nosize,nocom,noline = FALSE;

main (argc, argv)
int argc;
char *argv[];
{
    char   filepath[255], filenote[80];
    int    k,error;
    struct Process *proc;
    struct CommandLineInterface *cli;

    proc = (struct Process *)FindTask(NULL);
    cli =  (struct CommandLineInterface *)(proc->pr_CLI << 2);
    if(!cli  || argc == 0) exit(RETURN_ERROR);

    if((f_info=(struct FileInfoBlock *)
       AllocMem(sizeof(struct FileInfoBlock),MEMF_CHIP|MEMF_CLEAR))==0)
    {
        printf("[2m%s[0m  Can't Allocate Memory!",argv[0]);
        exit(RETURN_FAIL);
    }

        /* if no arguments supplied or the user type ? show usage       */
        /* Will probably use the 2.0 template stuff after 2.0           */
        /* is the OS of choice. (and i see some clean, small source     */
        /* code that I can learn it from!                               */

    if(argv[1][0]=='?') 
   	{
        printf("%s",Usage);
        exit(RETURN_WARN);
    }

    /* if not given, we must initialize */
    filepath[0] = '\0';
    filenote[0] = '\0';

    /* This is the Argument parsing stuff */
    for(k=1; k<argc; k++)
    {
        /* this is to find the '-' commands */
        if(argv[k][0] == '-')
        {
            switch( argv[k][1] )
            {
                case 'N':
                case 'n':
                    noline=TRUE;
                case 'm':
                case 'M':
                    match=TRUE;
                    break;
                case 'Q':
                case 'q':
                    nohead=TRUE;
                    nosize=TRUE;
                    nocom=TRUE;
                case 'f':
                case 'F':
                    noform=TRUE;
                    break;
                case 'H':
                case 'h':
                    nohead=TRUE;
                    break;
                case 'S':
                case 's':
                    nosize=TRUE;
                    break;
                case 'C':
                case 'c':
                    nocom=TRUE;
                case '\0'             /* so a '-' alone will be ignored */
                    break;            /* ignore the compiler warning    */
                default:
                    printf("\nUnknown command: %s\n",argv[k]);
                    exit(RETURN_ERROR);
             }
        }
        else
        {
            /* this puts the 1st and 2nd argument into their variables  */
            switch( k )     
            {
                case 1:
                    strcpy(filepath, argv[k]);
                    break;
                case 2:
                    strcpy(filenote, argv[k]);
                    break;
                default:
                    printf("\nUnknown command: (%d) \"%s\"\n",k,argv[k]);
                    exit(RETURN_ERROR);
            }
        }
    }
    /********************************************************************/
    /* ok, here we send the path and note to be searched.               */
    /* ListCom() should definately be cleaned up, but this part of the  */
    /* code will remain the same.  ListCom() returns an int value of the*/
    /* error encountered.  err_msg[] will have the error message for    */
    /* a returned value of -1.                                          */
    /********************************************************************/
    switch( error = ListCom(filepath,filenote) )       
    {
        case  0:
            return_value = RETURN_OK;       /* listed something          */
            break;
        case  1:
            return_value = RETURN_WARN;     /* didn't match included for */ 
            break;                          /* script usage              */
        case -1:
            return_value = RETURN_ERROR;    /* some kinda error          */
            printf("ListCom Error: %s.\n",err_msg);
            break;
        default:
            return_value = error;           /* AimgaDOS error            */
            printf("AmigaDOS Error: %d\n",error);
            break;
    }

    FreeMem(f_info,sizeof(struct FileInfoBlock));
    exit(return_value);
}

int ListCom(filepath, filenote)
char *filepath,*filenote;
{
    int  i,error = 0;
    int  showd = 1;
    long lock;
    char patternpath[80],patternfile[80];
    BOOL name_patmatch=FALSE;

    lock = Lock(filepath, ACCESS_READ);
                 /* have to do this as I don't know any other way! */
    if(!lock)    if(isapat(filepath))
    {
        strcpy(patternpath,filepath);
        /* patternpath is a copy of filepath, let's remove the file
           portion                                                      */
        for(i=(strlen(patternpath));i>=0;i--)
        {
            if(patternpath[i] == ':' || patternpath[i] == '/')
                break;
            else
                patternpath[i] = '\0';
        }

        /* put the patterned file info into patternfile                 */
        /* if any path exists from above, pull filename part            */
        if(strlen(patternpath)>0)
        {
            error=strmid(filepath,patternfile,i+2,30);
            if(error)     /* not sure why this would come up, but...    */
            {
                strcpy(err_msg,"Error in internal string manipulation");
                return(-1);
            }
            /* We're only here to pattern match the last node of the
               filepath.  ie: DH0:#?/test  <- Not allowed! (Maybe I'll
               get that in a later version when I learn more)           */
            if(isapat(patternpath))
            {
                strcpy(err_msg,"Can't pattern match the Path!");
                return(-1);
            }
        }
        else
            strcpy(patternfile,filepath);

        /* patternpath is really the path part of the argument, it
           will not use any wildcards, only "" for current dir.         */
        lock=Lock(patternpath, ACCESS_READ);
        if(!lock)
        {
            strcpy(err_msg,"`");
            strcat(err_msg,patternpath);
            strcat(err_msg,"' path not found");
            return(-1);
        }
        name_patmatch=TRUE;
    }
    else    /* failed orig lock and did not have any wildcards          */
    {
        strcpy(err_msg,"`");
        strcat(err_msg,filepath);
        strcat(err_msg,"' file not found");
        return(-1);
    }

    if((Examine(lock,f_info))==0)
    {
        strcpy(err_msg,"Unknown File");  /* this should never happen    */
        return(-1);
    }
    if(f_info->fib_DirEntryType > 0)   /* original lock is a Directory!! */
    {
        if(!nohead)
            printf("Listing of directory: \"%s\"\n",f_info->fib_FileName);   

        /*  Loop to read entries in directory                           */
        while ((ExNext(lock,f_info))!=0)
        {    
            /*  if were listing the whole directory or parrern matching
                a filename                                              */
            if(!name_patmatch || patternmatch(patternfile,f_info->fib_FileName))
            {
                /* is there a filenote to check? */
                if(strlen(filenote)>0)   
                {
                    /*  yes, so see if it is a pattern match to the
                        current file entry's comment                    */
                    if(patternmatch(filenote,f_info->fib_Comment)>0)
                    {
                        showd=showfileinfo();
                        if(match)   break;
                    }
                }
                else  /* no filenote, so show all files with comments   */
                    if(strlen(f_info->fib_Comment)>0)
                    {
                        showd=showfileinfo();
                        if(match)   break;
                    }
            }
        }
    }
    else    /* well, we were given a file name, it exists, so show it!  */
    {
        if(!name_patmatch || patternmatch(patternfile,f_info->fib_FileName))
            showd=showfileinfo();
    }
    UnLock(lock);

    error = IoErr();
    if(error = ERROR_NO_MORE_ENTRIES)
        return(showd);  /* ignore No more entries and send if we matched */
    else
        return(error);  /* was an AmigaDOS errorx is IoErr()            */
}


/*  Too much junk to put this in the ListCom() function.                */
/*  This function ALWAYS returns 0 = TRUE.                              */
/*  It is not BOOL due to the nature of the return value which in       */
/*  turn may be used as the return value of ListCom(), this in turn     */
/*  lets main() know how to exit()  ie: RETURN_OK, _WARN, _ERROR, _FAIL */
int showfileinfo(void)
{
    {
        if(noform)
            printf("%s",f_info->fib_FileName);
        else
            printf("%-20s",f_info->fib_FileName);
        if(!nosize)
        {
            if(f_info->fib_DirEntryType > 0 )
                if(noform)  printf(" Dir");
                else        printf("     Dir");
            else        
                if(noform)  printf(" %d",f_info->fib_Size);
            else            printf(" %7ld",f_info->fib_Size);
        }
        if(!nocom)
            if(noform)  printf(" %s",f_info->fib_Comment);
            else        printf(" \"%s\"",f_info->fib_Comment);
    }
    if(!noline)
        printf("\n");
    return(0);
}


/*  I tried to write this in obscure C (you know, tight, compact,
    un-intelligable)  but couldn't get it to work, so this fatter
    version will have to work till I can rewrite it                */
BOOL isapat(str)
char *str;
{
    int i;
    BOOL flag=FALSE;
    for(i=0; i<strlen(str); i++)
    {
        switch( str[i] )
        {
            case '#': flag=TRUE;
            case '?': flag=TRUE;
            default : break;
        }
    }
    return(flag);
}


/* this is just a pre-patternmatching function to call              */
/* the functions in PatMatch.c  See PatMatch.c for more             */
BOOL patternmatch(this,that)
char *this,*that;
{
    strcpy(Pat,this);
    strcpy(Str,that);
    if ( CmplPat( Pat, Aux ) == 0 )                    
    {                                               
       strcpy(err_msg,"Bad Wildcard Expression");         
       return(FALSE);                                     
    }                                               
    if ( Match( Pat, Aux, Str ) == 1 )                 
        return(TRUE);                                     
    else                                               
        return(FALSE);                                     
}

