Skip to content

alteixeira20/42_minishell

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

193 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

C badge Readline badge Make badge Shell badge Valgrind badge GDB badge

MiniShell

A strict-norm Bash replica with predictable tooling for 42 evaluations.

  1. At a Glance
  2. About
  3. Subject Compliance
  4. Custom Tester
  5. Repository Layout
  6. Build & Integration
  7. Usage Guidelines
  8. Feature Deep Dive
  9. Input & Prompt Flow
  10. Rendering & UX
  11. Internal Architecture
  12. Tester Workflow
  13. Results & Reporting
  14. Credits & Collaboration

At a Glance

Highlights: What evaluators can expect in the first five minutes.

  • Executes POSIX commands with pipes, redirects, and heredocs while mirroring Bash exit codes through the single global g_exit.
  • Builtins (echo, cd, pwd, export, unset, env, exit) run in-place or in child processes depending on pipeline context.
  • Parser defends against malformed syntax early, matching Minishell subject edge-cases (|, dangling redirects, empty tokens).
  • Custom tester automates Bash parity and Valgrind sweeps so every defense starts with a reproducible baseline.
  • Co-built by Paula Alexandra (paalexan) and João Pedro (jopedro-) with clear ownership per subsystem so knowledge transfers quickly at evaluation time.

About

Highlights: Why this shell feels reliable in daily use.

  • Interactive loop ties readline, prompt generation, and signal choreography so Ctrl-C interrupts safely without tearing down state.
  • Tokenization and expansion are staged: splitting respects quotes, then $ expansion and heredoc rules decide how much Bash-like magic to apply.
  • Execution reuses one command graph (t_cmd list) for both pipelines and single commands, cutting duplicated logic across forks.
Subsystem responsibilities
  • src/parser/ cleans input, expands environment variables, and tags tokens.
  • src/execution/ wires pipes, coordinates forks, and applies redirections.
  • src/redirection/ centralizes permission checks and heredoc lifecycle management.

Subject Compliance

Highlights: Direct trace between subject rules and implementation.

  • Mandatory builtins live under src/builtins/ and respect subject constraints (cmd_exit enforces numeric-only arguments, cmd_cd updates PWD/OLDPWD).
  • Signal handling matches expectations: ctrl_c_handler refreshes the prompt, heredoc forks switch to heredoc_sigint_handler, and child processes restore default behavior.
  • Only one global is present (g_exit), and every heap allocation flows through dedicated cleanup helpers (free_cmd, free_minishell, free_env_array).
  • readline is the sole external dependency; leaks from it are waived while project-owned allocations are released (see clean_all).
  • needs_pipe_continuation mirrors Bash multiline behavior, satisfying the “incomplete pipe” clause from the subject PDF.
Compliance checklist
  • Redirections: input/output/append/heredoc support via process_redirect and apply_single_redirect.
  • Environment editing: set_var, env_add_var, and del_var cover export and unset flows.
  • Error messaging: dedicated helpers mimic Bash wording (`print_syntax_error`, `handle_cmd_error`).

Custom Tester

Highlights: One command to prove parity with Bash.

  • tester/Makefile orchestrates runs against test_cases_auto.txt, stores Bash and Minishell outputs, and produces human-friendly diffs.
  • Shell scripts (run_minishell.sh, run_bash.sh) normalise prompts, colours, and SHLVL so comparisons stay meaningful across machines.
  • run_valgrind.sh applies readline suppressions automatically, marking tests green only when leak summaries are clean.
  • Full walkthroughs, edge-case notes, and extension tips live in the tester README.
cd tester
make              # run automated suite and generate diff_summary.txt
make valgrind     # optional leak run across the same command list

Automated tester running side-by-side with bash

Tester pipeline internals
  • Outputs land in tester/results/{minishell,bash,diff} with __CMD_START__/__CMD_END__ markers for parsing.
  • generate_summary_diff.py correlates failing diffs with the originating command for quick triage.
  • Manual scenarios live in tester/test_cases_manual.txt; copy lines into the suite when you confirm behaviour.

Repository Layout

