[comp.sources.amiga] v89i059: shell - csh-like command interpreter v3.02a, Part02/03

page@swan.ulowell.edu (Bob Page) (03/16/89)

Submitted-by: PERUGIA@ICNUCEVM.BITNET (Cesare Dieni)
Posting-number: Volume 89, Issue 59
Archive-name: unix/shell302a.2

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:    Shell Archiver
#	Run the following text with /bin/sh to create:
#	comm1.c
#	comm2.c
#	execom.c
# This archive created: Wed Mar 15 14:15:18 1989
cat << \SHAR_EOF > comm1.c
/*
 * COMM1.C
 *
 * Matthew Dillon, August 1986
 *
 * Version 2.07M by Steve Drew 10-Sep-87
 *
 * Version 3.02A by Carlo Borreo & Cesare Dieni 20-Dec-88
 *
 */

extern char *v_passed, *v_gotofwd, *v_cwd, *v_lasterr;

#define DIR_SHORT 0x01
#define DIR_FILES 0x02
#define DIR_DIRS  0x04

extern int has_wild;
char cwd[256];

/*
	Parse the options specified in sw[]
	Setting a bit in global variable options
	for each one found
*/

get_opt(sw,count)
char *sw;
int *count;
{
register char *c,*s;
unsigned int l,i = 0;

options=0;
while((++i < ac) && (av[i][0] == '-')) {
	for (c = av[i]+1; *c ; c++) {
		for(l = 0,s = sw;*s && *s != *c; ++s) ++l;
		if (*s) options |= (1 << l);
		}
	}
*count = i;
}

do_sleep()
{
int i;

if (ac == 2) {
	i = atoi(av[1]);
	while (i > 0) { Delay (100L); i -= 2; if (CHECKBREAK()) break; }
	}
return 0;
}

do_protect()
{
register long mask=0xf;
register char *s, *p, *flags="DEWRAPSH";
register unsigned int i;
for (s=av[--ac]; *s; s++)
	if (p=index(flags,Toupper(*s))) mask^=(1 << (p-flags));
	else ierror(av[ac],500);
for (i=1; i<ac; i++) if (!SetProtection(av[i],mask)) pError(av[i]);
return 0;
}

do_filenote()
{
char *note=av[--ac];
register unsigned int i;

for (i=1; i<ac; i++) if (!SetComment(av[i], note)) pError(av[i]);
return 0;
}

do_cat()
{
FILE *fopen(), *fi;
register unsigned int lctr;
unsigned int i;
char buf[256];

get_opt("n",&i);
if (i>=ac) {
	if (has_wild) { printf("No files matching\n"); return 20; }
	while (gets(buf) && !dobreak()) {
		if (options) printf("%4d ",++lctr);
		puts(buf);
		}
	}
for (; i<ac; i++)
	if (fi = fopen (av[i], "r")) {
		lctr=0;
		while (fgets(buf,256,fi) && !dobreak()) {
			if (options) printf("%4d ",++lctr);
			printf("%s",buf);
			}
		fclose (fi);
		}
	else pError(av[i]);
return 0;
}

do_info()
{
BPTR lock;
struct InfoData *info;
unsigned int size, free;
char *p,*s,*state;
struct DirectoryEntry *de_head=NULL, *de;

info=(struct InfoData *)AllocMem((long)sizeof(struct InfoData),MEMF_PUBLIC);
AddDADevs(&de_head, DLF_DEVICES | DLF_DISKONLY );
Myprocess->pr_WindowPtr = (APTR)(-1);
printf ("Unit  Size  Bytes  Used Blk/By-Free Full Errs  Status    Name\n");
for (de=de_head; de; de=de->de_Next) {
	printf("%-5s",de->de_Name);
	if (lock=Lock(de->de_Name,ACCESS_READ)) {
	    if (Info(lock, info)) {
		s = get_pwd(lock);
		if (p=index(s,':')) *p = '\0';
		size = ((info->id_NumBlocks + 2)* info->id_BytesPerBlock)/ 1024;
		free = (((info->id_NumBlocks-info->id_NumBlocksUsed))*
			   info->id_BytesPerBlock)/ 1024;
		switch(info->id_DiskState) {
			case ID_WRITE_PROTECTED: state="Read Only "; break;
			case ID_VALIDATED:	 state="Read/Write"; break;
			case ID_VALIDATING:	 state="Validating"; break;
			}
		printf("%4d%c%6ld%7ld%7ld%4d%c%4ld%%%4ld  %s %s\n",
			(size>1024) ? ((size+512) >> 10) : size,
			(size>1024) ? 'M' : 'K',
			info->id_BytesPerBlock,
			info->id_NumBlocksUsed,
			info->id_NumBlocks-info->id_NumBlocksUsed,
			(free>1024) ? ((free+512) >> 10) : free,
			(free>1024) ? 'M' : 'K',
			(info->id_NumBlocksUsed * 100)/info->id_NumBlocks,
			info->id_NumSoftErrors,
			state,
			s);
		}
	    else pError (de->de_Name);
	    UnLock(lock);
	    }
	else puts("  No disk present");
	}
FreeDAList(&de_head);
Myprocess->pr_WindowPtr = NULL;
FreeMem(info,(long)sizeof(struct InfoData));
return 0;
}

/* things shared with display_file */

char lspec[128];
int filecount, col;
long bytes, blocks;

/*
 * the args passed to do_dir will never be expanded
 */
do_dir()
{
   void display_file();
   int i;

   col = filecount = 0;
   bytes = blocks = 0L;
   *lspec = '\0';

   get_opt("sfd",&i);

   if (ac == i) {
      ++ac;
      av[i] = "";
   }
   if (!(options & (DIR_FILES | DIR_DIRS)))  options|=(DIR_FILES | DIR_DIRS);

   for (; i < ac; ++i) {
      char **eav;
      int c,eac;
      if (!(eav = expand(av[i], &eac)))
	  continue;
      QuickSort(eav, eac);
      for(c=0;c < eac && !breakcheck();++c) display_file(options,eav[c]);
      free_expand (eav);
      if (CHECKBREAK()) break;
   }
   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;
}

