/*
	shell.l - c main program
*/

-- common

#include "stddef.h"
#include "stdio.h"
#include "io.h"
#include "stdlib.h"
#include "string.h"
#include "ctype.h"

/***#pragma nonrec***/


#define	iskanji(c)	('\x81'<=(c)&&(c)<='\x9f' || '\xe0'<=(c)&&(c)<='\xfc')
#define	iskanji2(c)	('\x40'<=(c)&&(c)<='\x7e' || '\x80'<=(c)&&(c)<='\xfc')


#ifdef	CPM
	#define	ESCAPE	'\\'
#else
	#define	ESCAPE	'^'
#endif

typedef	char	bool;
#define	YES	1
#define	NO	0

#define	MAXFUNC	32

extern	int	_expand(char *, int, char **);
extern	int	_backquote(char *, int, char **);
extern	void	_exit(int);
extern	void	_puterrmes(char *);

#ifndef	CPM
extern	char	*_argv0;
#endif


-shell.c

extern	void	(*_func[MAXFUNC])();

#define	MAXARGS		1000
#define	MAXENVVARS	1000
#define	MAXLINE	255


static	char	*Comp = NULL;

static	char	Backch[3];
static	char	*Backp = Backch;

#ifdef	CPM
static	char	Termch;
static	char	*Stdifn, *Stdofn;
#endif



static	char	ERR_ESCAPE[] = "Illegal escape";
static	char	ERR_QUOTE[]  = "Unmached quote";
static	char	ERR_MEMORY[] = "out of memory";
#ifdef	CPM
static	char	ERR_OPEN[]   = "can't open: ";
#endif


static	void	_unget(char c)
{
	*Backp++ = c;
}

static	char	_get()
{
	char	c;

	if (Backp > Backch)
		return (*--Backp);
	if (Comp == NULL)
		return ('\n');
	c = *Comp++;
	if (c == '\0' || c == '\n') {
		c = '\n';
		Comp = NULL;
	}
	return (c);
}


static	char	_skipsp()
{
	char	c;

	while ((c = _get()) == ' ' || c == '\t')
		;
	return (c);
}

static	char	Wild;
#define	WILDCARD	1
#define	BACKQUOTE	2

static	char	*_gettok()
{
	char	c, quote, *p, *s;
	auto	char	buf[256];

	Wild = 0;
	c = _skipsp();
	quote = '\0';
	p = buf;
	while (c != '\n' && (quote || c != ' ' && c != '\t')) {
		if (c == quote)
			quote = '\0';
		else if (! quote && (c == '"' || c == '\'' || c == '`')) {
			quote = c;
			if (c == '`')
				Wild = BACKQUOTE;
		}
#ifdef	MSKANJI
		else if (iskanji(c)) {
			*p++ = c;
			c = _get();
			if (iskanji2(c))
				*p++ = c;
			else
				_unget(c);
		}
#endif
		else if (quote != '\'' && c == ESCAPE) {
			if ((c = _get()) != '\n')
				*p++ =	(c == 'n') ? '\n' :
					(c == 't') ? '\t' :
						     c;
			else {
				_puterrmes(ERR_ESCAPE);
				exit(1);
			}
		}
		else {
			if (! quote && (c == '*' || c == '?' || c == '['))
				Wild = WILDCARD;
			*p++ = c;
		}
		c = _get();
	}
	if (quote) {
		_puterrmes(ERR_QUOTE);
		exit(1);
	}
	_unget(c);
	*p++ = '\0';
	if ((s = malloc(strlen(buf) + 1)) == NULL)
		return (NULL);
	return (strcpy(s, buf));
}


#ifdef	CPM
static	char	*_np(char *s)
{
	return ((*s && s[1] == ':') ? s + 2 : s);
}
#endif


