Last active
March 3, 2023 04:00
-
-
Save spoonfree/f99ff84bc934b27c6ab768a883a75fd2 to your computer and use it in GitHub Desktop.
assign3.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <unistd.h> | |
| #include <sys/wait.h> | |
| #define MAX_LINE 102 | |
| #define MAX_ARGS 10 | |
| int main(int argc, char *argv[]) { | |
| // string to store custom prompt prefix | |
| char *prompt_prefix; | |
| // report error if user specifies too many arguments | |
| if (argc > 2) { | |
| printf("Too many arguments..Only need 1 argument to define custom prompt, otherwise the shell uses > "); | |
| return 1; | |
| } else if (argc == 2) { | |
| // set the custom prefix prompt from the command line argument | |
| prompt_prefix = argv[1]; | |
| } else { | |
| // If no value is specified use “> ” as the prompt. | |
| prompt_prefix = ">"; | |
| } | |
| // each line of input command should have max size of 102 bytes | |
| char commands[MAX_LINE]; | |
| // set max # of arguments per command to be 10 | |
| char *args[MAX_ARGS]; | |
| // status code for finished process that will be reported later | |
| int status; | |
| while (1) { | |
| // dispay the custom prompt | |
| printf("%s ", prompt_prefix); | |
| // use fgets to accpet the user input and truncate the input at 102 bytes if it exceeds the limit | |
| if (fgets(commands, MAX_LINE, stdin) == NULL) { | |
| // if the shell encounters EOF while reading a line of input, it should exit gracefully without reporting an error. | |
| return 0; | |
| } | |
| // if the user finishes the end of command with a '\n', then change it to file EOF identifier | |
| if (commands[strlen(commands) - 1] == '\n') { | |
| commands[strlen(commands) - 1] = '\0'; | |
| } | |
| // If the user entered an empty line, report an error and fetch a new line of input | |
| if (strlen(commands) == 0) { | |
| printf("the user entered an empty input, please provide a valid command\n"); | |
| continue; | |
| } | |
| // split the input command i into substrings by delimiter " " and store the substring into args array one by one | |
| char *substrings = strtok(commands, " "); | |
| int i = 0; | |
| while (substrings != NULL) { | |
| args[i] = substrings; | |
| substrings = strtok(NULL, " "); | |
| i++; | |
| } | |
| // append the arguments with NULL pointer to indicate the end of arguments | |
| args[i] = NULL; | |
| // quit our shell to normal shell if user enters "exit" | |
| if (strcmp(args[0], "exit") == 0) { | |
| return 1; | |
| } | |
| // create new child process using fork | |
| pid_t pid = fork(); | |
| // handle child process creation failure | |
| if (pid < 0) { | |
| printf("Fork failed. Exiting...\n"); | |
| return 1; | |
| } | |
| // pid = 0 means current process is a child process, so we can run the execute file with its arguments using `execvp` | |
| else if (pid == 0) { | |
| // first substring in args is executable file | |
| execvp(args[0], args); | |
| printf("Failed to execute command. Exiting...\n"); | |
| return 1; | |
| } else { | |
| // if pid != 0 means current process is a parent process, so we need to wait for the child process to be finished until moving forward | |
| waitpid(pid, &status, 0); | |
| printf("Child process %d exited with status: %d\n", pid, WEXITSTATUS(status)); | |
| } | |
| } | |
| return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment