-
Notifications
You must be signed in to change notification settings - Fork 0
2. Minishell Structure
Minishell maintains its internal state using several key structures.
These structures manage environment variables, built-in commands, and the shell state itself.
Minishell maintains an internal state for command execution, built-in handling, and process control.
The main structure of the shell.
-
env – A dynamically allocated NULL-terminated array of exported environment variables in
"key=value"format. Updated when variables are modified. - hash_table – Pointer to the hash table storing all environment variables.
- builtin – A list of built-in commands available in the shell.
- exit_status – The last exit status of a command, updated after every execution.
typedef struct s_mshell
{
char **env;
t_hash_table *hash_table;
char **builtin;
uint8_t exit_status;
} t_mshell;Minishell stores environment variables in a hash table for efficient lookup and modification. Each variable is stored as a linked list node, allowing multiple entries to be handled under the same hash bucket (chaining for collision handling).
Represents a single environment variable in Minishell.
-
key – The name of the variable (e.g.,
"PATH"). -
value – The value associated with the key (e.g.,
"/usr/bin:/bin"). If no value is assigned, it remainsNULL. -
exported – If
1, the variable is included in theenvarray and exported to child processes. If0, it is local to the shell. - next – Points to the next variable in the same hash bucket (linked list for handling collisions).
typedef struct s_mshell_var
{
char *key;
char *value;
int exported;
struct s_mshell_var *next;
} t_mshell_var;Stores all environment variables using a hash table of fixed size (HASH_SIZE). The hash function determines the index in buckets[], where a linked list is used for chaining.
-
buckets – An array of
HASH_SIZEpointers to linked lists oft_mshell_var. Each bucket stores multiple variables in case of collisions.
#define HASH_SIZE 128
typedef struct s_hash_table
{
t_mshell_var *buckets[HASH_SIZE];
} t_hash_table;The following example illustrates how the hash table stores environment variables.
hash_table->buckets[42] -> { "PATH", "/usr/bin:/bin", 1 } -> { "PWD", "/home/user", 1} -> NULL;
hash_table->buckets[87] -> { "HOME", "/home/user", 1 } -> NULL;
hash_table->buckets[23] -> { "LOCAL_VAR1" = "data1", 0 } -> NULL;
hash_table->buckets[77] -> { "LOCAL_VAR2" = NULL, 0 } -> NULL;export EDITOR=vim-
Hash function computes the index for
"EDITOR", e.g.,index = hash_function("EDITOR") % HASH_SIZE = 87. -
New variable added to
buckets[87](no collisions).
hash_table->buckets[87] -> { "EDITOR", "vim", q } -> NULL;-
New variable added to
buckets[87](collision with"HOME"handled via linked list).
hash_table->buckets[87] -> { "EDITOR", "vim", 1} -> { "HOME" = "/home/user" } -> NULL;export PWD=new value-
Hash function finds
"PWD"inbuckets[42]. - Value updated while key remains the same.
# before
hash_table->buckets[42] -> { "PWD", "old value", 1 } -> NULL;
# after
hash_table->buckets[42] -> { "PWD", "new value", 1 } -> NULL;This mechanism ensures efficient environment variable lookup, addition, and modification.
Minishell uses a DJB2 hash function to compute an index for each variable name. This function is fast, efficient, and widely used for string-based hash tables.
unsigned int hash_function(const char *key)
{
unsigned long hash;
int c;
hash = 5381;
while ((c = *key++))
hash = ((hash << 5) + hash) + c;
return (hash % HASH_SIZE);
}-
Start with a seed value (
5381). -
Iterate through each character in
key:- Multiply
hashby33(hash << 5 + hashis equivalent tohash * 33). - Add the character’s ASCII value (
+ c).
- Multiply
-
Modulo operation ensures the index stays within
HASH_SIZE.
hash_function("PATH"); // Returns an index within 0-127
hash_function("HOME"); // Different index, unless collision occursThe DJB2 function efficiently distributes environment variable keys across the hash table, reducing collisions and speeding up lookup times.