/*
 * COMM1.C
 *
 * Matthew Dillon, August 1986
 * version 2.01A (Manx ver) by Steve Drew 27 Sep 1986
 * mods for 16 bit compiling 4 Oct 1986. Steve Drew.
 *
 *
 *
 */

#include "shell.h"
 
#define DIR_SHORT 0x01
#define DIR_FILES 0x02
#define DIR_DIRS  0x04

#define BPTR_TO_C(strtag, var)  ((struct strtag *)(BADDR( (ULONG) var)))
#define C_TO_BPTR(strtag, var)  ((struct strtag *)(((ULONG)var)>>2))

extern char *btocstr();
extern int has_wild;
char Dir_name[60];
struct FileLock *Clock;
  
do_sleep()
{
   register int i;
 
   if (ac == 2) {
      i = atoi(av[1]);
      while (i > 0) {
         Delay ((long)50*2);
         i -= 2;
         if (CHECKBREAK())
            break;
      }
   }
   return (0);
}
 
 
do_number()
{
   return (0);
}
 
do_cat()
{
   FILE *fopen(), *fi;
   int i;
   char buf[256];

   if (ac == 1) {
      while (gets(buf)) {
      	 if (CHECKBREAK()) break;
         puts(buf);
         }
      clearerr(stdin);
      return (0);
   }

   for (i = 1; i < ac; ++i) {
      if ((fi = fopen (av[i], "r")) != 0) {
           while (fgets(buf,256,fi)) {
            fputs(buf,stdout);
            fflush(stdout); 
            if (CHECKBREAK())
               break;
         }
         fclose (fi);
      } else {
         fprintf (stderr, "could not open %s\n", av[i]);
      }
   }
   return (0);
}

/* things shared with disp_entry */

int   filecount, col; 
long  bytes, blocks;

do_dir(garbage, com)
char *garbage;
{
   void   		disp_entry();
   struct DPTR          *dp;
   struct InfoData      *info;
   char                 *name;
   int                  i = 0, stat, clen, more;
   char                 options = 0;
   char                 *c;
   char                 lspec[60];
   char                 volume[40];
   char                 *volname();
   char			*dates();
  
   col = filecount = 0;
   bytes = blocks = 0L;
   
   while((++i < ac) && (av[i][0] == '-')) {
   	for (c = av[i]+1; *c ; c++) {
   		switch(*c) {
   			case 's':
   				options |= DIR_SHORT;
   				break;
   			case 'f':
   				options |= DIR_FILES;
   				break;
   			case 'd':
   				options |= DIR_DIRS;
   				break;
   			default:
   				break;
   		}
   	}
   }
   
   if (ac == i) {
      ++ac;
      av[i] = "";
   if (has_wild)
      return(0);
   }
   if (!(options & (DIR_FILES | DIR_DIRS)))  options |= (DIR_FILES | DIR_DIRS);
   
   for (; i < ac; ++i) {
      if (!(dp = dopen (av[i], &stat)))
         continue;
      if (com < 0) {
         info = (struct InfoData *)AllocMem((long)sizeof(struct InfoData), MEMF_PUBLIC);
         if (Info (dp->lock, info)) {
            printf ("Unit:%2ld  Errs:%3ld  Used: %-4ld %3ld%% Free: %-4ld  Volume: %s\n",
                  info->id_UnitNumber,
                  info->id_NumSoftErrors,
                  info->id_NumBlocksUsed,
                  (info->id_NumBlocksUsed * 100)/ info->id_NumBlocks,
                  (info->id_NumBlocks - info->id_NumBlocksUsed),
                  volname(dp->lock,volume));

         } else {
            perror (av[i]);
         }
         FreeMem (info,(long) sizeof(*info));
         dclose(dp);
         continue;
         return(0);
      } 
 
     /* start of directory routine */
      
            c = av[i];
            clen = strlen(c);
            if (!stat || has_wild) {    /* if not wild and is a dir don't */
                                         /* extract dir from file name     */
               while (clen && c[clen] != '/' && c[clen] != ':') clen--;
               if (c[clen] == ':' || c[clen] == '/') clen++;
               c[clen] = '\0';
            }
            if (!clen)  c = Dir_name;
            if (strcmp (c, &lspec) != 0)  {
               strcpy(lspec, c);
               if (col)    printf("\n");
               printf ("Directory of %s\n", lspec);
               fflush(stdout);
               col = 0;
            } 
            more = stat;
            do {
            	if (more && !has_wild) {
            		*lspec = '\0';
            		if (!(more = dnext(dp, &name, &stat)))
            		break;
            	}
                if (CHECKBREAK()) {
              	   i = ac;
              	   break;
                }
                disp_entry (dp->fib, options);
      } while(more && !has_wild);     
      dclose(dp); 
    }                /* end for */
   if (col)  printf("\n");    
   if (filecount > 1) {
       blocks += filecount;     /* account for dir blocks */
       printf (" %ld Blocks, %ld Bytes used in %d files\n", blocks, bytes, filecount);
   }
   return (0);
}

