#include "expand.h" #include "preproc.h" #include "utils.h" #include 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; }