c0dc3f0781b3f1d8c34d8d1c081bd7ee32316354 — Simon Ser 16 days 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;
+}