char *
volname(lock,buf)
struct FileLock *lock;
char *buf;
{

        struct    DeviceList    *dl;
        char                    *p;

     Forbid();
                /* Only way I know to get Volume label since InfoData  */
                /* seems to always have NULL for this string           */

        lock = BPTR_TO_C(FileLock, lock);
        dl = BPTR_TO_C(DeviceList, lock->fl_Volume);
        p = btocstr(dl->dl_Name,buf);

     Permit();
     return p;
}

void
disp_entry(fib, options)
char options;
register struct FileInfoBlock *fib;
{

   char str[5];
   int italics;
   
   
   if (!(((options & DIR_FILES) && (fib->fib_DirEntryType < 0)) || 
         ((options & DIR_DIRS)  && (fib->fib_DirEntryType > 0))))
                return;
                
 if (!(options & DIR_SHORT)) { 
   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) ? '-' : 'e';
   str[3] = (fib->fib_Protection & FIBF_DELETE) ? '-' : 'd';

   printf ("   %-24s  %s  ", fib->fib_FileName, str);
   if (fib->fib_DirEntryType < 0) printf("%6ld %4ld", (long)fib->fib_Size, (long)fib->fib_NumBlocks);
    else printf("   Dir     ");
   printf("  %s", dates(&fib->fib_Date));
   fflush(stdout);
   } 
   else {
   
        if ((col == 2) && strlen(fib->fib_FileName)>18) {
        	printf("\n");
        	col = 0;
        } 
        if (fib->fib_DirEntryType > 0)  {
        	  printf ("\033[3m");
        	  italics = 1;
               }
               if (strlen(fib->fib_FileName)>18) {
        	printf(" %-37s",fib->fib_FileName);
        	col += 2;
        } 
        else { 
        	printf(" %-18s",fib->fib_FileName);
        	col++;
        } 
        if (col > 3) {
        	printf("\n");
        	col = 0;
        }
        if (italics) printf("\033[0m");
   }
   fflush(stdout);
   blocks += fib->fib_NumBlocks;
   bytes  += fib->fib_Size;
   filecount++;
   return;
}

/* converts dos date stamp to a time string of form dd-mmm-yy  */

char *
dates(dss)
struct DateStamp *dss;
{
   register struct tm tm;
   register long time, t;
   register int i;
   static char timestr[20];
   static char months[12][4] = {
   	"Jan","Feb","Mar","Apr","May","Jun",
   	"Jul","Aug","Sep","Oct","Nov","Dec"
   };
   static char days[12] = {
   	31,28,31,30,31,30,31,31,30,31,30,31
   };
   time = dss->ds_Days * 24 * 60 * 60 + dss->ds_Minute * 60 +
   				       dss->ds_Tick/TICKS_PER_SECOND;
   tm.tm_sec = time % 60; time /= 60;
   tm.tm_min = time % 60; time /= 60;
   tm.tm_hour= time % 24; time /= 24;
   tm.tm_wday= time %  7;
   tm.tm_year= 78 + (time/(4*365+1)) * 4; time %= 4 * 365 + 1;
   while (time) {
   	t = 365;
   	if ((tm.tm_year&3) == 0) t++;
   	if (time < t) break;
   	time -= t;
   	tm.tm_year++;
   }
   tm.tm_yday = ++time;
   for (i=0;i<12;i++) {
   	t = days[i];
   	if (i == 1 && (tm.tm_year&3) == 0) t++;
   	if (time <= t) break;
   	time -= t;
   }  
   tm.tm_mon = i;
   tm.tm_mday = time;
   
   sprintf(timestr,"%02d-%s-%2d %02d:%02d:%02d\n",tm.tm_mday,
   		months[tm.tm_mon],tm.tm_year,
   		tm.tm_hour,tm.tm_min,tm.tm_sec);
   return(timestr);
   
}
 
