/*
 * COMM2.C
 *
 * (c)1986 Matthew Dillon     9 October 1986
 *
 * Version 2.07M by Steve Drew 10-Sep-87
 *
 * Version 4.01A by Carlo Borreo & Cesare Dieni 17-Feb-90
 *
 */

/* Casting conveniences */
#define BPTR_TO_C(strtag, var)  ((struct strtag *)(BADDR( (ULONG) var)))
#define PROC(task)              ((struct Process *)task)
#define CLI(proc)               (BPTR_TO_C(CommandLineInterface, proc->pr_CLI))

/* Externs */
extern int has_wild;                    /* flag set if any arg has a ? or * */

/* globals */
int cp_update;
int cp_date;

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

do_return()
{
register int retcode=(ac<2 ? 0 : atoi(av[1]));
   Exec_abortline = 1;
   if (Src_stack) {
       FILE *ptr = (FILE *)Src_base[Src_stack - 1];
       ptr->_bp = ptr->_bend;
       ptr->_flags |= _EOF;
/*     fseek (Src_base[Src_stack - 1], 0L, 2); */
      return retcode;
   } else main_exit(retcode);
}

/*
 * STRHEAD
 *
 * place a string into a variable removing everything after and including
 * the 'break' character
 *
 * strhead varname breakchar string
 *
 */

do_strhead()
{
char *s;
if (s=index(av[3],*av[2])) *s='\0';
set_var (LEVEL_SET, av[1], av[3]);
return 0;
}

do_strtail()
{
char *s;
if (s=index(av[3],*av[2])) s++; else s=av[3];
set_var (LEVEL_SET, av[1], s);
return 0;
}

long dptrtosecs(d)
struct DPTR *d;
{
register struct DateStamp *ds=(&d->fib->fib_Date);
return ds->ds_Days*86400 + ds->ds_Minute*60 + ds->ds_Tick/TICKS_PER_SECOND;
}

long timeof(s)
char *s;
{
struct DPTR *d;
int dummy;
long n;

if ( (d=dopen(s,&dummy))==NULL ) return 0L;
n=dptrtosecs(d);
dclose(d);
return n;
}

/*
 * if -f file (exists) or:
 *
 * if A < B   <, >, =, <=, >=, <>, where A and B are either:
 * nothing
 * a string
 * a value (begins w/ number)
 */