void
display_file(options,filestr)
int options;
char *filestr;
{
   long atol();
   int isadir,slen;
   char sc;
   char *c,*s,*fi;
   BPTR lock;

/*	if current dir different from lspec then
	look for ':' or '/' if found lock it and get_pwd.
	else then use cwd.
*/
   for(s = c = filestr; *c; ++c) if (*c == ':' || *c == '/') s = c;
   if (*s == ':') ++s;
   sc = *s;
   *s = '\0';
   c = filestr;
   if (!*c) c = cwd;
   if (strcmp (c, &lspec))  {
	strcpy(lspec, c);
	if (col) printf("\n");
	if (lock=Lock(c,SHARED_LOCK)) {
		printf("Directory of %s\n", get_pwd(lock));
		UnLock(lock);
		}
	col = 0;
	}
   *s = sc;
   if (sc == '/') s++;
   slen = strlen(s);
   fi = s + slen + 1;
   isadir = (fi[12] =='D');

   if (!(((options & DIR_FILES) && !isadir) ||
	  ((options & DIR_DIRS) &&  isadir)))
      return;
   if (isadir) printf ("\23333m");
   if (options & DIR_SHORT) {
	if (col==3 && slen>18) { printf("\n"); col = 0; }
	if (slen>18) { printf(" %-37s",s); col+= 2; }
		else { printf(" %-18s",s); col++; }
	if (col > 3) { printf("\n"); col=0; }
	}
   else printf("   %-24s %s",s ,fi);
   if (isadir) printf("\2330m");
   fflush(stdout);
   fi[16] = fi[21] = '\0';
   bytes  += atol(fi+10);
   blocks += atol(fi+17);
   filecount++;
   return;
}

do_quit()
{
if (Src_stack) {
	Quit = 1;
	return(do_return());
	}
main_exit(0);
}

do_echo(str)
register char *str;
{
char nl=1;

for (; *str && *str != ' '; ++str);
if (*str==' ') ++str;
if (av[1] && !strcmp(av[1],"-n")) {
	nl = 0;
	str += 2;
	if (*str==' ') ++str;
	}
printf("%s",str);
if (nl) printf("\n");
fflush(stdout);
return 0;
}

/* gets a line from file, joining two lines if the first ends in '\' */

char *myfgets(buf, buflen, file)
char *buf;
FILE *file;
{
char *bufptr=buf;
int remain=buflen, n, flag;

do {
	if (fgets(bufptr, remain, file)==NULL) {
		if (remain != buflen)
			fprintf(stderr,"Source: file ends in '\\'\n");
		return NULL;
		}
	n=strlen(buf);
	bufptr += n;
	if (flag= (*(bufptr-2)=='\\')) bufptr-=2;
	remain -= (n+2);
    } while (flag);
return buf;
}

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

if (Src_stack == MAXSRC) {
	ierror(NULL,217);
	return -1;
	}
if ((fi = fopen (av[1], "r")) == 0) { pError(av[1]); return -1;	}
set_var(LEVEL_SET, v_passed, next_word(next_word(str)));
++H_stack;
Src_pos[Src_stack] = 0;
Src_base[Src_stack] = (long)fi;
++Src_stack;
while (myfgets (buf, 256, fi) && !dobreak()) {
	int len = strlen(buf);
	buf[len-1] = '\0';
	Src_pos[Src_stack - 1] += len;
	if (Verbose && !forward_goto) fprintf(stderr,"%s\n",buf);
	exec_command (buf);
	}
--H_stack;
--Src_stack;
if (forward_goto) ierror(NULL,501);
forward_goto = 0;
unset_level(LEVEL_LABEL + Src_stack);
unset_var(LEVEL_SET, v_gotofwd);
unset_var(LEVEL_SET, v_passed);
fclose (fi);
return 0;
}

/*
 * return ptr to string that contains full cwd spec.
 */
char *get_pwd(flock)
BPTR flock;
{
static char pwdstr[130];
PathName(flock, pwdstr, 128L);
return pwdstr;
}

/*
 * set process cwd name and $_cwd, if str != NULL also print it.
 */
do_pwd(str)
char *str;
{
char *ptr;

if (Myprocess->pr_CurrentDir == 0)
	attempt_cd(":"); /* if we just booted 0 = root lock */
strcpy(cwd,get_pwd(Myprocess->pr_CurrentDir,1));
if (str) puts(cwd);
set_var(LEVEL_SET, v_cwd, cwd);
/* put the current dir name in our CLI task structure */
CtoBStr(cwd, Mycli->cli_SetName, 128L);
}

/*
 * CD
 *
 * CD(str, 0)      -do CD operation.
 *
 *    standard operation: breakup path by '/'s and process independantly
 *    x:    -reset cwd base
 *    ..    -remove last cwd element
 *    N     -add N or /N to cwd
 */

do_cd(str)
char *str;
{
   char sc, *ptr;
   int err=0;

   str = next_word(str);
   if (*str == '\0') {
      puts(cwd);
      return(0);
   }
   str[strlen(str)+1] = '\0';		/* add second \0 on end */
   while (*str) {
      for (ptr = str; *ptr && *ptr != '/' && *ptr != ':'; ++ptr);
      switch (*ptr) {
      case ':':
	  sc = ptr[1];
	  ptr[1] = '\0';
	  err = attempt_cd(str);
	  ptr[1] = sc;
	  break;
      case '\0':
      case '/':
	  *ptr = '\0';
	  if (strcmp(str, "..") == 0 || str == ptr)
	     str = "/";
	  if (*str) err = attempt_cd(str);
	  break;
      }
      if (err) break;
      str = ptr + 1;
   }
   do_pwd(NULL);	  /* set $_cwd */
   return err;
}

attempt_cd(str)
char *str;
{
BPTR oldlock, filelock;

if (filelock=Lock(str, ACCESS_READ)) {
	if (isdir(str)) {
		if (oldlock=CurrentDir(filelock)) UnLock(oldlock);
		return (0);
		}
	UnLock(filelock);
	ierror(str, 212);
	}
else ierror(str, 205);
return -1;
}

