
/*
 * COMM1.C
 *
 * Matthew Dillon, 28 Apr 1986
 *
 * Most of the commands are in here (the variable commands are in set.c)
 *
 */

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

extern struct FileLock  *CreateDir(), *CurrentDir(), *ParentDir();
extern struct FileLock  *Lock(), *DupLock();
extern struct FileLock  *cdgo();
extern char *AllocMem();

extern long disp_entry();

struct FileLock *Clock;

do_run(str)
char *str;
{
   register int i, len;
   register char *build, *ptr;
   char from[128];
   char to[128];

   from[127] = to[127] = '\0';
   strcpy (from, "<*");
   strcpy (to, ">*");
   for (i = 1, len = 0; i < ac; ++i) {
      ptr = (*av[i] == '>') ? to : ((*av[i] == '<') ? from : NULL);
      if (ptr) {
         strncpy (ptr, av[i], 126);
         if (!ptr[1]) {
            av[i] = "";
            if (av[++i] == NULL)
               goto rerr;
            strncat (ptr, av[i], 125);
         }
         av[i] = "";
         break;
      }
      len += strlen(av[i]) + 1;
   }
   len += strlen(av[0]) + strlen(from) + strlen(to) + 4;
   build = malloc(len);
   strcpy (build, av[0]);
   strcat (build, " ");
   strcat (build, from);
   strcat (build, " ");
   strcat (build, to);
   for (i = 1; i < ac; ++i) {
      if (*av[i]) {
         strcat (build, " ");
         strcat (build, av[i]);
      }
   }
   i = Execute (build, 0, 0);
   free (build);
   return ((i) ? 1 : -1);
rerr:
   puts ("redirection syntax error");
   return (-1);
}

do_number()
{
   return (1);
}

do_cat()
{
   FILE *fi;
   int i;
   char buf[256];

   for (i = 1; i < ac; ++i) {
      if (fi = fopen (av[i], "r")) {
         while (fgets (buf, 256, fi)) {
            fputs (buf, stdout);
            fflush (stdout);
         }
         fclose (fi);
      } else {
         perror (av[i]);
      }
   }
}

do_dir(garbage, com)
char *garbage;
{
   struct DPTR          *dp;
   struct InfoData      *info;
   char *name;
   int i, stat;
   long total = 0;

   if (ac == 1) {
      ++ac;
      av[1] = "";
   }
   for (i = 1; i < ac; ++i) {
      if ((dp = dopen (av[i], &stat)) == NULL)
         continue;
      if (com < 0) {
         info = (struct InfoData *)AllocMem(sizeof(struct InfoData), MEMF_PUBLIC);
         if (Info (dp->lock, info)) {
            int bpb = info->id_BytesPerBlock;
            printf ("Unit:%2d  Errs:%3d  Bytes: %-7d Free: %-7d\n",
                  info->id_UnitNumber,
                  info->id_NumSoftErrors,
                  bpb * info->id_NumBlocks,
                  bpb * (info->id_NumBlocks - info->id_NumBlocksUsed));
         } else {
            perror (av[i]);
         }
         FreeMem (info, sizeof(*info));
      } else {
         if (stat) {
            while (dnext (dp, &name, &stat))
               total += disp_entry (dp->fib);
         } else {
            total += disp_entry(dp->fib);
         }

      }
      dclose (dp);
   }
   printf ("TOTAL: %ld\n", total);
   return (1);
}


long
disp_entry(fib)
register struct FileInfoBlock *fib;
{
   char str[5];
   register char *dirstr;

   str[4] = '\0';
   str[0] = (fib->fib_Protection & FIBF_READ) ? '-' : 'r';
   str[1] = (fib->fib_Protection & FIBF_WRITE) ? '-' : 'w';
   str[2] = (fib->fib_Protection & FIBF_EXECUTE) ? '-' : 'x';
   str[3] = (fib->fib_Protection & FIBF_DELETE) ? '-' : 'd';
   dirstr = (fib->fib_DirEntryType < 0) ? "   " : "DIR";

   printf ("%s %6ld %s  %s\n", str, (long)fib->fib_Size, dirstr, fib->fib_FileName);
   return ((long)fib->fib_Size);
}


do_quit()
{
   exit (1);
}

do_echo(str)
char *str;
{
   if (strcmp (av[1], "-n") == 0) {
      fputs (next_word(next_word(str)), stdout);
   } else {
      puts (next_word(str));
   }
   fflush (stdout);
   return (1);
}


