Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/wait.h>
- #include <signal.h>
- #include <fcntl.h>
- #define MAX_INPUT_LENGTH 510
- #define MAX_ARGS 10
- // Using LinkedList to store vars
- typedef struct node {
- char *name;
- char *value;
- struct node *next;
- } Node;
- typedef struct linked_list {
- Node *head;
- } LinkedList;
- int get_input(char *input);
- void parse_input(char *input, char **args, LinkedList *vars, int *stopped_process_pid);
- void exec_command(char **args, int ampersand, char *file_name, int pipe_num, int pipe_amount, int* pipefd, int* prev_pipefd);
- char *replace_vars(char *input, LinkedList *vars);
- void quots_remover(char *str);
- int is_echo(char *str);
- int is_CD(char *str);
- int is_BG(char *str);
- int is_redirection(char *str);
- int is_pipe(char *str);
- void pipe_parse(char **args, char *str, int pipes_amount);
- int have_illegal_spaces(char *str);
- void spaces_remover(char *str);
- void prompt_printer(int legCmds, int args);
- void splitToEqual(const char *str, char *left_string, char *right_string);
- int ampersand_finder_remover(char *str);
- void initialize(LinkedList *list);
- void insert(LinkedList *list, char *name, char *value);
- Node *search(LinkedList *list, char *name);
- void terminate(LinkedList *list);
- void sig_child_handler(int n);
- void father_handler(int n);
- int pidd = 0;
- int last_pid = 0;
- int redirect_flag = 0;
- int legalArgs = 0, legalCmds = 0;
- int main() {
- signal(SIGCHLD, sig_child_handler);
- int noCmdCounter = 0, inputStatus, stopped_process_pid = 0;
- char input[MAX_INPUT_LENGTH + 5];
- char *args[MAX_ARGS];
- for (int i = 0; i < MAX_ARGS; ++i) {
- args[i] = "\0";
- }
- // int* pidd = malloc(sizeof(int));
- LinkedList vars;
- initialize(&vars);
- while (1) {
- // prompt
- prompt_printer(legalCmds, legalArgs);
- inputStatus = get_input(input);
- // input len is greater than max
- if (inputStatus == 0) {
- printf("ERR\n");
- continue;
- }
- // user pressed enter 3 times in a row
- else if (inputStatus == -1) {
- noCmdCounter++;
- if (noCmdCounter == 3)
- break;
- continue;
- }
- // legal input
- else {
- noCmdCounter = 0;
- parse_input(input, args, &vars, &stopped_process_pid);
- }
- }
- terminate(&vars);
- }
- /* function that gets command input from the user */
- int get_input(char *input) {
- // printf("student@student-virtual-machine ~/ex1 $ ");
- fgets(input, MAX_INPUT_LENGTH + 5, stdin);
- input[strcspn(input, "\n")] = '\0'; // replaces last char (new-line char) to NULL terminator
- if (strlen(input) > MAX_INPUT_LENGTH)
- return 0; // if illegal input length
- else if (strlen(input) == 0)
- return -1; // if no cmd entered
- return 1; // if legal input length
- }
- /* function that divides the commands and their arguments */
- void parse_input(char *input, char **args, LinkedList *vars, int *stopped_process_pid) {
- char temp_str[520], temp_arg[520];
- char *token;
- int input_len = strlen(input), equal_val = '=', idx, quot_counter = 0, ampersand_flag, pipe_counter = 0;
- // ----------------------copying each command seperated by ';'-----------------------------------
- for (int i = 0, j = 0; i <= input_len; ++i) { // copying each command seperated by ';'
- if (input[i] == '\"') {
- if (quot_counter == 1)
- quot_counter = 0;
- else quot_counter = 1;
- }
- if ((input[i] == ';' || input[i] == '\0') && quot_counter == 0) { // end of command
- char *file_name;
- temp_str[j] = '\0';
- redirect_flag = 0;
- ampersand_flag = 0;
- ampersand_flag = ampersand_finder_remover(temp_str);
- quot_counter = 0;
- printf("command is : %s\n", temp_str);
- j = 0;
- // ******************working on each command***********************
- pipe_counter = is_pipe(temp_str);
- if (pipe_counter > 0){
- pipe_parse(args, temp_str, pipe_counter);
- continue;
- }
- // redirection
- if (is_redirection(temp_str) == 1) {
- redirect_flag = 1;
- char *command_to_redirect = strtok(temp_str, ">"); // holds the cmd
- file_name = strtok(NULL, ">"); // holds the file name
- spaces_remover(file_name);
- printf("@%s@\t@%s@\n", command_to_redirect, file_name);
- printf("--%s--\n", temp_str);
- }
- if (is_CD(temp_str) == 1) {
- printf("CD not supported!\n");
- continue;
- }
- // 'echo' cmd
- if (is_echo(temp_str) == 1 && pipe_counter == 0) {
- token = strtok(temp_str, " ");
- args[0] = token; // inserting "echo" to first exec array element
- token = strtok(NULL, "\0");
- args[1] = token; // inserting echo's argument into second exec array element
- args[2] = "\0";
- for (int k = 0; k < 10; ++k) {
- if (k != 0 && k != 1) args[k] = '\0';
- if (k == 1) {
- strcpy(temp_arg, replace_vars(args[1], vars));
- quots_remover(temp_arg);
- args[1] = temp_arg;
- }
- }
- }
- // if cmd has '=' then it's a variable cmd
- else if (strchr(temp_str, equal_val) != NULL && pipe_counter == 0) {
- char temp_str2[520];
- strcpy(temp_str2, temp_str);
- if (have_illegal_spaces(temp_str2) == 0) {
- char left[520], right[520];
- splitToEqual(temp_str, left, right); // left/right holds the two parts of the variable
- char var_name[520];
- strcpy(var_name, left);
- spaces_remover(var_name);
- char var_value[520];
- strcpy(var_value, right);
- quots_remover(var_value);
- insert(vars, var_name, var_value);
- continue;
- }
- }
- else if (is_BG(temp_str) == 1 && pipe_counter == 0) {
- kill(last_pid, SIGCONT);
- continue;
- }
- // regular command
- else {
- idx = 0;
- char *p = (char *) malloc(sizeof(char *));
- p = replace_vars(temp_str, vars);
- strcpy(temp_arg, p);
- token = strtok(temp_arg, " ");
- while (token != NULL) {
- spaces_remover(token);
- args[idx++] = token;
- token = strtok(NULL, " ");
- }
- while (idx < 10) {
- args[idx++] = NULL;
- }
- }
- if (redirect_flag == 1) {
- exec_command(args, ampersand_flag, file_name, 0, 0, NULL, NULL);
- continue;
- }
- exec_command(args, ampersand_flag, NULL, 0, 0, NULL, NULL);
- }
- // ***************************************************************
- else { // copying next letter
- temp_str[j] = input[i];
- j++;
- }
- }
- // --------------------------------------------------------------------------------------------
- }
- void printArr(char **arr) {
- fprintf(stderr, "printArr:\n");
- for (int i = 0; arr[i] != NULL; i++)
- fprintf(stderr, "%s\n", arr[i]);
- }
- /* function that creates a son process and sends the command to execvp */
- void exec_command(char **args, int ampersand, char *file_name, int pipe_num, int pipe_amount, int* pipefd, int* prev_pipefd) {
- int status;
- pidd = fork();
- // child
- if (pidd == 0) {
- signal(SIGTSTP, SIG_DFL);
- if (redirect_flag == 1) {
- int fd = open(file_name, O_WRONLY | O_TRUNC | O_CREAT, 0644);
- dup2(fd, STDOUT_FILENO);
- if (fd == -1) perror("ERR file");
- }
- if (pipe_amount != 0) {
- for (int i = 0; i < 10; ++i)
- printf("!%s\t", args[i]);
- printf("\n");
- // first pipe
- if (pipe_num == 0) {
- printf("first pipe\n");
- close(pipefd[0]); // close read
- if (dup2(pipefd[1], STDOUT_FILENO) == -1) { // redirect stdout to write
- perror("pipe 1 dup");
- exit(EXIT_FAILURE);
- }
- }
- // last pipe
- else if (pipe_num == pipe_amount){
- printf("last pipe\n");
- close(prev_pipefd[1]); // close unused write end of previous pipe
- if(dup2(prev_pipefd[0], STDIN_FILENO) == -1) { // redirect stdin to read end of previous pipe
- perror("pipe 3 dup");
- exit(EXIT_FAILURE);
- }
- close(pipefd[0]); // close unused read end of pipe
- }
- // mid pipes
- else{
- printf("mid pipe\n");
- close(prev_pipefd[1]); // close unused write end of previous pipe
- dup2(prev_pipefd[0], STDIN_FILENO); // redirect stdin to read end of previous pipe
- close(pipefd[0]); // close unused read end of pipe
- dup2(pipefd[1], STDOUT_FILENO); // redirect stdout to write end of pipe
- }
- }
- execvp(args[0], args);
- printf("after exec\n");
- perror("ERR0");
- exit(1);
- }
- // error
- else if (pidd < 0) {
- perror("ERR1\n");
- exit(0);
- }
- // parent
- else {
- if (pipe_amount != 0) {
- if (prev_pipefd[0] != -1) close(prev_pipefd[0]);
- if (prev_pipefd[1] != -1) close(prev_pipefd[1]);
- prev_pipefd[0] = pipefd[0];
- prev_pipefd[1] = pipefd[1];
- printf("parent process\n");
- }
- signal(SIGTSTP, father_handler);
- if (ampersand == 0)
- waitpid(pidd, &status, WUNTRACED);
- legalCmds += 1; // inc cmds counter
- for (int i = 0; i < 10; ++i) // inc args counter
- if (args[i] != NULL)
- legalArgs += 1;
- }
- // if (prev_pipefd[0] != -1) close(prev_pipefd[0]);
- // if (prev_pipefd[1] != -1) close(prev_pipefd[1]);
- }
- /* function that removes quots from a string */
- void quots_remover(char *str) {
- int len = strlen(str);
- int i, j;
- for (i = 0, j = 0; i < len; i++)
- if (str[i] != '\"')
- str[j++] = str[i];
- str[j] = '\0';
- }
- /* function that checks if it's an echo command */
- int is_echo(char *str) {
- int counter = 0;
- for (int i = 0; i < strlen(str); ++i) {
- if (str[i] == 'e') {
- counter++;
- continue;
- }
- if (str[i] == 'c' && counter == 1) {
- counter++;
- continue;
- }
- if (str[i] == 'h' && counter == 2) {
- counter++;
- continue;
- }
- if (str[i] == 'o' && counter == 3) {
- counter++;
- break;
- }
- counter = 0;
- }
- if (counter == 4)
- return 1;
- return 0;
- }
- int is_CD(char *str) {
- int counter = 0;
- for (int i = 0; i < strlen(str); ++i) {
- if (str[i] == 'c') {
- counter++;
- continue;
- }
- if (str[i] == 'd' && counter == 1) {
- counter++;
- break;
- }
- counter = 0;
- }
- if (counter == 2)
- return 1;
- return 0;
- }
- int is_BG(char *str) {
- int counter = 0;
- for (int i = 0; i < strlen(str); ++i) {
- if (str[i] == 'b') {
- counter++;
- continue;
- }
- if (str[i] == 'g' && counter == 1) {
- counter++;
- break;
- }
- counter = 0;
- }
- if (counter == 2)
- return 1;
- return 0;
- }
- /* function that determines how many pipes the command have, if any */
- int is_pipe(char *str) {
- int counter = 0;
- for (int i = 0; i < strlen(str); ++i)
- if (str[i] == '|') counter++;
- return counter;
- }
- /* function that parses the command by pipes */
- void pipe_parse(char **args, char *str, int pipes_amount) {
- char curr_cmd[510];
- for (int i = 0; i < 510; ++i) curr_cmd[i] = '\0';
- int pipes_executed = 0;
- char *token;
- int pipefd[2];
- int prev_pipefd[2] = {-1, -1};
- if (pipe(pipefd) == -1) {
- perror("ERR pipe");
- exit(1);
- }
- for (int i = 0, j = 0; i < strlen(str); ++i) {
- if (str[i] == '|' || str[i] == '\0') {
- curr_cmd[j] = '\0';
- j = 0;
- //printf("@%s@\n", curr_cmd);
- token = strtok(curr_cmd, " ");
- args[0] = token;
- int k = 0;
- for (; token != NULL; k++, token = strtok(NULL, " "))
- args[k] = token;
- for (; k < 10; k++) args[k] = NULL;
- exec_command(args, 0, NULL, pipes_executed, pipes_amount, pipefd, prev_pipefd);
- pipes_executed++;
- }
- else {
- curr_cmd[j++] = str[i];
- }
- }
- }
- /* function that checks if an environmental variable command has illegal spaces*/
- int have_illegal_spaces(char *str) {
- char *temp = str;
- char *toke = strtok(temp, "=");
- int flag = 0;
- for (int i = 0; i < strlen(toke); ++i) {
- if (temp[i] != ' ') {
- flag = 1;
- }
- if (temp[i] == ' ' && flag != 0)
- return 1;
- }
- return 0;
- }
- /* function that removes spaces */
- void spaces_remover(char *str) {
- int len = strlen(str);
- int i, j;
- for (i = 0, j = 0; i < len; i++)
- if (str[i] != ' ')
- str[j++] = str[i];
- str[j] = '\0';
- }
- /* function that prints the prompt line */
- void prompt_printer(int legCmds, int args) {
- char cwd[256];
- if (getcwd(cwd, sizeof(cwd)) == NULL)
- printf("ERR getcwd"); // TODO: CHANGE TO WHAT?
- else
- printf("#cmd:%d|#args:%d@%s ", legCmds, args, cwd);
- }
- /* function that replaces all variables calls with their values */
- char *replace_vars(char *input, LinkedList *vars) {
- char *temp = (char *) malloc(520);
- memset(temp, '\0', sizeof(*temp)); // TODO: add * before temp inside sizeof ??
- char name_temp[520];
- memset(name_temp, '\0', sizeof(name_temp));
- int flag = 0, tempIdx = 0, nameIdx = 0;
- char c[2];
- c[1] = 0;
- for (int i = 0; i < strlen(input) + 1; ++i) {
- if (input[i] == '$')
- flag = 1;
- else if (input[i] == ' ' || input[i] == '\0' || input[i] == '\"') { // check for var in list
- flag = 0;
- Node *temp_node = search(vars, name_temp);
- if (temp_node != NULL) { // var exist
- strcat(temp, temp_node->value);
- }
- else { // var doesn't exist
- strcat(temp, " ");
- }
- memset(name_temp, '\0', sizeof(name_temp));
- if (input[i] == ' ') {
- strcat(temp, " ");
- }
- }
- else if (input[i] != ' ') { // copy char
- sprintf(c, "%c", input[i]);
- //printf("%c\n", c[0]);
- if (flag == 1) { // copy to name
- strcat(name_temp, c);
- }
- else { // copy to temp
- strcat(temp, c);
- }
- }
- }
- return temp;
- }
- /* function that splits the environmental variable */
- void splitToEqual(const char *str, char *left, char *right) {
- memset(left, '\0', MAX_INPUT_LENGTH);
- memset(right, '\0', MAX_INPUT_LENGTH);
- int flag = 0, j = 0;
- for (int i = 0; i < strlen(str); ++i) {
- if (str[i] == '=') {
- flag = 1, j = 0;
- }
- else {
- if (flag == 0) left[j++] = str[i];
- else right[j++] = str[i];
- }
- }
- }
- void sig_child_handler(int n) {
- waitpid(-1, NULL, WNOHANG);
- }
- void father_handler(int n) {
- last_pid = pidd;
- }
- /* function that looks if command has ampersand, if it does it'll delete it */
- int ampersand_finder_remover(char *str) {
- int i, j;
- int insideQuotes = 0;
- int deleted = 0;
- for (i = 0, j = 0; str[i]; i++) {
- if (str[i] == '\"') {
- insideQuotes = !insideQuotes; // toggle flag
- }
- else if (str[i] == '&' && !insideQuotes) {
- deleted = 1;
- continue; // skip ampersand if not inside quotes
- }
- else {
- str[j++] = str[i];
- }
- }
- str[j] = '\0';
- return deleted;
- }
- /* function that checks for '>' char and determines if the cmd is a concat cmd */
- int is_redirection(char *str) {
- for (int i = 0; i < strlen(str); ++i)
- if (str[i] == '>')
- return 1;
- return 0;
- }
- /* Function to initialize the linked list */
- void initialize(LinkedList *list) {
- list->head = NULL;
- }
- // function to insert a new node into the linked list
- void insert(LinkedList *list, char *name, char *value) {
- Node *new_node = malloc(sizeof(Node));
- if (new_node == NULL) {
- printf("ERR");
- exit(1);
- }
- new_node->name = strdup(name);
- new_node->value = strdup(value);
- new_node->next = NULL;
- // check if list is empty
- if (list->head == NULL) {
- list->head = new_node;
- }
- else {
- // search the node with the same name
- Node *current_node = list->head;
- while (current_node != NULL) {
- if (strcmp(current_node->name, name) == 0) {
- // replace the existing node with the new node
- free(current_node->value);
- current_node->value = strdup(value);
- free(new_node->name);
- free(new_node->value);
- free(new_node);
- return;
- }
- current_node = current_node->next;
- }
- /* Insert the new node at the end of the list */
- current_node = list->head;
- while (current_node->next != NULL) {
- current_node = current_node->next;
- }
- current_node->next = new_node;
- }
- }
- /* Function to search for a node with a given name */
- Node *search(LinkedList *list, char *name) {
- Node *current_node = list->head;
- while (current_node != NULL) {
- if (strcmp(current_node->name, name) == 0) {
- return current_node;
- }
- current_node = current_node->next;
- }
- return NULL;
- }
- // function to terminate the linked list and free all memory
- void terminate(LinkedList *list) {
- Node *current_node = list->head;
- while (current_node != NULL) {
- Node *next_node = current_node->next;
- free(current_node->name);
- free(current_node->value);
- free(current_node);
- current_node = next_node;
- }
- list->head = NULL;
- }
Add Comment
Please, Sign In to add comment