#line 1 "main.s"
/*lint -e527 -e10 -e720 -e529 -e715 */
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <fcntl.h>
#include <setjmp.h>
typedef struct /* used to find builtin commands */
{
char *cmdname;
int (*func)();
} builtin;
int std_save();
void std_restore();
void (*signal())();
extern builtin commands[];
extern char *histerr;
extern unsigned j,hiscount;
extern char *history[];
extern unsigned histsize;
extern unsigned numcmds;
#define CMDBUFSIZ 512
char *version = "SHELL VERSION 1.6 Kent Williams";
int verbose = 0;
static int oldswitch;
void save_switch()
{
struct { int ax,bx,cx,dx,si,di,ds,es; } regs;
regs.ax = 0x3700;
(void)sysint(0x21,®s,®s);
oldswitch = regs.dx & 0xFF;
regs.ax = 0x3701;
regs.dx = '-';
(void)sysint(0x21,®s,®s);
}
void restore_switch()
{
struct { int ax,bx,cx,dx,si,di,ds,es; } regs;
regs.ax = 0x3701;
regs.dx = oldswitch;
(void)sysint(0x21,®s,®s);
}
jmp_buf env;
char *pipename[] =
{
"\\shtmp1",
"\\shtmp2"
};
int currname = 0;
int result = 0;
main(argc,argv)
int argc; char **argv;
{
int files[3];
void exit();
int i = 1;
char argbuf[64];
signal(SIGINT,SIG_IGN); /* ignore breaks */
argv[0] = "shell"; /* put our name in */
/* initialize local environment */
init_env();
/* put the command line arguments into the environment */
while (--argc)
{
++argv;
if ((*argv)[0] == '-')
{
char *opt = &(*argv)[1];
while (*opt)
{
switch(toupper(*opt))
{
case 'V':
verbose = 1;
break;
case 'S': /* execute startup command file */
if (filep("shell.rc"))
{
(void)std_save(files);
close(0);
(void)open("shell.rc",O_RDONLY);
(void)cli();
close(0);
std_restore(files);
}
break;
default:
fprintf(stderr,"unknown option %c\n",*opt);
break;
}
opt++;
}
continue;
}
sprintf(argbuf,"%d=%s",i,*argv);
(void)add_env(argbuf);
++i;
}
/* change switch character */
save_switch();
(void) cli();
restore_switch();
exit(0);
}
int quiet;
int histecho;
int getline(cmdbuf)
char *cmdbuf;
{
register char *current;
int readresult;
/*
* The following code simply reads a line from standard input.
* It is so complicated because when you save the standard stream
* files and execute another program/command, standard input is
* left in an uncertain state - the FILE stdin seems to be at EOF,
* even when standard input is associated with the console, and
* cr/lf combinations show up as line terminators, whereas usually
* only linefeeds get placed in the input stream.
* WHY? beats me. Something could be wrong with
* 1. AZTEC C runtime
* 2. PCDOS
* 3. Me
* 4. All three, or permutations of 1-3 reducto ad absurdum.
* All I know is this works
*/
for (current = cmdbuf;;current++)
{
if ((readresult = read(0,current,1)) == 0 ||
readresult == -1)
{
return 0;
}
if (*current == '\r')
{
if ((readresult = read(0,current,1)) == 0 ||
readresult == -1)
{
return 0;
}
*current = '\0';
break;
}
else if (*current == '\n')
{
*current = '\0'; /* terminate string */
break;
}
}
current = cmdbuf; /* point current at start of buffer */
return 1;
/*
* end of input weirdness
*/
}
cli()
{
char cmdbuf[512],*savestr();
int parseline();
quiet = !isatty(0); /* quiet = batch shell */
histecho = 0;
j = 0;
for (;;)
{
/* kill tmp files */
unlink(pipename[0]); unlink(pipename[1]);
/* hiscount is current position in history */
hiscount = j % histsize;
if(!quiet)
fprintf(stderr,"%d%% ",j);
/* get user input */
if (0 == getline(cmdbuf))
break;
/* if we're recycling history strings, free previous one */
if (history[hiscount])
free(history[hiscount]);
/* save current in history array */
history[hiscount] = savestr(cmdbuf);
/* parse command for compound statements and pipes */
(void)parseline(cmdbuf);
j++;
}
}
#ifndef SNODEBUG
#define SNODEBUG
#endif
#line 198 "main.s"
int
/*
* statemachine parseline
*/
parseline (cmdbuf)
#line 201 "main.s"
char *cmdbuf;
{
#line 203 "main.s"
/* global variables for command line interpreter */
unsigned repeat;
int inpipe = 0;
char histbuf[256];
char tail[256];
unsigned histindex,argindex,takeline;
char *current,*curr_save;
char *ntharg(), *argptr;
char *savestr();
char localbuf[256];
char *local = localbuf;
/*
* end of declarations for parseline
*/
/* $ */ goto init;
#line 217 "main.s"
init:
{
#line 217 "main.s"
local = localbuf; /* set pointer to start of buffer */
current = cmdbuf;
setmem(localbuf,sizeof(localbuf),0); /* clear buffer */
/* $ */ goto eatwhitespace;
#ifndef SNODEBUG
goto badstate;
#endif
/*
* $endstate init
*/
};
#line 222 "main.s"
charstate:
{
#line 224 "main.s"
switch(*current)
{
case '\0':
*local = '\0';
current++;
/* $ */ goto emit;
case '"' :
*local++ = *current++;
/* $ */ goto doublequotes;
#ifdef NOTDEF
case '/' :
*local++ = '\\';
current++;
/* $ */ goto charstate;
#endif
case '\'':
*local++ = *current++;
/* $ */ goto singlequotes;
case '\\':
*local++ = *++current;
current++;
/* $ */ goto charstate;
case ';':
*local = '\0';
current++;
/* $ */ goto compound;
case '&':
*local = '\0';
++current;
if (*current == '&')
++current;
/* $ */ goto andcompound;
case '|':
*local = '\0';
current++;
if (*current == '|')
{
++current;
/* $ */ goto orcompound;
}
/* $ */ goto pipe;
case '!':
current++;
/* $ */ goto histstate;
case '$':
current++;
if (*current != '$')
/* $ */ goto varstate;
/* FALL INTO DEFAULT - (bad karma, I know ... ) */
default:
*local++ = *current++;
/* $ */ goto charstate;
}
#ifndef SNODEBUG
goto badstate;
#endif
/*
* $endstate charstate
*/
};
#line 278 "main.s"
emit:
{
#line 280 "main.s"
if (inpipe)
{
inpipe = 0;
strcat(localbuf," < ");
strcat(localbuf,pipename[currname]);
}
command(localbuf);
/* $ */ goto done;
#ifndef SNODEBUG
goto badstate;
#endif
/*
* $endstate emit
*/
};
#line 289 "main.s"
compound:
{
#line 291 "main.s"
if (inpipe)
{
inpipe = 0;
strcat(localbuf," < ");
strcat(localbuf,pipename[currname]);
}
command(localbuf);
local = localbuf;
setmem(localbuf,sizeof(localbuf),0); /* clear buffer */
/* $ */ goto eatwhitespace;
#ifndef SNODEBUG
goto badstate;
#endif
/*
* $endstate compound
*/
};
#line 302 "main.s"
andcompound:
{
#line 304 "main.s"
if (inpipe)
{
inpipe = 0;
strcat(localbuf," < ");
strcat(localbuf,pipename[currname]);
}
command(localbuf);
if (result != 0)
/* $ */ goto terminal;
local = localbuf;
setmem(localbuf,sizeof(localbuf),0); /* clear buffer */
/* $ */ goto eatwhitespace;
#ifndef SNODEBUG
goto badstate;
#endif
/*
* $endstate andcompound
*/
};
#line 317 "main.s"
orcompound:
{
#line 319 "main.s"
if (inpipe)
{
inpipe = 0;
strcat(localbuf," < ");
strcat(localbuf,pipename[currname]);
}
command(localbuf);
if (result == 0)
/* $ */ goto terminal;
local = localbuf;
setmem(localbuf,sizeof(localbuf),0); /* clear buffer */
/* $ */ goto eatwhitespace;
#ifndef SNODEBUG
goto badstate;
#endif
/*
* $endstate orcompound
*/
};
#line 332 "main.s"
singlequotes:
{
#line 334 "main.s"
switch (*current)
{
case '\0':
write(2,"No closing quotes!!\r\n",21);
/* $ */ goto parserr;
case '\'':
*local++ = *current++;
/* $ */ goto charstate;
default:
*local++ = *current++;
/* $ */ goto singlequotes;
}
#ifndef SNODEBUG
goto badstate;
#endif
/*
* $endstate singlequotes
*/
};
#line 347 "main.s"
doublequotes:
{
#line 349 "main.s"
switch(*current)
{
case '\0':
write(2,"No closing quotes!!\r\n",21);
/* $ */ goto done;
case '"':
*local++ = *current++;
/* $ */ goto charstate;
default:
*local++ = *current++;
/* $ */ goto doublequotes;
}
#ifndef SNODEBUG
goto badstate;
#endif
/*
* $endstate doublequotes
*/
};
#line 362 "main.s"
histstate:
{
#line 364 "main.s"
/* handle history substitutions */
setmem(histbuf,sizeof(histbuf),0); /* clear buffer */
/* set histecho so expansions get echoed */
histecho++;
/* save current pointer into command buffer */
curr_save = current;
/* copy command head */
strncpy(histbuf,cmdbuf,(int)(current-cmdbuf)-1);
/* takeline means take all arguments past current one */
takeline = 0;
/* parse history expression */
switch (*current)
{
case '!': /* last command line */
if (j) /* special case first time through */
{
histindex = hiscount ? hiscount - 1 : histsize - 1;
}
else
{
/* force error condition */
write(2,(char *)histerr,strlen(histerr));
/* $ */ goto parserr;
}
current++; /* point to next */
break;
case '-': /* negative (relative #) */
/* a particular numbered command */
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/* repeat numbered command */
repeat = atoi(current);
if (repeat < 0) /* handle relative addressing */
repeat += j;
/* if command is within range */
if ((j - repeat) <= histsize && repeat < j)
{
histindex = repeat % histsize;
}
else
{
/* $ */ goto parserr;
}
/* skip past numeric expression */
while(isdigit(*current)||*current=='-')
++current;
break;
case '#': /* look through current command line */
if (isspace(current[1]) || current[1] == '\0')
{
write(2,"recursive history expression\r\n",30);
/* $ */ goto parserr;
}
histindex = j; /* use current command */
++current;
break;
default:
write(2,"Bad history expression\r\n",24);
/* $ */ goto parserr;
}
/* look for particular argument substitutions */
switch (*current)
{
/* we want the whole enchilada */
case '\0':
case '\t':
case '\r':
case '\n':
case ' ':
strcat(histbuf,history[histindex]);
break;
case ':':
++current; /* point past colon */
switch (*current)
{
case '^':
argindex = 1;
++current;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
/* index of argument */
argindex = atoi(current);
while(isdigit(*current))
++current;
if (*current == '*')
{
takeline = 1;
current++;
}
break;
case '$':
argindex = lastarg(history[histindex]);
current++;
break;
case '*':
takeline = 1; /* take arg 1 through arg n */
argindex = 1;
current++;
break;
default:
/* $ */ goto parserr;
}
/* pick up pointer to argument in history we need */
if (takeline == 0)
{
if (NULL ==
(argptr = ntharg(history[histindex],argindex)))
{
/* $ */ goto parserr;
}
strcat(histbuf,argptr);
}
else
{
while (NULL !=
(argptr = ntharg(history[histindex],argindex++)))
{
strcat(histbuf,argptr);
strcat(histbuf," ");
}
}
}
/* history substitutions */
/* copy command buffer tail to tail buffer */
strcpy(tail,current);
/* copy histbuf back to cmdbuf */
strcpy(cmdbuf,histbuf);
/* point current at history substitution to continue parsing */
current = --curr_save; /* -1 to backup over first ! */
/* copy tail in */
strcat(cmdbuf,tail);
free(history[hiscount]);
history[hiscount] = savestr(cmdbuf);
/* $ */ goto charstate;
#ifndef SNODEBUG
goto badstate;
#endif
/*
* $endstate histstate
*/
};
#line 523 "main.s"
pipe:
{
#line 525 "main.s"
if (inpipe++)
{
inpipe = 1;
strcat(localbuf," < ");
strcat(localbuf,pipename[currname]);
}
strcat(localbuf," > ");
currname ^= 1;
strcat(localbuf,pipename[currname]);
command(localbuf);
local = localbuf;
setmem(localbuf,sizeof(localbuf),0);
/* $ */ goto eatwhitespace;
#ifndef SNODEBUG
goto badstate;
#endif
/*
* $endstate pipe
*/
};
#line 539 "main.s"
varstate:
{
#line 541 "main.s"
/* handle substitutions out of environment */
char *envstring, *get_env();
char *envcopy;
void *malloc();
/* borrow the history buffer for an environment buffer */
setmem(histbuf,sizeof(histbuf),0); /* clear buffer */
/* save current */
curr_save = current;
/* copy command head to buffer , up to $ */
strncpy(histbuf,cmdbuf,(int)(current-cmdbuf)-1);
/* allocate a buffer for getting the string out of environment */
if (NULL == (envstring = malloc((unsigned)128)))
{
perror("cli");
(void)my_exit(-1);
}
/* get a copy of the string we're looking for */
envcopy = envstring;
while(isalpha(*current) || isdigit(*current))
*envcopy++ = *current++;
*envcopy = '\0'; /* terminate string */
/* look string up in environment */
if (NULL == (envcopy = get_env(envstring)))
{
envcopy = "";
}
/* append environment string to hist buff */
strcat(histbuf,envcopy);
/* append command tail */
strcat(histbuf,current);
/* copy back to command buffer */
strcpy(cmdbuf,histbuf);
/* free environment string */
free(envstring);
/* restore current to point at beginning of substitution */
current = --curr_save; /* -1 to back up over $ */
/* continue processing */
/* $ */ goto charstate;
#ifndef SNODEBUG
goto badstate;
#endif
/*
* $endstate varstate
*/
};
#line 589 "main.s"
eatwhitespace:
{
#line 591 "main.s"
/* strip out leading white space */
while(isspace(*current))
current++;
if (!*current)
/* $ */ goto parserr;
else
/* $ */ goto charstate;
#ifndef SNODEBUG
goto badstate;
#endif
/*
* $endstate eatwhitespace
*/
};
#line 599 "main.s"
parserr:
{
#line 601 "main.s"
/* $ */ goto terminal;
#ifndef SNODEBUG
goto badstate;
#endif
/*
* $endstate parserr
*/
};
#line 603 "main.s"
done:
{
#line 605 "main.s"
/* $ */ goto terminal;
#ifndef SNODEBUG
goto badstate;
#endif
/*
* $endstate done
*/
};
#line 607 "main.s"
/*
* BAD STATE LABEL
*/
badstate:
fprintf(stderr,"Fallen off end of a state!!!\n");
return -1;
/*
* TERMINAL STATE LABEL
*/
terminal:
return 0;
/*
* end of state machine parseline
*/
}
void onintr()
{
longjmp(env,-1);
}
static recursing = 0;
command(current)
register char *current;
{
int files[3]; /* save current standard input and output */
char *alias, *get_env();
char aliasbuf[512];
extern int do_prog();
register int i;
int findcmd();
#ifdef DEBUG
fprintf(stderr,"current = %s\n",current);
fprintf(stderr,"ntharg(current,0) = %s, get_env() = %s\n",
ntharg(current,0),get_env(ntharg(current,0)));
#endif
if (verbose || (!quiet && histecho))
{
fprintf(stderr,"%s\n",current);
histecho = 0;
}
(void)std_save(files);
if (-1 != (i = findcmd(current)))
{
if (-1 != setjmp(env))
{
signal(SIGINT,onintr);
result = _Croot(current,commands[i].func);
}
signal(SIGINT,SIG_IGN);
}
else if (!recursing && (NULL != (alias = get_env(ntharg(current,0)))))
{
recursing++; /* don't expand alias twice */
strcpy(aliasbuf,alias); /* copy stuff out of environment */
alias = current;
while (*alias && !isspace(*alias))
++alias;
strcat(aliasbuf,alias); /* add tail */
parseline(aliasbuf); /* call parseline recursively */
recursing = 0;
}
else
{
ctl_brk_setup();
result = _Croot(current,do_prog);
ctl_brk_restore();
}
std_restore(files);
}
char *
ntharg(line,index)
register char *line;
unsigned index;
{
register unsigned i;
static char buf[64];
char *bptr;
for (i = 0; *line;i++)
{
/* find start of arg[i] */
while(*line && isspace(*line))
{
++line;
}
/* if this is start of requested arg, return pointer to it */
if (i == index)
{
bptr = buf;
while(*line && !isspace(*line))
*bptr++ = *line++;
*bptr = '\0';
return buf;
}
/* find end of arg[i] */
while(*line && !isspace(*line))
++line;
}
return NULL;
}
int lastarg(line)
register char *line;
{
register int i;
for (i = 0; *line;i++)
{
/* find start of arg[i] */
while(*line && isspace(*line))
++line;
/* find end of arg[i] */
while(*line && !isspace(*line))
++line;
}
return i-1;
}
/*lint -restore */