/* shell208.c Jeff Ondich, 16 February 2022 Updated 16 February 2023 Modified by Tanya Amert for Fall 2023 This is a rough framework for your CS 208 command shell assignment. Reading one line of text from stdin while giving the user useful feedback about that line of text can be finicky, so I have included a detailed get_command function that you may use if you wish. Note that this program has a weird issue. If you hit Ctrl-D while running it, you'll get an infinite loop of error messages. (You can hit Ctrl-C to stop the program.) Any idea why this happens? Any idea how to fix it? */ #include #include #include // The command buffer will need to have room to hold the // command, the \n at the end of the command, and the \0. // That's why the maximum command size is 2 less than the // command buffer size. #define COMMAND_BUFFER_SIZE 102 #define MAX_COMMAND_SIZE COMMAND_BUFFER_SIZE - 2 // Return values for get_command #define COMMAND_INPUT_SUCCEEDED 0 #define COMMAND_INPUT_FAILED 1 #define COMMAND_END_OF_FILE 2 #define COMMAND_TOO_LONG 3 int get_command(char *command_buffer, int buffer_size); void execute_command(char *command_line); int main() { const char *prompt = "shell208> "; char command_line[COMMAND_BUFFER_SIZE]; // The main infinite loop while (1) { printf("%s", prompt); fflush(stdout); int result = get_command(command_line, COMMAND_BUFFER_SIZE); if (result == COMMAND_END_OF_FILE) { // stdin has reached EOF, so it's time to be done; this often happens // when the user hits Ctrl-D break; } else if (result == COMMAND_INPUT_FAILED) { fprintf(stderr, "There was a problem reading your command. Please try again.\n"); // we could try to analyze the error using ferror and respond in different // ways depending on the error, but instead, let's just bail break; } else if (result == COMMAND_TOO_LONG) { fprintf(stderr, "Commands are limited to length %d. Please try again.\n", MAX_COMMAND_SIZE); } else { execute_command(command_line); } } return 0; } /* Retrieves the next line of input from stdin (where, typically, the user has typed a command) and stores it in command_buffer. The newline character (\n, ASCII 10) character at the end of the input line will be read from stdin but not stored in command_buffer. The input stored in command_buffer will be \0-terminated. Returns: COMMAND_TOO_LONG if the number of chars in the input line (including the \n), is greater than or equal to buffer_size COMMAND_INPUT_FAILED if the input operation fails with an error COMMAND_END_OF_FILE if the input operation fails with feof(stdin) == true COMMAND_INPUT_SUCCEEDED otherwise Preconditions: - buffer_size > 0 - command_buffer != NULL - command_buffer points to a buffer large enough for at least buffer_size chars */ int get_command(char *command_buffer, int buffer_size) { assert(buffer_size > 0); assert(command_buffer != NULL); if (fgets(command_buffer, buffer_size, stdin) == NULL) { if (feof(stdin)) { return COMMAND_END_OF_FILE; } else { return COMMAND_INPUT_FAILED; } } int command_length = strlen(command_buffer); if (command_buffer[command_length - 1] != '\n') { // If we get here, the input line hasn't been fully read yet. // We need to read the rest of the input line so the unread portion // of the line doesn't corrupt the next command the user types. // Note that we won't store what we read, now, though, as the // user hasn't entered a valid command (because it's too long). char ch = getchar(); while (ch != '\n' && ch != EOF) { ch = getchar(); } return COMMAND_TOO_LONG; } // remove the newline character command_buffer[command_length - 1] = '\0'; return COMMAND_INPUT_SUCCEEDED; } void execute_command(char *command_line) { // Do whatever you want to do printf("Hello from the stub version of execute_command.\n"); printf("Here's your command: %s\n", command_line); }