Skip to content

ArgParse

Description

Parser state. Stack-allocate, init once, register verbs, run.

name – shown as the program name in --help and errors. about – one-line description at the top of --help. May be NULL. alloc – where the specs Vec and any owned strings come from.

Usage example (Cross-references)

Usage examples (Cross-references)
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/ArgParse.h>
    #include <Misra/Std/Log.h>
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        const char *listen = NULL;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        const char *listen = NULL;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        const char *listen = NULL;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        u32 timeout = 30;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        u32 timeout = 30;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        bool verbose = false;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        bool verbose = false;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        u32 verbose = 0;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        u32 verbose = 0;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("cp", NULL, A);
    
        const char *src = NULL;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("cp", NULL, A);
    
        const char *src     = NULL;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        u32 n = 0;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        i64 v = 0;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        f64 ratio = 1.0;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        Str name = StrInit(A);
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        const char *listen = NULL;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("cp", NULL, A);
    
        const char *src = NULL;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        bool v = false;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        u32 n = 0;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        u8 v = 0;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", NULL, A);
    
        const char *x = NULL;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("cat", NULL, A);
    
        const char *file = NULL;
        DefaultAllocator a = DefaultAllocatorInit();
        Allocator       *A = ALLOCATOR_OF(&a);
        ArgParse         p = ArgParseInit("prog", "test prog", A);
    
        const char *required = NULL;
    
    int main(void) {
        WriteFmt("[INFO] Starting ArgParse tests\n\n");
    
        TestFunction tests[] = {
        };
    
        return run_test_suite(tests, sizeof(tests) / sizeof(tests[0]), NULL, 0, "ArgParse");
    }
    /// for the public API surface and the design notes.
    
    #include <Misra/Std/ArgParse.h>
    #include <Misra/Std/File.h>
    #include <Misra/Std/Io.h>
    /* ------------------------------------------------------------------ */
    
    static ArgSpec *find_long(ArgParse *self, const char *long_name) {
        VecForeachPtr(&self->specs, sp) {
            if (sp->role == ARG_ROLE_POSITIONAL)
    }
    
    static ArgSpec *find_short(ArgParse *self, const char *short_name) {
        VecForeachPtr(&self->specs, sp) {
            if (sp->role == ARG_ROLE_POSITIONAL)
    }
    
    static void print_help(ArgParse *self) {
        File err = FileStderr();
    
    void arg_register(
        ArgParse   *self,
        ArgRole     role,
        const char *short_name,
    /* ------------------------------------------------------------------ */
    
    ArgParse arg_parse_init(const char *name, const char *about, Allocator *alloc) {
        if (!name)
            LOG_FATAL("ArgParseInit: name is required");
        if (!alloc)
            LOG_FATAL("ArgParseInit: allocator is required");
        ArgParse p = {0};
        p.alloc    = alloc;
        p.name     = name;
    }
    
    void ArgParseDeinit(ArgParse *self) {
        if (!self)
            return;
    // `ARG_RUN_ERROR` on failure (after printing the error).
    static ArgRun handle_option_token(
        ArgParse   *self,
        const char *tok,  // the current argv[i] token
        int        *i_io, // walked forward by 1 when we consume a value
    // when -v is a Flag or a Count. -lFOO (stuck value) is intentionally
    // not supported in v1.
    static ArgRun handle_short_bundle(ArgParse *self, const char *tok, File *err) {
        // tok looks like "-XYZ..."; verify every char maps to a Flag/Count.
        for (const char *p = tok + 1; *p; ++p) {
    }
    
    ArgRun ArgParseRun(ArgParse *self, int argc, char **argv) {
        if (!self || argc < 0 || (argc > 0 && !argv)) {
            LOG_ERROR("ArgParseRun: bad arguments");
    #include <Misra/Std/Allocator/Heap.h>
    #include <Misra/Std/Allocator/Page.h>
    #include <Misra/Std/ArgParse.h>
    #include <Misra/Std/Container.h>
    #include <Misra/Std/Container/Str.h>
            const char *about;
            ArgSpecs    specs;
        } ArgParse;
    
        ///
        /// FAILURE: Aborts via `LOG_FATAL` on allocator OOM.
        ///
        ArgParse arg_parse_init(const char *name, const char *about, Allocator *alloc);
    
    #define ArgParseInit(...)                      MISRA_OVERLOAD(ArgParseInit, __VA_ARGS__)
        /// safe on a zero-initialised one.
        ///
        void ArgParseDeinit(ArgParse *self);
    
        ///
        ///           `ARG_RUN_ERROR` (parse error logged + usage hint).
        ///
        ArgRun ArgParseRun(ArgParse *self, int argc, char **argv);
    
        ///
        ///
        void arg_register(
            ArgParse   *self,
            ArgRole     role,
            const char *short_name,
    #include <Misra/Parsers/Http.h>
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/ArgParse.h>
    #include <Misra/Sys/Dns.h>
    #include <Misra/Sys/Socket.h>
            const char *upstream_spec = NULL;
    
            ArgParse ap = ArgParseInit("beam", "small reverse-proxy");
            ArgRequired(&ap, "-l", "--listen", &listen_spec, "host:port to listen on");
            ArgRequired(&ap, "-u", "--upstream", &upstream_spec, "upstream host:port");
    #include <Misra.h>
    #include <Misra/Std/Allocator/Default.h>
    #include <Misra/Std/ArgParse.h>
    #include <Misra/Sys/Dns.h>
    #include <Misra/Sys/Socket.h>
            const char *hostname = NULL;
    
            ArgParse ap = ArgParseInit("resolve", "look up a hostname via /etc/hosts and DNS");
            ArgPositional(&ap, "hostname", &hostname, "name to resolve");
Last updated on