Metropoli BBS
VIEWER: shell.c MODE: TEXT (ASCII)
/*
	SHELL.C		Simple extendable command interpreter
				for MS-DOS version 2.0 and later

	Copyright 1988 Ray Duncan

	Compile:	C>CL SHELL.C

	Usage:		C>SHELL
*/

#include <stdio.h>
#include <process.h>
#include <stdlib.h>
#include <signal.h>

									/* macro to return number of
									   elements in a structure */
#define dim(x) (sizeof(x) / sizeof(x[0]))

unsigned intrinsic(char *);			/* function prototypes */
void extrinsic(char *);
void get_cmd(char *);
void get_comspec(char *);
void break_handler(void);
void cls_cmd(void);
void dos_cmd(void);
void exit_cmd(void);

struct cmd_table {					/* intrinsic commands table */
		           char *cmd_name;
           		   int  (*cmd_fxn)(); 
				 }   commands[] =

               	 { "CLS",   cls_cmd,
                   "DOS",   dos_cmd,
                   "EXIT",  exit_cmd, };

static char com_spec[64];			/* COMMAND.COM filespec */


main(int argc, char *argv[])
{   
	char inp_buf[80];             	/* keyboard input buffer */

    get_comspec(com_spec);			/* get COMMAND.COM filespec */

									/* register new handler
							     	   for Ctrl-C interrupts */
	if(signal(SIGINT, break_handler) == (int(*)()) -1)
    {	
		fputs("Can't capture Control-C Interrupt", stderr);
	    exit(1); 
    }

    while(1)                       	/* main interpreter loop */
    {	
		get_cmd(inp_buf);           /* get a command */
        if (! intrinsic(inp_buf) )	/* if it's intrinsic,
                                       run its subroutine */
           extrinsic(inp_buf);		/* else pass to COMMAND.COM */
        }
}


/*      
	Try and match user's command with intrinsic command 
	table.  If a match is found, run the associated routine 
	and return true, else return false.
*/

unsigned intrinsic(char *input_string)
{   
	int i, j;						/* some scratch variables */

									/* scan off leading blanks */
    while(*input_string == '\x20') input_string++ ;

									/* search command table */
    for(i=0; i < dim(commands); i++)
    {	
		j = strcmp(commands[i].cmd_name, input_string);

        if(j == 0) 					/* if match, run routine */
        { 
			(*commands[i].cmd_fxn)();  
            return(1);				/* and return true */
        }
	}
    return(0);						/* no match, return false */
}


/* 
	Process an extrinsic command by passing it
    to an EXEC'd copy of COMMAND.COM.
*/

void extrinsic(char *input_string)
{   
	int status;						

    status = system(input_string);	/* call EXEC function */

    if(status) 						/* if failed, display
									   error message */
	    fputs("\nEXEC of COMMAND.COM failed\n", stderr);
}


/* 
	Issue prompt, get user's command from standard input,
    fold it to upper case.
*/

void get_cmd(char *buffer)
{   
	printf("\nsh: ");                   /* display prompt */
    gets(buffer);                       /* get keyboard entry */
    strupr(buffer);                     /* fold to upper case */
}       


/*	
	Get the full path and file specification for COMMAND.COM
	from the "COMSPEC=" variable in the environment.
*/

void get_comspec(char *buffer)
{   
	strcpy(buffer, getenv("COMSPEC"));

    if(buffer[0] == NULL)		
    {   
		fputs("\nNo COMSPEC in environment\n", stderr);
 	    exit(1);
    }
}


/*
	This Ctrl-C handler keeps SHELL from losing control.
	It just re-issues the prompt and returns.
*/

void break_handler(void)
{   
	signal(SIGINT, break_handler);		/* reset handler */
    printf("\nsh: ");                   /* display prompt */
}	


/*      
	These are the subroutines for the intrinsic commands.
*/

void cls_cmd(void)         				/* CLS command */
{   
	printf("\033[2J");  				/* ANSI escape sequence */
}										/* to clear screen */

void dos_cmd(void)         				/* DOS command */
{   
	int status;
										/* run COMMAND.COM */
    status = spawnlp(P_WAIT, com_spec, com_spec, NULL);

    if (status)	
		fputs("\nEXEC of COMMAND.COM failed\n",stderr); 
}

void exit_cmd(void)        				/* EXIT command */
{   
	exit(0);							/* terminate SHELL */
}
[ RETURN TO DIRECTORY ]