     1	/*
     2	 * Simple Unix Shell.
     3	 * 
     4	 * Loop reading lines from standard input.
     5	 * Split each line into blank-separated tokens.
     6	 * Call the forkexec() function to fork and exec the tokens as a
     7	 * command and arguments.
     8	 *
     9	 * This is an example of the fork() and exec() system calls mentioned
    10	 * in Chapter 1 of the Linux Shells by Example book.
    11	 *
    12	 * To compile this on Unix:    cc -o simshell thisfile.c
    13	 * Compiled and linked output will be put in file "simshell".
    14	 *
    15	 * -IAN! idallen@ncf.ca
    16	 */
    17	#include <sys/types.h>
    18	#include <sys/wait.h>
    19	#include <stdio.h>
    20	#include <string.h>
    21	#include <stdlib.h>
    22	#include <unistd.h>
    23	
    24	/*
    25	 * Fork and then submit the arguments to the Unix "execvp" function that
    26	 * replaces the current executing process image with the given command
    27	 * binary and its arguments.  PATH is used; execvp tries to find
    28	 * the command name in each of the components of the PATH.  The parent
    29	 * waits for the forked child to finish.
    30	 */
    31		static int
    32	forkexec( int argc, char **argv ){
    33		int pid;
    34	
    35		switch( pid=fork() ) {
    36		case -1:	/* ERROR */
    37			perror("fork");
    38			return 1;
    39		case 0:		/* CHILD */
    40			execvp(argv[0],argv);
    41			perror(argv[0]);
    42			printf("*** Could not execute '%s'\n", argv[0]);
    43			exit(1);	// forked child process exits non-zero
    44		default:{	/* PARENT */
    45			int status;
    46			wait( &status );
    47			return (status == 0) ? 0 : 1;
    48		    }
    49		}
    50		/*NOTREACHED*/
    51	}
    52	
    53	#define CMD_BUFSIZ 4096
    54	#define CMD_NARGS 1024
    55	#define CMD_DELIM " \t\n"
    56		int
    57	main(int argc, char **argv){
    58		char buf[CMD_BUFSIZ];	// buffer to hold command line
    59		char *edge[CMD_NARGS];	// edge vector of pointers to each token
    60		char **ep;		// iterates over edge vector
    61		char **eend;		// pointer to end of edge vector
    62		char *strbuf;		// first arg to strtok
    63		int ecount;		// count of tokens
    64		char *token;		// token returned by strtok
    65		int i;			// misc
    66	
    67	    	for(;;){
    68		    	/*
    69			 * Prompt and get one line of input.
    70			 */
    71		    	printf("simsh$ ");
    72			if ( fgets(buf,sizeof(buf),stdin) == NULL ) {
    73			    	if ( ferror(stdin) ) {
    74				    	perror("standard input");
    75					printf("\n*** Error reading stdin\n");
    76				} else {
    77					printf("\n*** EOF\n");
    78				}
    79			    	break;
    80			}
    81			if ( strchr(buf,'\n') == NULL ) {
    82				printf("\n*** EOF or line longer than %d chars\n",
    83					CMD_BUFSIZ);
    84				break;
    85			}
    86	
    87			/*
    88			 * Fill the edge vector with pointers to tokens.
    89			 * The last pointer must be set to NULL.
    90			 */
    91			ep = edge;			// start filling here
    92			eend = edge + CMD_NARGS;	// stop filling here
    93			strbuf = buf;	// strtok gets buf on first time through
    94			while( (token=strtok(strbuf,CMD_DELIM)) != NULL ) {
    95				if( ep >= eend ) {
    96					printf("*** More than %d args\n", CMD_NARGS);
    97					break;
    98				}
    99				*ep++ = token;
   100				strbuf = NULL; // strtok gets NULL on subsequent times
   101			}
   102			if ( ep >= eend )
   103				ep = eend - 1;
   104			*ep = NULL;
   105			ecount = ep - edge;
   106	
   107			/*
   108			 * DEBUG: display the list of tokens.
   109			 */
   110			for( i=0; i<ecount; i++ ){
   111				printf( "*** DEBUG: Arg %d is '%s'\n", i, edge[i] );
   112			}
   113	
   114			/*
   115			 * Execute the tokens as a command and arguments.
   116			 * Print the status returned if not zero.
   117			 */
   118			if( ecount <= 0 ){
   119				printf("*** Nothing to execute.\n");
   120			} else {
   121				int status;
   122				if( (status=forkexec(ecount,edge)) != 0 ){
   123				    	printf("*** Command %s returned %d.\n",
   124						edge[0], status);
   125				}
   126			}
   127		}
   128		printf("*** Goodbye.\n");
   129		return 0;
   130	}
   131	