Highlights: Navigate modules without grepping.

  • src/ – project code organised by responsibility (parser, tokenizer, execution, builtins, env, redirection, signals, cleanup, error).
  • libft/ – cloned automatically when make runs; exposes string helpers, list utilities, and get_next_line.
  • tester/ – parity and leak harness, including reusable scripts and sample files.
  • subject_minishell.pdf – original requirements for cross-referencing during peer reviews.
Directory cheat sheet
DirectoryPurpose
src/execution/Pipelines, forks, builtin routing, wait loops.
src/redirection/Redirect parsing, permission checks, heredoc tempfiles.
src/cleanup/Memory hygiene and descriptor sweeping before exit.
tester/test_files/Fixtures (empty, large, permission-locked) for edge cases.

Build & Integration

Highlights: Rebuild, relaunch, and lint with two targets.

  • make clones libft if missing, compiles objects into .obj/, and links with -lreadline.
  • make valgrind spins up an interactive session with the pre-generated suppression file, matching tester behaviour.
  • make clean and make fclean sweep objects, binary, suppression file, and even libft/ so you can benchmark fresh checkouts.
sudo apt install libreadline-dev  # If not installed already
make                              # build minishell (libft fetched if absent)
make re                           # full rebuild
make norm                         # run norminette with coloured status output

Usage Guidelines

Highlights: How to interact like a real user would.

  • Launch ./minishell, type commands exactly as in Bash, and exit with Ctrl-D or the builtin exit.
  • Builtins mutate the active environment when they run in the parent (single command) or mutate a fork-local copy inside pipelines.
  • Error codes mirror Bash: missing command returns 127, permission issues return 126, and signal exits follow 128 + signal.
./minishell
minishell> export FILES="src parser"
minishell> echo "$FILES" | tr ' ' '\n'
minishell> cat <<EOT | grep minishell
prompt
minishell loop
EOT
minishell> exit
Everyday tips
  • Use needs_pipe_continuation behaviour: ending a line with | keeps the prompt open for the continuation.
  • Heredoc delimiters honour quotes: quoted delimiters disable expansion, unquoted pass through handle_expansion.
  • Unset PATH to test fallback error paths (`minishell: command not found`).

Feature Deep Dive

Highlights: From raw input to child processes.

Stage Key files Notes
Tokenization src/tokenizer/tokenizer_split.c, tokenizer_utils.c split_input, get_next_segment, and unescape_token turn raw lines into typed t_token nodes ready for expansion.
Expansion src/parser/parser_expansion.c, tokenizer_lst.c expand_token, handle_all, and handle_dollar apply env lookups while preserving quote flags for later decisions.
Command graph src/builtins/builtins_utils.c, execution/exec_cmd.c build_cmd_list, process_token, and cmd_from_tokens consolidate tokens into t_cmd nodes with redirect chains.
Execution src/execution/exec_pipes.c, exec_child.c exec_pipeline, run_single_cmd, and exec_child coordinate pipes, builtins, forks, and exit propagation.
Cleanup src/cleanup/cleanup_cmd.c, cleanup_utils.c clean_all, free_cmd, and free_hc_minishell release argv, env copies, and heredoc tmpfiles to finish cleanly.
  • Control keeps looping through mainloop until EOF; each iteration builds tokens, compiles commands, feeds them to exec_pipeline, and updates g_exit for the next prompt.
  • Redirection helpers (process_redirect, setup_redirections, apply_single_redirect) sit between parsing and execution so every child inherits pre-vetted descriptors.
Redirection specifics
  • check_output_permission inspects parent directories so messages stay informative even before a file exists.
  • write_heredoc_to_tmp creates /tmp/.minishell_heredoc_* files and tracks them for removal in free_heredoc_tmpfiles.
  • apply_single_redirect centralises dup2 and marks failures for later error printing.
Environment lifecycle
  • `copy_env_array` and `init_env` duplicate the inherited environment so mutating builtins never touch the parent process env.
  • `export_assign` handles both direct replacement and `+=` concatenation (`export VAR+=suffix`).
  • `cmd_unset` rebuilds the env array minus the target key, ensuring no dangling strings remain.

Input & Prompt Flow

Highlights: Keeping the REPL responsive.

  • build_prompt composes user@hostname:cwd$ using cached env data (sh->home, sh->user) and collapses $HOME to ~ for readability.
  • Before each readline, set_interactive_signals arms SIGINT and SIGQUIT; after reading, handlers flip to child-friendly defaults.
  • handle_input_line stores tokens on the shell struct, runs syntax guards, executes, and frees everything before the next loop.
