home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
074.lha
/
CShell
/
Sources
/
execom.c
< prev
next >
Wrap
C/C++ Source or Header
|
1986-11-20
|
16KB
|
727 lines
/*
* EXECOM.C
*
* Matthew Dillon, 10 August 1986
* Finally re-written.
*
* Version 2.07M by Steve Drew 10-Sep-87
*
*
*/
#include "shell.h"
#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_run(), do_number();
extern int do_quit(), do_set_var(), do_unset_var();
extern int do_echo(), do_source(), do_mv();
extern int do_cd(), do_pwd(), do_rm(), do_mkdir(), do_history();
extern int do_mem(), do_cat(), do_dir(), do_devinfo(), 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();
extern int do_copy(), date(), do_ps();
extern int do_forever(), do_abortline();
char *push_cpy();
static struct COMMAND Command[] = {
do_run , 0, ST_AV, 0, "\001", /* may call do_source */
do_number , 0, 0, 0 , "\001",
do_set_var , 0, 0, LEVEL_ALIAS, "alias", /* uses avline */
do_abortline, 0, 0, 0, "abortline",
do_cat , 0, 0, 0 , "cat",
do_cd , 0, 0, 0 , "cd",
do_copy , 1, 0, 0 , "copy",
date , 0, 0, 0 , "date",
do_dir , 0, ST_NOEXP, 0 , "dir",
do_inc , 1, 0, -1 , "dec",
do_devinfo , 0, 0, 0 , "devinfo",
do_echo , 0, 0, 0 , "echo", /* uses avline */
do_if , 0, ST_COND, 1 , "else",
do_if , 0, ST_COND, 2 , "endif",
do_foreach , 3, ST_NORED, 0 , "foreach",
do_forever , 1, ST_NORED, 0 , "forever",
do_goto , 1, 0, 0 , "goto",
do_help , 0, 0, 0 , "help",
do_history , 0, 0, 0 , "history",
do_if , 1, ST_COND, 0 , "if",
do_inc , 1, 0, 1 , "inc",
do_input , 1, 0, 0 , "input",
do_label , 1, ST_COND, 0, "label",
do_mem , 0, 0, 0 , "mem",
do_mkdir , 0, 0, 0 , "mkdir",
do_mv , 2, 0, 0 , "mv",
do_ps , 0, 0, 0, "ps",
do_pwd , 0, 0, 0 , "pwd",
do_quit , 0, ST_NORED, 0 , "quit",
do_return , 0, 0, 0 , "return",
do_run , 1, ST_NORED, 0, "run",
do_rm , 0, 0, 0 , "rm",
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_strhead , 3, 0, 0 , "strhead",
do_strtail , 3, 0, 0 , "strtail",
do_unset_var, 0, 0, LEVEL_ALIAS, "unalias",
do_unset_var, 0, 0, LEVEL_SET , "unset",
do_ver , 0, 0, 0 , "version",
'\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;
register int i;
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); /* 4X */
preformat(base, scr);
i = fcomm(scr, 1);
return ((i) ? -1 : 1);
}
isalphanum(c)
char c;
{
if (c >= '0' && c <= '9')
return (1);
if (c >= 'a' && c <= 'z')
return (1);
if (c >= 'A' && c <= 'Z')
return (1);
if (c == '_')
return (1);
return (0);
}
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);
}
}
/*
* 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, len;
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;
struct _dev *stdfp;
fflush(stdout);
ccno = find_command (command);
if ((Command[ccno].stat & (ST_NORED | ST_COND)) == 0) {
if (Cin_name) {
if ((Cin = (long)Open(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)Open(Cout_name, 1005L)) ) {
Seek(Cout, 0L, 1L);
} else {
Cout = (long)Open(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;
Close(Cin);
FreeMem(Cin_buf, 202L);
}
if (Cout_name) {
fflush(stdout);
clearerr(stdout);
stdout->_flags &= ~_DIRTY; /* because of nil: device */
Close(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;
{
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));
}