do_mkdir()
{
register unsigned int i;
BPTR lock;

for (i=1; i<ac; ++i) {
	if (exists(av[i])) ierror(av[i],203);
	else if (lock=CreateDir(av[i])) UnLock (lock);
	else pError(av[i]);
	}
return 0;
}

do_mv()
{
char *dest, buf[256];
int dirflag;
register unsigned int i;

dirflag=isdir(dest=av[--ac]);
if (ac>3 && !dirflag) { ierror(dest, 507); return (-1); }
for (i=1; i<ac; ++i) {
	strcpy(buf, dest);
	if (dirflag) TackOn(buf, BaseName(av[i]));
	if (Rename(av[i], buf)==0)
		{ pError(av[i]); return -1; }
	}
return 0;
}

int dirstoo;

all_args(args, action, dirsflag)
char *args;
int (*action)();
{
unsigned int i;

get_opt(args, &i);
dirstoo=dirsflag;
for (; i<ac && !dobreak(); ++i)
	if (isdir(av[i])) {
		if (options & 1) recurse(av[i], action);
			else if (dirstoo) (*action)(av[i]);
		}
	else (*action)(av[i]);
return 0;
}

char *searchstring;

search_file(s)
char *s;
{
FILE *fopen(), *fi;
unsigned int lctr, len=strlen(searchstring);
int yesno;
char buf[256], lowbuf[256], first;
register char *p, *l, *t;

if (!(options & 2)) for (t=searchstring; *t=Toupper(*t); t++);
first=*searchstring;
if ((fi=fopen(s, "r"))==NULL) { pError(s); return; }
lctr=0;
if (!(options & 32)) printf("Examining %s...\n",s);
while (fgets(buf,256,fi) && !dobreak()) {
	lctr++;
	if (options & 4) yesno=compare_ok(searchstring,buf);
	else {
		yesno=0;
		p=buf;
		if (!(options & 2)) {
			l=lowbuf;			/* p is already =buf */
			while (*l++=Toupper(*p++));	/* lowbuf=upper(buf) */
			p=lowbuf;
			}
		while (p=index(p,first))
			if (!strncmp(p++,searchstring,len)) { yesno=1; break; }
		}
	if (yesno ^ ((options & 16)!=0) ) {
			/* default: print line numbers */
		if (!(options & 8)) printf("%4d ",lctr);
		printf("%s",buf);
		}
	}
fclose (fi);
}

do_search()
{
searchstring=av[--ac];
all_args("rcwneq", search_file, 0);
return 0;
}

rm_file(file)
char *file;
{
if (has_wild) printf(" %s...",file);
if (options & 2) SetProtection(file,0L);
if (!DeleteFile(file)) pError (file); else if (has_wild) printf("Deleted\n");
}

do_rm()
{
all_args("rp", rm_file, 1);
return 0;
}

recurse(name, action)
char *name;
int (*action)();
{
register BPTR lock, cwd;
register FIB *fib=(FIB *)AllocMem((long)sizeof(FIB),MEMF_PUBLIC);
char *namecopy=malloc(256);

if (name[0] =='\0') return;
namecopy[0]=0;
if (lock=Lock(name,ACCESS_READ)) {
    cwd =CurrentDir(lock);
    if (Examine(lock, fib))
	while (ExNext(lock, fib) && !CHECKBREAK()) {
	    if (*namecopy) { (*action)(namecopy); namecopy[0]=0; }
	    if (fib->fib_DirEntryType>=0) recurse(fib->fib_FileName,action);
		else strcpy(namecopy,fib->fib_FileName);
	    }
    if (*namecopy) (*action)(namecopy);
    UnLock(CurrentDir(cwd));
    if (dirstoo) (*action)(name);
    }
else pError(name);
free(namecopy);
FreeMem(fib, (long)sizeof(FIB));
}

do_history()
{
register struct HIST *hist;
int i = H_tail_base;
int len = (av[1]) ? strlen(av[1]) : 0;

for (hist = H_tail; hist && !dobreak(); hist = hist->prev)
	if (len == 0 || !strncmp(av[1], hist->line, len))
		printf("%3d %s\n", i++, hist->line);
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\nCHIP memory: %ld\n", ffree, cfree);
printf("Total  Free: %ld\n", cfree+ffree);
return 0;
}

/* forline i RAM:temp echo line $_linenum: $i */

do_forline()
{
char vname[33], buf[256];
register unsigned short lctr;
FILE *f;
char *cstr;
static char *linenumname="_linenum";

strcpy(vname,av[1]);
f=fopen(av[2],"r");
if (f==NULL) pError(av[2]);
lctr=0;
++H_stack;
cstr = compile_av (av, 3, ac, ' ');
while (fgets(buf,256,f) && !dobreak()) {
	buf[strlen(buf)-1]='\0';	/* remove CR */
	lctr++;
	set_var(LEVEL_SET, vname, buf);
	sprintf(buf,"%d",lctr);
	set_var(LEVEL_SET, linenumname, buf);
	exec_command(cstr);
	}
fclose(f);
--H_stack;
free (cstr);
unset_var (LEVEL_SET, vname);
unset_var (LEVEL_SET, linenumname);
return 0;
}

/* fornum i 1 10 echo $i */

do_fornum()
{
char vname[33], buf[16];
int n1, n2;
char *cstr;
register int i;

strcpy(vname,av[1]);
n1=myatoi(av[2],0 ,32767); if (Errno) return 20;
n2=myatoi(av[3],n1,    32767); if (Errno) return 20;
++H_stack;
cstr = compile_av (av, 4, ac, ' ');
for (i=n1; i<=n2 && !CHECKBREAK(); i++) {
	sprintf(buf,"%d",i);
	set_var (LEVEL_SET, vname, buf);
	exec_command(cstr);
	}
--H_stack;
free (cstr);
unset_var (LEVEL_SET, vname);
return 0;
}

