Clipp: A Powerful C++ Library for Command Line Argument Parsing

What is Clipp?

Clipp is a command line argument parsing library designed specifically for C++11/14/17. The entire library consists of a single header file, eliminating the need for complex compilation or dependency management. It provides an intuitive and expressive API that makes it easy to define and parse various command line arguments.

Main Features

  • Single Header File Design: Simply include clipp.h to access all functionalities
  • Modern C++ Support: Fully compatible with C++11/14/17 standards
  • Rich Parameter Types: Supports options, flags, positional parameters, commands, and more
  • Powerful Composition Capabilities: Supports nested alternatives, decision trees, and other complex logic
  • Automatic Documentation Generation: Capable of generating well-formatted help information and usage manuals
  • Flexible Error Handling: Provides clear error messages and validation mechanisms

Basic Usage Example

Below are several specific examples demonstrating the basic usage of Clipp.

Basic Command Line Parsing

Suppose we need to create a command line tool that supports the following parameters:

  • An input file (positional parameter)
  • Recursive option -r or --recursive
  • Output format option -o followed by format value
  • UTF-16 encoding flag -utf16

The corresponding code implementation is as follows:

#include <iostream>
#include "clipp.h"  // Include Clipp header file

using namespace clipp;
using std::cout;
using std::string;

int main(int argc, char* argv[]) {
    // Define variables to store parsing results
    bool rec = false;       // Recursive flag
    bool utf16 = false;     // UTF-16 encoding flag  
    string infile = "";    // Input file
    string fmt = "csv";    // Output format, default is csv

    // Define command line parameter structure
    auto cli = (
        value("input file", infile),                  // Positional parameter: input file
        option("-r", "--recursive").set(rec)          // Option: recursive, set rec to true
           .doc("convert files recursively"),         // Help documentation
        option("-o") & value("output format", fmt),   // Combination: option -o must be followed by a value
        option("-utf16").set(utf16)                   // Option: set utf16 to true
           .doc("use UTF-16 encoding")                // Help documentation
    );

    // Parse command line parameters
    if(!parse(argc, argv, cli)) {
        // If parsing fails, display help information
        cout << make_man_page(cli, argv[0]);
    } else {
        // Parsing succeeded, use the obtained parameter values
        cout << "Input file: " << infile << "\n"
             << "Recursive: " << (rec ? "yes" : "no") << "\n"
             << "Output format: " << fmt << "\n"
             << "UTF-16 encoding: " << (utf16 ? "yes" : "no") << "\n";
    }

    return 0;
}

This simple example demonstrates the core usage of Clipp:

  • Using value() to define positional parameters
  • Using option() to define options
  • Using set() to associate options with boolean variables
  • Using doc() to add documentation to parameters
  • Using & operator to combine options and values
  • Using parse() function for actual parsing
  • Using make_man_page() to automatically generate help information

Complex Command Line Interface

For more complex scenarios, such as needing to support multiple subcommands, Clipp can also handle it elegantly:

#include <iostream>
#include "clipp.h"

using namespace clipp;
using std::cout;
using std::string;

enum class mode { add, remove, list, help };

int main(int argc, char* argv[]) {
    mode selected = mode::help;
    string item_name;
    int quantity = 1;
    bool verbose = false;

    // Define complex command line structure with multiple subcommands
    auto cli = (
        command("add", "Add item to inventory").set(selected, mode::add) |
        command("remove", "Remove item from inventory").set(selected, mode::remove) |  
        command("list", "Show inventory contents").set(selected, mode::list) |
        command("help", "Show help").set(selected, mode::help)
        ,
        option("-v", "--verbose").set(verbose).doc("show detailed output"),
        (required("-n", "--name") & value("item name", item_name)).doc("specify item name"),
        (option("-q", "--quantity") & integer("count", quantity)).doc("item quantity")
    );

    if(!parse(argc, argv, cli)) {
        // Display formatted help information on parsing failure
        cout << usage_lines(cli, argv[0]) << "\n\n";
        cout << documentation(cli) << "\n";
    } else {
        // Execute corresponding operation based on selected command
        switch(selected) {
            case mode::add:
                cout << "Adding " << quantity << " of '" << item_name << "'\n";
                break;
            case mode::remove:
                cout << "Removing " << quantity << " of '" << item_name << "'\n"; 
                break;
            case mode::list:
                cout << "Listing inventory" << (verbose ? " (verbose)" : "") << "\n";
                break;
            case mode::help:
                cout << make_man_page(cli, argv[0]);
                break;
        }
    }

    return 0;
}

This example showcases Clipp’s more advanced features:

  • Using command() to define subcommands
  • Using | operator to indicate mutually exclusive subcommand choices
  • Using required() to define mandatory options
  • Using integer() to ensure parameter values are of integer type
  • Using usage_lines() and documentation() to generate help information in different formats

Advanced Features

Parameter Grouping and Validation

Clipp supports grouping parameters and adding complex validation logic:

auto input_group = (
    required("-i", "--input") & value("input file", input_file),
    option("--format") & value("fmt", format).call([](const string& f) {
        // Custom validation function to ensure format support
        if(f != "json" && f != "xml" && f != "csv") {
            throw std::runtime_error("Unsupported format: " + f);
        }
    })
).doc("Input options");

auto output_group = (
    required("-o", "--output") & value("output file", output_file),
    option("--overwrite").set(overwrite)
).doc("Output options");

auto cli = (input_group, output_group);

Generating High-Quality Documentation

Clipp can automatically generate documentation in various formats:

// Generate concise usage instructions
cout << usage_lines(cli, "myapp") << "\n";

// Generate detailed documentation
cout << documentation(cli) << "\n"; 

// Generate complete help in man page format
cout << make_man_page(cli, "myapp");

Practical Application Scenarios

Clipp is well-suited for various C++ applications, especially:

  1. System Tools: File processors, network tools, system administration tools, etc.
  2. Development Tools: Code generators, build tools, format converters, etc.
  3. Data Processing Tools: Data transformation, analysis, filtering tools, etc.
  4. Testing Tools: Automated testing frameworks, benchmarking tools, etc.

Conclusion

With its simple API design, powerful features, and single header convenience, Clipp has become an ideal choice for developing C++ command line tools. Whether you are developing simple tools or complex enterprise-level applications, Clipp provides an elegant and efficient solution for command line argument parsing.

Its automatic documentation generation feature ensures good usability of the tools, while the rich parameter types and composition capabilities make handling the most complex command line interfaces possible.

If you are looking for a modern, lightweight, and fully-featured C++ command line parsing library, Clipp is definitely worth trying. Just include a single header file in your project, and you can enjoy professional-level command line processing capabilities.

Leave a Comment