feat(expansion) 10291 expansion

This commit is contained in:
william.valenduc 2026-01-19 17:55:16 +00:00
parent 2ebf56dde7
commit b443cd1876
4 changed files with 75 additions and 14 deletions

View file

@ -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); size_t r = parse_var_name(*str + pos, &var_name);
if (r > 0 && var_name != NULL) if (r > 0 && var_name != NULL)
{ {
char *value = get_var_or_env(vars, var_name); char *value;
if (value == NULL) char rnd_str[10]; // max 5 digits + null terminator
// Undefined variable: expand to empty string if (strcmp(var_name, "RANDOM") == 0)
value = ""; {
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); char *p = insert_into(*str, value, pos, r);
free(var_name); free(var_name);

View file

@ -2,8 +2,11 @@
#include "vars.h" #include "vars.h"
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <time.h>
#include <unistd.h>
#include "../hash_map/hash_map.h" #include "../hash_map/hash_map.h"
@ -14,6 +17,26 @@ struct hash_map *vars_init(void)
return hash_map_init(VARS_INITIAL_SIZE); 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) char *get_var(const struct hash_map *vars, const char *key)
{ {
return (char *)hash_map_get(vars, key); return (char *)hash_map_get(vars, key);

View file

@ -10,6 +10,16 @@
*/ */
struct hash_map *vars_init(void); 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. * 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 * the hash_map and need to be on the heap. Returns true on success, false on
* failure. * 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 * Same as set_var, but makes copies of key and value so you don't have to worry

View file

@ -42,7 +42,7 @@ Test(expand, single_quotes_no_expansion)
cr_assert_str_eq((char *)command2->command->data, "echo $VAR", cr_assert_str_eq((char *)command2->command->data, "echo $VAR",
"Variable should not expand inside single quotes"); "Variable should not expand inside single quotes");
ast_free(&ast); ast_free(&ast);
hash_map_free(vars); hash_map_free(&vars);
} }
Test(expand, single_dollar) Test(expand, single_dollar)
@ -61,7 +61,7 @@ Test(expand, single_dollar)
cr_assert_str_eq((char *)command2->command->data, "echo $ sign", cr_assert_str_eq((char *)command2->command->data, "echo $ sign",
"Variable should not expand inside single quotes"); "Variable should not expand inside single quotes");
ast_free(&ast); ast_free(&ast);
hash_map_free(vars); hash_map_free(&vars);
} }
Test(expand, empty_braces_no_expansion) Test(expand, empty_braces_no_expansion)
@ -78,7 +78,7 @@ Test(expand, empty_braces_no_expansion)
struct ast_command *command2 = expand(ast_command, vars); struct ast_command *command2 = expand(ast_command, vars);
cr_assert_null(command2, "Expansion should fail on empty braces"); cr_assert_null(command2, "Expansion should fail on empty braces");
ast_free(&ast); ast_free(&ast);
hash_map_free(vars); hash_map_free(&vars);
} }
Test(expand, basic_expansion) Test(expand, basic_expansion)
@ -97,7 +97,7 @@ Test(expand, basic_expansion)
cr_assert_str_eq((char *)command2->command->data, "echo expanded", cr_assert_str_eq((char *)command2->command->data, "echo expanded",
"Variable should expand correctly"); "Variable should expand correctly");
ast_free(&ast); ast_free(&ast);
hash_map_free(vars); hash_map_free(&vars);
} }
Test(expand, multiple_expansion) Test(expand, multiple_expansion)
@ -119,7 +119,7 @@ Test(expand, multiple_expansion)
"echo expanded values here", "echo expanded values here",
"Multiple variables should expand correctly"); "Multiple variables should expand correctly");
ast_free(&ast); ast_free(&ast);
hash_map_free(vars); hash_map_free(&vars);
} }
Test(expand, env_variable) Test(expand, env_variable)
@ -154,7 +154,7 @@ Test(expand, undefined_variable)
cr_assert_str_eq((char *)command2->command->data, "echo ", cr_assert_str_eq((char *)command2->command->data, "echo ",
"Undefined variable should expand to empty string"); "Undefined variable should expand to empty string");
ast_free(&ast); ast_free(&ast);
hash_map_free(vars); hash_map_free(&vars);
} }
Test(expand, nested_expansion) Test(expand, nested_expansion)
@ -174,7 +174,7 @@ Test(expand, nested_expansion)
cr_assert_str_eq((char *)command2->command->data, "echo expanded", cr_assert_str_eq((char *)command2->command->data, "echo expanded",
"Nested variable should expand correctly"); "Nested variable should expand correctly");
ast_free(&ast); ast_free(&ast);
hash_map_free(vars); hash_map_free(&vars);
} }
Test(expand, mixed_quotes_expansion) Test(expand, mixed_quotes_expansion)
@ -196,7 +196,7 @@ Test(expand, mixed_quotes_expansion)
"Variable in double quotes should expand, while variable " "Variable in double quotes should expand, while variable "
"in single quotes should not"); "in single quotes should not");
ast_free(&ast); ast_free(&ast);
hash_map_free(vars); hash_map_free(&vars);
} }
Test(expand, adjacent_variables) Test(expand, adjacent_variables)
@ -216,5 +216,21 @@ Test(expand, adjacent_variables)
cr_assert_str_eq((char *)command2->command->data, "echo helloworld", cr_assert_str_eq((char *)command2->command->data, "echo helloworld",
"Adjacent variables should expand correctly"); "Adjacent variables should expand correctly");
ast_free(&ast); 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);
} }