This project is a custom implementation of the C standard library printf.
Its objective was not merely functional replication, but the construction of a uniform, extensible, and architecturally disciplined output engine.
The defining architectural decision is the enforcement of a single, identical function signature for every component that writes to the output stream.
-
Total Polymorphism Every handler — whether processing literal characters or conversion specifiers — follows the same function signature. Each receives a pointer to a shared context structure (
t_poly). -
Literal / Specifier Symmetry Literal characters are treated with the same operational contract as complex specifiers. The dispatcher does not distinguish between “simple” and “complex” work — it executes handlers uniformly.
-
Architectural Motivation By forcing every unit of output into the same interface, the main loop becomes a pure executor of homogeneous operations. This eliminates special-case branching and preserves structural symmetry.
The parser follows a Negative Path First approach to minimize branching depth and reduce cognitive overhead.
-
Guard Clause Strategy The processor first evaluates whether a sequence is not a valid specifier (e.g., literal text, trailing
%, invalid flags). -
Literal Path If the guard condition is met, the character is immediately processed via the universal handler.
-
Dispatch Path Only after clearing the negative conditions does the system proceed to specifier resolution.
This collapses multiple edge cases into a single decision branch and keeps the “happy path” flat.
The implementation uses compound literals with designated initializers to configure numeric base mappings.
-
Localized Initialization A
base_initfunction constructs at_basesstructure using:(t_bases){ .base = { ... } }
-
Declarative Mapping Enums are mapped to base strings using designated initializers, such as:
[HEX_BASE_LO] = "0123456789abcdef"
-
Encapsulation & Safety This avoids global variables while keeping configuration explicit, localized, and memory-safe.
The %p specifier is implemented with portability and correctness as priorities.
-
Correct Integer Representation Pointers are cast to
uintptr_torunsigned long, ensuring proper handling on 64-bit architectures (e.g., x86_64). -
Isolation from libft A dedicated
ft_numlen_ptrutility was created instead of modifying core library functions, preserving separation of concerns. -
NULL Handling
NULLis explicitly rendered as"(nil)", matching standard system behavior and returning the correct output length.
Although lookup strategies could be optimized further, the design intentionally favors clarity.
-
Negligible Overhead With a small, fixed set of specifiers, dispatcher overhead remains trivial.
-
Structural Extensibility New specifiers or flags can be added without altering dispatcher logic, preserving architectural integrity.
A custom unit testing layer validates each handler in isolation prior to integration.
-
Output Capture
pipe()anddup2()are used to capture and compare output fromprintfandft_printf. -
Variadic Wrappers Wrapper functions bridge the gap between variadic test utilities and handler-level testing.
-
Edge Case Coverage Special attention is given to:
NULLstringsNULLpointers- Boundary integers (e.g.,
INT_MIN)
The project’s core philosophy is interface uniformity over conditional complexity. By treating every output operation identically, the engine becomes modular, predictable, and mechanically extensible — not just functionally correct.