date()
{
   struct   DateStamp   dss;
   char *s, *dates();

   DateStamp(&dss);
   s = dates(&dss);
   printf("%s",s);
   return(0);
}
 
do_quit()
{
   if (Src_stack) {
      Quit = 1;
      return(do_return());
   }
   main_exit (0);
}
 
 
do_echo(str)
char *str;
{
   register char *ptr;
   char nl = 1;
 
   for (ptr = str; *ptr && *ptr != ' '; ++ptr);
   if (*ptr == ' ')
      ++ptr;
   if (av[1] && strcmp (av[1], "-n") == 0) {
      nl = 0;
      ptr += 2;
      if (*ptr == ' ')
         ++ptr;
   }
   printf("%s",ptr);
   fflush(stdout);
   if (nl)
      printf("\n");
   return (0);
}
 
 
do_source(str)
char *str;
{

   register int;
   register FILE *fi;
   char buf[256];
 
   if (Src_stack == MAXSRC) {
      fprintf (stderr,"Too many source levels\n");
      return(-1);
   }
   if ((fi = fopen (next_word(str), "r")) == 0) {
      fprintf (stderr,"Cannot open %s\n", next_word(str));
      return(-1);
   }
   ++H_stack;
   Src_pos[Src_stack] = 0;
   Src_base[Src_stack] = (long)fi;
   ++Src_stack;
   while (fgets (buf, 256, fi)) {
      buf[strlen(buf)-1] = '\0';
      Src_pos[Src_stack - 1] += 1+strlen(buf);
      if (Verbose)
         fprintf(stderr,"%s\n",buf);
      if (buf[0] != '#')               /* allow '#' for comments */
          exec_command (buf);
      if (CHECKBREAK())
         break;
   }
   --H_stack;
   --Src_stack;
   unset_level(LEVEL_LABEL + Src_stack);
   fclose (fi);
   return (0);
}

do_cd()
{
   register 	char 		*s;
   		int		i;
   struct 	FileLock 	*tmplock;
   struct	FileInfoBlock   fib;
		char		temp[60];
   		char		*index(),*strcat();
    
   if (Clock) getcd();		/* in case someone did a C:CD dir */
   
   strcpy(temp, Dir_name);
   if (ac != 2) puts(Dir_name);
   else {
       s = av[1];
       if (*s == '/') {
           while (*s == '/') {
               s++;
     	       for (i=strlen(Dir_name)-2; 
     	           Dir_name[i] != '/' && Dir_name[i] != ':' && i; i--);
               Dir_name[i+1] = '\0';
           }
           strcat(Dir_name, s);
       }
       else if (index(s, ':') == 0) {
           if (Dir_name[strlen(Dir_name)-1] != ':')
               strcat(Dir_name, "/");
           strcat(Dir_name, s);
       }
       else strcpy(Dir_name, s);
       tmplock = (struct FileLock *)Lock(Dir_name, ACCESS_READ);
       if (tmplock == 0L) {
           fprintf (stderr,"not found\n");
           strcpy(Dir_name, temp);
           return(-1);
       } else {
           if (Examine(tmplock,&fib)) {
               if (fib.fib_DirEntryType > 0) {
	           Clock = tmplock;
          	   if (tmplock = (struct FileLock *)CurrentDir(Clock)) 
          	       UnLock(tmplock);
           	   if (Dir_name[strlen(Dir_name)-1] == '/')
                       Dir_name[strlen(Dir_name)-1] = '\0';
	           if (s = index(Dir_name,':')) 
                       strcpy(Dir_name, strcat(volname(Clock,temp),s));
            
	    	/* put the current dir name in our CLI task structure */

           	   s = (char *)((ULONG)((struct CommandLineInterface *)
   	  	       BADDR(Myprocess->pr_CLI))->cli_SetName << 2);
                   s[0] = strlen(Dir_name);
                   movmem(Dir_name,s+1,(int)s[0]);
               }  
               else {
	           fprintf(stderr,"not a directory\n");            
                   return(-1);
               }
           }
           else return(-1);
       }
   }
   return(0);
}

do_mkdir()
{
   register int i;
   register struct FileLock *lock;
 
   for (i = 1; i < ac; ++i) {
      if (lock = (struct FileLock *)CreateDir (av[i])) {
         UnLock (lock);
         continue;
      }
      perror (av[i]);
   }
   return (0);
}
 
 
do_mv()
{
   if (Rename (av[1], av[2]))
      return (0);
   perror (NULL);
   return (-1);
}
 
do_rm()
{
   register int i;

   for (i = 1; i < ac; ++i) {
      if (ac !=2) printf("  %s...",av[i]);
      fflush(stdout);
      if (CHECKBREAK()) break;
      if (!DeleteFile(av[i]))
         perror (av[i]);
     else {
        if (ac !=2) printf("Deleted\n");
          }
   }
   return (0);
}
 
 
do_history()
{
   register struct HIST *hist;
   register int i = H_tail_base;
   register int len = (av[1]) ? strlen(av[1]) : 0;
 
   for (hist = H_tail; hist; hist = hist->prev) {
      if (len == 0 || strncmp(av[1], hist->line, len) == 0) {
         printf ("%3d ", i);
         puts (hist->line);
      }
      ++i;
      if (CHECKBREAK())
         break;
   }
   return (0);
}
 
do_mem()
{
   long cfree, ffree;
   extern long AvailMem();

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

   if (ffree)       {
   printf ("FAST memory: %ld\n", ffree);  
   printf ("CHIP memory: %ld\n", cfree);   
   }
   printf ("Total  Free: %ld\n", cfree + ffree);
   return(0);
}

/*
 * 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) {
      fprintf (stderr,"')' expected\n");
      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);
      if (CHECKBREAK())
         break;
      exec_command (cstr);
      *ptr = old;
   }
   --H_stack;
   free (args);
   free (cstr);
   unset_var (LEVEL_SET, vname);
   free (vname);
   return (0);
}
 
 

do_copy()
{
   struct DPTR    *dp;
   char tofile[60],todir[60];
   int i, stat, fstat;
   char *p;

   todir[0] = '\0';
   --ac;
   if (ac == 1)
         strcpy(todir, Dir_name);
   else if (ac == 2) {
         strcpy(todir, av[ac]);
         }
   else  {
         strcpy (todir,av[ac]);
         --ac;
         if (strcmp(av[ac],"to") && strcmp(av[ac],"TO"))  ++ac;
        }
   stat = 0;
   if (ac == 1) ++ac;

      dp = dopen (todir, &stat);
      dclose(dp);



   for (i = 1;i < ac; ++i) {
      if (stat)  {
        if (todir[strlen(todir)-1] != '/' && todir[strlen(todir)-1] != ':')
                     strcat(todir,"/");
        strcpy(tofile, todir);
        p = &av[i][strlen(av[i])-1];
        while (p != av[i] && *p != ':' && *p != '/')
           p--;
        if (*p == ':' || *p == '/')
           p++;
        strcat(tofile, p);
        }
      else   {
        strcpy(tofile, todir);
        if (ac > 2) {
          fprintf (stderr,"Copy error: %s is not a directory\n", todir);
          return(-1);
          }
      }

   /* if from file is a dir name don't copy     */

   dp = dopen(av[i], &fstat);
   dclose(dp);
   if (fstat) continue;

   printf("copying %s to %s....", av[i], tofile);
   fflush(stdout);
   if (!file_copy(av[i], tofile)) printf("[ok]\n");
   if (CHECKBREAK()) {
      return(0);
      }
   }
   return(0);
}

file_copy(s, tofile)
char  *s, *tofile;
{
   struct      FileHandle  *copyin;
   struct      FileHandle  *copyout;
   long        size;
   long        actual;
   int         ok = 1;
   char        *copybuf;
 
      copyin = Open(s, MODE_OLDFILE);
   if (copyin == 0L)
      perror(s);

 else {
        copyout = Open(tofile, MODE_NEWFILE);

      if (copyout == 0) {
         perror(tofile);
         Close(copyin);
         }
      else {

         size = Seek(copyin, 0L, OFFSET_END);
         size = Seek(copyin, 0L, OFFSET_BEGINING);
 
       if (size != 0L) {                     /* if zero length close em */
         do {
            copybuf = AllocMem(size, MEMF_PUBLIC|MEMF_CLEAR);
            if (copybuf == 0L)
               size = size/2;
            }
         while (copybuf == 0L & size > 512);
         if (copybuf == 0L) {
           fprintf(stderr,"Copy Error: Not Enough Memory\n");
            }
         else
            do {
               ok = 0;
               actual = Read(copyin, copybuf, size);
               if (Write(copyout, copybuf, actual) != actual) {
                  ok = perror(NULL);
                  break;
                  }
               }
            while (actual == size);
          }
            Close(copyin);
            Close(copyout);
         FreeMem(copybuf, size);
         if (size == 0L) ok = 0;
         }
     }
return(ok);
}

