#line 1 "main.s" /*lint -e527 -e10 -e720 -e529 -e715 */ #include #include #include #include #include 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 */