From b443cd1876b452c9a99ad41008a55d1ff4cbe3d6 Mon Sep 17 00:00:00 2001 From: "william.valenduc" Date: Mon, 19 Jan 2026 17:55:16 +0000 Subject: [PATCH] feat(expansion) 10291 expansion --- src/expansion/expansion.c | 19 +++++++++++++++---- src/utils/vars/vars.c | 23 +++++++++++++++++++++++ src/utils/vars/vars.h | 13 ++++++++++++- tests/unit/expansion/expand.c | 34 +++++++++++++++++++++++++--------- 4 files changed, 75 insertions(+), 14 deletions(-) diff --git a/src/expansion/expansion.c b/src/expansion/expansion.c index dca13ec..407e2f7 100644 --- a/src/expansion/expansion.c +++ b/src/expansion/expansion.c @@ -86,10 +86,21 @@ static bool expand_var(char **str, size_t pos, const struct hash_map *vars) size_t r = parse_var_name(*str + pos, &var_name); if (r > 0 && var_name != NULL) { - char *value = get_var_or_env(vars, var_name); - if (value == NULL) - // Undefined variable: expand to empty string - value = ""; + char *value; + char rnd_str[10]; // max 5 digits + null terminator + if (strcmp(var_name, "RANDOM") == 0) + { + short rnd = short_random(); + snprintf(rnd_str, 10, "%d", rnd); + value = rnd_str; + } + else + { + value = get_var_or_env(vars, var_name); + if (value == NULL) + // Undefined variable: expand to empty string + value = ""; + } char *p = insert_into(*str, value, pos, r); free(var_name); diff --git a/src/utils/vars/vars.c b/src/utils/vars/vars.c index da3afa2..9a4f13f 100644 --- a/src/utils/vars/vars.c +++ b/src/utils/vars/vars.c @@ -2,8 +2,11 @@ #include "vars.h" #include +#include #include #include +#include +#include #include "../hash_map/hash_map.h" @@ -14,6 +17,26 @@ struct hash_map *vars_init(void) return hash_map_init(VARS_INITIAL_SIZE); } +void vars_default(struct hash_map *vars) +{ + set_var_copy(vars, "?", "0"); + pid_t pid = getpid(); + char pid_str[20]; + snprintf(pid_str, sizeof(pid_str), "%d", pid); + set_var_copy(vars, "$$", pid_str); +} + +short short_random(void) +{ + static bool seeded = false; + if (!seeded) + { + srand((unsigned)time(NULL)); + seeded = true; + } + return (short)(rand() & 0x7FFF); // force 16 bits positive +} + char *get_var(const struct hash_map *vars, const char *key) { return (char *)hash_map_get(vars, key); diff --git a/src/utils/vars/vars.h b/src/utils/vars/vars.h index de1c4c6..85fb5ee 100644 --- a/src/utils/vars/vars.h +++ b/src/utils/vars/vars.h @@ -10,6 +10,16 @@ */ struct hash_map *vars_init(void); +/** + * Set default variables. + */ +void vars_default(struct hash_map *vars); + +/** + * Generate a random short integer (16 bits positive [0-32767]). + */ +short short_random(void); + /** * Get the value of a variable, NULL if not found. */ @@ -26,7 +36,8 @@ char *get_var_or_env(const struct hash_map *vars, const char *key); * the hash_map and need to be on the heap. Returns true on success, false on * failure. */ -bool set_var(struct hash_map *vars, const char *key, const char *value); +bool set_var(struct hash_map *vars, const char *key, const char *value, + bool *updated); /** * Same as set_var, but makes copies of key and value so you don't have to worry diff --git a/tests/unit/expansion/expand.c b/tests/unit/expansion/expand.c index 1e25d7c..cb84c80 100644 --- a/tests/unit/expansion/expand.c +++ b/tests/unit/expansion/expand.c @@ -42,7 +42,7 @@ Test(expand, single_quotes_no_expansion) cr_assert_str_eq((char *)command2->command->data, "echo $VAR", "Variable should not expand inside single quotes"); ast_free(&ast); - hash_map_free(vars); + hash_map_free(&vars); } Test(expand, single_dollar) @@ -61,7 +61,7 @@ Test(expand, single_dollar) cr_assert_str_eq((char *)command2->command->data, "echo $ sign", "Variable should not expand inside single quotes"); ast_free(&ast); - hash_map_free(vars); + hash_map_free(&vars); } Test(expand, empty_braces_no_expansion) @@ -78,7 +78,7 @@ Test(expand, empty_braces_no_expansion) struct ast_command *command2 = expand(ast_command, vars); cr_assert_null(command2, "Expansion should fail on empty braces"); ast_free(&ast); - hash_map_free(vars); + hash_map_free(&vars); } Test(expand, basic_expansion) @@ -97,7 +97,7 @@ Test(expand, basic_expansion) cr_assert_str_eq((char *)command2->command->data, "echo expanded", "Variable should expand correctly"); ast_free(&ast); - hash_map_free(vars); + hash_map_free(&vars); } Test(expand, multiple_expansion) @@ -119,7 +119,7 @@ Test(expand, multiple_expansion) "echo expanded values here", "Multiple variables should expand correctly"); ast_free(&ast); - hash_map_free(vars); + hash_map_free(&vars); } Test(expand, env_variable) @@ -154,7 +154,7 @@ Test(expand, undefined_variable) cr_assert_str_eq((char *)command2->command->data, "echo ", "Undefined variable should expand to empty string"); ast_free(&ast); - hash_map_free(vars); + hash_map_free(&vars); } Test(expand, nested_expansion) @@ -174,7 +174,7 @@ Test(expand, nested_expansion) cr_assert_str_eq((char *)command2->command->data, "echo expanded", "Nested variable should expand correctly"); ast_free(&ast); - hash_map_free(vars); + hash_map_free(&vars); } Test(expand, mixed_quotes_expansion) @@ -196,7 +196,7 @@ Test(expand, mixed_quotes_expansion) "Variable in double quotes should expand, while variable " "in single quotes should not"); ast_free(&ast); - hash_map_free(vars); + hash_map_free(&vars); } Test(expand, adjacent_variables) @@ -216,5 +216,21 @@ Test(expand, adjacent_variables) cr_assert_str_eq((char *)command2->command->data, "echo helloworld", "Adjacent variables should expand correctly"); ast_free(&ast); - hash_map_free(vars); + hash_map_free(&vars); +} + +Test(expand, random) +{ + char str[] = "$RANDOM"; + char *str_heap = strdup(str); + struct list *list = list_append(NULL, str_heap); + struct ast *ast = ast_create_command(list); + struct ast_command *ast_command = ast_get_command(ast); + + struct ast_command *command2 = expand(ast_command, NULL); + cr_assert_not_null(command2, "Expansion returned NULL"); + int rnd = atoi((char *)command2->command->data); + cr_assert(rnd >= 0 && rnd <= 32767, + "RANDOM variable should expand to a value between 0 and 32767"); + ast_free(&ast); }