/* * Simple shell program (based on pseudocode in Tanenbaum's _Modern Operating * Systems_). * * Input (from stdin) is a sequence of lines, each containing a command and zero * or more arguments. For each line, the program tries to execute the specified * command with the specified arguments. It prints an error message if the * command cannot be found. In this version, the command is specified by giving * a complete path (possibly relative), and no environment variables are passed * to the command. * * Parsing of input lines is extremely primitive -- the command and arguments * are separated by whitespace, there is no variable or other substitution, etc. */ #include #include #include #include /* artificially low for testing */ #define LINESIZE 80 #define MAX_TOKENS 10 /* ---- function declarations ---- */ /* * Prompt for and get input line from stdin, discarding lines that are * too long and replacing ending '\n' with '\0'. * Parameters are array to hold line and its size. * Follows fgets() convention by returning NULL on EOF, otherwise * input parameter inbuff. (Notice that if the line was too long * inbuff will contain an empty string.) */ char* prompt_and_get_input(char* inbuff, int inbuff_sz); /* * "Tokenize" input line -- i.e., split into substrings separated by * white space. Discards any leading or trailing whitespace. * Parameters are input line (assumed to be a valid C-style string), * an array to hold pointers to substrings, and the array's size. * Returns the number of tokens found, or zero if the line contained * more than max_tokens of them. */ int get_tokens(char* inbuff, char* tokens[], int max_tokens); /* ---- main program ---- */ int main(void) { char inbuff[LINESIZE]; /* why MAX_TOKENS+1? read man page for execve carefully */ char* tokens[MAX_TOKENS+1]; while (prompt_and_get_input(inbuff, LINESIZE) != NULL) { /* FIXME debug print -- remove later */ printf("DBG input line '%s'\n", inbuff); int num_tokens = get_tokens(inbuff, tokens, MAX_TOKENS); /* FIXME debug print -- remove later */ printf("DBG %d tokens\n", num_tokens); for (int i = 0; i < num_tokens; ++i) { printf("DBG token '%s'\n", tokens[i]); } if (num_tokens > 0) { /* FIXME your code goes here */ /* sketch for now -- modify as needed */ //if (fork() == 0) { /* child process: use execve to execute command */ //} else { /* parent process: use waitpid to wait for child */ //} } } return (feof(stdin)) ? EXIT_SUCCESS : EXIT_FAILURE; } /* ---- function definitions ---- */ char* prompt_and_get_input(char* inbuff, int inbuff_sz) { puts("next command?"); char* rval = fgets(inbuff, LINESIZE, stdin); if (rval != NULL) { char* p = strchr(inbuff, '\n'); if (p == NULL) { fprintf(stderr, "input line too long (max %d chars)\n", LINESIZE-1); /* clear input line */ int inchar; while (((inchar = fgetc(stdin)) != EOF) && (inchar != '\n')); inbuff[0] = '\0'; } else { *p = '\0'; } } return rval; } int get_tokens(char* inbuff, char* tokens[], int max_tokens) { int count = 0; char* p = inbuff; char* p_limit = inbuff + strlen(inbuff); while (p != p_limit) { /* skip whitespace */ while ((p != p_limit) && isspace(*p)) ++p; /* nothing left? */ if (p == p_limit) { return count; } /* save pointer to start of token */ if (count < max_tokens) { tokens[count++] = p; } else { fprintf(stderr, "too many tokens on input line (max %d)\n", max_tokens); return 0; } /* scan for end of token */ while ((p != p_limit) && !isspace(*p)) ++p; if (p != p_limit) *(p++) = '\0'; } return count; }