home *** CD-ROM | disk | FTP | other *** search
- #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;
- }
-