void	exit(int rc)
{
	FILE	*fp;
	int	i;
#ifdef	CPM
	static	char	pipein[10] = "<";
	char	*p;
#endif

	for (i = MAXFUNC; --i >= 0; )
		if (_func[i] != (void (*)())NULL)
			(*_func[i])();
	for (fp = _iob; fp < _iob + _SYS_STREAMS; fp++)
		if (fp->mode)
			fflush(fp);
	for (; fp < _iob + SYS_OPEN; fp++)
		if (fp->mode)
			fclose(fp);
#ifdef	CPM
	if (rc == 0) {
		for (p = Comp; *p; p++)
			if (*p == '\r' || *p == '\n')
				break;
		*p = '\0';
		if (*_np(Stdifn) == '|')
			unlink(Stdifn);
		if (Termch == ';') {
			p = _gettok();
			execl(p, p, Comp, NULL);
		}
		else if (Termch == '|') {
			p = _gettok();
			rename(Stdofn, "|");
			_np(Stdofn)[1] = '\0';
			strcpy(&pipein[1], Stdofn);
			execl(p, p, pipein, Comp, NULL);
		}
	}
#endif
	_exit(rc);
}


int	_anarg(char *comlin, char ***arvp)
{
#ifdef	CPM
	static	char	pipeout[] = "_:|out";
	char	*wmode = "w";
#endif
	auto	char	*arv[MAXARGS];
	int	arc, n;
	char	c, *p;

#ifdef	CPM
	Stdofn = Stdifn = "con:";
	arv[0] = "";
#else
	if (_argv0 == NULL)
		arv[0] = "";
	else
		arv[0] = _argv0;
#endif
	arc = 1;
	Comp = comlin;
#ifdef	CPM
	while ((c = _skipsp()) != '\n' && c != ';' && c != '|') {
		if (c == '<') {
			Stdifn = _gettok();
			continue;
		}
		if (c == '>') {
			if ((c = _get()) == '>')
				wmode = "a";
			else {
				_unget(c);
				wmode = "w";
			}
			Stdofn = _gettok();
			continue;
		}
#else
	while ((c = _skipsp()) != '\n') {
#endif
		_unget(c);
		p = _gettok();
		n = 0;
		if (p == NULL || arc >= MAXARGS)
			n = -1;
		else if (Wild == WILDCARD)
			n = _expand(p, MAXARGS - arc, arv + arc);
		else if (Wild == BACKQUOTE) {
			if ((n = _backquote(p, MAXARGS - arc, arv + arc)) == 0)
				continue;
		}
		if (n < 0) {
			_puterrmes(ERR_MEMORY);
			exit(1);
		}
		if (n == 0)
			arv[arc++] = p;
		else
			arc += n;
	}
	arv[arc] = NULL;
#ifdef	CPM
	Termch = c;
	if (c == '|') {
		c = _get();
		if ('a' <= (c | ' ') && (c | ' ') <= 'p') {
			pipeout[0] = c;
			Stdofn = pipeout;
		} else {
			_unget(c);
			Stdofn = pipeout + 2;
		}
	}
	if (freopen(Stdifn, "r", stdin) == NULL) {
		_puterrmes(ERR_OPEN);
		_puterrmes(Stdifn);
		exit(1);
	}
	if (freopen(Stdofn, wmode, stdout) == NULL) {
		_puterrmes(ERR_OPEN);
		_puterrmes(Stdifn);
		exit(1);
	}
	if (freopen("con:", "w", stderr) == NULL) {
		_puterrmes(ERR_OPEN);
		_puterrmes("con:");
		exit(1);
	}
#else
	fdreopen(0, "r", stdin);
	fdreopen(1, "w", stdout);
	fdreopen(2, "w", stderr);
	fdreopen(3, "w+b", stdaux);
	fdreopen(4, "wb", stdprn);
#endif
	setvbuf(stdin, NULL, _IOFBF, BUFSIZ);
	if ((*arvp = malloc(sizeof(char *) * (arc + 1))) == NULL)
		_puterrmes(ERR_MEMORY), exit(1);
	memcpy(*arvp, arv, sizeof(char *) * (arc + 1));
	return (arc);
}


#ifndef	CPM

extern	char	*_environ;
char	**environ;

static	void	_setenviron()
{
	int	n;
auto	char	*envp[MAXENVVARS];
	char	**ep;
	char	*p;

	ep = envp;
	n = 0;
	for (p = _environ; *p; p += strlen(p) + 1) {
		if (++n >= MAXENVVARS)
			_puterrmes(ERR_MEMORY), exit(1);
		*ep++ = p;
	}
	*ep = NULL;
	if ((environ = malloc(sizeof(char *) * (n + 1))) == NULL)
		_puterrmes(ERR_MEMORY), exit(1);
	memcpy(environ, envp, sizeof(char *) * (n + 1));
}

#endif


void	_main(char *comlin)
{
#ifdef	CPM
	int	main(int, char *[]);
#else
	int	main(int, char *[], char *[]);
#endif
	int	arc;
	char	**arv;

#ifdef	CPM
	arc = _anarg(comlin, &arv);
	exit(main(arc, arv));
#else
	_setenviron();
	arc = _anarg(comlin, &arv);
	exit(main(arc, arv, environ));
#endif
}


-onexit.c

/* for compatibility with earlier version... */

onexit_t	onexit(void (*func)())
{
	return (atexit(func) ? NULL : func);
}

-atexit.c

extern	void	(*_func[MAXFUNC])();

int	atexit(void (*func)())
{
	int	n;

	for (n = 0; n < MAXFUNC; n++)
		if (_func[n] == (void (*)())NULL) {
			_func[n] = func;
			return (0);
		}
	return (-1);
}


-_exfunc.c

void	(*_func[MAXFUNC])();


-abort.c

#include <signal.h>

extern	void	_raise();

void	abort(void)
{
static	char	mes[] = "\r\nAbnormal program termination\r\n";

	_puterrmes(mes);
#ifdef	CPM
	exit(3);
#else
	_raise(SIGABRT);
	_exit(3);
#endif
}


-_backquo.c

int	_backquote(char *pat, int maxargc, char *xargv[])
{
	xargv[0] = pat;
	return (1);
}


-_calcSum.c

int	_checkSum;

int	_calcSum(void)
{
	char	*p;

	for (p = (char *)0, _checkSum = 0; p < (char *)16; p++)
		_checkSum += *p;
}


-_nullchk.c

int	_nullcheck(void)
{
static	char	mes[] = "\r\nNULL pointer assignment\r\n";
	char	*p;
	int	v;
extern	int	_checkSum;

	v = 0;
	for (p = (char *)0; p < (char *)16; p++)
		v += *p;
	if (v -= _checkSum)
		_puterrmes(mes);
	return (v);
}

--	assembly language part

#if	_P_FAR
#define	CALLX	callf
#define	RETX	retf
#define	JMPX	jmpf
#define	PAR	(bp+2+4)
_GENETEXT	CSEG
#else
#define	CALLX	call
#define	RETX	ret
#define	JMPX	jmp
#define	PAR	(bp+2+2)
CGROUP	GROUP	TEXT
TEXT	CSEG
#endif

-_putemsg.p86

;void	_puterrmes(char *mes);

_puterrmes_::
#if	CPM
	push	cx
	mov	cx,ax
	CALLX	strlen_##
	mov	bx,cx
	mov	cx,ax
	mov	ax,2
	CALLX	write_##
	pop	cx
#else	/* CPM */
#if	_D_FAR
	PUSH	CX
	PUSH	DX
	MOV	DX,AX
	MOV	CX,BX
	CALLX	strlen_##
	PUSH	DS
	MOV	DS,CX
	MOV	CX,AX
	MOV	BX,2	; stderr
	MOV	AH,40h	; write handle
	INT	21h
	POP	DS
	POP	DX
	POP	CX
#else
	PUSH	CX
	PUSH	DX
	MOV	DX,AX
	CALLX	strlen_##
	MOV	CX,AX
	MOV	BX,2	; stderr
	MOV	AH,40h	; write handle
	INT	21h
	POP	DX
	POP	CX
#endif
#endif	/* CPM */
	RETX

