Skip to content

2. Minishell Structure

Ilia Munaev edited this page Mar 9, 2025 · 4 revisions

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 Core Structure

Minishell maintains an internal state for command execution, built-in handling, and process control.

struct s_mshell

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;

Environment Variable Management

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).

struct s_mshell_var

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 remains NULL.
  • exported – If 1, the variable is included in the env array and exported to child processes. If 0, 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;

struct s_hash_table

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_SIZE pointers to linked lists of t_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;

Hash Table Example

The following example illustrates how the hash table stores environment variables.

Example: Storing 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;

Example: Adding a New Variable

export EDITOR=vim
  1. Hash function computes the index for "EDITOR", e.g., index = hash_function("EDITOR") % HASH_SIZE = 87.
  2. New variable added to buckets[87] (no collisions).
hash_table->buckets[87] -> { "EDITOR", "vim", q } -> NULL;
  1. New variable added to buckets[87] (collision with "HOME" handled via linked list).
hash_table->buckets[87] -> { "EDITOR", "vim", 1} -> { "HOME" = "/home/user" } -> NULL;

Example: Modifying a Variable

export PWD=new value
  1. Hash function finds "PWD" in buckets[42].
  2. 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.


Hash Function

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.

hash_function

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);
}

How It Works:

  1. Start with a seed value (5381).
  2. Iterate through each character in key:
    • Multiply hash by 33 (hash << 5 + hash is equivalent to hash * 33).
    • Add the character’s ASCII value (+ c).
  3. Modulo operation ensures the index stays within HASH_SIZE.

Example:

hash_function("PATH");  // Returns an index within 0-127
hash_function("HOME");  // Different index, unless collision occurs

The DJB2 function efficiently distributes environment variable keys across the hash table, reducing collisions and speeding up lookup times.


Clone this wiki locally