Skip to content

A modern, header-only C++20 argument parser with a fluent API and type-safe custom type support.

License

Notifications You must be signed in to change notification settings

tynes0/Argonaut

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 

Repository files navigation

Argonaut

A lightweight, header-only C++20 argument parser library with a fluent, chainable API.

C++ Standard

Argonaut is a lightweight, single-header C++20 library for parsing command-line arguments. It features a readable fluent API, automatic help generation, exception-based control flow, and an extensible type conversion system.

Features

  • Header-Only: Just copy Argonaut.h into your project and include it.
  • Fluent API: Use method chaining to define arguments and configure the parser.
  • Rich Argument Support:
    • Options with values (e.g., --mode fast or --mode=fast)
    • Flags (boolean switches, e.g., --verbose)
    • Positional arguments (e.g., my-app <input-file>)
  • Automatic Help & Version:
    • Generates a formatted help message with AutoHelp(true).
    • Handles version requests with AutoVersion(true).
  • Clean Flow Control: Throws exceptions like HelpRequestedException instead of calling exit(0), giving your application full control over its lifecycle.
  • Modern & Robust: Supports required arguments, default values, multi-value arguments, and callbacks.
  • Type Safe: Retrieve values directly as int, float, bool, double, or define Custom Types using the ArgumentConverter system.

Requirements

  • C++20 Compiler: Argonaut uses C++20 features like std::map::contains and std::ranges.
  • Standard Library: No external dependencies.

Installation

Argonaut is a header-only library.

  1. Download Argonaut.h from this repository.
  2. Place it in your project's include path.
  3. #include "Argonaut.h" in your main.cpp or equivalent.

Quick Start

Here is a complete example of a simple application using type-safe retrieval.

#include "Argonaut.h"
#include <iostream>
#include <string>
#include <vector>

