parg is a small C23 command-line argument parser. It parses caller-supplied
argc/argv data, matches short and long options, and can reorder argv
entries in place. It does not perform file I/O, network I/O, dynamic
allocation, privilege separation, sandboxing, or secret management.
Everything passed into the public API should be treated as untrusted input.
That includes option strings, long-option tables, argv contents, and any
storage reachable through caller-provided pointers.
argc,argv,optstring, andstruct parg_optionarrays are caller-controlled.- Every argument string is parsed as raw NUL-terminated bytes. The library does not validate encoding, normalize Unicode, or apply shell-style escaping.
parg_reorder()mutates the caller'sargvarray in place.parg_getopt_long()writes throughlongopts[i].flagwhen that pointer is non-null. Those destinations are part of the caller's trusted state.struct parg_stateis caller-owned mutable state. Sharing one parser state across threads without external synchronization is outside the supported model.
- Memory safety inside the parser when the caller honors the documented pointer and lifetime requirements.
- Deterministic option parsing for short options, long options, optional arguments, and GNU-style non-option handling.
- Rejection of unknown or ambiguous long options by returning
'?'. - Reporting of missing required arguments via
'?'or':', depending on the leading character ofoptstring.
- The implementation is small and self-contained in
include/parg/parg.handsrc/parg.c. - No heap allocation occurs in the library, which removes allocator misuse and ownership-transfer bugs from the core parser.
- No global mutable state is used. Parser progress lives in
struct parg_stateprovided by the caller. - Parsing uses bounded string primitives such as
strchr(),strcspn(), andstrncmp()rather than ad hoc pointer walks. - Public entry points assert that required pointers such as
ps,argv, andoptstringare not null. - Public parsing entry points reject negative
argcvalues and caller-mutated parser states whoseoptindfalls outside[1, argc], avoiding out-of-boundsargvindexing even when a caller corruptsstruct parg_state. - The build is configured for
-std=c23 -Wall -Wextra -Wpedantic -Werror,-fstack-protector-strong, and-fno-omit-frame-pointerin bothbuild.zigandcompile_flags.txt. - Zig debug builds enable
sanitize_c = .full, which provides C sanitizer coverage during debug test runs. - Regression tests cover ambiguous and unknown long options, missing required
arguments, extraneous long-option arguments,
flagwrites, option reordering, and invalid parser-state rejection.
- This library only parses command-line argument vectors. It does not sanitize application-specific values such as paths, numbers, URLs, or shell fragments carried inside those arguments.
- All input strings must remain valid and NUL-terminated for the duration of
parsing. Passing dangling pointers, unterminated byte sequences, or invalid
argvlayouts is undefined at the C level. struct parg_statemust be initialized withparg_init()before first use.parg_reorder()requires a writableargvarray. Do not call it on immutable storage or shared vectors that other code expects to remain in the original order.longoptsmust be terminated by an entry whosenameisnullptr.- Any non-null
longopts[i].flagmust point to writable storage of typeint. - The parser is byte-oriented and locale-agnostic. If your security model cares about canonicalization, homoglyphs, or Unicode normalization, enforce that in the application before acting on parsed values.
- The library is not a policy engine. Authorization, command whitelisting, filesystem safety checks, and environment hardening belong in the caller.
Validation paths present in this checkout:
zig buildbuilds the static library and example program.zig build testbuilds and runs the parser regression tests intests/parg_tests.c.just testdelegates tozig build test.- Debug builds use Zig's C sanitizer support; release-style builds keep the warning policy but disable sanitizers by default.
- The README and
examples/simple.cintentionally use bounded integer parsing viastrtol()rather thanatoi().
This repository does not currently publish a separate maintained-branches
matrix. Report security issues against the current main branch unless the
maintainer states otherwise.
This repository does not currently publish a dedicated private security contact or coordinated disclosure workflow in-tree. If you need to report a security issue, use an existing maintainer contact channel if you already have one and avoid posting exploit details publicly before the maintainer has had a chance to assess the report.