Metropoli BBS
VIEWER: main.c MODE: TEXT (ASCII)
#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,&regs,&regs);
	oldswitch = regs.dx & 0xFF;
	regs.ax = 0x3701;
	regs.dx = '-';
	(void)sysint(0x21,&regs,&regs);
}

void restore_switch()
{
	struct { int ax,bx,cx,dx,si,di,ds,es; } regs;
	regs.ax = 0x3701;
	regs.dx = oldswitch;
	(void)sysint(0x21,&regs,&regs);
}

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 */
[ RETURN TO DIRECTORY ]