summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
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
commitca675175742174d6bfcd0263583f840e250fc58f (patch)
treecd11ec9f8345fa31dddb2a5f0c21d59bb19816b1
parent24ba34266cc977b22d777bceca9683a45dd73042 (diff)
quicksaving
-rw-r--r--exec.c188
-rw-r--r--exec.h9
-rw-r--r--expand.c101
-rw-r--r--expand.h32
-rw-r--r--preproc.c69
-rw-r--r--preproc.h30
-rw-r--r--utils.c7
-rw-r--r--utils.h9
8 files changed, 214 insertions, 231 deletions
diff --git a/exec.c b/exec.c
index 318638e..d683099 100644
--- a/exec.c
+++ b/exec.c
@@ -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);
}
diff --git a/exec.h b/exec.h
index ca0b1a5..9ee8164 100644
--- a/exec.h
+++ b/exec.h
@@ -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);
diff --git a/preproc.c b/preproc.c
index c982636..1d9e921 100644
--- a/preproc.c
+++ b/preproc.c
@@ -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;
}
diff --git a/preproc.h b/preproc.h
index 1ba76cf..7907f9d 100644
--- a/preproc.h
+++ b/preproc.h
@@ -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;
diff --git a/utils.c b/utils.c
index 5ecd0a8..1f08445 100644
--- a/utils.c
+++ b/utils.c
@@ -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);
+}
diff --git a/utils.h b/utils.h
index 2463b45..a213c71 100644
--- a/utils.h
+++ b/utils.h
@@ -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);