/* * shell-ast * Manage the abstract syntax tree resulting from parsing * command lines from a simple shell grammar. * * Refactored by Godmar Back for CS 3214 Summer 2020 * Virginia Tech. */ #include <stdio.h> #include <sys/types.h> #include <limits.h> #include <stdlib.h> #include "shell-ast.h" /* Create new command structure. Takes ownership of argv. */ struct ast_command * ast_command_create(char ** argv, bool dup_stderr_to_stdout) { struct ast_command *cmd = malloc(sizeof *cmd); cmd->argv = argv; cmd->dup_stderr_to_stdout = dup_stderr_to_stdout; return cmd; } /* Create a new pipeline */ struct ast_pipeline * ast_pipeline_create(char *iored_input, char *iored_output, bool append_to_output) { struct ast_pipeline *pipe = malloc(sizeof *pipe); list_init(&pipe->commands); pipe->iored_output = iored_output; pipe->iored_input = iored_input; pipe->append_to_output = append_to_output; pipe->bg_job = false; return pipe; } /* Add a new command to this pipeline */ void ast_pipeline_add_command(struct ast_pipeline *pipe, struct ast_command *cmd) { list_push_back(&pipe->commands, &cmd->elem); } /* Create an empty command line */ struct ast_command_line * ast_command_line_create_empty(void) { struct ast_command_line *cmdline = malloc(sizeof *cmdline); list_init(&cmdline->pipes); return cmdline; } /* Create a command line with a single pipeline */ struct ast_command_line * ast_command_line_create(struct ast_pipeline *pipe) { struct ast_command_line *cmdline = ast_command_line_create_empty(); list_push_back(&cmdline->pipes, &pipe->elem); return cmdline; } /* Print ast_command structure to stdout */ void ast_command_print(struct ast_command *cmd) { char **p = cmd->argv; printf(" Command:"); while (*p) printf(" %s", *p++); printf("\n"); if (cmd->dup_stderr_to_stdout) printf(" stderr shall also be redirected\n"); } /* Print ast_pipeline structure to stdout */ void ast_pipeline_print(struct ast_pipeline *pipe) { int i = 1; printf(" Pipeline consists of %ld commands\n", list_size(&pipe->commands)); for (struct list_elem * e = list_begin(&pipe->commands); e != list_end(&pipe->commands); e = list_next(e)) { struct ast_command *cmd = list_entry(e, struct ast_command, elem); printf(" %d. ", i++); ast_command_print(cmd); } if (pipe->iored_output) printf(" the stdout of the last command %ss to %s\n", pipe->append_to_output ? "append" : "write", pipe->iored_output); if (pipe->iored_input) printf(" stdin of the first command reads from %s\n", pipe->iored_input); if (pipe->bg_job) printf(" - is a background job\n"); else printf(" - should be started as a regular foreground job\n"); } /* Print ast_command_line structure to stdout */ void ast_command_line_print(struct ast_command_line *cmdline) { printf("Command line\n"); for (struct list_elem * e = list_begin (&cmdline->pipes); e != list_end (&cmdline->pipes); e = list_next (e)) { struct ast_pipeline *pipe = list_entry(e, struct ast_pipeline, elem); printf(" ------------- \n"); ast_pipeline_print(pipe); } printf("==========================================\n"); } /* Deallocation functions. */ void ast_command_line_free(struct ast_command_line *cmdline) { for (struct list_elem * e = list_begin(&cmdline->pipes); e != list_end(&cmdline->pipes); ) { struct ast_pipeline *pipe = list_entry(e, struct ast_pipeline, elem); e = list_remove(e); ast_pipeline_free(pipe); } free(cmdline); } void ast_pipeline_free(struct ast_pipeline *pipe) { for (struct list_elem * e = list_begin(&pipe->commands); e != list_end(&pipe->commands); ) { struct ast_command *cmd = list_entry(e, struct ast_command, elem); e = list_remove(e); ast_command_free(cmd); } if (pipe->iored_input) free(pipe->iored_input); if (pipe->iored_output) free(pipe->iored_output); free(pipe); } void ast_command_free(struct ast_command * cmd) { char ** p = cmd->argv; while (*p) { free(*p++); } free(cmd->argv); free(cmd); }