/*
 * foreach var_name  ( str str str str... str ) commands
 * spacing is important (unfortunately)
 *
 * 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 cstart, cend;
register char *cstr;
char **fav;
char vname[33];
int i;

get_opt("v",&i);
strcpy(vname, av[i++]);
if (*av[i] == '(') i++;
cstart = i;
while (i<ac && *av[i] != ')') i++;
if (i > ac) { fprintf(stderr,"')' expected\n"); return 20; }
++H_stack;
cend = i;

fav = (char **)malloc(sizeof(char *) * (ac));
cstr = compile_av (av, cend + 1, ac, ' ');

for (i = cstart; i < cend; ++i) fav[i] = av[i];

for (i = cstart; i<cend && !CHECKBREAK(); ++i) {
	set_var (LEVEL_SET, vname, fav[i]);
	if (options & 1) printf("foreach: %s\n", fav[i]);
	exec_command(cstr);
	}
--H_stack;
free (fav);
free (cstr);
unset_var (LEVEL_SET, vname);
return 0;
}

do_forever(str)
char *str;
{
int rcode = 0;
char *ptr = next_word(str);

++H_stack;
for (;;) {
	if (CHECKBREAK()) { rcode = 20; break; }
	if (exec_command (ptr) < 0) {
		str = get_var(LEVEL_SET, v_lasterr);
		rcode = (str) ? atoi(str) : 20;
		break;
		}
	}
--H_stack;
return rcode;
}

do_exec(str)
char *str;
{
return exec_command(next_word(str));
}

extern struct Window *w;
extern struct IntuitionBase *IntuitionBase;

do_window()
{
long x, y, maxwidth, maxheight, arg[5];
unsigned int i;
struct Screen *screen;
struct Window *window;

get_opt("slfbaq", &i);
if (options & 1)
	SizeWindow(w, (long)(w->MinWidth-w->Width), (long)(w->MinHeight-w->Height));
if (options & 2) {
	x=-w->LeftEdge;
	y=-w->TopEdge;
	MoveWindow(w,x,y);
	x=IntuitionBase->ActiveScreen->Width -w->Width;
	y=IntuitionBase->ActiveScreen->Height-w->Height;
	SizeWindow(w,x,y);
	}
if (options & 4) WindowToFront(w);
if (options & 8) WindowToBack(w);
if (options & 16) ActivateWindow(w);
if(ac >= 5) {
	for(i=1; i<5; i++) {
		arg[i] = myatoi(av[i],0,1023);
		if (Errno) return 20;
		}
	maxwidth = w->WScreen->Width;
	maxheight= w->WScreen->Height;
	if (arg[3] > maxwidth - arg[1] || arg[4] > maxheight- arg[2]) {
		ierror(NULL, 500);
		return 20;
		}
	x = -w->LeftEdge;
	y = -w->TopEdge;
	MoveWindow(w, x, y);
	x = arg[3] - w->Width;
	y = arg[4] - w->Height;
	SizeWindow(w, x, y);
	x = arg[1];
	y = arg[2];
	MoveWindow(w, x, y);
	}
if(options & 32) {
	for (screen=IntuitionBase->FirstScreen; screen; screen=screen->NextScreen) {
	    printf("\nScreen \"%s\" (%d,%d,%dx%d):\n",
			screen->Title,
			screen->LeftEdge,
			screen->TopEdge,
			screen->Width,
			screen->Height
			);
		for (window=screen->FirstWindow; window; window=window->NextWindow) {
		printf("\tWindow\t\"%s\" (%d,%d,%dx%d)\n",
			window->Title,
			window->LeftEdge,
			window->TopEdge,
			window->Width,
			window->Height
			);
		}
	    }
	return 0;
	}
Delay(25L); /* pause 1/2 sec. before trying to print */
printf("\014");
return 0;
}

setsystemtime(ds)
struct DateStamp *ds;
{
struct timerequest tr;
long secs= ds->ds_Days*86400 + ds->ds_Minute*60 + ds->ds_Tick/TICKS_PER_SECOND;

if (OpenDevice(TIMERNAME, UNIT_VBLANK, &tr, 0L)) {
	fprintf(stderr,"Clock error: can't open timer device\n");
	return;
	}
tr.tr_node.io_Message.mn_Node.ln_Type = NT_MESSAGE;
tr.tr_node.io_Message.mn_Node.ln_Pri = 0L;
tr.tr_node.io_Message.mn_Node.ln_Name = NULL;
tr.tr_node.io_Message.mn_ReplyPort = NULL;
tr.tr_node.io_Command = TR_SETSYSTIME;
tr.tr_time.tv_secs = secs;
tr.tr_time.tv_micro = 0L;
if (DoIO (&tr)) fprintf(stderr,"Clock error: can't talk to timer device\n");
CloseDevice (&tr);
}

char tday[10];

char *dates(dss)
struct DateStamp *dss;
{
static char timestr[40];
char tdate[10], ttime[10];
struct DateTime dt;
struct DateStamp *myds=&(dt.dat_Stamp);

dt.dat_Format=FORMAT_DOS;
dt.dat_StrDay=tday;
dt.dat_StrDate=tdate;
dt.dat_StrTime=ttime;
dt.dat_Flags=NULL;
myds->ds_Days=dss->ds_Days;
myds->ds_Minute=dss->ds_Minute;
myds->ds_Tick=dss->ds_Tick;
StamptoStr(&dt);
sprintf(timestr,"%s %s\n",tdate,ttime);
timestr[18]='\n';
timestr[19]='\0';	/* protection against bad timestamped files */
return timestr;
}

