#ifdef MSDOS	/* { */
#include	"grep_msd.h"
#endif		/* } */
static char sccsID[] = "@(#) Shell.c V1.0 Author Julian H. Stacey\n" ;
#undef DEBUG

/* OURNIX(MSDOS) Command Interpreter
enhancements needed:
many, including:
.coms to .exe
does not understand quotes etc.
unbuffered io for prompt needed	*/

/* Features:
allows commands	with or	without	parameters,
allows parameters to have one or more white space chars
blocks signals
changes	directory
Does not suffer	the directory change problems of nested	msdos interpretes.
Can type cd <cr>.
Can run	from scripts

Bugs:
blows when run from a shell file.
*/

#include	<signal.h>
#include 	<ctype.h>
#include 	<stdio.h>
#include 	<process.h>
#include 	<fcntl.h>

#define	UTMP	"/etc/utmp"

#define	CTL_D	4	/* control char	that exits this	interpreter */
#define	EXITT	"exit"	/* command that	exits this interpreter */
#define	CHDIR	"cd"	/* change directory inbuilt command */
#define	SET	"set"	/* display environment */
#define	EX_EXT	".exe"	/* executable extension	*/

#define	EX_LEN	12	/* maximum length of an	msdos name (excluding null) 
			typical	abcdefgh.ijk\0 */
#define	PATH_LN	50	/* maximum allowable path length */

#define	MSDOS		
#ifdef MSDOS
			/* directory restoral needed after each	exec */
#endif
#ifdef UNIX
			/* directory restoral not needed after each exec */
#endif

struct	passwd	{
	char	*pw_name;
	char	*pw_passwd;
	char	*pw_dir;
	char	*pw_shell;
	char	*pw_shargs;	/* shell args */
		};

typedef	char	flag;
#define	strequ	!strcmp

#include "lib/getpwnam.c"

int ARGC ; char	**ARGV ; char **ENVP;

main(argc,argv,envp)
	int argc ; char	**argv ; char **envp ;
	{

	flag opened = 0	;
	ARGC = argc ; ARGV = argv ; ENVP = envp	;

	printf(Sccsid);
	signal(SIGINT,SIG_IGN);
#define	DEBUG

	if ( dup2(0,17)	|| dup2(1,18) || dup2(2,19) )
		printf("sh: program error dup failed\n");

	printf("sh argc	is %d argv 1st element is %s\n",argc, *argv);
	while (argc-- >	1)
		{
		if ( **++argv == '-' ) 
			switch(*++*argv)
				{
				case 'I':	
						printf("got Initial flag\n");
						break;
				default:	printf("bad sh option\n");
						break;
				}
		else	{
			if (!opened)
				{
				close(0);
				/* step	past a delimeter typically \- */
				if (**argv == '\\') (*argv)++ ;
				open(*argv++,O_RDONLY);
				opened = 1;
				}
			}
		/* remove input	file name from command string */
		*(ARGV+1) = *ARGV; ARGV++;
		}
	doit();
	}

char *getline()
	{
	static char	line_buf[200] ;
	int	c ;
	char	*p ;
	for (p = line_buf ; ((c	= getchar()) !=	EOF) ; *p++ = (char)c )
		{
		c = (char)c & 0x7f ;
		if (c == '\n') break;
		}
 	*p = '\0'; 

	if (c == EOF) return((char *)0);
	else return(line_buf);
	}

doit()
	{
	char	*pb; 	/* pointer to beginning	of command */
	char	*pe;	/* pointer to end of command */
	char	**pp ;	/* environmment	pointer	*/
	char	executable[PATH_LN + EX_LEN + 1]; /* command to	be executed */
	char	*ptr[20] ;	/* array of pointers */
	int	ret;		/* return value	*/
#ifdef	MSDOS
#define	CWD_LN	PATH_LN
	char	cwd[CWD_LN];	/* current working directory */
#endif
	FILE	*utmp ;
	struct passwd  *who_s ;
	char	who_o[20] ;	/* person name */
	flag	sh_result ;	/* will	be used	as per unix $RESULT one	day */
	char	putter[100] ;	/* cludge for putenv */

	ptr[0] = executable ; /* first element of argv will allways be
				name of	executable command */
	while(1)
		{
		/* output prompt */
#ifdef MSDOS
		getcwd(cwd,CWD_LN+2);
		printf("%s %%\n",cwd);
#endif
#ifdef UNIX
		/* no need to state directory as pwd does this */
		printf("%%\n");
#endif
		if ((pb	= getline()) ==	(char *)0 ) break ;
#ifdef DEBUG
		printf("Command	line is: %s.\n",pb);
#endif
		/* append a second null	for later use between end of line
		& end of command name */
		pe = pb	; while	(*pe++ != '\0')	; *pe =	'\0';

		/* find	executable name	*/
		while isspace(*pb++) ; 
		pe = --pb ; 
		while (!isspace(*pe) &&	(*pe !=	'\0')) pe++ ;
		*pe++ =	'\0' ;
		while (isspace(*pe++)) ; pe-- ;
		/* pe now points to first char of 1st possible param 
			(or \0 if end of line) */

		strncpy(executable,pb,PATH_LN +	EX_LEN);
		executable[PATH_LN + EX_LEN] = '\0' ;

		/* remove spaces between subsequent strings */
		for( pp	= ptr +	1, ptr[1] = "\0" ;
			(*pe !=	'\0');
			/* mark	end of array */
			*pp = "\0" )
			{
			while (isspace(*pe++)) ; 
			/* store address of argument */
			if (*--pe != '\0')
				{
				*pp++ =	pe ;
#ifdef DEBUG
				printf("next param start is %s\n",pe);
#endif
				}
			else break ;
			while (!isspace(*pe) &&	(*pe !=	'\0')) pe++ ;
			*pe++ =	'\0' ;
			}
#ifdef DEBUG
		printf("Parameters including executable	are:\n");
		for ( pp=ptr ; **pp != '\0' ; pp++ )
			printf("Parm is	|%s|\n",*pp);

		if (executable[0] == '\0') continue ; /* empty line */

		if ((executable[0] == CTL_D) ||	strequ(executable,EXITT))
			{
#ifdef DEBUG
			printf("Shell exiting.\n");
#endif
			exit(0)	;
			}

		/* test	for inbuilt cd command */
		if (strequ(CHDIR,executable) )
			{
			if (*ptr[1] == '\0')
				{
				/* no directory	named to change	to,
				so change to login directory */
				utmp = fopen(UTMP,"r");
				fscanf(utmp,"%s",who_o);
				fclose(utmp);
				who_s =	getpwnam(who_o);
				endpwent() ;
				ptr[1] = who_s->pw_dir;	
				}
			if (chdir(ptr[1]))  
				{
				printf("Failed to chdir	to %s\n",ptr[1]);
				sh_result = 1 ;
				}
			continue ;
			}

		/* test	for inbuilt set	command	*/
		/* export this */
		if (strequ(SET,executable,strlen(SET)) )
			{
			if (*(ptr[1]) != '\0')
				{
#ifdef DEBUG
				printf("setting	new env	var %s\n",ptr[1]);
#endif
				strcpy(putter,ptr[1]);strcat(putter,"\n");
				putenv(putter);
				continue ;
				}
			/* else	let code fall through so that a	process
			called set does	the display,
			(so output can be redirected if	necessary) */
			}

		/* prepare to call spawn */
		strcat(executable,EX_EXT);
#ifdef DEBUG
		printf("Executable file	name is: %s.\n",executable);
#endif

		pp = ptr ;
#ifdef DEBUG
		while (**pp != '\0') 
			printf("spawn env var is %s\n",*pp++);
#endif

#ifdef DEBUG
		printf("env path is %s\n",getenv("PATH"));
#endif
		/* convert for spawn protocol */
		pp = ptr ; while (**pp++ != '\0') ; *--pp = (char *)0 ;
#ifdef MSDOS
		getcwd(cwd,CWD_LN+2);
#endif
#ifdef DEBUG
		printf("Calling	command	now\n");
#endif
		ret = spawnlp(P_WAIT,executable,executable,*(ptr+1),
			*(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5),	*(ptr+6),
			*(ptr+7), *(ptr+8), *(ptr+9), *(ptr+10), *(ptr+11),
			*(ptr+12), *(ptr+13), *(ptr+14), *(ptr+15), *(ptr+16),
			*(ptr+17), *(ptr+18), *(ptr+19), *(ptr+20), (char *)0);
#ifdef MSDOS
		/* unix	doesnt need this */
		chdir(cwd);	
#endif
		if (ret) printf("Command not found or failed.\n");
		}
	}
