
/*
 * COMM2.C
 *
 *
 * (c)1986 Matthew Dillon     9 October 1986
 *
 *    ABORTLINE
 *    RETURN
 *    STRHEAD
 *    STRTAIL
 *    IF
 *    LABEL
 *    GOTO
 *    INC
 *    INPUT
 *    VER
 *    CP
 *
 */

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

typedef struct FileInfoBlock FIB;
typedef struct FileLock LOCK;

extern LOCK *CurrentDir(), *Lock(), *CreateDir();

do_abortline()
{
   Exec_abortline = 1;
   return (0);
}

do_return()
{
   Exec_abortline = 1;
   if (Src_stack) {
      xseek (Src_base[Src_stack - 1], 0, 1);
      return ((ac < 2) ? 0 : atoi(av[1]));
   } else {
      main_exit ((ac < 2) ? 0 : atoi(av[1]));
   }
}

/*
 * STRHEAD
 *
 * place a string into a variable removing everything after and including
 * the 'break' character or until a space is found in the string.
 *
 * strhead varname breakchar string
 *
 */

do_strhead()
{
   register char *str = av[3];
   register char bc = *av[2];

   while (*str && *str != bc)
      ++str;
   *str = '\0';
   set_var (LEVEL_SET, av[1], av[3]);
   return (0);
}

do_strtail()
{
   register char *str = av[3];
   register char bc = *av[2];

   while (*str && *str != bc)
      ++str;
   if (*str)
      ++str;
   set_var (LEVEL_SET, av[1], str);
   return (0);
}



/*
 * if A < B   <, >, =, <=, >=, !=, where A and B are either:
 * nothing
 * a string
 * a value (begins w/ number)
 */

do_if(garbage, com)
char *garbage;
{
   register char *v1, *v2, *v3, result, num;
   register int n1, n2;

   switch (com) {
   case 0:
      if (If_stack && If_base[If_stack - 1]) {
         If_base[If_stack++] = 1;
         break;
      }
      result = num = 0;
      if (ac <= 2) {       /* if $var; */
         if (ac == 1 || strlen(av[1]) == 0 || (strlen(av[1]) == 1 && *av[1] == ' '))
            goto do_result;
         result = 1;
         goto do_result;
      }
      if (ac != 4) {
         ierror(NULL, 500);
         break;
      }
      v1 = av[1]; v2 = av[2]; v3 = av[3];
      while (*v1 == ' ')
         ++v1;
      while (*v2 == ' ')
         ++v2;
      while (*v3 == ' ')
         ++v3;
      if (*v1 >= '0' && *v1 <= '9') {
         num = 1;
         n1 = atoi(v1);
         n2 = atoi(v3);
      }
      while (*v2) {
         switch (*v2++) {
         case '>':
            result |= (num) ? (n1 >  n2) : (strcmp(v1, v3) > 0);
            break;
         case '<':
            result |= (num) ? (n1 <  n2) : (strcmp(v1, v3) < 0);
            break;
         case '=':
            result |= (num) ? (n1 == n2) : (strcmp(v1, v3) ==0);
            break;
         default:
            ierror (NULL, 503);
            break;
         }
      }
do_result:
      If_base[If_stack++] = !result;
      break;
   case 1:
      if (If_stack > 1 && If_base[If_stack - 2])
         break;
      if (If_stack)
         If_base[If_stack - 1] ^= 1;
      break;
   case 2:
      if (If_stack)
         --If_stack;
      break;
   }
   Disable = (If_stack) ? If_base[If_stack - 1] : 0;
   return (0);
}

do_label()
{
   char aseek[32];

   if (Src_stack == 0) {
      ierror (NULL, 502);
      return (-1);
   }
   sprintf (aseek, "%ld %ld", Src_pos[Src_stack-1], If_stack);
   set_var (LEVEL_LABEL + Src_stack - 1, av[1], aseek);
   return (0);
}

do_goto()
{
   register long new;
   register long pos;
   register char *lab;

   if (Src_stack == 0) {
      ierror (NULL, 502);
   } else {
      lab = get_var (LEVEL_LABEL + Src_stack - 1, av[1]);
      if (lab == NULL) {
         ierror (NULL, 501);
      } else {
         pos = atoi(lab);
         xseek (Src_base[Src_stack - 1], pos, -1);
         Src_pos[Src_stack - 1] = pos;
         new = atoi(next_word(lab));
         for (; If_stack < new; ++If_stack)
            If_base[If_stack] = 0;
         If_stack = new;
      }
   }
   Exec_abortline = 1;
   return (0);      /* Don't execute rest of this line */
}


do_inc(garbage, com)
char *garbage;
{
   register char *var;
   char num[32];

   if (ac == 3)
      com = atoi(av[2]);
   var = get_var (LEVEL_SET, av[1]);
   if (var) {
      sprintf (num, "%ld", atoi(var)+com);
      set_var (LEVEL_SET, av[1], num);
   }
   return (0);
}