Continuation & history logic
  • Empty lines are ignored; non-empty lines hit `add_history` so testers can arrow through commands like Bash.
  • When heredocs are detected, the shell flags `is_heredoc` to disable further expansions inside delimiters.
  • Pipe continuations stay open because `needs_pipe_continuation` trims trailing whitespace before checking for `|`.

Rendering & UX

Highlights: Output designed for evaluators reading diffs.

  • Error printers prefix with minishell: and reuse Bash wording, ensuring the tester diff is only triggered by behavioural differences.
  • Redirect failures are deferred until after execution so the parent can report them once per pipeline (print_redirect_error).
  • prompt_utils.c trims hostname newlines and handles empty PWD gracefully to keep the interface tidy on remote hosts.
Message helpers
  • print_syntax_error and print_syntax_error_eof centralise subject messaging for malformed inputs.
  • handle_cd_error differentiates between invalid options, missing HOME, and `chdir` failures.
  • exec_invalid_cmd ensures blank commands return `127` without leaking file descriptors.

Internal Architecture

Highlights: Data structures and lifetime management.

  • t_msh (singleton returned by get_shell) caches env copies, prompt metadata, heredoc bookkeeping, and the running command list.
  • t_cmd nodes form a doubly linked list with argv arrays, redirect chains, builtin flags, and cached open file descriptors.
  • t_token keeps raw/expanded strings plus metadata (quoted, expanded_empty) so later stages can decide how to treat empty strings.
  • t_redirect captures redirect type and target path, chained per command for sequential application.
Global state discipline
  • `g_exit` is updated on every command; builtins and child processes set it before returning or exiting.
  • `free_final_minishell` and `free_hc_minishell` variants tailor cleanup for graceful exits versus heredoc aborts.
  • `clean_fds` closes descriptors from `3` onward before exiting to avoid stray handles between tests.

Tester Workflow

Highlights: How to run, inspect, and iterate quickly.

  • make -C tester wipes previous results, executes the auto list, and prints OK/KO per command with orange indexes.
  • Review mismatches in tester/results/diff/test*.diff or open diff_summary.txt for side-by-side comparisons.
  • Extend coverage by appending commands to tester/test_cases_auto.txt; scripts automatically renumber outputs.
make -C tester clean   # optional: nuke previous run without touching binaries
make -C tester run     # alias: only regenerate minishell/bash outputs
Manual scenarios
  • Lines under "To be Fixed" in `test_cases_manual.txt` capture behaviours observed during development.
  • Use the included fixtures (`big_file`, `invalid_permission`) to check performance and error reporting.
  • Valgrind logs store per-command traces in `tester/results/valgrind_logs/` for deep dives.

Results & Reporting

Highlights: Actionable, low-noise logs.

  • The tester prefixes every command with markers so Python scripts can slice outputs without guessing prompt lines.
  • diff_summary.txt lists command numbers, the original input, both outputs, and the diff chunk for fast triage.
  • Valgrind runs append OK/KO lines into results/valgrind_results.txt with the offending command when leaks appear.
  • Console summaries emphasise counts (pass/fail/total) instead of raw diff dumps, keeping defences focused on high-signal issues.
Next steps after a KO
  • Open the matching `testN.diff` and reproduce the command manually inside `./minishell`.
  • Use `tester/scripts/run_minishell.sh` directly if you need to tweak sed cleaning or prompts.
  • Capture Bash behaviour with `tester/scripts/run_bash.sh` to confirm whether the subject expects the deviation.

Credits & Collaboration

Highlights: Two minds, one shell.

  • Paulo Alexandre (paalexan) drove the parsing, execution, and error-handling layers, making sure every t_cmd is battle-tested before it forks.
  • João Pedro (jopedro-) focused on environment management, cleanup strategy, and user-facing polish, locking down memory hygiene and prompt comfort.
  • Pair-programming sessions aligned architecture decisions; we reviewed each module before merging so any 42 evaluation can call on either of us for clarifications.
  • Special thanks to our peers who stress-tested the tester farm and uncovered early heredoc quirks.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

1 watching

Forks

Contributors