do_if(garbage, com)
char *garbage;
{
int result;
int i;

switch (com) {
    case 0:
	if (If_stack && If_base[If_stack - 1]) If_base[If_stack++] = 1;
	else {
		get_opt("rftmdvn",&i);
		result=evalif(i);
		If_base[If_stack++]=(options & 64 ? result : !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;
if (If_stack >= MAXIF) {
	fprintf(stderr,"If's too deep\n");
	disable = If_stack = 0;
	return -1;
	}
if (forward_goto) disable = If_base[If_stack - 1] = 0;
return 0;
}

evalif(i)
register unsigned int i;
{
char c;
long num, t0, isint;
long AvailMem();

switch(options & ~64) {
    case 0:
	if (ac-i != 3) return (ac>i && *av[i]);
	num  = Atol(av[i]);
	isint  = ! IoErr();
	num -= Atol(av[i+2]);
	isint &= ! IoErr();
	if (!isint) num=strcmp(av[i],av[i+2]);
	if (num < 0)	   c='<';
	else if (num > 0)  c='>';
	else if (num == 0) c='=';
	return index(av[i+1], c) != NULL;
    case 1:
	return do_rpn(NULL,i);
    case 2:
	return exists(av[i]);
    case 4:
	t0=timeof(av[i++]);
	for ( ; i<ac ; i++)
		if (t0<=timeof(av[i])) return 1;
	return 0;
    case 8:
	return (AvailMem( (long)MEMF_FAST )!=0);
    case 16:
	return (isdir(av[i])!=0);
    case 32:
	return (get_var(LEVEL_SET,av[i]) != 0);
    default:
	ierror(NULL,500);
	return 0;
    }
}

do_label()
{
   char aseek[32];

   if (Src_stack == 0) {
      ierror (NULL, 502);
      return (-1);
   }

   sprintf (aseek, "%ld %d", Src_pos[Src_stack-1], If_stack);
   set_var (LEVEL_LABEL + Src_stack - 1, av[1], aseek);
   if (!strcmp(av[1],get_var(LEVEL_SET,v_gotofwd)))
      forward_goto = 0;
   return 0;
}

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

   if (Src_stack == 0) {
      ierror (NULL, 502);
   } else {
      lab = get_var (LEVEL_LABEL + Src_stack - 1, av[1]);
      if (lab == NULL) {
         forward_goto = 1;
         set_var (LEVEL_SET, v_gotofwd, av[1]);
         return(0);
      } else {
         pos = atoi(lab);
         fseek (Src_base[Src_stack - 1], pos, 0);
         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;
{
char *var, num[32];

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

do_input()
{
char in[256], *p,*s;
unsigned int i;

for (i=1; i < ac; ++i)
    if (gets(in)) {
	for(p = in; *p; p = s) {
		s = next_word(p);
		if (*s) *(s-1) = 0xA0;
		}
	set_var (LEVEL_SET, av[i], in);
	}
return 0;
}

do_ver()
{
extern char shellname[];

puts(shellname);
puts("(c)1986 Matthew Dillon\n\
Manx (M) versions by Steve Drew\n\
ARP (A) versions by Carlo Borreo & Cesare Dieni\n");
return 0;
}

do_ps()
{
/* this code fragment based on ps.c command by Dewi Williams */

register int	count;		/* loop variable		*/
struct Task	*task;		/* EXEC descriptor		*/
char		strbuf[64+1];	/* scratch for btocstr()	*/
char		cmd[40+1];	/* holds cmd name		*/
long ncli;

printf("Proc Command Name         CLI Type    Pri.  Address  Directory\n");
Forbid();

ncli=(long)FindCLI(0L);
for (count = 1; count <= ncli ; count++)
		/* or just assume 20?*/
    if (task = (struct Task *)FindCLI((long)count)) {
	if (task==NULL) continue;
	/* Sanity check just in case */
	if (PROC(task)->pr_TaskNum == 0 || PROC(task)->pr_CLI == 0) continue;
							/* or complain? */
	BtoCStr(cmd,   CLI(PROC(task))->cli_CommandName, 40L);
	BtoCStr(strbuf,CLI(PROC(task))->cli_SetName    , 64L);
	printf("%2d   %-20.20s %-11.11s %3d  %8lx  %s\n",
		count,
		cmd,
		task->tc_Node.ln_Name,
		task->tc_Node.ln_Pri,
		task,
		strbuf);
	}
Permit();
return 0;
}

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

char *errstr;          /* let's be alittle more informative */

do_copy()
{
register int recur, ierr;
register char *destname;
register char destisdir;
register FIB *fib;
int i;

errstr = "";
ierr = 0;

fib = (FIB *)AllocMem((long)sizeof(FIB), MEMF_PUBLIC);

get_opt("rud",&i);
recur     = (options & 0x01);
cp_update = (options & 0x02);
cp_date   = (!(options & 0x04)); /* the default is keep orignal file date */

destname = av[ac - 1];

if (ac < i + 2) {
	ierr = 500;
	goto done;
	}
destisdir = isdir(destname);
if (ac > i + 2 && !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<ac-1 && !dobreak(); ++i) {
	short srcisdir = isdir(av[i]);
	if (srcisdir && has_wild && (ac >2)) /* hack to stop dir's from */
		continue;		     /* getting copied if specified */
					     /* from wild expansion */
	if (srcisdir) {
		BPTR srcdir, destdir;
		if (!destisdir) {
			if (exists(destname)) {
				ierr = 507;	/* disallow dir to file */
				goto done;
				}
			if (destdir = CreateDir(destname)) UnLock(destdir);
			destisdir = 1;
			}
		if (!(destdir = Lock(destname, ACCESS_READ))) {
			ierr = 205;
			errstr = destname;
			goto done;
			}
		if (!(srcdir = Lock(av[i], ACCESS_READ))) {
			ierr = 205;
			errstr = av[i];
			UnLock(destdir);
			goto done;
			}
		ierr = copydir(srcdir, destdir, recur);
		UnLock(srcdir);
		UnLock(destdir);
		if (ierr) break;
		}
	else {		/* FILE to DIR,   FILE to FILE   */
		BPTR destdir, srcdir, tmp;
		char *destfilename;

		srcdir = (BPTR)(Myprocess->pr_CurrentDir);

		if ((tmp = Lock(av[i], ACCESS_READ)) == NULL || !Examine(tmp,fib)) {
			if (tmp) UnLock(tmp);
			ierr = 205;
			errstr = av[i];
			goto done;
			}
		UnLock(tmp);
		if (destisdir) {
			destdir = Lock(destname, ACCESS_READ);
			destfilename = fib->fib_FileName;
			}
		else {
			destdir = srcdir;
			destfilename = destname;
			}
		printf(" %s..",av[i]);
		fflush(stdout);
		ierr = copyfile(av[i], srcdir, destfilename, destdir);
		if (destisdir) UnLock(destdir);
		if (ierr) break;
		}
	}

done:

FreeMem(fib, (long)sizeof(FIB));
if (ierr) {
	ierror(errstr, ierr);
	return(20);
	}
return 0;
}


copydir(srcdir, destdir, recur)
register BPTR srcdir, destdir;
{
   BPTR cwd;
   register FIB *srcfib;
   register BPTR destlock, srclock;
   int ierr;
   static int level;

   level++;
   ierr = 0;
   srcfib = (FIB *)AllocMem((long)sizeof(FIB), MEMF_PUBLIC);
   if (Examine(srcdir, srcfib)) {
      while (ExNext(srcdir, srcfib)) {
         if (CHECKBREAK())
            break;
         if (srcfib->fib_DirEntryType < 0) {
            printf("%*s%s..",(level-1) * 6," ",srcfib->fib_FileName);
            fflush(stdout);
            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, ACCESS_WRITE))) {
                     destlock = CreateDir(srcfib->fib_FileName);
                     printf("%*s%s (Dir)....[Created]\n",(level-1) * 6,
                                " ",srcfib->fib_FileName);

                        /* UnLock and re Lock if newly created
                           for file_date() to work properly
                        */
                     if (destlock) UnLock(destlock);
                     destlock = Lock(srcfib->fib_FileName, ACCESS_WRITE);
                  }
                  else
                     printf("%*s%s (Dir)\n",(level-1) * 6," ",srcfib->fib_FileName);
                  if (destlock) {
                     ierr = copydir(srclock, destlock, recur);
                     UnLock(destlock);
                  } else {
                     ierr = (int)((long)IoErr());
                  }
                  UnLock(srclock);
               } else {
                  ierr = (int)((long)IoErr());
               }
               CurrentDir(cwd);
               if (ierr)
                  break;
            }
         }
      }
   } else {
      ierr = (int)((long)IoErr());
   }
   --level;
   FreeMem(srcfib, (long)sizeof(FIB));
   return(ierr);
}


copyfile(srcname, srcdir, destname, destdir)
char *srcname, *destname;
BPTR srcdir, destdir;
{
BPTR cwd;
BPTR f1, f2;
long i;
int stat,ierr;
char *buf;
struct DPTR *dp, *dps = NULL;

if ((buf = (char *)AllocMem(8192L, MEMF_PUBLIC|MEMF_CLEAR))==NULL)
	{ ierr = 103; goto fail; }
ierr = 0;
cwd = CurrentDir(srcdir);
if ((f1=Open(srcname, MODE_OLDFILE))==NULL)
	{ errstr = srcname; ierr = 205; goto fail; }
dps = dopen(srcname,&stat);
CurrentDir(destdir);
if (cp_update)
	{
	dp=dopen(destname, &stat);
	if ( dptrtosecs(dp) >= dptrtosecs(dps) &&
		!strcmp(dps->fib->fib_FileName, dp->fib->fib_FileName))
		{ dclose(dp); Close(f1); printf("..not newer\n"); goto fail; }
	dclose(dp);
	}
if ((f2=Open(destname, MODE_NEWFILE))==NULL)
    { Close(f1); ierr = (int)((long)IoErr()); errstr=destname; goto fail;  }
while (i = Read(f1, buf, 8192L))
	if (Write(f2, buf, i) != i) { ierr = (int)((long)IoErr()); break; }
Close(f2);
Close(f1);
if (!ierr)
	{
	if (cp_date) file_date(&dps->fib->fib_Date, destname);
	printf("..copied\n");
	}
else DeleteFile(destname);
fail:
 dclose(dps);
 if (buf) FreeMem(buf, 8192L);
 CurrentDir(cwd);
 return(ierr);
}

do_touch()
{
struct DateStamp ds;
register unsigned int i;
DateStamp(&ds);
for (i=1; i<ac; i++) if (file_date(&ds, av[i])) ierror(av[i],500);
return 0;
}

file_date(date,name)
struct DateStamp *date;
char *name;
{
long packargs[7];
UBYTE *ptr;
struct MsgPort *task;
BPTR dirlock;
struct DPTR *tmp;
int stat;

if (!(task = (struct MsgPort *)DeviceProc(name))) return(1);
if (tmp = dopen(name, &stat)) {
	dirlock = ParentDir(tmp->lock);
	ptr=AllocMem(65L,MEMF_PUBLIC);
	CtoBStr(tmp->fib->fib_FileName,(ULONG)ptr >> 2L,64L);
	dclose(tmp);
	packargs[1]=dirlock;
	packargs[2]=(ULONG)ptr >> 2L;
	packargs[3]=(long)date;
	SendPacket(ACTION_SET_DATE,packargs,task);
	UnLock(dirlock);
	FreeMem(ptr,65L);
	}
return 0;
}

do_addbuffers()
{
long packargs[7];
long n;
struct MsgPort *task=(struct MsgPort *)DeviceProc(av[1]);

if (!task) { ierror(av[1],510); return 20; }
n=myatoi(av[2],1,32767); if (atoierr) return 20;
packargs[0]=n;
SendPacket(ACTION_MORE_CACHE,packargs,task);
return 0;
}

do_relabel()
{
long packargs[7];
UBYTE *ptr;
struct MsgPort *task=(struct MsgPort *)DeviceProc(av[1]);

if (!task) { ierror(av[1],510); return 20; }
ptr=AllocMem(65L,MEMF_PUBLIC);
CtoBStr(av[2],(ULONG)ptr >> 2L,64L);
packargs[0]=(ULONG)ptr >> 2L;
SendPacket(ACTION_RENAME_DISK,packargs,task);
FreeMem(ptr,65L);
changedisk(task);
return 0;
}

do_diskchange()
{
struct MsgPort *task=(struct MsgPort *)DeviceProc(av[1]);

if (!task) { ierror(av[1],510); return 20; }
changedisk(task);
return 0;
}

changedisk(task)
struct MsgPort *task;
{
long packargs[7];

packargs[0]=1L;
SendPacket(ACTION_INHIBIT,packargs,task);
packargs[0]=0L;
SendPacket(ACTION_INHIBIT,packargs,task);
}
