Command Line Argument Parser

#import "extra/argparse"

Generic command line argument parsing tool.

Example

#import "extra/argparse"

MyOptLevel :: enum {
    DEBUG;
    RELEASE_SMALL;
    RELEASE_FAST;
}

// Some options we need.
MyArgs :: struct {
    is_debug: bool;
    worker_count: s32;
    directory: string_view;
    inputs: []string_view;
    outputs: []string_view;
    optimization: MyOptLevel;
}

main :: fn () s32 {
    using argparse;

    // Create and initialize new instance of argument parser.
    parser: Parser;
    init(&parser, "This is cool testing application parsing command-line arguments, enjoy!");
    // Don't forget to terminate it!
    defer terminate(&parser);

    args: MyArgs;

    // Set the executable name (used in help).
    set_executable_name(&parser, command_line_arguments[0]);

    // Add very basic usage information.
    add_usage(&parser, "[options]");

    // Register positional argument prefixes for input and output files.
    add_positional(&parser, &args.inputs, "--input", "-i", "List of input files.");
    add_positional(&parser, &args.outputs, "--output", "-o", "List of output files.");

    // Register all other arguments.
    add(&parser, &args.is_debug, "--debug", "-d", "Enable debug mode"); // Boolean flag.
    add(&parser, &args.worker_count, "--worker-count", "", "Count of worker threads."); // Integer value.
    add(&parser, &args.directory, "--dir", "", "Root directory path."); // String view (no need to be preallocated).
    add(&parser, &args.optimization, "--opt", "", "Optimization level."); // Enumerator value.

    // Parse all command line arguments here.
    parsed_argument_count, parse_error :: parse(&parser, command_line_arguments);
    if parse_error {
        // Print error and show the help.
        print_err(parse_error);
        print_help(&parser);
        return 1;
    }

    // Use the parsed options.
    print("\nParsed arguments: %\n", parsed_argument_count);
    print("%\n", args);
    return 0;
}


Possible application output.

Note that '--help' argument was added implicitly.

./out.exe --help -o first.txt second.txt
This is cool testing application parsing command-line arguments, enjoy!
Usage:
  out.exe [options]

Options:
  -d, --debug                   Enable debug mode
  -h, --help                    Print this help.
  -i, --input                   List of input files.
  -o, --output                  List of output files.
  --dir=<STR>                   Root directory path.
  --opt=<DEBUG|RELEASE_SMALL|RELEASE_FAST>
                                Optimization level.
  --worker-count=<N>            Count of worker threads.

Parsed arguments: 2
MyArgs {is_debug = false, worker_count = 0, directory = , inputs = [], outputs = [first.txt, second.txt], optimization = MyOptLevel.DEBUG}

argparse.Parser

Parser :: struct {
    usage: [..]string_view;
    argument_list: [..]Argument;
    help: bool;
    info: string_view;
    executable_name: string_view;
    allocator: *Allocator;
}

File: argparse.bl

argparse.init

init :: fn (parser: *Parser, info :: , allocator : *Allocator: ) 

Initialize argument parser. Custom application information can be set as optional info, this information is later shown in the help message printed by print_help function.

Optional allocator can be specified.

Use terminate function to release all resources needed by parser.

File: argparse.bl

argparse.terminate

terminate :: fn (parser: *Parser) 

Release all parser resources.

File: argparse.bl

argparse.add

add :: fn (parser: *Parser, target: *?T, long: string_view, short :: , help :: , is_required :: ) 

Add a single argument to the parser. Generic target pointer must point to the actual value modified by this argument. Basic types as (numbers, floats, strings and bools) are supported. The long specifies the argument long name (i.e. --worker-count) and short specifies the shortcut for the long name (i.e. -wc). The short name is optional. The help is optional user friendly hint message printed with help. In case is_required is true, the argument must be provided by user every time.

Note

String values must be allocated before any parsing is done.

Warning

Argument parser internally does NOT duplicate any argument related metadata (i.e. long name).

File: argparse.bl

argparse.add_positional

add_positional :: fn (parser: *Parser, target: *[]string_view, long: string_view, short :: , help :: , is_required :: ) 

Add positional argument prefix to the parser. In case such prefix argument is parsed from the input arguments, all following input argument entries are added into target list (no duplication is done). All following input arguments are added until parser hits some known argument name or the input argument list is empty. @Incomplete: Example

File: argparse.bl

argparse.add_usage

add_usage :: fn (parser: *Parser, usage: string_view) 

Add usage string message listed in Usage section in the help message.

File: argparse.bl

argparse.set_executable_name

set_executable_name :: fn (parser: *Parser, name: string_view) 

Sets the executable name used in help message.

File: argparse.bl

argparse.parse

parse :: fn (parser: *Parser, args: []string_view, first_arg_index :: 1) (parsed_arguments_count: s32, result: Error
)

Start parsing of args argument list using the parser configuration. The first_arg_index can be used to skip first N entries in the args list (one by default to skip usual executable name in case of command line arguments are beeing parsed).

Returns count of successfully parsed arguments or an error. Client side should handle error cases gracefully (i.e. by printing help message or terminating the application).

File: argparse.bl

argparse.print_help

print_help :: fn (parser: *Parser) 

Print formated help message. The parser should be already initialized with all argumenst.

File: argparse.bl