int main(int argc, char* argv[])
{
    // 1. Create a parser instance
    Argonaut::Parser parser;
    
    // 2. Configure the parser using the fluent API
    parser
        .SetVersion("v1.2.3")
        .AutoHelp(true)
        .AutoVersion(true)
        .Add(
            // A required positional argument
            Argonaut::Argument("FILE")
                .SetDescription("The input file to process.")
                .Required()
        )
        .Add(
            // An integer option with default value
            Argonaut::Argument("COUNT")
                .SetDescription("Number of iterations.")
                .AddAlias("-n")
                .AddAlias("--count")
                .SetDefaultValue("10")
        )
        .Add(
            // A simple flag
            Argonaut::Argument("VERBOSE")
                .SetDescription("Enable verbose output.")
                .AddAlias("--verbose")
                .Flag()
        )
        .Add(
            // A floating point multi-value option
            Argonaut::Argument("SCALE")
                .SetDescription("Scale factors.")
                .AddAlias("-s")
                .AddAlias("--scale")
                .MultiValue()
        );

    // 3. Run the parser inside a try...catch block
    try
    {
        parser.Parse(argc, argv);
    }
    catch (const Argonaut::HelpRequestedException& e)
    {
        std::cout << e.what(); // Print help and exit
        return 0; 
    }
    catch (const Argonaut::VersionRequestedException& e)
    {
        std::cout << "My-App " << e.what() << std::endl; // Print version and exit
        return 0; 
    }
    catch (const Argonaut::Exception& e)
    {
        std::cerr << "Error: " << e.what() << "\n\n";
        std::cerr << parser.Help(); // Print help on error
        return 1;
    }

    // 4. Retrieve your parsed values (Type-Safe!)
    try
    {
        // Retrieve string (default)
        std::string inputFile = parser.GetValuesOf("FILE")[0];
        
        // Retrieve integer automatically
        int count = parser.GetValuesOf<int>("COUNT")[0];
        
        // Retrieve boolean automatically (checks for "true", "1", "yes", "on")
        // For flags, we usually check emptiness, but GetValuesOf<bool> works if provided explicitly.
        bool verbose = !parser.GetValuesOf("VERBOSE").empty();

        // Retrieve vector of floats
        std::vector<float> scales = parser.GetValuesOf<float>("SCALE");

        // --- Application Logic ---
        std::cout << "File: " << inputFile << "\n";
        std::cout << "Count: " << count << "\n";
        std::cout << "Verbose: " << std::boolalpha << verbose << "\n";
        
        for(float s : scales) std::cout << "Scale: " << s << "\n";

    }
    catch(const std::exception& e)
    {
        std::cerr << "Conversion Error: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}

Advanced: Custom Types

You can teach Argonaut how to parse your own types by specializing Argonaut::ArgumentConverter<T>.

struct Vector3 { float x, y, z; };

// Specialize the converter in the Argonaut namespace
namespace Argonaut {
    template<> struct ArgumentConverter<Vector3> {
        static Vector3 Convert(const std::string& v) {
            // Example parsing logic for "1.0,2.0,3.0"
            Vector3 result{0,0,0};
            sscanf(v.c_str(), "%f,%f,%f", &result.x, &result.y, &result.z);
            return result;
        }
    };
}

// Usage in main:
// parser.Add(Argonaut::Argument("POS").AddAlias("--pos"));
// ...
// Vector3 pos = parser.GetValuesOf<Vector3>("POS")[0];

Compiling and Running

# Compile (requires C++20)
g++ -std=c++20 main.cpp -o my_app

# Run with --help
./my_app --help
# Output:
# Usage: ./my_app [OPTIONS] <FILE>
#
# Positional Arguments:
#   FILE    The input file to process.
#           [REQUIRED] 
#
# Options:
#   -m <value>, --mode <value>    Set processing mode (fast, safe).
#                                 [Default: "safe"]
#   --verbose                   Enable verbose output.
#   -I <value>, --include <value> Path to include.
#                                 [Multi-value] 
#   -h, --help                    Show this help message and exit.
#   -v, --version                 Show version.

# Run normally
./my_app "data.bin" --verbose -I ./lib -I /usr/lib --mode=fast
# Output:
# [Callback] Including path: ./lib
# [Callback] Including path: /usr/lib
# --- Application Running ---
# Input File: data.bin
# Mode: fast
# Verbose: true
# Final Include Path: ./lib
# Final Include Path: /usr/lib

# Run with an error
./my_app --mode
# Error: Argonaut Exception: Last argument should take value.
#
# Usage: ./my_app [OPTIONS] <FILE>
# ... (help message) ...

API Reference

Argonaut::Argument

Created by calling Argonaut::Argument("UNIQUE_ID").

Method Description
SetDescription(std::string desc) Sets the text shown in the help message.
AddAlias(std::string alias) Adds a trigger alias (e.g., "-f" or "--file").
Required(bool value = true) Marks the argument as mandatory.
Flag(bool value = true) Marks the argument as a boolean flag (takes no value).
MultiValue(bool value = true) Allows the argument to be provided multiple times.
SetDefaultValue(std::string value) Provides a default value if not specified by the user.
SetCallback(std::function<...>) Sets a void(const std::string&) callback to run when the argument is parsed.

Argonaut::Parser

The main class used to manage parsing.

Method Description
Add(Argument arg) Adds a configured Argument object to the parser.
AutoHelp(bool value = true) Automatically adds the --help and -h arguments.
AutoVersion(bool value = true) Automatically adds the --version and -v arguments.
SetVersion(std::string version) Sets the version string to be displayed.
Parse(int argc, char* argv[]) Parses the command-line arguments. Throws exceptions on errors or for help/version requests.
GetValuesOf<T>(std::string id) Returns a std::vector of values. Automatically converts string input to T. Supports int, float, double, bool, etc.
GetAllValues() Returns a const std::map<std::string, std::vector<std::string>>& of all parsed results.
Help() Returns the formatted help message as a std::string.
GetProgramName() Returns the program name (argv[0]).

Limitations

  • No Short Option Clustering: Argonaut does not currently support combining short options (e.g., -xvf). Each short option must be specified separately (e.g., -x -v -f).

License

This project is licensed under the MIT License.

About

A modern, header-only C++20 argument parser with a fluent API and type-safe custom type support.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages