/* shell208.c Jeff Ondich, 16 February 2022 Updated 16 February 2023 This is a rough framework for your CS208 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. 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); }