home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-386-Vol-2of3.iso
/
c
/
csh4.zip
/
MAIN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1985-09-05
|
12KB
|
516 lines
#include <debug.h>
#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;
extern builtin commands[];
extern char histerr[];
extern int j,hiscount;
extern char *history[];
extern int histsize;
extern int numcmds;
char *version = "SHELL VERSION 1.1 Kent Williams";
jmp_buf env;
char *pipename[] =
{
"\\shtmp1",
"\\shtmp2"
};
char cmdbuf[512];
int currname = 0;
int result = 0;
main(argc,argv)
char *argv[];
{
register int i;
int repeat, quiet, state, inpipe = 0;
static char localbuf[256];
static char histbuf[256];
static char tail[256];
int histindex,argindex,takeline;
char *local = localbuf;
register char *current,*curr_save;
char *ntharg(), *argptr;
char *savestr();
signal(SIGINT,SIG_IGN); /* ignore breaks */
quiet = !isatty(0); /* quiet = batch shell */
/* initialize local environment */
init_env();
/* command interpreter loop */
for(j=0;;)
{
/* kill tmp files */
unlink(pipename[0]); unlink(pipename[1]);
hiscount = j % histsize; /* hiscount is current position in history */
if(!quiet)
fprintf(stderr,"%d%% ",j);
/*
* 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
*/
/* clear command buffer so string read is null terminated */
setmem(cmdbuf,sizeof(cmdbuf),0);
for (current = cmdbuf;;current++)
{
int readresult;
if ((readresult = read(0,current,1)) == 0 ||
readresult == -1)
{
exit (0);
}
if (*current == '\r')
{
if ((readresult = read(0,current,1)) == 0 ||
readresult == -1)
{
exit (0);
}
*current = '\0';
break;
}
else if (*current == '\n')
{
*current = '\0'; /* terminate string */
break;
}
}
current = cmdbuf; /* point current at start of buffer */
/*
* end of input weirdness
*/
/* if we're recycling history strings, free previous one */
if (history[hiscount])
free(history[hiscount]);
/* save current in history array */
history[hiscount] = savestr(current);
#define CHAR -1
#define PIPE -2
#define DOUBLEQUOTES -3
#define SINGLEQUOTES -4
#define EMIT -5
#define COMPOUND -6
#define DONE -7
#define EATWHITESPACE -8
#define HISTORY -9
#define CONTINUE -0xA
/* parse command for compound statements and pipes */
state = EATWHITESPACE;
local = localbuf;
setmem(localbuf,sizeof(localbuf),0); /* clear buffer */
while (state != DONE && state != CONTINUE)
{
switch(state)
{
case CHAR:
switch(*current)
{
case '\0':
*local = '\0';
state = EMIT;
break;
case '"' :
state = DOUBLEQUOTES;
*local++ = *current;
break;
case '/' :
*local++ = '\\';
break;
case '\'':
state = SINGLEQUOTES;
*local++ = *current;
break;
case '\\':
*local++ = *++current;
break;
case ';':
*local = '\0';
state = COMPOUND;
break;
case '|':
*local = '\0';
state = PIPE;
break;
case '!':
state = HISTORY;
break;
default:
*local++ = *current;
break;
}
current++;
break;
case EMIT:
if (inpipe)
{
inpipe = 0;
strcat(localbuf," < ");
strcat(localbuf,pipename[currname]);
}
command(localbuf);
state = DONE;
break;
case COMPOUND:
if (inpipe)
{
inpipe = 0;
strcat(localbuf," < ");
strcat(localbuf,pipename[currname]);
}
command(localbuf);
local = localbuf;
setmem(localbuf,sizeof(localbuf),0); /* clear buffer */
state = EATWHITESPACE;
break;
case SINGLEQUOTES:
switch (*current)
{
case '\0':
write(2,"No closing quotes!!\r\n",21);
state = DONE;
break;
case '\'':
state = CHAR;
*local++ = *current;
break;
#ifdef TEST
case '\\':
*local++ = *++current;
break;
#endif
default:
*local++ = *current;
}
current++;
break;
case DOUBLEQUOTES:
switch(*current)
{
case '\0':
write(2,"No closing quotes!!\r\n",21);
state = DONE;
break;
case '"':
state = CHAR;
break;
#ifdef TEST
case '\\':
++current;
break;
#endif
}
*local++ = *current++;
break;
case HISTORY:
/* handle history substitutions */
setmem(histbuf,sizeof(histbuf),0); /* clear buffer */
/* save current pointer into command buffer */
curr_save = current;
DEBUGGER(fprintf(stderr,"current = %s\n",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 */
DEBUGGER(fprintf(stderr,"last command\n"););
if (j) /* special case first time through */
{
histindex = hiscount ? hiscount - 1 : histsize - 1;
}
else
{
/* force error condition */
write(2,histerr,strlen(histerr));
state = CONTINUE;
}
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':
DEBUGGER(fprintf(stderr,\
"numbered command current = %s\n",current););
/* 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
{
state = CONTINUE;
}
DEBUGGER(fprintf(stderr,"number %d\n",histindex););
while(isdigit(*current)||*current=='-')
++current;
break;
default:
write(2,"Bad history expression\r\n",24);
state = CONTINUE;
break;
}
if (state == CONTINUE) /* error state */
break;
/* look for particular argument substitutions */
DEBUGGER(fprintf(stderr,\
"looking for colon expression, current = %s\n",current););
switch (*current)
{
/* we want the whole enchilada */
case '\0':
case '\t':
case '\r':
case '\n':
case ' ':
DEBUGGER(fprintf(stderr,"whole cmdline\n"););
DEBUGGER(fprintf(stderr,"current = %s\n",current););
strcat(histbuf,history[histindex]);
state = CHAR;
break;
case ':':
++current; /* point past colon */
DEBUGGER(fprintf(stderr,"current = %s\n",current););
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);
DEBUGGER(fprintf(stderr,"%s = %d\n",current,argindex););
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:
state = CONTINUE;
break;
}
DEBUGGER(fprintf(stderr,"arg %d\n",argindex););
if (state == CONTINUE)
break;
/* pick up pointer to argument in history we need */
if (takeline == 0)
{
if (NULL ==
(argptr = ntharg(history[histindex],argindex)))
{
DEBUGGER(fprintf(stderr,"can't find ntharg"););
state = CONTINUE;
break;
}
strcat(histbuf,argptr);
}
else
{
while (NULL !=
(argptr = ntharg(history[histindex],argindex++)))
{
strcat(histbuf,argptr);
strcat(histbuf," ");
}
}
}
if (state == CONTINUE)
break;
/* 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);
DEBUGGER(fprintf(stderr,"current = %s\n",current);)
DEBUGGER(fprintf(stderr,"cmdbuf = %s\n",cmdbuf);)
free(history[hiscount]);
history[hiscount] = savestr(cmdbuf);
state = CHAR;
break;
case PIPE:
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);
state = EATWHITESPACE;
break;
case EATWHITESPACE:
/* strip out leading white space */
while(isspace(*current))
current++;
if (!*current)
state = CONTINUE;
else
state = CHAR;
break;
default:
fprintf(stderr,"Bad state parsing command line\n");
state = DONE;
break;
}
}
if (state == CONTINUE)
continue;
j++; /* next command # */
}
}
onintr()
{
longjmp(env,-1);
}
command(current)
register char *current;
{
extern do_prog();
register int i;
DEBUGGER(write(2,current,strlen(current)); crlf();)
std_save();
if (-1 == (i = findcmd(current)))
result = _Croot(current,do_prog);
else
{
if (!setjmp(env))
{
signal(SIGINT,onintr);
result = _Croot(current,commands[i].func);
}
signal(SIGINT,SIG_IGN);
}
std_restore();
}
char *
ntharg(line,index)
register char *line;
{
register int 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)
{
DEBUGGER(fprintf(stderr,"Found arg %d = %s\n",index,line););
bptr = buf;
while(*line && !isspace(*line))
*bptr++ = *line++;
*bptr = '\0';
return buf;
}
/* find end of arg[i] */
while(*line && !isspace(*line))
++line;
}
return NULL;
}
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;
}