/* mp2.c */ /*************************************** * A minimally usable shell * * Author: Douglas W. Jones * * Revised by: Douglas W. Jones * * to conform to manual of C style * ***************************************/ #include #include /* string terminator character */ #define NUL '\000' /* maximum line length */ #define COMMANDLEN 100 /* maximum number of arguments, worst case: one char each separted by blanks */ #define ARGVLEN (COMMANDLEN / 2) /* the command line, a character string, later a collection of strings initialized by getcommand modified by parseargv indirectly used by launch */ char command[COMMANDLEN]; /* the argument vector, an array of strings initialized by parseargv used by launch */ char *argv[ARGVLEN]; void getcommand() /* read one command line from standard input note: result returned in the global variable command */ { char ch; /* one character from standard input */ int i = 0; /* a count of the number of characters on the line */ /* prompt for input */ putchar('>'); /* collect the input line, one character at a time */ do { ch = getchar(); if (i < COMMANDLEN) { command[i] = ch; i++; } } while (ch != '\n'); /* replace the newline at the end with a string termiantor */ command[i - 1] = NUL; } void parseargv() /* parse the command line into a sequence of arguments note: result returned in the global variable argv chops the string stored in the global variable command into substrings */ { int i = 0; /* index of the current argument in argv */ int j = 0; /* index of the current character in the command */ for (;;) { /* iterate once per argument */ /* look for the start of an argument */ while (command[j] == ' ') j++; if (command[j] == NUL) break; /* mark the start of the argument */ if (i < (ARGVLEN - 1)) { argv[i] = &command[j]; i++; } /* find the end of the argument */ while ((command[j] != ' ') &&(command[j] != NUL)) { j++; } if (command[j] == NUL) break; /* mark the end of the argument */ command[j] = NUL; j++; } /* mark the end of argv */ argv[i] = NULL; } void launch() /* launch the application required to execute the command note: uses the global variable argv for the command name and arguments */ { if (fork() == 0) { /*child*/ /* try to launch the application */ execve( argv[0], argv, NULL ); /* if launch fails, error message */ printf( "no such command\n" ); exit( EXIT_FAILURE ); } else { /*parent*/ /* wait for command to finish */ wait( NULL ); } } int main() /* repeatedly read, parse and execute commands from standard input note: communication between subsidiary routines is through global variables */ { for (;;) { getcommand(); parseargv(); launch(); } }