~emersion/mrsh

c0dc3f0781b3f1d8c34d8d1c081bd7ee32316354 — Simon Ser 8 months ago 776206c
Introduce expand_word

This function performs all word expansions at once.
3 files changed, 44 insertions(+), 41 deletions(-)

M include/shell/task.h
M shell/task/simple_command.c
M shell/task/word.c
M include/shell/task.h => include/shell/task.h +4 -0
@@ 25,6 25,10 @@ struct mrsh_context;

/* Perform parameter expansion, command substitution and arithmetic expansion. */
int run_word(struct mrsh_context *ctx, struct mrsh_word **word_ptr);
/* Perform all word expansions, as specified in section 2.6. Fills `fields`
 * with `char *` elements. Not suitable for assignments. */
int expand_word(struct mrsh_context *ctx, const struct mrsh_word *word,
	struct mrsh_array *fields);
int run_simple_command(struct mrsh_context *ctx, struct mrsh_simple_command *sc);
int run_command(struct mrsh_context *ctx, struct mrsh_command *cmd);
int run_and_or_list(struct mrsh_context *ctx, struct mrsh_and_or_list *and_or_list);

M shell/task/simple_command.c => shell/task/simple_command.c +11 -41
@@ 227,32 227,6 @@ static int expand_assignments(struct mrsh_context *ctx,
	return 0;
}

static void get_args(struct mrsh_array *args, struct mrsh_simple_command *sc,
		struct mrsh_context *ctx) {
	struct mrsh_array fields = {0};
	const char *ifs = mrsh_env_get(ctx->state, "IFS", NULL);
	split_fields(&fields, sc->name, ifs);
	for (size_t i = 0; i < sc->arguments.len; ++i) {
		struct mrsh_word *word = sc->arguments.data[i];
		split_fields(&fields, word, ifs);
	}
	assert(fields.len > 0);

	if (ctx->state->options & MRSH_OPT_NOGLOB) {
		get_fields_str(args, &fields);
	} else {
		expand_pathnames(args, &fields);
	}

	for (size_t i = 0; i < fields.len; ++i) {
		mrsh_word_destroy(fields.data[i]);
	}
	mrsh_array_finish(&fields);

	assert(args->len > 0);
	mrsh_array_add(args, NULL);
}

static struct mrsh_simple_command *copy_simple_command(
		const struct mrsh_simple_command *sc) {
	struct mrsh_command *cmd = mrsh_command_copy(&sc->command);


@@ 296,26 270,25 @@ int run_simple_command(struct mrsh_context *ctx, struct mrsh_simple_command *sc)
	// we'll mutate the tree
	sc = copy_simple_command(sc);

	expand_tilde(state, &sc->name, false);
	int ret = run_word(ctx, &sc->name);
	if (ret < 0) {
		return ret;
	}

	ret = expand_assignments(ctx, &sc->assignments);
	struct mrsh_array args = {0};
	int ret = expand_word(ctx, sc->name, &args);
	if (ret < 0) {
		return ret;
	}

	for (size_t i = 0; i < sc->arguments.len; ++i) {
		struct mrsh_word **arg_ptr =
			(struct mrsh_word **)&sc->arguments.data[i];
		expand_tilde(state, arg_ptr, false);
		ret = run_word(ctx, arg_ptr);
		struct mrsh_word *arg = sc->arguments.data[i];
		ret = expand_word(ctx, arg, &args);
		if (ret < 0) {
			return ret;
		}
	}
	assert(args.len > 0);
	mrsh_array_add(&args, NULL);

	ret = expand_assignments(ctx, &sc->assignments);
	if (ret < 0) {
		return ret;
	}

	for (size_t i = 0; i < sc->io_redirects.len; ++i) {
		struct mrsh_io_redirect *redir = sc->io_redirects.data[i];


@@ 335,9 308,6 @@ int run_simple_command(struct mrsh_context *ctx, struct mrsh_simple_command *sc)
		}
	}

	struct mrsh_array args = {0};
	get_args(&args, sc, ctx);

	char **argv = (char **)args.data;
	int argc = args.len - 1; // argv is NULL-terminated
	const char *argv_0 = argv[0];

M shell/task/word.c => shell/task/word.c +29 -0
@@ 591,3 591,32 @@ static int _run_word(struct mrsh_context *ctx, struct mrsh_word **word_ptr,
int run_word(struct mrsh_context *ctx, struct mrsh_word **word_ptr) {
	return _run_word(ctx, word_ptr, false);
}

int expand_word(struct mrsh_context *ctx, const struct mrsh_word *_word,
		struct mrsh_array *expanded_fields) {
	struct mrsh_word *word = mrsh_word_copy(_word);
	expand_tilde(ctx->state, &word, false);

	int ret = run_word(ctx, &word);
	if (ret < 0) {
		return ret;
	}

	struct mrsh_array fields = {0};
	const char *ifs = mrsh_env_get(ctx->state, "IFS", NULL);
	split_fields(&fields, word, ifs);
	mrsh_word_destroy(word);

	if (ctx->state->options & MRSH_OPT_NOGLOB) {
		get_fields_str(expanded_fields, &fields);
	} else {
		expand_pathnames(expanded_fields, &fields);
	}

	for (size_t i = 0; i < fields.len; ++i) {
		mrsh_word_destroy(fields.data[i]);
	}
	mrsh_array_finish(&fields);

	return ret;
}