date()
{
struct DateStamp dss;
register unsigned short i;
struct DateTime dt;

dt.dat_Format=FORMAT_DOS;
if (ac==1) {
	DateStamp(&dss);
	printf("%s %s",tday,dates(&dss));
	}
else {
	DateStamp(& (dt.dat_Stamp));
	for (i=1; i<ac; i++) {
		dt.dat_StrDate=NULL;
		dt.dat_StrTime=NULL;
		dt.dat_Flags=DTF_FUTURE;
		if (index(av[i],':')) dt.dat_StrTime=av[i];
			else dt.dat_StrDate=av[i];
		if (StrtoStamp(&dt)) ierror(av[i],500);
		}
	setsystemtime( & (dt.dat_Stamp) );
	}
return 0;
}
SHAR_EOF
cat << \SHAR_EOF > comm2.c
/*
 * COMM2.C
 *
 * (c)1986 Matthew Dillon     9 October 1986
 *
 * Version 2.07M by Steve Drew 10-Sep-87
 *
 * Version 3.02A by Carlo Borreo & Cesare Dieni 20-Dec-88
 *
 */

extern char *v_gotofwd;

/* 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("rftmdn",&i);
		result=evalif(i);
		If_base[If_stack++]=(options & 32 ? 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;
long AvailMem();

switch(options & ~32) {
    case 0:
	if (ac-i != 3) return (ac>i && *av[i]);
	Errno=0;
	num=Atol(av[i])-Atol(av[i+2]);
	if (Errno) 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);
    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()
{
puts("Shell V3.02A\n\
(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))) {
                     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);
                  }
                  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 (Errno) return 20;
packargs[0]=n;
SendPacket(ACTION_MORE_CACHE,packargs,task);
return 0;
}

do_relabel()
{
long packargs[7];
UBYTE *ptr;
long n;
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);
}
SHAR_EOF
cat << \SHAR_EOF > execom.c
/*
 * EXECOM.C
 *
 * Matthew Dillon, 10 August 1986
 *    Finally re-written.
 *
 * Version 2.07M by Steve Drew 10-Sep-87
 *
 * Version 3.02A by Carlo Borreo & Cesare Dieni 20-Dec-88
 *
 */

extern char *v_histnum, *v_except;

#define F_EXACT 0
#define F_ABBR  1

#define ST_COND   0x01
#define ST_NORED  0x02
#define ST_NOEXP  0x04
#define ST_AV     0x08 /* delimit args within a variable */

int has_wild = 0;                 /* set if any arg has wild card */

struct COMMAND {
	int (*func)();
	short minargs;
	short stat;
	int val;
	char *name;
};

extern char *format_insert_string();
extern char *mpush(), *exarg();

extern int do_strleft(), do_strright(), do_strmid(), do_strlen();
extern int do_fornum(), do_forline(), do_exec();
extern int do_diskchange(), do_stack(), do_fault(), do_path(), do_pri();
extern int do_rpn(), do_resident(), do_truerun(), do_aset(), do_howmany();
extern int do_open(), do_close(), do_fileslist(), do_htype();
extern int do_run(), do_number(), do_assign(), do_join();
extern int do_quit(), do_set_var(), do_unset_var();
extern int do_echo(), do_source(), do_mv(), do_addbuffers();
extern int do_cd(), do_pwd(), do_rm(), do_mkdir(), do_history();
extern int do_mem(), do_cat(), do_dir(), do_info(), do_inc();
extern int do_foreach(), do_return(), do_if(), do_label(), do_goto();
extern int do_input(), do_ver(), do_sleep(), do_help();
extern int do_strhead(), do_strtail(), do_relabel();
extern int do_copy(), date(), do_protect(), do_ps();
extern int do_forever(), do_abortline(), do_strings(), do_touch();
extern int do_window(), do_search(), do_filenote();
char *push_cpy();

static struct COMMAND Command[] = {
do_run,		0, ST_AV,	0,	"\001",   /* may call do_source */
do_set_var,	0, 0, LEVEL_ALIAS,	"alias",  /* uses avline */
do_abortline,	0, 0,		0,	"abortline",
do_addbuffers,	2, 0,		0,	"addbuffers",
do_aset,	1, 0,		0,	"aset",
do_assign,	0, 0,		0,	"assign",
do_cat,		0, 0,		0,	"cat",
do_cd,		0, 0,		0,	"cd",
do_close,	0, 0,		0,	"close",
do_copy,	1, 0,		0,	"copy",
do_copy,	1, 0,		0,	"cp",
date,		0, 0,		0,	"date",
do_rm,		0, 0,		0,	"delete",
do_dir,		0, ST_NOEXP,	0,	"dir",
do_diskchange,	1, 0,		0,	"diskchange",
do_inc,		1, 0,		-1,	"dec",
do_echo,	0, 0,		0,	"echo", /* uses avline */
do_if,		0, ST_COND,	1,	"else",
do_if,		0, ST_COND,	2,	"endif",
do_exec,	1, 0,		0,	"exec",
do_fault,	1, 0,		0,	"fault",
do_filenote,	2, 0,		0,	"filenote",
do_fileslist,	0, 0,		0,	"flist",
do_foreach,	3, ST_NORED,	0,	"foreach",
do_forever,	1, ST_NORED,	0,	"forever",
do_forline,	3, ST_NORED,	0,	"forline",
do_fornum,	4, ST_NORED,	0,	"fornum",
do_goto,	1, 0,		0,	"goto",
do_help,	0, 0,		0,	"help",
do_history,	0, 0,		0,	"history",
do_howmany,	0, 0,		0,	"howmany",
do_htype,	1, 0,		0,	"htype",
do_if,		1, ST_COND|ST_NORED,0,	"if",
do_inc,		1, 0,		1,	"inc",
do_info,	0, 0,		0,	"info",
do_join,	2, 0,		1,	"join",
do_input,	1, 0,		0,	"input",
do_label,	1, ST_COND,	0,	"label",
do_dir,		0, ST_NOEXP,	0,	"ls",
do_mkdir,	0, 0,		0,	"md",
do_mem,		0, 0,		0,	"mem",
do_mkdir,	0, 0,		0,	"mkdir",
do_mv,		2, 0,		0,	"mv",
do_open,	3, 0,		0,	"open",
do_path,	0, 0,		0,	"path",
do_pri,		2, 0,		0,	"pri",
do_protect,	2, 0,		0,	"protect",
do_ps,		0, 0,		0,	"ps",
do_pwd,		0, 0,		0,	"pwd",
do_quit,	0, ST_NORED,	0,	"quit",
do_truerun,	1, ST_NORED,	1,	"rback",
do_mv,		2, 0,		0,	"rename",
do_relabel,	2, 0,		0,	"relabel",
do_resident,	0, 0,		0,	"resident",
do_return,	0, 0,		0,	"return",
do_rm,		0, 0,		0,	"rm",
do_rpn,		0, ST_NOEXP|ST_NORED,0,	"rpn",
do_truerun,	1, ST_NORED,	0,	"run",
do_search,	2, 0,		0,	"search",
do_set_var,	0, ST_AV, LEVEL_SET,	"set",
do_sleep,	0, 0,		0,	"sleep",
do_source,	0, ST_NORED|ST_AV, 0,	"source", /* uses avline */
do_stack,	0, 0,		0,	"stack",
do_strhead,	3, 0,		0,	"strhead",
do_strings,	1, 0,		0,	"strings",
do_strleft,	3, 0,		0,	"strleft",
do_strlen,	2, 0,		0,	"strlen",
do_strmid,	3, 0,		0,	"strmid",
do_strright,	3, 0,		0,	"strright",
do_strtail,	3, 0,		0,	"strtail",
do_touch,	0, 0,		0,	"touch",
do_cat,		0, 0,		0,	"type",
do_unset_var,	0, 0, LEVEL_ALIAS,	"unalias",
do_unset_var,	0, 0, LEVEL_SET  ,	"unset",
do_ver,		0, 0,		0,	"version",
do_window,	0, ST_NOEXP,	0,	"window",
'\0',		0, 0,		0,	NULL
};

static unsigned char elast;		/* last end delimeter */
static char Cin_ispipe, Cout_ispipe;

exec_command(base)
char *base;
{
register char *scr;
char buf[32];

if (!H_stack) {
	add_history(base);
	sprintf(buf, "%d", H_tail_base + H_len);
	set_var(LEVEL_SET, v_histnum, buf);
	}
scr = malloc((strlen(base) << 2) + 2);
preformat(base, scr);
return (fcomm(scr, 1) ? -1 : 1);
}

isalphanum(c)
register char c;
{
return (
	(c >= '0' && c <= '9') ||
	(c >= 'a' && c <= 'z') ||
	(c >= 'A' && c <= 'Z') ||
	(c == '_')
	);
}

preformat(s, d)
register char *s, *d;
{
register int si, di, qm;

si = di = qm = 0;
while (s[si] == ' ' || s[si] == 9) ++si;
while (s[si]) {
	if (qm && s[si] != '\"' && s[si] != '\\') {
		d[di++] = s[si++] | 0x80;
		continue;
		}
	switch (s[si]) {
		case ' ':
		case 9:
			d[di++] = ' ';
			while (s[si] == ' ' || s[si] == 9) ++si;
			if (s[si] == 0 || s[si] == '|' || s[si] == ';') --di;
			break;
		case '*':
		case '?':
			d[di++] = 0x80;
		case '!':
			d[di++] = s[si++];
			break;
		case '#':
			d[di++] = '\0';
			while (s[si]) ++si;
			break;
		case ';':
		case '|':
			d[di++] = s[si++];
			while (s[si] == ' ' || s[si] == 9) ++si;
			break;
		case '\\':
			d[di++] = s[++si] | 0x80;
			if (s[si]) ++si;
			break;
		case '\"':
			qm = 1 - qm;
			++si;
			break;
		case '^':
			d[di++] = s[++si] & 0x1F;
			if (s[si]) ++si;
			break;
		case '$': /* search end of var name and place false space */
			d[di++] = 0x80;
			d[di++] = s[si++];
			while (isalphanum(s[si])) d[di++] = s[si++];
			d[di++] = 0x80;
			break;
		default:
			d[di++] = s[si++];
			break;
		}
	}
d[di++]=0;
d[di]=0;
if (debug) fprintf (stderr,"PREFORMAT: %d :%s:\n", strlen(d), d);
}

extern BPTR extOpen();

/*
 * process formatted string.  ' ' is the delimeter.
 *
 *    0: check '\0': no more, stop, done.
 *    1: check $.     if so, extract, format, insert
 *    2: check alias. if so, extract, format, insert. goto 1
 *    3: check history or substitution, extract, format, insert. goto 1
 *
 *    4: assume first element now internal or disk based command.
 *
 *    5: extract each ' ' or 0x80 delimited argument and process, placing
 *       in av[] list (except 0x80 args appended).  check in order:
 *
 *             '$'         insert string straight
 *             '>'         setup stdout
 *             '>>'        setup stdout flag for append
 *             '<'         setup stdin
 *             '*' or '?'  do directory search and insert as separate args.
 *
 *             ';' 0 '|'   end of command.  if '|' setup stdout
 *                          -execute command, fix stdin and out (|) sets
 *                           up stdin for next guy.
 */


