/* This code is taken largely from Carolyn Scheppner's "which.c" program
 * from 11/87.  There were no copyright notices in the original file,
 * so to the best of my knowledge it is in the Public Domain.
*/

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

#define SBUFSZ 256
#define CBUFSZ 80

extern BOOL getPath();
extern struct Task *FindTask();		/* To scare away warning msgs */
extern VOID *AllocMem();
	
struct Path
   {
   BPTR  path_Next;
   LONG  path_Lock;
   };

char *FindIt(command)
char *command;
{
   struct Process *proc;
   struct CommandLineInterface *cli;
   struct Path *path;
   struct FileInfoBlock *fib;
   APTR oldWindowPtr;
   LONG lock, startcd;
   BOOL Found, InitialCD, FullPath;
   int  i;
   char sbuf[SBUFSZ], cbuf[CBUFSZ];

   /* Fail if not CLI process */
   proc = (struct Process *)FindTask(NULL);
   cli = (struct CommandLineInterface *)(proc->pr_CLI << 2);
   if(!cli)  exit(RETURN_ERROR);

   /* Allocate a FileInfoBlock - must be longword aligned */
   if(!(fib=(struct FileInfoBlock *)
     AllocMem(sizeof(struct FileInfoBlock),MEMF_PUBLIC|MEMF_CLEAR)))
      printf("Not enough memory\n"), exit(RETURN_FAIL);

   /* Save old WindowPtr, and disable volume requesters */
   oldWindowPtr = proc->pr_WindowPtr;
   proc->pr_WindowPtr = (APTR)-1L;

   /* Were we given full path in command name ? */
   for(FullPath = FALSE, i=0; i<strlen(command); i++)
     {
     if(command[i] == ':')
        {
        FullPath = TRUE;
        break;
        }
     }

   /* Check current directory */
   if(Found = getPath(command,fib,sbuf))
      {
      if((!FullPath)&&(command[0]))  strcpy(sbuf,command);
      }

   /* Check paths */
   if((!Found)&&(!FullPath))
      {
      InitialCD = TRUE;
      /* Follow the BPTR path list */
      for(path = (struct Path *) BADDR(cli->cli_CommandDir);
          (path) && (!Found);
            path = (struct Path *) BADDR(path->path_Next))
         {
         /* CD to each path */
         lock = CurrentDir(path->path_Lock);
         if(InitialCD)  startcd = lock, InitialCD = FALSE;

         /* See if command is there */
         Found = getPath(command,fib,sbuf);
         }
      /* If we CD'd anywhere, restore initial CD */
      if(! InitialCD)  CurrentDir(startcd);
      }

   /* Check C: */
   if((!Found)&&(!FullPath))
      {
      strcpy(cbuf,"C:");
      strcpy(&cbuf[2],command);
      if(Found = getPath(cbuf,fib,sbuf))  strcpy(sbuf,cbuf);
      }

   /* Re-enable volume requesters */
   proc->pr_WindowPtr = oldWindowPtr;

   /* Free fib */
   if (fib)
	FreeMem(fib, sizeof(struct FileInfoBlock));

   if(Found)
	return(sbuf);
   else
	return(NULL);
}


BOOL
getPath(command,fib,buf)
char *command;
struct FileInfoBlock *fib;
char *buf;
   {
   LONG lock;
   BOOL Success = FALSE;

   if(lock = Lock(command,ACCESS_READ))
      {
      if(Examine(lock,fib))
         {
         Success = TRUE;
         buildPath(lock,fib,buf);
         }
      UnLock(lock);
      }
   return(Success);
   }


buildPath(inlock,fib,buf)
LONG inlock;
struct FileInfoBlock *fib;
char *buf;
   {
   int i;
   LONG lock,oldlock;
   BOOL MyOldLock = FALSE;

   buf[0] = NULL;
   lock = inlock;

   while(lock)
      {
      if(Examine(lock,fib))
         {
         if(fib->fib_FileName[0] > ' ')
            {
            if(buf[0]) insert(buf,"/");
            insert(buf,fib->fib_FileName);
            }
         }
      oldlock = lock;
      lock = ParentDir(lock);
      if(MyOldLock)  UnLock(oldlock);
      else           MyOldLock = TRUE;
      }

   if(fib->fib_FileName[0] > ' ')
      {
      for(i=0; i<(strlen(buf)); i++)
         {
         if(buf[i] == '/')
            {
            buf[i] = ':';
            break;
            }
         }
      }
   else  insert(buf,"RAM:");

   return(strlen(buf));
   }

insert(buf,s)
char *buf,*s;
   {
   char tmp[SBUFSZ];

   strcpy(tmp,buf);
   strcpy(buf,s);
   strcpy(&buf[strlen(s)],tmp);
   }

