/* * src/hush.c * * HUSH -- The HU Shell * A minimal shell for CISC 301, Operating Systems * * CISC 301 -- Operating Systems, Project 2 * * Copyright (C) 2025 Douglas B. Rumbaugh * * Distributed under the Modified BSD License * */ #include #include #include #include #include #include "config.h" #include "lexer.h" #include "command.h" #include "variables.h" #include "builtin.h" FILE *open_input(int argc, char **argv) { FILE *input_file = (argc > 1) ? fopen(argv[1], "r") : stdin; if (!input_file) { fprintf(stderr, "ERROR: Failed to open input file %s\n", argv[1]); exit(EXIT_FAILURE); } return input_file; } static size_t get_command_len(char *cmdstr) { size_t len = strlen(cmdstr); if (cmdstr[len - 1] != '\n') { len = 0; } return len; } void variable_substitution(command *cmds) { for (command *cmd = cmds; cmd; cmd = cmd->next) { for (size_t i=0; i < MAX_ARGUMENT_CNT + 1; i++) { if (is_variable(cmd->args[i])) { cmd->args[i] = get_variable(cmd->args[i]); } } if (is_variable(cmd->outfile)) { cmd->outfile = get_variable(cmd->outfile); } if (is_variable(cmd->infile)) { cmd->infile = get_variable(cmd->infile); } } } int main(int argc, char **argv) { FILE *input_file = open_input(argc, argv); char buffer[MAX_LINE_LEN]; if (!init_variable_store()) { fprintf(stderr, "ERROR: Failed to initialize variable store\n"); exit(EXIT_FAILURE); } fprintf(stdout, "$ "); while (fgets(buffer, MAX_LINE_LEN, input_file)) { char *cmdstr = trim(buffer); if (!cmdstr) { fprintf(stderr, "ERROR: Specified command is too long\n"); goto draw_prompt; } if (strlen(cmdstr) == 0) { goto draw_prompt; } token *parsed_cmd; if (!(parsed_cmd = parse_command(cmdstr))) { fprintf(stderr, "ERROR: Failed to parse command\n"); goto draw_prompt; } { token *error; if ((error = validate_command(parsed_cmd))) { fprintf(stderr, "ERROR: Invalid syntax near %s\n", error->text); print_parsed_command(stdout, parsed_cmd); goto free_tokens; } } if (parsed_cmd->type == TKN_VARKEY) { if (!add_variable(parsed_cmd->text, parsed_cmd->next->text)) { fprintf(stderr, "ERROR: Failed to create variable\n"); } goto free_tokens; } size_t commands; command *cmds; if (!(cmds = commands_from_tokens(parsed_cmd, &commands ))) { fprintf(stderr, "ERROR: Unable to create commands from tokens"); goto free_tokens; } variable_substitution(cmds); for (command *cmd = cmds; cmd; cmd = cmd->next) { if (!run_builtin(cmd)) { pid_t result = execute_command(cmd); if (result < 0) { break; } } } for (command *cmd = cmds; cmd; cmd = cmd->next) { if (cmd->pid > 0) { waitpid(cmd->pid, NULL, 0); } } free_commands: destroy_commands(cmds); free_tokens: destroy_tokens(parsed_cmd); draw_prompt: fprintf(stdout, "$ "); } destroy_variable_store(); }