fcomm(str, freeok)
register char *str;
{
   static int alias_count;
   int p_alias_count = 0;
   char *istr;
   char *nextstr;
   char *command;
   char *pend_alias = NULL;
   char err = 0;
   has_wild = 0;

   ++alias_count;

   mpush_base();
   if (*str == 0)
      goto done1;
step1:
   if (alias_count == MAXALIAS || ++p_alias_count == MAXALIAS) {
      fprintf(stderr,"Alias Loop\n");
      err = 20;
      goto done1;
   }
/*
   if (str[1] == '$') {
      if (istr = get_var (LEVEL_SET, str + 2))
         str = format_insert_string(str, istr, &freeok);
   }
*/
   istr = NULL;
   if (*(unsigned char *)str < 0x80)
      istr = get_var (LEVEL_ALIAS, str);  /* only if not \command */
   *str &= 0x7F;                          /* remove \ teltail     */
   if (istr) {
      if (*istr == '%') {
         pend_alias = istr;
      } else {
         str = format_insert_string(str, istr, &freeok);
         goto step1;
      }
   }
   if (*str == '!') {
      char *p, c;                     /* fix to allow !cmd1;!cmd2 */
      for(p = str; *p && *p != ';' ; ++p);
      c = *p;
      *p = '\0';
      istr = get_history(str);
      *p = c;
      replace_head(istr);
      str = format_insert_string(str, istr, &freeok);
      goto step1;
   }
   nextstr = str;
   command = exarg(&nextstr);
   if (*command == 0)
      goto done0;
   if (pend_alias == 0) {
      if (cmd_stat(command) & ST_COND)
         goto skipgood;
   }
   if (disable || forward_goto) {
      while (elast && elast != ';' && elast != '|')
         exarg(&nextstr);
      goto done0;
   }
skipgood:
   {
      register char *arg, *ptr, *scr;
      short redir;
      short doexpand;
      short cont;
      short inc;

      ac = 1;
      av[0] = command;
step5:                                          /* ac = nextac */
      if (!elast || elast == ';' || elast == '|')
         goto stepdone;

      av[ac] = '\0';
      cont = 1;
      doexpand = redir = inc = 0;

      while (cont && elast) {
         int cstat = cmd_stat(command);

         ptr = exarg(&nextstr);
         inc = 1;
         arg = "";
         cont = (elast == 0x80);
         switch (*ptr) {
         case '<':
            redir = -2;
         case '>':
            if (cstat & (ST_NORED | ST_COND)) {
                                                        /* don't extract   */
                redir = 0;                              /* <> stuff if its */
                arg = ptr;                              /* external cmd.   */
                break;
            }
            ++redir;
            arg = ptr + 1;
            if (*arg == '>') {
               redir = 2;        /* append >> */
               ++arg;
            }
            cont = 1;
            break;
         case '$':
            /* restore args if from set command or pend_alias */
            if ((arg = get_var(LEVEL_SET, ptr + 1)) != NULL) {
               if (cstat & ST_COND) {
                  char *tp;
                  tp = push_cpy(arg);
                  arg = tp;
               }
               else {
                  char *pe, sv, *index();
                  while (pe = index(arg,0xA0)) {
                     sv = *pe;
                     *pe = '\0';
                     av[ac++] = push_cpy(arg);
                     *pe = sv;
                     av[ac] = '\0';
                     arg = pe+1;
                  }
               }
            }
            else
               arg = ptr;
            break;
         case '*':
         case '?':
            if ((cstat & ST_NOEXP) == 0)
               doexpand = 1;
            arg = ptr;
            break;
         default:
            arg = ptr;
            break;
         }

         /* Append arg to av[ac] */

         for (scr = arg; *scr; ++scr)
            *scr &= 0x7F;
         if (av[ac]) {
            register char *old = av[ac];
            av[ac] = mpush(strlen(arg)+strlen(av[ac]));
            strcpy(av[ac], old);
            strcat(av[ac], arg);
         } else {
            av[ac] = push_cpy(arg);
         }
         if (elast != 0x80)
            break;
      }

      /* process expansion */

      if (doexpand) {
         char **eav, **ebase;
         int eac;
         has_wild = 1;
         eav = ebase = expand(av[ac], &eac);
         inc = 0;
         if (eav) {
            if (ac + eac + 2 > MAXAV) {
               ierror (NULL, 506);
               err = 1;
            } else {
               QuickSort(eav, eac);
               for (; eac; --eac, ++eav)
                  av[ac++] = push_cpy(*eav);
            }
            free_expand (ebase);
         }
      }

      /* process redirection  */

      if (redir && !err) {
         register char *file = (doexpand) ? av[--ac] : av[ac];

         if (redir < 0)
            Cin_name = file;
         else {
            Cout_name = file;
            Cout_append = (redir == 2);
         }
         inc = 0;
      }

      /* check elast for space */

      if (inc) {
         ++ac;
         if (ac + 2 > MAXAV) {
            ierror (NULL, 506);
            err = 1;                /* error condition */
            elast = 0;              /* don't process any more arguemnts */
         }
      }
      if (elast == ' ')
         goto step5;
   }
stepdone:
   av[ac] = '\0';

   /* process pipes via files */

   if (elast == '|' && !err) {
      static int which;             /* 0 or 1 in case of multiple pipes */
      which = 1 - which;
      Cout_name = (which) ? Pipe1 : Pipe2;
      Cout_ispipe = 1;
   }


   if (err)
      goto done0;

   {
      register int i;
      char save_elast;
      char *compile_av();
      register char *avline;
      unsigned char delim = ' ';

      save_elast = elast;
      if (pend_alias || (cmd_stat(command) & ST_AV))
         delim = 0xA0;
      avline = compile_av(av,((pend_alias) ? 1 : 0), ac , delim);


      if (pend_alias) {                               /* special % alias */
         register char *ptr, *scr;
         for (ptr = pend_alias; *ptr && *ptr != ' '; ++ptr);
         set_var (LEVEL_SET, pend_alias + 1, avline);
         free (avline);

         scr = malloc((strlen(ptr) << 2) + 2);
         preformat (ptr, scr);
         fcomm (scr, 1);
         unset_var (LEVEL_SET, pend_alias + 1);
      } else {                                        /* normal command  */
         register int ccno;
         long  oldcin  = Myprocess->pr_CIS;
         long  oldcout = Myprocess->pr_COS;
         char *Cin_buf;
         struct FileHandle *ci;
         long oldbuf;

         fflush(stdout);
         ccno = find_command (command);
         if ((Command[ccno].stat & (ST_NORED | ST_COND)) == 0) {
            if (Cin_name) {
               if ((Cin = (long)extOpen(Cin_name,1005L)) == 0L) {
                  ierror (NULL, 504);
                  err = 1;
                  Cin_name = '\0';
               } else {
                  Myprocess->pr_CIS = _devtab[stdin->_unit].fd = Cin;
                  ci = (struct FileHandle *)(((long)Cin)<<2);
                  Cin_buf = (char *)AllocMem(202L, MEMF_PUBLIC);
                  oldbuf = ci->fh_Buf;
                  if (ci->fh_Buf == 0) /* fexec expects a CIS buffer */
                     ci->fh_Buf = (long)Cin_buf>>2;
               }
            }
            if (Cout_name) {
               if (Cout_append && (Cout =(long)extOpen(Cout_name, 1005L)) ) {
                     Seek(Cout, 0L, 1L);
               } else {
                  Cout = (long)extOpen(Cout_name,1006L);
               }
               if (Cout == NULL) {
                  err = 1;
                  ierror (NULL, 504);
                  Cout_name = '\0';
                  Cout_append = 0;
               } else {
                  Myprocess->pr_COS = _devtab[stdout->_unit].fd = Cout;
               }
            }
         }
         if (ac < Command[ccno].minargs + 1) {
            ierror (NULL, 500);
            err = -1;
         } else if (!err) {
            i = (*Command[ccno].func)(avline, Command[ccno].val);
            if (i < 0)
               i = 20;
            err = i;
         }
         free (avline);
         if (E_stack == 0 && Lastresult != err) {
            Lastresult = err;
            seterr();
         }
         if ((Command[ccno].stat & (ST_NORED | ST_COND)) == 0) {
            if (Cin_name) {
               fflush(stdin);
               clearerr(stdin);
               ci->fh_Buf = oldbuf;
               extClose(Cin);
               FreeMem(Cin_buf, 202L);
            }
            if (Cout_name) {
               fflush(stdout);
               clearerr(stdout);
               stdout->_flags &= ~_DIRTY;    /* because of nil: device */
               extClose(Cout);
               Cout_append = 0;
            }
         }
         Myprocess->pr_CIS =  _devtab[stdin->_unit].fd  = oldcin;
         Myprocess->pr_COS =  _devtab[stdout->_unit].fd = oldcout;
      }

      if (Cin_ispipe && Cin_name)
         DeleteFile(Cin_name);
      if (Cout_ispipe) {
         Cin_name = Cout_name;         /* ok to assign.. static name */
         Cin_ispipe = 1;
      } else {
         Cin_name = '\0';
      }
      Cout_name = '\0';
      Cout_ispipe = 0;
      elast = save_elast;
   }
   mpop_tobase();                      /* free arguments   */
   mpush_base();                       /* push dummy base  */

done0:
   {
      char *str;
      if (err && E_stack == 0) {
         str = get_var(LEVEL_SET, v_except);
         if (err >= ((str)?atoi(str):1)) {
            if (str) {
               ++H_stack;
               ++E_stack;
               exec_command(str);
               --E_stack;
               --H_stack;
            } else {
               Exec_abortline = 1;
            }
         }
      }
      if (elast != 0 && Exec_abortline == 0)
         err = fcomm(nextstr, 0);
      Exec_abortline = 0;
      if (Cin_name)
         DeleteFile(Cin_name);
      Cin_name = NULL;
      Cin_ispipe = 0;
   }
done1:
   mpop_tobase();
   if (freeok)
      free(str);
   --alias_count;
   return ((int)err);                  /* TRUE = error occured    */
}


char *
exarg(ptr)
unsigned char **ptr;
{
   register unsigned char *end;
   register unsigned char *start;

   start = end = *ptr;
   while (*end && *end != 0x80 && *end != ';' && *end != '|' && *end != ' ')
      ++end;
   elast = *end;
   *end = '\0';
   *ptr = end + 1;
   return ((char *)start);
}

static char **Mlist;

mpush_base()
{
   char *str;

   str = malloc(5);
   *(char ***)str = Mlist;
   str[4] = 0;
   Mlist = (char **)str;
}

char *
mpush(bytes)
{
   char *str;

   str = malloc(6 + bytes + 2);   /* may need extra 2 bytes in do_run() */
   *(char ***)str = Mlist;
   str[4] = 1;
   Mlist = (char **)str;
   return (str + 5);
}

mpop_tobase()
{
   register char *next;
   while (Mlist) {
      next = *Mlist;
      if (((char *)Mlist)[4] == 0) {
         free (Mlist);
         Mlist = (char **)next;
         break;
      }
      free (Mlist);
      Mlist = (char **)next;
   }
}


/*
 * Insert 'from' string in front of 'str' while deleting the
 * first entry in 'str'.  if freeok is set, then 'str' will be
 * free'd
 */



char *
format_insert_string(str, from, freeok)
char *str;
char *from;
int *freeok;
{
   register char *new1, *new2;
   register unsigned char *strskip;
   int len;

   for (strskip = (unsigned char *)str;
                   *strskip && *strskip != ' ' 
                   && *strskip != ';' && *strskip != '|'
                   && *strskip != 0x80; ++strskip);
   len = strlen(from);
   new1 = malloc((len << 2) + 2);
   preformat(from, new1);
   len = strlen(new1) + strlen(strskip);
   new2 = malloc(len+2);
   strcpy(new2, new1);
   strcat(new2, strskip);
   new2[len+1] = 0;
   free (new1);
   if (*freeok)
      free (str);
   *freeok = 1;
   return (new2);
}

cmd_stat(str)
char *str;
{
   return(Command[find_command(str)].stat);
}

find_command(str)
char *str;
{
   register unsigned int i;
   int len = strlen(str);

   if (*str >= '0'  &&  *str <= '9')
      return (1);
   for (i = 0; Command[i].func; ++i) {
      if (strncmp (str, Command[i].name, len) == 0)
         return (i);
   }
   return (0);
}

do_help()
{
   register struct COMMAND *com;
   int i= 0;


   for (com = &Command[2]; com->func; ++com) {
      printf ("%-12s", com->name);
      if (++i  % 6 == 0) printf("\n");
   }
   printf("\n");
   return(0);
}

char *push_cpy(s)
char *s;
{
return strcpy(mpush(strlen(s)), s);
}
SHAR_EOF
#	End of shell archive
exit 0
-- 
Bob Page, U of Lowell CS Dept.  page@swan.ulowell.edu  ulowell!page
Have five nice days.