Skip to content

WillEdgington/cshell

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

111 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

cshell

A zero-configuration POSIX command-line shell engineered in pure C, featuring dynamic multi-stage execution pipelines and persistent background job tracking.

Built as part of a self-directed C curriculum.


Build

Requires gcc and make. Once the repository is cloned from the remote, you can run these build commands:

runtime builds:

make setup_deps # Clone the dependency repos
make            # Compiles the executable cshell binary

dev builds:

make test       # Compiles and runs the test suite (./tests)
make debug      # Builds with debug symbols and sanitisers

clean:

make clean_deps # Cleans compiled binaries, .o, .a, and .d files (including compiled dependencies)
make clean      # Cleans compiled binaries, .o, and .d files (just for cshell)

Project Structure

include/cshell/   # Public interface definitions
├── test_framework.h  # Basic test framework macros
├── executor.h        # Pipeline execution, forking, and descriptor hygiene
├── expansion.h       # Environment variable token identification and translation
├── parser.h          # Lexical analysis and Pipeline/Command AST generation
├── prompt.h          # Context-aware path formatting and ANSI escape logic
└── tracker.h         # Persistent background job tables and state interfaces
src/                  # Core implementation (.c files)
tests/                # Per-module unit tests

Native Built-in Commands

To prevent subshell forks from discarding state mutations, cshell routes environment and directory manipulations directly to internal system calls within the parent process context.

  • cd [path]: Updates the current working directory of the shell via chdir(). Supports environment variables (e.g., cd $HOME).
  • export KEY=VALUE: Assigns or modifies environment variables in the process environment block via setenv().
  • exit (or CTRL+D): Cleanly breaks the REPL control loop and terminates the shell.

Core Interactive Features

1. Dynamic, Context-Aware Prompt

The prompt dynamically evaluates the user's workspace on every REPL iteration. To maintain screen real estate, it detects the HOME environment variable prefix and cleanly truncates it to a ~ shorthand while isolating the path visually using high-contrast ANSI colour-coding

cshell:/mnt/c/Users> cd $HOME
cshell:~> cd ./projects/cshell
cshell:~/projects/cshell>

Note: The ANSI colour-coding is not possible to convey in this documentation. If you run the cshell binary, you will see that the path (between : and >) is in pink and the rest is in default terminal colours (white for me).

2. Multi-Stage Pipelines & Subshell Isolation

cshell orchestrates arbitrary N-stage pipelines. It distinguishes between isolated subshell execution and parent-process evaluation: single built-in commands run in-place to mutate the parent environment, whereas pipelined built-ins automatically cascade into isolated child subshells to protect parent state.

cshell:~> echo systems_programming | grep -o programming
programming

3. Stream Redirection Engine

External process execution safely handles low-level input (<) and output (>) file descriptor redirection, routing byte streams seamlessly across disk boundaries.

cshell:~> echo hello > source.txt # write "hello" to source.txt
cshell:~> cat < source.txt > destination.txt # "hello" copies to destination.txt

4. Persistent Background Job Tracking

Trailing & operators intercept parsing boundaries to launch non-blocking background pipelines. Job lifetimes are managed natively by a dedicated tracking engine that prints clean, lifecycle status updates immediately before rendering the next prompt.

cshell:~> sleep 10 &
[1] 11754
cshell:~> # wait 10 seconds
[1]+  Done                    sleep 10 &

5. Environment Variable Expansion

Tokens prefixed with $ are scanned, extracted, and resolved via process environment blocks at runtime prior to pipeline execution routing, ensuring universal variable availability across both external binaries and internal built-ins.

As discussed in the Native Built-in Commands section, it is possible to create environment variables through export KEY=VALUE.

cshell:~> export PROJECT_DIR=/tmp/test
cshell:~> cd $PROJECT_DIR
cshell:/tmp/test>

Project Architecture & Components

The design of cshell centers around absolute memory determinism and safe systems orchestration without third-party library wrappers.

Epoch-Based Arena Allocation

To eliminate heap fragmentation, tracking overhead, and complex pointer bookkeeping, memory requested during tokenisation and pipeline generation is bound to a single execution epoch. Once a pipeline completes its execution lifecycle, the arena offset is reset to zero in a single, deterministic O(1) operation, bypassing individual node destruction loops.

Rolling Descriptor Pipeline Loops

The multi-stage execution engine drives an N-stage rolling file descriptor allocation loop. Instead of generating a massive global matrix of pipes ahead of time, standard descriptors are created and rotated progressively. Child contexts copy active boundaries via dup2, while rigorous parent-process descriptor hygiene explicitly closes unused write ends to guarantee that pipelines never deadlock or leak descriptors.

Hardened Signal Barriers & Synchronous Harvesting

cshell utilises signal blocking barriers around critical process forks and transferring process harvesting ownership entirely to a synchronous tracking engine. Active background jobs are monitored via non-blocking waitpid(..., WNOHANG) inquiries executed strictly at the top of the REPL loop, preserving the SA_RESTART integrity of your user input streams.


Author

Created by WillEdgington

📧 willedge037@gmail.com  |  🔗 LinkedIn

About

A POSIX shell written in C

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors