#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include "ast.h" bool mrsh_position_valid(const struct mrsh_position *pos) { return pos->line > 0; } bool mrsh_range_valid(const struct mrsh_range *range) { return mrsh_position_valid(&range->begin) && mrsh_position_valid(&range->end); } void mrsh_word_destroy(struct mrsh_word *word) { if (word == NULL) { return; } switch (word->type) { case MRSH_WORD_STRING:; struct mrsh_word_string *ws = mrsh_word_get_string(word); free(ws->str); free(ws); return; case MRSH_WORD_PARAMETER:; struct mrsh_word_parameter *wp = mrsh_word_get_parameter(word); free(wp->name); mrsh_word_destroy(wp->arg); free(wp); return; case MRSH_WORD_COMMAND:; struct mrsh_word_command *wc = mrsh_word_get_command(word); mrsh_program_destroy(wc->program); free(wc); return; case MRSH_WORD_ARITHMETIC:; struct mrsh_word_arithmetic *wa = mrsh_word_get_arithmetic(word); mrsh_word_destroy(wa->body); free(wa); return; case MRSH_WORD_LIST:; struct mrsh_word_list *wl = mrsh_word_get_list(word); for (size_t i = 0; i < wl->children.len; ++i) { struct mrsh_word *child = wl->children.data[i]; mrsh_word_destroy(child); } mrsh_array_finish(&wl->children); free(wl); return; } assert(false); } void mrsh_io_redirect_destroy(struct mrsh_io_redirect *redir) { if (redir == NULL) { return; } mrsh_word_destroy(redir->name); for (size_t i = 0; i < redir->here_document.len; ++i) { struct mrsh_word *line = redir->here_document.data[i]; mrsh_word_destroy(line); } mrsh_array_finish(&redir->here_document); free(redir); } void mrsh_assignment_destroy(struct mrsh_assignment *assign) { if (assign == NULL) { return; } free(assign->name); mrsh_word_destroy(assign->value); free(assign); } void command_list_array_finish(struct mrsh_array *cmds) { for (size_t i = 0; i < cmds->len; ++i) { struct mrsh_command_list *l = cmds->data[i]; mrsh_command_list_destroy(l); } mrsh_array_finish(cmds); } void case_item_destroy(struct mrsh_case_item *item) { for (size_t j = 0; j < item->patterns.len; ++j) { struct mrsh_word *pattern = item->patterns.data[j]; mrsh_word_destroy(pattern); } mrsh_array_finish(&item->patterns); command_list_array_finish(&item->body); free(item); } void mrsh_command_destroy(struct mrsh_command *cmd) { if (cmd == NULL) { return; } switch (cmd->type) { case MRSH_SIMPLE_COMMAND:; struct mrsh_simple_command *sc = mrsh_command_get_simple_command(cmd); mrsh_word_destroy(sc->name); for (size_t i = 0; i < sc->arguments.len; ++i) { struct mrsh_word *arg = sc->arguments.data[i]; mrsh_word_destroy(arg); } mrsh_array_finish(&sc->arguments); for (size_t i = 0; i < sc->io_redirects.len; ++i) { struct mrsh_io_redirect *redir = sc->io_redirects.data[i]; mrsh_io_redirect_destroy(redir); } mrsh_array_finish(&sc->io_redirects); for (size_t i = 0; i < sc->assignments.len; ++i) { struct mrsh_assignment *assign = sc->assignments.data[i]; mrsh_assignment_destroy(assign); } mrsh_array_finish(&sc->assignments); free(sc); return; case MRSH_BRACE_GROUP:; struct mrsh_brace_group *bg = mrsh_command_get_brace_group(cmd); command_list_array_finish(&bg->body); free(bg); return; case MRSH_SUBSHELL:; struct mrsh_subshell *s = mrsh_command_get_subshell(cmd); command_list_array_finish(&s->body); free(s); return; case MRSH_IF_CLAUSE:; struct mrsh_if_clause *ic = mrsh_command_get_if_clause(cmd); command_list_array_finish(&ic->condition); command_list_array_finish(&ic->body); mrsh_command_destroy(ic->else_part); free(ic); return; case MRSH_FOR_CLAUSE:; struct mrsh_for_clause *fc = mrsh_command_get_for_clause(cmd); free(fc->name); for (size_t i = 0; i < fc->word_list.len; ++i) { struct mrsh_word *word = fc->word_list.data[i]; mrsh_word_destroy(word); } mrsh_array_finish(&fc->word_list); command_list_array_finish(&fc->body); free(fc); return; case MRSH_LOOP_CLAUSE:; struct mrsh_loop_clause *lc = mrsh_command_get_loop_clause(cmd); command_list_array_finish(&lc->condition); command_list_array_finish(&lc->body); free(lc); return; case MRSH_CASE_CLAUSE:; struct mrsh_case_clause *cc = mrsh_command_get_case_clause(cmd); mrsh_word_destroy(cc->word); for (size_t i = 0; i < cc->items.len; ++i) { struct mrsh_case_item *item = cc->items.data[i]; case_item_destroy(item); } mrsh_array_finish(&cc->items); free(cc); return; case MRSH_FUNCTION_DEFINITION:; struct mrsh_function_definition *fd = mrsh_command_get_function_definition(cmd); free(fd->name); mrsh_command_destroy(fd->body); free(fd); return; } assert(0); } void mrsh_node_destroy(struct mrsh_node *node) { if (node == NULL) { return; } switch (node->type) { case MRSH_NODE_PIPELINE:; struct mrsh_pipeline *p = mrsh_node_get_pipeline(node); for (size_t i = 0; i < p->commands.len; ++i) { struct mrsh_command *cmd = p->commands.data[i]; mrsh_command_destroy(cmd); } mrsh_array_finish(&p->commands); free(p); return; case MRSH_NODE_BINOP:; struct mrsh_binop *binop = mrsh_node_get_binop(node); mrsh_node_destroy(binop->left); mrsh_node_destroy(binop->right); free(binop); return; } assert(0); } void mrsh_command_list_destroy(struct mrsh_command_list *l) { if (l == NULL) { return; } mrsh_node_destroy(l->node); free(l); } void mrsh_program_destroy(struct mrsh_program *prog) { if (prog == NULL) { return; } command_list_array_finish(&prog->body); free(prog); } struct mrsh_word_string *mrsh_word_string_create(char *str, bool single_quoted) { struct mrsh_word_string *ws = calloc(1, sizeof(struct mrsh_word_string)); ws->word.type = MRSH_WORD_STRING; ws->str = str; ws->single_quoted = single_quoted; return ws; } struct mrsh_word_parameter *mrsh_word_parameter_create(char *name, enum mrsh_word_parameter_op op, bool colon, struct mrsh_word *arg) { struct mrsh_word_parameter *wp = calloc(1, sizeof(struct mrsh_word_parameter)); wp->word.type = MRSH_WORD_PARAMETER; wp->name = name; wp->op = op; wp->colon = colon; wp->arg = arg; return wp; } struct mrsh_word_command *mrsh_word_command_create(struct mrsh_program *prog, bool back_quoted) { struct mrsh_word_command *wc = calloc(1, sizeof(struct mrsh_word_command)); wc->word.type = MRSH_WORD_COMMAND; wc->program = prog; wc->back_quoted = back_quoted; return wc; } struct mrsh_word_arithmetic *mrsh_word_arithmetic_create( struct mrsh_word *body) { struct mrsh_word_arithmetic *wa = calloc(1, sizeof(struct mrsh_word_arithmetic)); wa->word.type = MRSH_WORD_ARITHMETIC; wa->body = body; return wa; } struct mrsh_word_list *mrsh_word_list_create(struct mrsh_array *children, bool double_quoted) { struct mrsh_word_list *wl = calloc(1, sizeof(struct mrsh_word_list)); wl->word.type = MRSH_WORD_LIST; wl->children = *children; wl->double_quoted = double_quoted; return wl; } struct mrsh_word_string *mrsh_word_get_string(const struct mrsh_word *word) { assert(word->type == MRSH_WORD_STRING); return (struct mrsh_word_string *)word; } struct mrsh_word_parameter *mrsh_word_get_parameter( const struct mrsh_word *word) { assert(word->type == MRSH_WORD_PARAMETER); return (struct mrsh_word_parameter *)word; } struct mrsh_word_command *mrsh_word_get_command(const struct mrsh_word *word) { assert(word->type == MRSH_WORD_COMMAND); return (struct mrsh_word_command *)word; } struct mrsh_word_arithmetic *mrsh_word_get_arithmetic( const struct mrsh_word *word) { assert(word->type == MRSH_WORD_ARITHMETIC); return (struct mrsh_word_arithmetic *)word; } struct mrsh_word_list *mrsh_word_get_list(const struct mrsh_word *word) { assert(word->type == MRSH_WORD_LIST); return (struct mrsh_word_list *)word; } struct mrsh_simple_command *mrsh_simple_command_create(struct mrsh_word *name, struct mrsh_array *arguments, struct mrsh_array *io_redirects, struct mrsh_array *assignments) { struct mrsh_simple_command *cmd = calloc(1, sizeof(struct mrsh_simple_command)); cmd->command.type = MRSH_SIMPLE_COMMAND; cmd->name = name; cmd->arguments = *arguments; cmd->io_redirects = *io_redirects; cmd->assignments = *assignments; return cmd; } struct mrsh_brace_group *mrsh_brace_group_create(struct mrsh_array *body) { struct mrsh_brace_group *bg = calloc(1, sizeof(struct mrsh_brace_group)); bg->command.type = MRSH_BRACE_GROUP; bg->body = *body; return bg; } struct mrsh_subshell *mrsh_subshell_create(struct mrsh_array *body) { struct mrsh_subshell *s = calloc(1, sizeof(struct mrsh_subshell)); s->command.type = MRSH_SUBSHELL; s->body = *body; return s; } struct mrsh_if_clause *mrsh_if_clause_create(struct mrsh_array *condition, struct mrsh_array *body, struct mrsh_command *else_part) { struct mrsh_if_clause *ic = calloc(1, sizeof(struct mrsh_if_clause)); ic->command.type = MRSH_IF_CLAUSE; ic->condition = *condition; ic->body = *body; ic->else_part = else_part; return ic; } struct mrsh_for_clause *mrsh_for_clause_create(char *name, bool in, struct mrsh_array *word_list, struct mrsh_array *body) { struct mrsh_for_clause *fc = calloc(1, sizeof(struct mrsh_for_clause)); fc->command.type = MRSH_FOR_CLAUSE; fc->name = name; fc->in = in; fc->word_list = *word_list; fc->body = *body; return fc; } struct mrsh_loop_clause *mrsh_loop_clause_create(enum mrsh_loop_type type, struct mrsh_array *condition, struct mrsh_array *body) { struct mrsh_loop_clause *lc = calloc(1, sizeof(struct mrsh_loop_clause)); lc->command.type = MRSH_LOOP_CLAUSE; lc->type = type; lc->condition = *condition; lc->body = *body; return lc; } struct mrsh_case_clause *mrsh_case_clause_create(struct mrsh_word *word, struct mrsh_array *items) { struct mrsh_case_clause *cc = calloc(1, sizeof(struct mrsh_case_clause)); cc->command.type = MRSH_CASE_CLAUSE; cc->word = word; cc->items = *items; return cc; } struct mrsh_function_definition *mrsh_function_definition_create(char *name, struct mrsh_command *body) { struct mrsh_function_definition *fd = calloc(1, sizeof(struct mrsh_function_definition)); fd->command.type = MRSH_FUNCTION_DEFINITION; fd->name = name; fd->body = body; return fd; } struct mrsh_simple_command *mrsh_command_get_simple_command( const struct mrsh_command *cmd) { assert(cmd->type == MRSH_SIMPLE_COMMAND); return (struct mrsh_simple_command *)cmd; } struct mrsh_brace_group *mrsh_command_get_brace_group( const struct mrsh_command *cmd) { assert(cmd->type == MRSH_BRACE_GROUP); return (struct mrsh_brace_group *)cmd; } struct mrsh_subshell *mrsh_command_get_subshell( const struct mrsh_command *cmd) { assert(cmd->type == MRSH_SUBSHELL); return (struct mrsh_subshell *)cmd; } struct mrsh_if_clause *mrsh_command_get_if_clause( const struct mrsh_command *cmd) { assert(cmd->type == MRSH_IF_CLAUSE); return (struct mrsh_if_clause *)cmd; } struct mrsh_for_clause *mrsh_command_get_for_clause( const struct mrsh_command *cmd) { assert(cmd->type == MRSH_FOR_CLAUSE); return (struct mrsh_for_clause *)cmd; } struct mrsh_loop_clause *mrsh_command_get_loop_clause( const struct mrsh_command *cmd) { assert(cmd->type == MRSH_LOOP_CLAUSE); return (struct mrsh_loop_clause *)cmd; } struct mrsh_case_clause *mrsh_command_get_case_clause( const struct mrsh_command *cmd) { assert(cmd->type == MRSH_CASE_CLAUSE); return (struct mrsh_case_clause *)cmd; } struct mrsh_function_definition *mrsh_command_get_function_definition( const struct mrsh_command *cmd) { assert(cmd->type == MRSH_FUNCTION_DEFINITION); return (struct mrsh_function_definition *)cmd; } struct mrsh_pipeline *mrsh_pipeline_create(struct mrsh_array *commands, bool bang) { struct mrsh_pipeline *pl = calloc(1, sizeof(struct mrsh_pipeline)); pl->node.type = MRSH_NODE_PIPELINE; pl->commands = *commands; pl->bang = bang; return pl; } struct mrsh_binop *mrsh_binop_create(enum mrsh_binop_type type, struct mrsh_node *left, struct mrsh_node *right) { struct mrsh_binop *binop = calloc(1, sizeof(struct mrsh_binop)); binop->node.type = MRSH_NODE_BINOP; binop->type = type; binop->left = left; binop->right = right; return binop; } struct mrsh_pipeline *mrsh_node_get_pipeline(const struct mrsh_node *node) { assert(node->type == MRSH_NODE_PIPELINE); return (struct mrsh_pipeline *)node; } struct mrsh_binop *mrsh_node_get_binop(const struct mrsh_node *node) { assert(node->type == MRSH_NODE_BINOP); return (struct mrsh_binop *)node; } static void position_next(struct mrsh_position *dst, const struct mrsh_position *src) { *dst = *src; ++dst->offset; ++dst->column; } void mrsh_word_range(struct mrsh_word *word, struct mrsh_position *begin, struct mrsh_position *end) { if (begin == NULL && end == NULL) { return; } struct mrsh_position _begin, _end; if (begin == NULL) { begin = &_begin; } if (end == NULL) { end = &_end; } switch (word->type) { case MRSH_WORD_STRING:; struct mrsh_word_string *ws = mrsh_word_get_string(word); *begin = ws->range.begin; *end = ws->range.end; return; case MRSH_WORD_PARAMETER:; struct mrsh_word_parameter *wp = mrsh_word_get_parameter(word); *begin = wp->dollar_pos; if (mrsh_position_valid(&wp->rbrace_pos)) { position_next(end, &wp->rbrace_pos); } else { *end = wp->name_range.end; } return; case MRSH_WORD_COMMAND:; struct mrsh_word_command *wc = mrsh_word_get_command(word); *begin = wc->range.begin; *end = wc->range.end; return; case MRSH_WORD_ARITHMETIC: assert(false); // TODO case MRSH_WORD_LIST:; struct mrsh_word_list *wl = mrsh_word_get_list(word); if (wl->children.len == 0) { *begin = *end = (struct mrsh_position){0}; } else { struct mrsh_word *first = wl->children.data[0]; struct mrsh_word *last = wl->children.data[wl->children.len - 1]; mrsh_word_range(first, begin, NULL); mrsh_word_range(last, NULL, end); } return; } assert(false); } void mrsh_command_range(struct mrsh_command *cmd, struct mrsh_position *begin, struct mrsh_position *end) { if (begin == NULL && end == NULL) { return; } struct mrsh_position _begin, _end; if (begin == NULL) { begin = &_begin; } if (end == NULL) { end = &_end; } switch (cmd->type) { case MRSH_SIMPLE_COMMAND:; struct mrsh_simple_command *sc = mrsh_command_get_simple_command(cmd); if (sc->name != NULL) { mrsh_word_range(sc->name, begin, end); } else { assert(sc->assignments.len > 0); struct mrsh_assignment *first = sc->assignments.data[0]; *begin = first->name_range.begin; *end = *begin; // That's a lie, but it'll be fixed by the code below } struct mrsh_position maybe_end; for (size_t i = 0; i < sc->arguments.len; ++i) { struct mrsh_word *arg = sc->arguments.data[i]; mrsh_word_range(arg, NULL, &maybe_end); if (maybe_end.offset > end->offset) { *end = maybe_end; } } for (size_t i = 0; i < sc->io_redirects.len; ++i) { struct mrsh_io_redirect *redir = sc->io_redirects.data[i]; mrsh_word_range(redir->name, NULL, &maybe_end); if (maybe_end.offset > end->offset) { *end = maybe_end; } } for (size_t i = 0; i < sc->assignments.len; ++i) { struct mrsh_assignment *assign = sc->assignments.data[i]; mrsh_word_range(assign->value, NULL, &maybe_end); if (maybe_end.offset > end->offset) { *end = maybe_end; } } return; case MRSH_BRACE_GROUP:; struct mrsh_brace_group *bg = mrsh_command_get_brace_group(cmd); *begin = bg->lbrace_pos; position_next(end, &bg->rbrace_pos); return; case MRSH_SUBSHELL:; struct mrsh_subshell *s = mrsh_command_get_subshell(cmd); *begin = s->lparen_pos; position_next(end, &s->rparen_pos); return; case MRSH_IF_CLAUSE:; struct mrsh_if_clause *ic = mrsh_command_get_if_clause(cmd); *begin = ic->if_range.begin; *end = ic->fi_range.end; return; case MRSH_FOR_CLAUSE:; struct mrsh_for_clause *fc = mrsh_command_get_for_clause(cmd); *begin = fc->for_range.begin; *end = fc->done_range.end; return; case MRSH_LOOP_CLAUSE:; struct mrsh_loop_clause *lc = mrsh_command_get_loop_clause(cmd); *begin = lc->while_until_range.begin; *end = lc->done_range.end; return; case MRSH_CASE_CLAUSE:; struct mrsh_case_clause *cc = mrsh_command_get_case_clause(cmd); *begin = cc->case_range.begin; *end = cc->esac_range.end; return; case MRSH_FUNCTION_DEFINITION:; struct mrsh_function_definition *fd = mrsh_command_get_function_definition(cmd); *begin = fd->name_range.begin; mrsh_command_range(fd->body, NULL, end); } assert(false); } static void word_str(struct mrsh_word *word, struct mrsh_buffer *buf) { switch (word->type) { case MRSH_WORD_STRING:; struct mrsh_word_string *ws = mrsh_word_get_string(word); mrsh_buffer_append(buf, ws->str, strlen(ws->str)); return; case MRSH_WORD_PARAMETER: case MRSH_WORD_COMMAND: case MRSH_WORD_ARITHMETIC: assert(false); case MRSH_WORD_LIST:; struct mrsh_word_list *wl = mrsh_word_get_list(word); for (size_t i = 0; i < wl->children.len; ++i) { struct mrsh_word *child = wl->children.data[i]; word_str(child, buf); } return; } assert(false); } char *mrsh_word_str(struct mrsh_word *word) { struct mrsh_buffer buf = {0}; word_str(word, &buf); mrsh_buffer_append_char(&buf, '\0'); return mrsh_buffer_steal(&buf); } struct mrsh_word *mrsh_word_copy(const struct mrsh_word *word) { switch (word->type) { case MRSH_WORD_STRING:; struct mrsh_word_string *ws = mrsh_word_get_string(word); struct mrsh_word_string *ws_copy = mrsh_word_string_create(strdup(ws->str), ws->single_quoted); return &ws_copy->word; case MRSH_WORD_PARAMETER:; struct mrsh_word_parameter *wp = mrsh_word_get_parameter(word); struct mrsh_word *arg = NULL; if (wp->arg != NULL) { arg = mrsh_word_copy(wp->arg); } struct mrsh_word_parameter *wp_copy = mrsh_word_parameter_create( strdup(wp->name), wp->op, wp->colon, arg); return &wp_copy->word; case MRSH_WORD_COMMAND:; struct mrsh_word_command *wc = mrsh_word_get_command(word); struct mrsh_word_command *wc_copy = mrsh_word_command_create( mrsh_program_copy(wc->program), wc->back_quoted); return &wc_copy->word; case MRSH_WORD_ARITHMETIC:; struct mrsh_word_arithmetic *wa = mrsh_word_get_arithmetic(word); struct mrsh_word_arithmetic *wa_copy = mrsh_word_arithmetic_create( mrsh_word_copy(wa->body)); return &wa_copy->word; case MRSH_WORD_LIST:; struct mrsh_word_list *wl = mrsh_word_get_list(word); struct mrsh_array children = {0}; mrsh_array_reserve(&children, wl->children.len); for (size_t i = 0; i < wl->children.len; ++i) { struct mrsh_word *child = wl->children.data[i]; mrsh_array_add(&children, mrsh_word_copy(child)); } struct mrsh_word_list *wl_copy = mrsh_word_list_create(&children, wl->double_quoted); return &wl_copy->word; } assert(0); } struct mrsh_io_redirect *mrsh_io_redirect_copy( const struct mrsh_io_redirect *redir) { struct mrsh_io_redirect *redir_copy = calloc(1, sizeof(struct mrsh_io_redirect)); redir_copy->io_number = redir->io_number; redir_copy->op = redir->op; redir_copy->name = mrsh_word_copy(redir->name); mrsh_array_reserve(&redir_copy->here_document, redir->here_document.len); for (size_t i = 0; i < redir->here_document.len; ++i) { struct mrsh_word *line = redir->here_document.data[i]; mrsh_array_add(&redir_copy->here_document, mrsh_word_copy(line)); } return redir_copy; } struct mrsh_assignment *mrsh_assignment_copy( const struct mrsh_assignment *assign) { struct mrsh_assignment *assign_copy = calloc(1, sizeof(struct mrsh_assignment)); assign_copy->name = strdup(assign->name); assign_copy->value = mrsh_word_copy(assign->value); return assign_copy; } static void command_list_array_copy(struct mrsh_array *dst, const struct mrsh_array *src) { mrsh_array_reserve(dst, src->len); for (size_t i = 0; i < src->len; ++i) { struct mrsh_command_list *l = src->data[i]; mrsh_array_add(dst, mrsh_command_list_copy(l)); } } static struct mrsh_case_item *case_item_copy(const struct mrsh_case_item *ci) { struct mrsh_case_item *ci_copy = calloc(1, sizeof(struct mrsh_case_item)); mrsh_array_reserve(&ci_copy->patterns, ci->patterns.len); for (size_t i = 0; i < ci->patterns.len; ++i) { struct mrsh_word *pattern = ci->patterns.data[i]; mrsh_array_add(&ci_copy->patterns, mrsh_word_copy(pattern)); } command_list_array_copy(&ci_copy->body, &ci->body); return ci_copy; } struct mrsh_command *mrsh_command_copy(const struct mrsh_command *cmd) { switch (cmd->type) { case MRSH_SIMPLE_COMMAND:; struct mrsh_simple_command *sc = mrsh_command_get_simple_command(cmd); struct mrsh_word *name = NULL; if (sc->name != NULL) { name = mrsh_word_copy(sc->name); } struct mrsh_array arguments = {0}; mrsh_array_reserve(&arguments, sc->arguments.len); for (size_t i = 0; i < sc->arguments.len; ++i) { struct mrsh_word *arg = sc->arguments.data[i]; mrsh_array_add(&arguments, mrsh_word_copy(arg)); } struct mrsh_array io_redirects = {0}; mrsh_array_reserve(&io_redirects, sc->io_redirects.len); for (size_t i = 0; i < sc->io_redirects.len; ++i) { struct mrsh_io_redirect *redir = sc->io_redirects.data[i]; mrsh_array_add(&io_redirects, mrsh_io_redirect_copy(redir)); } struct mrsh_array assignments = {0}; mrsh_array_reserve(&assignments, sc->assignments.len); for (size_t i = 0; i < sc->assignments.len; ++i) { struct mrsh_assignment *assign = sc->assignments.data[i]; mrsh_array_add(&assignments, mrsh_assignment_copy(assign)); } struct mrsh_simple_command *sc_copy = mrsh_simple_command_create( name, &arguments, &io_redirects, &assignments); return &sc_copy->command; case MRSH_BRACE_GROUP:; struct mrsh_brace_group *bg = mrsh_command_get_brace_group(cmd); struct mrsh_array bg_body = {0}; command_list_array_copy(&bg_body, &bg->body); struct mrsh_brace_group *bg_copy = mrsh_brace_group_create(&bg_body); return &bg_copy->command; case MRSH_SUBSHELL:; struct mrsh_subshell *ss = mrsh_command_get_subshell(cmd); struct mrsh_array ss_body = {0}; command_list_array_copy(&ss_body, &ss->body); struct mrsh_subshell *ss_copy = mrsh_subshell_create(&ss_body); return &ss_copy->command; case MRSH_IF_CLAUSE:; struct mrsh_if_clause *ic = mrsh_command_get_if_clause(cmd); struct mrsh_array ic_condition = {0}; command_list_array_copy(&ic_condition, &ic->condition); struct mrsh_array ic_body = {0}; command_list_array_copy(&ic_body, &ic->body); struct mrsh_command *else_part = NULL; if (ic->else_part != NULL) { else_part = mrsh_command_copy(ic->else_part); } struct mrsh_if_clause *ic_copy = mrsh_if_clause_create(&ic_condition, &ic_body, else_part); return &ic_copy->command; case MRSH_FOR_CLAUSE:; struct mrsh_for_clause *fc = mrsh_command_get_for_clause(cmd); struct mrsh_array word_list = {0}; mrsh_array_reserve(&word_list, fc->word_list.len); for (size_t i = 0; i < fc->word_list.len; ++i) { struct mrsh_word *word = fc->word_list.data[i]; mrsh_array_add(&word_list, mrsh_word_copy(word)); } struct mrsh_array fc_body = {0}; command_list_array_copy(&fc_body, &fc->body); struct mrsh_for_clause *fc_copy = mrsh_for_clause_create( strdup(fc->name), fc->in, &word_list, &fc_body); return &fc_copy->command; case MRSH_LOOP_CLAUSE:; struct mrsh_loop_clause *lc = mrsh_command_get_loop_clause(cmd); struct mrsh_array lc_condition = {0}; command_list_array_copy(&lc_condition, &lc->condition); struct mrsh_array lc_body = {0}; command_list_array_copy(&lc_body, &lc->body); struct mrsh_loop_clause *lc_copy = mrsh_loop_clause_create(lc->type, &lc_condition, &lc_body); return &lc_copy->command; case MRSH_CASE_CLAUSE:; struct mrsh_case_clause *cc = mrsh_command_get_case_clause(cmd); struct mrsh_array items = {0}; mrsh_array_reserve(&items, cc->items.len); for (size_t i = 0; i < cc->items.len; ++i) { struct mrsh_case_item *ci = cc->items.data[i]; mrsh_array_add(&items, case_item_copy(ci)); } struct mrsh_case_clause *cc_copy = mrsh_case_clause_create(mrsh_word_copy(cc->word), &items); return &cc_copy->command; case MRSH_FUNCTION_DEFINITION:; struct mrsh_function_definition *fd = mrsh_command_get_function_definition(cmd); struct mrsh_function_definition *fd_copy = mrsh_function_definition_create(strdup(fd->name), mrsh_command_copy(fd->body)); return &fd_copy->command; } assert(0); } struct mrsh_node *mrsh_node_copy(const struct mrsh_node *node) { switch (node->type) { case MRSH_NODE_PIPELINE:; struct mrsh_pipeline *pl = mrsh_node_get_pipeline(node); struct mrsh_array commands = {0}; mrsh_array_reserve(&commands, pl->commands.len); for (size_t i = 0; i < pl->commands.len; ++i) { struct mrsh_command *cmd = pl->commands.data[i]; mrsh_array_add(&commands, mrsh_command_copy(cmd)); } struct mrsh_pipeline *p_copy = mrsh_pipeline_create(&commands, pl->bang); return &p_copy->node; case MRSH_NODE_BINOP:; struct mrsh_binop *binop = mrsh_node_get_binop(node); struct mrsh_binop *binop_copy = mrsh_binop_create(binop->type, mrsh_node_copy(binop->left), mrsh_node_copy(binop->right)); return &binop_copy->node; } assert(0); } struct mrsh_command_list *mrsh_command_list_copy( const struct mrsh_command_list *l) { struct mrsh_command_list *l_copy = calloc(1, sizeof(struct mrsh_command_list)); l_copy->node = mrsh_node_copy(l->node); l_copy->ampersand = l->ampersand; return l_copy; } struct mrsh_program *mrsh_program_copy(const struct mrsh_program *prog) { struct mrsh_program *prog_copy = calloc(1, sizeof(struct mrsh_program)); command_list_array_copy(&prog_copy->body, &prog->body); return prog_copy; }