do_input()
{
   char in[256];

   if (Ogets(in))
      set_var (LEVEL_SET, av[1], in);
   return (0);
}

do_ver()
{
   Oputs (VERSION);
   return (0);
}


/*
 * CP file file
 * CP file file file... destdir
 * CP [-r] dir dir dir... destdir
 */

do_cp()
{
   register short recur, i, ierr;
   register char *destname;
   register char destisdir;
   register FIB *fib;

   ierr = 0;
   fib = (FIB *)AllocMem(sizeof(FIB), 0);
   recur = (strncmp(av[1], "-r", 2)) ? 0 : 1;
   destname = av[ac - 1];

   if (ac < recur + 3) {
      ierr = 500;
      goto done;
   }

   destisdir = isdir(destname);
   if (ac > recur + 3 && !destisdir) {
      ierr = 507;
      goto done;
   }

   /*
    * copy set:                        reduce to:
    *    file to file                     file to file
    *    dir  to file (NOT ALLOWED)
    *    file to dir                      dir to dir
    *    dir  to dir                      dir to dir
    *
    */


   for (i = recur + 1; i < ac - 1; ++i) {
      short srcisdir = isdir(av[i]);
      if (srcisdir) {
         struct FileLock *srcdir, *destdir;
         if (!destisdir) {        /* disallow dir to file */
            ierr = 507;
            goto done;
         }
         if (!(destdir = Lock(destname, ACCESS_READ))) {
            ierr = 205;
            goto done;
         }
         if (!(srcdir = Lock(av[i], ACCESS_READ))) {
            ierr = 205;
            UnLock(destdir);
            goto done;
         }
         ierr = copydir(srcdir, destdir, recur);
         UnLock(srcdir);
         UnLock(destdir);
         if (ierr)
            break;
      } else {                      /* FILE to DIR,   FILE to FILE   */
         struct FileLock *destdir, *srcdir, *tmp;
         char *destfilename;

         srcdir = (struct FileLock *)((struct Process *)FindTask(0))->pr_CurrentDir;
         if (destisdir) {
            if ((tmp = Lock(av[i], ACCESS_READ)) == NULL || !Examine(tmp,fib)){
               if (tmp) UnLock(tmp);
               ierr = 205;
               goto done;
            }
            UnLock(tmp);
            destdir = Lock(destname, ACCESS_READ);
            destfilename = fib->fib_FileName;
         } else {
            destdir = srcdir;
            destfilename = destname;
         }
         ierr = copyfile(av[i], srcdir, destfilename, destdir);
         if (destisdir)
            UnLock(destdir);
         if (ierr)
            break;
      }
   }
done:
   FreeMem(fib, sizeof(*fib));
   if (ierr) {
      ierror("cp", ierr);
      return(20);
   }
   return(0);
}


copydir(srcdir, destdir, recur)
register struct FileLock *srcdir, *destdir;
{
   LOCK *cwd;
   register FIB *srcfib;
   register LOCK *destlock, *srclock;
   int ierr;

   ierr = 0;
   srcfib = (FIB *)AllocMem(sizeof(FIB), 0);
   if (Examine(srcdir, srcfib)) {
      while (ExNext(srcdir, srcfib)) {
         if (srcfib->fib_DirEntryType < 0) {
            ierr = copyfile(srcfib->fib_FileName,srcdir,srcfib->fib_FileName,destdir);
            if (ierr)
               break;
         } else {
            if (recur) {
               cwd = CurrentDir(srcdir);
               if (srclock = Lock(srcfib->fib_FileName, ACCESS_READ)) {
                  CurrentDir(destdir);
                  if (!(destlock = Lock(srcfib->fib_FileName)))
                     destlock = CreateDir(srcfib->fib_FileName);
                  if (destlock) {
                     ierr = copydir(srclock, destlock, recur);
                     UnLock(destlock);
                  } else {
                     ierr = IoErr();
                  }
                  UnLock(srclock);
               } else {
                  ierr = IoErr();
               }
               CurrentDir(cwd);
               if (ierr)
                  break;
            }
         }
      }
   } else {
      ierr = IoErr();
   }
   FreeMem(srcfib, sizeof(FIB));
   return(ierr);
}


copyfile(srcname, srcdir, destname, destdir)
char *srcname, *destname;
struct FileLock *srcdir, *destdir;
{
   struct FileLock *cwd;
   long f1, f2;
   int i, ierr;
   char buf[256];

   ierr = 0;
   cwd = (LOCK *)CurrentDir(srcdir);
   f1 = xopen(srcname, "r", 8192);
   if (f1 == NULL) {
      ierr = 205;
      goto fail;
   }
   CurrentDir(destdir);
   f2 = xopen(destname, "w", 8192);
   if (f2 == NULL) {
      xclose(f1);
      ierr = IoErr();
      goto fail;
   }
   while (i = xread(f1, buf, 256))
      xwrite(f2, buf, i);
   xclose(f2);
   xclose(f1);
fail:
   CurrentDir(cwd);
   return(ierr);
}