do_source(str)
char *str;
{
   register FILE *fi;
   char buf[256];

   if (Src_stack == MAXSRC) {
      puts ("Too many source levels");
      return(-1);
   }
   fi = fopen (next_word(str), "r");
   if (fi == NULL) {
      printf ("Cannot open %s\n", str);
      return(-1);
   }
   ++H_stack;
   Src_pos[Src_stack] = 0;
   Src_base[Src_stack] = fi;
   ++Src_stack;
   while (fgets (buf, 256, fi) != NULL) {
      Src_pos[Src_stack - 1] += strlen(buf);
      buf[strlen(buf) - 1] = '\0';
      exec_command (buf);
   }
   --H_stack;
   --Src_stack;
   unset_level(LEVEL_LABEL + Src_stack);
   fclose (fi);
   return (1);
}

/*
 * cd.  Additionally, allow '..' to get you back one directory in the path.
 */

do_cd()
{
   static char root[32];
   register struct FileLock *lock;
   register char *str, *ptr;
   register int notdone;

   if (ac != 2) {
      puts (root);
      Clock = cdgo (root, NULL);
      return (1);
   }
   str = av[1];
   while (*str == '/') {
      ++str;
      if (Clock)
         Clock = cdgo (NULL, Clock);
   }
   notdone = 1;
   while (notdone) {
      ptr = str;
      while (*str && *str != '/' && *str != ':')
         ++str;
      notdone = *str;
      *str++ = '\0';
      if (ptr == str - 1)
         continue;
      if (notdone == ':') {
         *(str-1) = notdone;
         notdone = *str;
         *str = '\0';
         strcpy (root, ptr);
         Clock = cdgo (root, NULL);
         *str = notdone;
      } else
      if (strcmp (ptr, "..") == 0) {
         if (Clock)
            Clock = cdgo (NULL, Clock);
      } else {
         if ((lock = cdgo (ptr, NULL)) == NULL)
            puts ("not found");
         else
            Clock = lock;
      }
   }
   return (1);
}


struct FileLock *
cdgo(ptr, lock)
char *ptr;
struct FileLock *lock;
{
   struct FileLock *newlock, *oldlock;

   if (lock)
      newlock = ParentDir (lock);
   else
      newlock = Lock (ptr, ACCESS_READ);
   if (newlock) {
      if (oldlock = CurrentDir (newlock))
         UnLock (oldlock);
   }
   return (newlock);
}


do_mkdir()
{
   register int i;
   register struct FileLock *lock;

   for (i = 1; i < ac; ++i) {
      if (lock = CreateDir (av[i])) {
         UnLock (lock);
         continue;
      }
      perror (av[i]);
   }
   return (1);
}

do_mv()
{
   if (Rename (av[1], av[2]))
      return (1);
   perror (NULL);
   return (-1);
}

do_rm()
{
   register int i;

   for (i = 1; i < ac; ++i) {
      if (!DeleteFile(av[i]))
         perror (av[i]);
   }
   return (1);
}


do_history()
{
   register struct HIST *hist;
   register int i = H_tail_base;

   for (hist = H_tail; hist; hist = hist->prev) {
      printf ("%3d %s\n", i, hist->line);
      ++i;
   }
   return (1);
}

do_mem()
{
   long cfree, ffree;
   extern long AvailMem();

   Forbid();
   cfree = AvailMem (MEMF_CHIP);
   ffree = AvailMem (MEMF_FAST);
   Permit();

   if (ffree)
      printf ("FAST memory:%10ld\n", ffree);
   printf ("CHIP memory:%10ld\n", cfree);
   printf ("Total -----:%5ld K\n", (ffree + cfree)/1024L);
}

/*
 * foreach var_name  ( str str str str... str ) commands
 * spacing is important (unfortunetly)
 *
 * ac=0    1 2 3 4 5 6 7
 * foreach i ( a b c ) echo $i
 * foreach i ( *.c )   "echo -n "file ->";echo $i"
 */

do_foreach()
{
   register int i, cstart, cend, old;
   register char *cstr, *vname, *ptr, *scr, *args;

   cstart = i = (*av[2] == '(') ? 3 : 2;
   while (i < ac) {
      if (*av[i] == ')')
         break;
      ++i;
   }
   if (i == ac) {
      puts ("')' expected");
      return (-1);
   }
   ++H_stack;
   cend = i;
   vname = strcpy(malloc(strlen(av[1])+1), av[1]);
   cstr = compile_av (av, cend + 1, ac);
   ptr = args = compile_av (av, cstart, cend);
   while (*ptr) {
      while (*ptr == ' ' || *ptr == 9)
         ++ptr;
      scr = ptr;
      if (*scr == '\0')
         break;
      while (*ptr && *ptr != ' ' && *ptr != 9)
         ++ptr;
      old = *ptr;
      *ptr = '\0';
      set_var (LEVEL_SET, vname, scr);
      exec_command (cstr);
      *ptr = old;
   }
   --H_stack;
   free (args);
   free (cstr);
   unset_var (LEVEL_SET, vname);
   free (vname);
   return (1);
}


