diff options
| author | Ákos Kőrösi <korakos99@gmail.com> | 2026-05-18 16:23:26 +0200 |
|---|---|---|
| committer | Ákos Kőrösi <korakos99@gmail.com> | 2026-05-18 16:23:26 +0200 |
| commit | ca675175742174d6bfcd0263583f840e250fc58f (patch) | |
| tree | cd11ec9f8345fa31dddb2a5f0c21d59bb19816b1 | |
| parent | 24ba34266cc977b22d777bceca9683a45dd73042 (diff) | |
quicksaving
| -rw-r--r-- | exec.c | 188 | ||||
| -rw-r--r-- | exec.h | 9 | ||||
| -rw-r--r-- | expand.c | 101 | ||||
| -rw-r--r-- | expand.h | 32 | ||||
| -rw-r--r-- | preproc.c | 69 | ||||
| -rw-r--r-- | preproc.h | 30 | ||||
| -rw-r--r-- | utils.c | 7 | ||||
| -rw-r--r-- | utils.h | 9 |
8 files changed, 214 insertions, 231 deletions
@@ -9,108 +9,10 @@ #include "utils.h" #include "exec.h" #include "preproc.h" +#include "expand.h" -char* get_var(char* varname, ShellState* shstate) { - MaybeStr maybe_varval = get_map_value(&shstate->shell_vars, varname); - if (maybe_varval.some == true) return maybe_varval.value; - return getenv(varname); -} - -typedef struct { - QuotationMode qmode; - char* content; -} ExpandedChunk; - - -ExpandedChunk expand_chunk(Chunk chunk, ShellState* shstate) { - char* content; - if (chunk.qmode == SINGLE_Q || chunk.kind == LITERAL) { - if (chunk.qmode == SINGLE_Q && chunk.kind != LITERAL) exit(69); - content = chunk.as.literal_str; - } else if (chunk.kind == VAR_EXP) { - content = get_var(chunk.as.varname, shstate); - } else if (chunk.kind == REGION_EXP) { - exit(7); // Not supported yet; arithm - } - return (ExpandedChunk){.qmode = chunk.qmode, .content = content}; -} - - -typedef struct { - StrVec complete_strs; - String active_str; -} WordSplittingGerm; - -void add_expchunk(char* next_str, WordSplittingGerm* curr_res) { - for (int pos = 0; pos < strlen(next_str); pos++) { - if (next_str[pos] == ' ') { - push_to_StrVec(&curr_res->complete_strs, inner(&curr_res->active_str)); - curr_res->active_str = make_String(256); - } else { - push_to_String(&curr_res->active_str, next_str[pos]); - } - } -} - -StrVec expand_word(Word word, ShellState* state) { - WordSplittingGerm curr_res = {.complete_strs = make_StrVec(256), .active_str = make_String(25)}; - for (int i = 0; i < word.count; i++) { - Chunk curr_cunk = **get_from_Word(&word, i); - ExpandedChunk curr_exp = expand_chunk(curr_cunk, state); - switch (curr_exp.qmode) { - case UN_Q: - add_expchunk(curr_exp.content, &curr_res); - break; - case SINGLE_Q: - append_str_to_String(&curr_res.active_str, curr_exp.content); - break; - case DOUBLE_Q: - append_str_to_String(&curr_res.active_str, curr_exp.content); - } - } - - if (curr_res.active_str.count > 0) { - push_to_StrVec(&curr_res.complete_strs, inner(&curr_res.active_str)); - } - - return curr_res.complete_strs; -} - - -void merge_strvecs(StrVec* target, StrVec* source) { - for (int i = 0; i < source->count; i++) { - push_to_StrVec(target, *get_from_StrVec(source, i)); - } -} - - -char** make_cmd_args(Command command, ShellState* shstate) { - StrVec arg_str_vec = make_StrVec(256); - for (int i = 0; i < command.args.count; i++) { - Token arg_i = *get_from_TokenVec(&command.args, i); - StrVec expanded_i; - switch (arg_i.kind) { - case TOK_WORD: - expanded_i = expand_word(arg_i.as.word, shstate); - merge_strvecs(&arg_str_vec, &expanded_i); - break; - default: - exit(67); - } - } - int argcount = arg_str_vec.count; - char** arg_str_arr = malloc(sizeof(char*) * (argcount + 1)); - for (int j = 0; j < argcount; j++) { - arg_str_arr[j] = *get_from_StrVec(&arg_str_vec, j); - } - arg_str_arr[argcount] = NULL; - return arg_str_arr; -} - - - -void execute_command(ExecutableCommand cmd, int* pgid) { +void execute_command(Command cmd, int* pgid) { pid_t pid = fork(); if (pid == 0) { @@ -150,58 +52,55 @@ void execute_command(ExecutableCommand cmd, int* pgid) { } } +Command make_command(SlotVec cmd_slots) { + Command cmd = { + .child_close_fds = make_IntVec(64), + .parent_close_fds = make_IntVec(64), + .redirs = make_FdRedirectVec(32) + }; + StrVec arg_strs = make_StrVec(256); + for (int i = 0; i < cmd_slots.count; i++) { + Slot slot = *get_from_SlotVec(&cmd_slots, i); + switch (slot.kind) { + case SLOT_STR: + push_to_StrVec(&arg_strs, slot.as.str); + default: + exit(67); + // TODO: other slot kinds + } + } + cmd.args = malloc(sizeof(char*) * arg_strs.count); + for (int j = 0; j < arg_strs.count; j++) { + cmd.args[j] = *get_from_StrVec(&arg_strs, j); + } + return cmd; +} - -void run_pipeline(Pipeline pl, ShellState* shstate) { +void run_cmds(CommandVec cmds) { signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); - int last_pipe_fd; + int trunk_fd = STDIN_FILENO; int pgid = -1; - for (int i = 0; i < pl.count; i++) { - PipelineElement elem = *get_from_Pipeline(&pl, i); - ExecutableCommand cmd = { - .child_close_fds = make_IntVec(64), - .parent_close_fds = make_IntVec(64), - .redirs = make_FdRedirectVec(32) - }; - cmd.args = make_cmd_args(elem.cmd, shstate); + for (int i = 0; i < cmds.count; i++) { + Command cmd = *get_from_CommandVec(&cmds, i); + cmd.stdin_fd = trunk_fd; - if (i == 0) { - cmd.stdin_fd = STDIN_FILENO; - } else { - cmd.stdin_fd = last_pipe_fd; - push_to_IntVec(&cmd.child_close_fds, last_pipe_fd); - push_to_IntVec(&cmd.parent_close_fds, last_pipe_fd); + if (i > 0) { + push_to_IntVec(&cmd.child_close_fds, trunk_fd); + push_to_IntVec(&cmd.parent_close_fds, trunk_fd); } - if (elem.conn == CONN_PIPE) { + cmd.stdout_fd = STDOUT_FILENO; + if (cmd.term = CONN_PIPE) { int pipe_fds[2]; pipe(pipe_fds); cmd.stdout_fd = pipe_fds[1]; push_to_IntVec(&cmd.child_close_fds, pipe_fds[1]); push_to_IntVec(&cmd.parent_close_fds, pipe_fds[1]); - last_pipe_fd = pipe_fds[0]; - } else { - cmd.stdout_fd = STDOUT_FILENO; - } - - for (int j = 0; j < elem.cmd.redirects.count; j++) { - Redirect rd = *get_from_RedirectVec(&elem.cmd.redirects, j); - switch (rd.kind) { - case STDIN_REDIR: - /* - int in_fd = open(rd.as.std_redir_filename, O_RDONLY, 0644); - push_to_FdRedirectVec(&cmd.redirs, (FdRedirect){.old_fd = STDIN_REDIR, .new_fd = in_fd}); - push_to_IntVec(&cmd.child_close_fds, in_fd); - push_to_IntVec(&cmd.parent_close_fds, in_fd); - */ - break; - default: - exit(69); - } + trunk_fd = pipe_fds[0]; } execute_command(cmd, &pgid); @@ -210,12 +109,23 @@ void run_pipeline(Pipeline pl, ShellState* shstate) { close(*get_from_IntVec(&cmd.parent_close_fds, j)); } } + tcsetpgrp(STDIN_FILENO, pgid); while (waitpid(-pgid, NULL, 0) > 0); tcsetpgrp(STDIN_FILENO, getpgrp()); } +CommandVec make_cmd_vec_pl(ExpandedPipeline pl) { + CommandVec cmds = make_CommandVec(256); + for (int i = 0; i < pl.count; i++) { + ExpandedPipelineElement elem = *get_from_ExpandedPipeline(&pl, i); + Command cmd = make_command(elem.cmd_slots); + push_to_CommandVec(&cmds, cmd); + } +} + + void process_input_line(char* line, ShellState* shstate) { PreprocArena arena = { .tokens = make_TokenVec(256), @@ -228,7 +138,9 @@ void process_input_line(char* line, ShellState* shstate) { line_toks[i] = **get_from_TokenPtrVec(&line_tok_ptrs, i); } Pipeline pl = parse_tokstream(line_toks); - run_pipeline(pl, shstate); + ExpandedPipeline exp_pl = expand_pipeline(&pl, shstate); + CommandVec cmds = make_cmd_vec_pl(exp_pl); + run_cmds(cmds); free(line_toks); } @@ -18,12 +18,9 @@ typedef struct { int stdout_fd; IntVec child_close_fds; IntVec parent_close_fds; -} ExecutableCommand; + Connector term; +} Command; - -typedef struct { - KeyValMap aliases; - KeyValMap shell_vars; -} ShellState; +DECLARE_VEC(Command, CommandVec) void process_input_line(char* line, ShellState* shstate); diff --git a/expand.c b/expand.c new file mode 100644 index 0000000..e88ec6c --- /dev/null +++ b/expand.c @@ -0,0 +1,101 @@ +#include "expand.h" +#include "preproc.h" +#include "utils.h" +#include <string.h> + + +typedef struct { + QuotationMode qmode; + char* content; +} ExpandedChunk; + + +ExpandedChunk expand_chunk(Chunk chunk, ShellState* shstate) { + char* content; + if (chunk.qmode == SINGLE_Q || chunk.kind == LITERAL) { + if (chunk.qmode == SINGLE_Q && chunk.kind != LITERAL) exit(69); + content = chunk.as.literal_str; + } else if (chunk.kind == VAR_EXP) { + content = get_var(chunk.as.varname, shstate); + } else if (chunk.kind == REGION_EXP) { + exit(7); // Not supported yet; arithm + } + return (ExpandedChunk){.qmode = chunk.qmode, .content = content}; +} + + +typedef struct { + StrVec complete_strs; + String active_str; +} WordSplittingGerm; + +void add_expchunk(char* next_str, WordSplittingGerm* curr_res) { + for (int pos = 0; pos < strlen(next_str); pos++) { + if (next_str[pos] == ' ') { + push_to_StrVec(&curr_res->complete_strs, inner(&curr_res->active_str)); + curr_res->active_str = make_String(256); + } else { + push_to_String(&curr_res->active_str, next_str[pos]); + } + } +} + + +void expand_word(Word word, SlotVec* target, ShellState* shstate) { + WordSplittingGerm curr_res = { + .complete_strs = make_StrVec(256), + .active_str = make_String(256) + }; + for (int i = 0; i < word.count; i++) { + Chunk chunk = **get_from_Word(&word, i); + ExpandedChunk expchunk = expand_chunk(chunk, shstate); + switch (expchunk.qmode) { + case UN_Q: + add_expchunk(expchunk.content, &curr_res); + break; + case SINGLE_Q: + append_str_to_String(&curr_res.active_str, expchunk.content); + break; + case DOUBLE_Q: + // TODO: further expansions here + append_str_to_String(&curr_res.active_str, expchunk.content); + break; + } + } + for (int j = 0; j < curr_res.complete_strs.count; j++) { + char* str = *get_from_StrVec(&curr_res.complete_strs, j); + push_to_SlotVec(target, (Slot){.kind = SLOT_STR, .as.str = str}); + } +} + +ExpandedPipelineElement expand_pipeline_element(PipelineElement elem, ShellState* shstate) { + ExpandedPipelineElement result = {.cmd_slots = make_SlotVec(256), .conn = elem.conn}; + for (int i = 0; i < elem.cmd_toks.count; i++) { + Token curr_tok = *get_from_TokenVec(&elem.cmd_toks, i); + switch (curr_tok.kind) { + case TOK_WORD: + expand_word(curr_tok.as.word, &result.cmd_slots, shstate); + break; + case TOK_SPECIAL: + push_to_SlotVec(&result.cmd_slots, (Slot){.kind = SLOT_SPEC, .as.spec = curr_tok.as.spec}); + break; + case TOK_PROCSUB_IN: + push_to_SlotVec(&result.cmd_slots, (Slot){.kind = SLOT_PROC_IN, .as.proc_reg= curr_tok.as.procsub_region}); + break; + case TOK_PROCSUB_OUT: + push_to_SlotVec(&result.cmd_slots, (Slot){.kind = SLOT_PROC_OUT, .as.proc_reg= curr_tok.as.procsub_region}); + break; + } + } + return result; +} + +ExpandedPipeline expand_pipeline(Pipeline* pl, ShellState *shstate) { + ExpandedPipeline exp_pl = make_ExpandedPipeline(256); + for (int i = 0; i < pl->count; i++) { + PipelineElement elem = *get_from_Pipeline(pl, i); + ExpandedPipelineElement exp_elem = expand_pipeline_element(elem, shstate); + push_to_ExpandedPipeline(&exp_pl, exp_elem); + } + return exp_pl; +} diff --git a/expand.h b/expand.h new file mode 100644 index 0000000..8d00a72 --- /dev/null +++ b/expand.h @@ -0,0 +1,32 @@ +# pragma once + +#include "exec.h" +#include "preproc.h" +#include "utils.h" + +typedef enum { + SLOT_STR, + SLOT_SPEC, + SLOT_PROC_IN, + SLOT_PROC_OUT, +} SlotKind; + +typedef struct { + SlotKind kind; + union { + char* str; + SpecialToken spec; + Region* proc_reg; + } as; +} Slot; + +DECLARE_VEC(Slot, SlotVec) + +typedef struct { + SlotVec cmd_slots; + Connector conn; +} ExpandedPipelineElement; + +DECLARE_VEC(ExpandedPipelineElement, ExpandedPipeline) + +ExpandedPipeline expand_pipeline(Pipeline* pl, ShellState* shstate); @@ -298,68 +298,21 @@ TokenPtrVec lex(char* input, PreprocArena* arena) { // Parsing -Connector parse_connector(Token* toks, size_t* tok_pos) { - Token tok = toks[*tok_pos]; - if (tok.kind != TOK_SPECIAL) exit(67); - switch (tok.as.spec) { - case PIPE: - (*tok_pos)++; - return CONN_PIPE; - case EOL: - (*tok_pos)++; - return CONN_EOL; - default: exit(76); - } -} - - -Command parse_command(Token* toks, size_t* tok_pos) { - TokenVec args = make_TokenVec(256); - RedirectVec redirects = make_RedirectVec(256); - while (true) { - Token curr_tok = toks[*tok_pos]; - if (curr_tok.kind == TOK_SPECIAL &&(curr_tok.as.spec == PIPE || curr_tok.as.spec == EOL)) { - break; - } - - switch (curr_tok.kind) { - case TOK_SPECIAL: - (*tok_pos)++; - Token name_tok = toks[*tok_pos]; - switch (curr_tok.as.spec) { - case WRITE_REDIR_TRUNC: - if(name_tok.kind != TOK_WORD) exit(1); - push_to_RedirectVec(&redirects, (Redirect){.kind = STDOUT_REDIR_TRUNC, .as.std_redir_filename = name_tok.as.word}); - break; - case WRITE_REDIR_APPEND: - if(name_tok.kind != TOK_WORD) exit(1); - push_to_RedirectVec(&redirects, (Redirect){.kind = STDOUT_REDIR_APPEND, .as.std_redir_filename = name_tok.as.word}); - break; - case READ_REDIR: - if(name_tok.kind != TOK_WORD) exit(1); - push_to_RedirectVec(&redirects, (Redirect){.kind = STDOUT_REDIR_APPEND, .as.std_redir_filename = name_tok.as.word}); - break; - default: - exit(69); - } - break; - default: - push_to_TokenVec(&args, curr_tok); - } - (*tok_pos)++; - } - return (Command){.args = args, .redirects = redirects}; -} - - Pipeline parse_tokstream(Token* toks) { size_t tok_pos = 0; Pipeline result = make_Pipeline(256); + TokenVec tok_buf = make_TokenVec(256); while (true) { - Command cmd = parse_command(toks, &tok_pos); - Connector conn = parse_connector(toks, &tok_pos); - push_to_Pipeline(&result, (PipelineElement){.cmd = cmd, .conn = conn}); - if (conn == CONN_EOL) break; + Token curr_tok = toks[tok_pos++]; + if (curr_tok.kind == TOK_SPECIAL && curr_tok.as.spec == PIPE) { + push_to_Pipeline(&result, (PipelineElement){.cmd_toks = tok_buf, .conn = CONN_PIPE}); + tok_buf = make_TokenVec(256); + } else if (curr_tok.kind == TOK_SPECIAL && curr_tok.as.spec == EOL) { + push_to_Pipeline(&result, (PipelineElement){.cmd_toks = tok_buf, .conn = CONN_EOL}); + break; + } else { + push_to_TokenVec(&tok_buf, curr_tok); + } } return result; } @@ -93,34 +93,6 @@ TokenPtrVec lex(char* input, PreprocArena* arena); // Parsing typedef enum { - STDIN_REDIR, - STDOUT_REDIR_TRUNC, - STDOUT_REDIR_APPEND, -} RedirKind; - - -typedef struct { - RedirKind kind; - - union { - Word std_redir_filename; - } as; -} Redirect; - - -DECLARE_VEC(Redirect, RedirectVec) - - - - -typedef struct { - TokenVec args; - RedirectVec redirects; - // TODO: prefix variable settings -} Command; - - -typedef enum { CONN_PIPE, CONN_EOL, // TODO: add the |& thingy @@ -129,7 +101,7 @@ typedef enum { DECLARE_MAYBE(Connector, MaybeConnector) typedef struct { - Command cmd; + TokenVec cmd_toks; Connector conn; } PipelineElement; @@ -62,3 +62,10 @@ void unset_map_key(KeyValMap* map, char* key) { } } } + + +char* get_var(char* varname, ShellState* shstate) { + MaybeStr maybe_varval = get_map_value(&shstate->shell_vars, varname); + if (maybe_varval.some == true) return maybe_varval.value; + return getenv(varname); +} @@ -97,6 +97,15 @@ typedef struct { char* val; } StrPair; DECLARE_VEC(StrPair, KeyValMap) + void set_map_pair(KeyValMap* map, char* key, char* val); MaybeStr get_map_value(KeyValMap* map, char* key); void unset_map_key(KeyValMap* map, char* key); + + +typedef struct { + KeyValMap aliases; + KeyValMap shell_vars; +} ShellState; + +char* get_var(char* varname, ShellState* shstate); |
