/* mp2.c * a Minimally Usable SHell * by Douglas Jones, extended to solve MP2, Sept 29, 2013 \***\ * all lines changed to solve MP2 are marked on the right \***\ * \***\ * this solution has a reduced 'intellectual footprint' in that \***\ * solutions using less code require understanding more of the \***\ * tools in the C standard library. \***\ */ #include #include #include extern char **environ; /* the environment */ /***/ char command[100]; /* the command line */ char * argv[100]; /* result of parsing the command line */ char * path; /* the search path extracted from the environment */ /***/ char * patha[100]; /* result of parsing the path */ /***/ void getcommand() { char ch; int i = 0; putchar( '>' ); do { ch = getchar(); command[i] = ch; i++; } while (ch != '\n'); command[i - 1] = '\000'; } void parseargv() { int i = 0; int j = 0; for (;;) { while (command[j] == ' ') j++; if (command[j] == '\000') break; argv[i] = &command[j]; i++; while ((command[j] != ' ') && (command[j] != '\000')) { j++; } if (command[j] == '\000') break; command[j] = '\000'; j++; } argv[i] = NULL; } void getparsepath() { /***/ /* get the path and pick it apart into patha */ /***/ int i = 0; /* index into patha, array of path part pointers */ /***/ int j = 0; /* index into path, the text of the value of $PATH */ /***/ /***/ /* get a pointer to $PATH in the environ */ /***/ path = getenv( "PATH" ); /***/ /***/ if (path != NULL) { /* $PATH might not be defined in environ */ /***/ /***/ /* make a copy of path so we can still pass environ */ /***/ path = strcpy( malloc( strlen( path ) ), path ); /***/ /***/ /* pick out components of path, index them in patha */ /***/ /* this logic was borrowed from parseargv */ /***/ for (;;) { /***/ if (path[j] == '\000') break; /***/ patha[i] = &path[j]; /***/ i++; /***/ while ((path[j] != ':') /***/ && (path[j] != '\000')) { /***/ j++; /***/ } /***/ if (path[j] == '\000') break; /***/ path[j] = '\000'; /***/ j++; /***/ } /***/ } /***/ patha[i] = NULL; /***/ } /***/ char * gluepath( char * left, char * right ) { /***/ /* concatenate left and right, with a / between them */ /***/ char * result; /***/ /***/ /* how long is result string? including / and null terminator */ /***/ result = malloc( strlen( left ) + 1 + strlen( right ) + 1 ); /***/ /***/ strcpy( result, left ); /***/ strcat( result, "/" ); /***/ strcat( result, right ); /***/ return result; /***/ } /***/ void launch() { if (fork() == 0) { /*child*/ int i; /***/ /***/ /* first try it with the literal command */ /***/ execve( argv[0], argv, environ ); /***/ /***/ /* if that fails, try with successive path components */ /***/ getparsepath(); /***/ i = 0; /***/ while (patha[i] != NULL) { /***/ execve( gluepath( patha[i], argv[0] ), /***/ argv, environ ); /***/ i++; /***/ } /***/ /***/ /* if that fails, we are lost */ /***/ printf( "no such command\n" ); exit( EXIT_FAILURE ); } else { /*parent*/ wait( NULL ); } } main(){ for (;;) { getcommand(); parseargv(); launch(); } }