Modern C library for command-line argument parsing with a powerful, declarative API
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
int opt, verbose = 0, port = 8080;
char *output = "output.txt";
char *input = NULL;
struct option long_options[] = {
{"verbose", no_argument, 0, 'v'},
{"output", required_argument, 0, 'o'},
{"port", required_argument, 0, 'p'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
while ((opt = getopt_long(argc, argv, "vo:p:h", long_options, NULL)) != -1) {
switch (opt) {
case 'v': verbose = 1; break;
case 'o': output = optarg; break;
case 'p':
port = atoi(optarg);
if (port < 1 || port > 65535) {
fprintf(stderr, "Error: Port must be 1-65535\n");
return 1;
}
break;
case 'h':
printf("Usage: %s [-v] [-o FILE] [-p PORT] INPUT\n", argv[0]);
printf(" -v, --verbose Enable verbose output\n");
printf(" -o, --output Output file (default: output.txt)\n");
printf(" -p, --port Port number (1-65535)\n");
printf(" -h, --help Show this help\n");
return 0;
case '?':
fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
return 1;
}
}
if (optind >= argc) {
fprintf(stderr, "Error: Missing required INPUT file\n");
return 1;
}
input = argv[optind];
// Finally ready to use the parsed arguments...
}
#include <argus.h>
ARGUS_OPTIONS(
options,
HELP_OPTION(),
VERSION_OPTION(),
OPTION_FLAG(
'v', "verbose",
HELP("Enable verbose output")
),
OPTION_STRING(
'o', "output",
HELP("Output file"),
DEFAULT("output.txt")
),
OPTION_INT(
'p', "port",
HELP("Port number"),
DEFAULT(8080),
VALIDATOR(V_RANGE(1, 65535))
),
POSITIONAL_STRING(
"input",
HELP("Input file")
),
)
int main(int argc, char **argv)
{
argus_t argus = argus_init(options, "my_tool", "1.0.0");
if (argus_parse(&argus, argc, argv) != ARGUS_SUCCESS)
return 1;
// Type-safe access - validation and help generation automatic
int port = argus_get(&argus, "port").as_int;
bool verbose = argus_get(&argus, "verbose").as_bool;
const char *output = argus_get(&argus, "output").as_string;
const char *input = argus_get(&argus, "input").as_string;
argus_free(&argus);
return 0;
}
Every library has its sweet spot. Here's where each one shines:
Perfect when: Every byte of performance counts, embedded systems, strict memory constraints
You'll need: Manual validation, custom help text, extensive error handling code
Perfect when: Building core GNU/Linux utilities, maximum compatibility with existing tools
Limitation: Tied to GNU ecosystem, complex callback patterns for advanced features
Perfect when: Legacy C compiler constraints, need strong typing without modern features
Missing: No subcommands, manual environment handling, verbose initialization
Perfect when: You want to focus on your application logic, not argument parsing infrastructure
Modern requirement: C11+ compiler needed, but you get everything built-in
Join the developers who chose declarative over imperative.
Your future self will thank you.
* PCRE2 optional for regex validation