
/*
 * FEXEC1.C
 *
 *    wait() and fexecv()
 *
 *    This code originated from Manx's fexecv code.  I claim credit only
 *    for the major modifications I've done to it.
 *
 */

#include "shell.h"
#include <libraries/dosextens.h>

typedef struct FileHandle           FH;
typedef struct CommandLineInterface CLI;
typedef struct Process              PROC;

static int ret_val;

extern PROC *FindTask();
extern char *AllocMem();

wait()
{
   return(ret_val);
}


fexecv(cmd, argv, stdin_str, stdout_str, stdout_append)
char *cmd, **argv;
char *stdin_str, *stdout_str;
{
   register CLI *cli;
   register char **ap, *cp, *arg;
   PROC *pp;
   APTR sav_ret;
   BPTR sav_CIS, sav_COS;
   long save_stdin_buf, save_stdin_pos, save_stdin_end;
   long len, seg, sav_seg;
   long openmode;
   long *stk;
   FH *fhp, *stdin, *stdout;
   char buf[40];

   pp = FindTask(0L);
   if ((cli = (CLI *)((long)pp->pr_CLI << 2)) == 0)
      return(-1);
   if ((seg = LoadIt(cmd)) == 0)
      return(-3);
   stdin = (FH *)((stdin_str)? Open(stdin_str, 1005) : pp->pr_CIS);
   if (!stdin) {
      fprintf(Cerr, "Input redirection error\n");
      return(-4);
   }
   openmode = (stdout_append) ? 1005 : 1006;
   stdout= (FH *)((stdout_str)? Open(stdout_str, openmode) : pp->pr_COS);
   if (!stdout) {
      fprintf(Cerr, "Output redirection error\n");
      if (stdin_str)
         Close(stdin);
      return(-5);
   }
   if (stdout_append)
      Seek(stdout, 0, 1);
   sav_seg = cli->cli_Module;
   cli->cli_Module = seg;
   stk = (long *)AllocMem(4 * cli->cli_DefaultStack + 8, 0);
   *stk = 4 * cli->cli_DefaultStack + 8;
   stk = (long *)((long)stk + 4 * cli->cli_DefaultStack);
   stk[0] = 4 * cli->cli_DefaultStack;
   stk[1] = ((long *)pp->pr_ReturnAddr)[1];
   sav_ret = pp->pr_ReturnAddr;
   pp->pr_ReturnAddr = (APTR)stk;

   for (len = 1, ap = argv + 1; *ap; ++ap)
      len += strlen(*ap) + 1;
   cp = arg = AllocMem(len, 0);
   for (ap = argv + 1; *ap; ++ap) {
      strcpy(cp, *ap);
      strcat(cp, " ");
      cp += strlen(cp);
   }
   arg[len-1] = '\n';
   cp = (char *)((long)cli->cli_CommandName << 2);
   movmem(cp, buf, 40);
   strcpy(cp + 1, cmd);
   cp[0] = strlen(cmd);

   fhp = (FH *)((long)stdin << 2);
   save_stdin_buf = fhp->fh_Buf;
   save_stdin_pos = fhp->fh_Pos;
   save_stdin_end = fhp->fh_End;

   fhp->fh_Buf = (long)AllocMem(202, 0) >> 2;
   strncpy(fhp->fh_Buf<<2, arg, (int)((len < 200)?len:199));
   fhp->fh_Pos = 0;
   fhp->fh_End = (len < 200)?len:199;

   sav_CIS = pp->pr_CIS;
   sav_COS = pp->pr_COS;

   pp->pr_CIS = (BPTR)stdin;
   pp->pr_COS = (BPTR)stdout;

   ret_val = doexec(len, arg, (seg+1)<<2, stk);

   FreeMem(fhp->fh_Buf<<2, 202);
   fhp->fh_Buf = save_stdin_buf;
   fhp->fh_Pos = save_stdin_pos;
   fhp->fh_End = save_stdin_end;
   /*
   fhp->fh_Pos = fhp->fh_End;
   */

   if (stdin_str)
      Close(stdin);
   if (stdout_str)
      Close(stdout);
   pp->pr_CIS = sav_CIS;
   pp->pr_COS = sav_COS;

   UnLoadSeg(cli->cli_Module);
   pp->pr_ReturnAddr = sav_ret;
   cli->cli_Module = sav_seg;
   FreeMem(arg, len);
   movmem(buf, cp, 40);
   return(0);
}


LoadIt(cmd)
char *cmd;
{
   char buf[128];
   long seg;

   seg = LoadSeg(FindIt(cmd, "", buf));
   return (seg);
}


char *
FindIt(cmd, ext, buf)
char *cmd;
char *ext;
char *buf;
{
   int n;
   long lock = 0;
   APTR original;
   PROC *myproc = FindTask(0);
   char *ptr;
   char *p;

   original = myproc->pr_WindowPtr;
   myproc->pr_WindowPtr = (APTR)(-1);

   if ((p = get_var(LEVEL_SET, V_PATH)) == NULL)
      p = "";
   for (ptr = cmd; *ptr; ++ptr) {
      if (*ptr == '/' || *ptr == ':')
         p = "";
   }

   strcpy(buf, cmd);
   strcat(buf, ext);
   while ((lock = Lock(buf, ACCESS_READ)) == 0) {
      if (*p == '\0')
         break;
      for (n = 0; p[n] && p[n] != ','; ++n);
      strncpy(buf, p, n);
      strcat(buf, cmd);
      strcat(buf, ext);
      p += n + (*p != 0);
   }
   myproc->pr_WindowPtr = original;
   if (lock)
      UnLock(lock);
   return(buf);
}


