Skip to content

A lightweight, record-based command-line argument parser for Free Pascal. `ArgParser-FP` is designed for small to medium console applications, offering a clean API to handle arguments with minimal setup.

License

Notifications You must be signed in to change notification settings

ikelaiah/argparser-fp

🌿 ArgParser-FP: A simple command-line argument parser for Free Pascal

FPC Lazarus License Documentation Version

A lightweight, record-based command-line argument parser for Free Pascal. ArgParser-FP is designed for small to medium console applications, offering a clean API to handle arguments with minimal setup.

Why use ArgParser-FP

  • Small, dependency-free, and focused on console apps built with Free Pascal.

  • Compact API: define options, parse once, and retrieve typed values.

Quickstart — run in under 30 seconds

  1. Copy both src/ArgParser.pas and src/ArgTokenizer.pas into your project folder, and add ArgParser to uses.

  2. Save this minimal program as quick.pas and compile:

program Quick;

uses ArgParser, SysUtils;

var 
  P: TArgParser;
begin
  P.Init;
  P.AddBoolean('h','help','Show this help message');
  P.AddString('f','file','Input file','',True);
  
  P.ParseCommandLine;
  
  if P.HasError then
  begin
    Writeln('Error: ', P.Error);
    P.ShowUsage;
    Exit;
  end;
  
  if P.GetBoolean('help') then 
  begin
    P.ShowHelp;
    Exit;
  end;
  
  Writeln('File=',P.GetString('file'));
end.

Build & run (PowerShell):

fpc quick.pas
.\quick.exe --help

More examples and full docs are below. If you like short, clear APIs, try the examples/ folder.

✨ Features

  • Type-Safe Parsing: Natively parse strings, integers, floats, booleans, and arrays.
  • Flexible Syntax: Support for multiple argument formats:
    • Short options: -f input.txt or -finput.txt
    • Boolean flags: --verbose or --verbose=true/false
  • Automatic Help Text: Generates --help and usage text from your option definitions.
  • Required Options: Enforce mandatory arguments.
  • Default Values: Provide default values for optional arguments.

Here is a complete example of a simple application:

// File: examples/MyApp/MyApp.pas
program MyApp;

uses
  SysUtils,
  ArgParser;

var
  Parser: TArgParser;
  i: integer;

begin
  // Initialize
  Parser.Init;
  Parser.SetUsage('MyApp [options]');

  // Add options using convenience methods
  Parser.AddInteger('c', 'count', 'Set count value', 5);
  Parser.AddBoolean('v', 'verbose', 'Enable verbose mode');
  Parser.AddString('f', 'file', 'Specify a file path', '', True); // Required
  Parser.AddArray('t', 'tags', 'Comma-separated list of tags');   // Add array option
  Parser.AddBoolean('h', 'help', 'Show this help message');

  // Parse command line arguments with one call

  if Parser.HasError then
  begin
    Writeln('Error: ', Parser.Error);
    Parser.ShowUsage;
    Exit;
  end;

  // Show help if requested
  if Parser.GetBoolean('help') then
  begin
    Parser.ShowHelp;
    Exit;
  end;

  // Access parsed values
  Writeln('Count: ', Parser.GetInteger('count'));
  Writeln('File: ', Parser.GetString('file'));

  // Display array values if provided
  if Length(Parser.GetArray('tags')) > 0 then
  begin
    Write('Tags: ');
    for i := 0 to High(Parser.GetArray('tags')) do
    begin
      Write(Parser.GetArray('tags')[i]);
      if i < High(Parser.GetArray('tags')) then
        Write(', ');
    end;
    Writeln;
  end;

  if Parser.GetBoolean('verbose') then
    Writeln('Verbose mode is ON');

  Writeln('Done.');
end.

Compile and run the application with --help to see the auto-generated documentation:

fpc MyApp.pas
./MyApp --help

Output:

Usage: MyApp [options]

Options:
  -h, --help     Show this help message
  -c, --count    Set count value
  -v, --verbose  Enable verbose mode
  -f, --file     Specify a file path (required)
  -t, --tags     Comma-separated list of tags
  
Note: the help printer (`ShowHelp`) automatically appends " (required)" to the
help text for any option or positional argument marked `Required = True`.

Example Usage

# Traditional format
./MyApp --file input.txt --count 10 --verbose

# Equals format
./MyApp --file=input.txt --count=10 --verbose=true

# Mixed formats
./MyApp --file=input.txt -v --count 10

Additional notes: quote arguments containing spaces according to your shell's rules.

⚠️ Common Pitfalls

  • Standalone tokens without a preceding option

    • A token not starting with - must be the value of the previous option. Otherwise it triggers Invalid argument format: <token>.
  • Boolean flags and values

    • Presence sets to true: --verbose ⇒ true.
    • If you need an explicit value, use --verbose=true|false or -v=false. Writing --verbose false treats false as a separate token and will fail.
  • Short combined flags

    • The tokenizer's default policy (controlled by SplitCombinedShorts in src/ArgTokenizer.pas) will split small all-alpha combined shorts like -abc into separate flags -a -b -c. Mixed or numeric groups (for example -a1b) are preserved as a single token. Set SplitCombinedShorts := False if you prefer conservative behavior.
  • PowerShell split quirk (Windows)

    • PowerShell may split -finput.txt into two tokens: -finput and .txt. The parser reattaches .txt for string options so the value becomes input.txt.
  • Single dash and negative numbers

    • A single dash token - is preserved as a positional token (commonly used to mean stdin). Numeric tokens that start with - such as -1 are treated as positional values unless an option matching that token exists.

    Examples:

    • Read from stdin: mytool - input.txt # '-' preserved as a positional (stdin)
    • Negative numeric positional: mytool process -1 # '-1' is a positional value, not an option
  • Arrays are comma-separated

    • Use a single token like --list=a,b,c. If values contain spaces, quote according to your shell.

-- separator and leftovers

ParseCommandLine now detects a -- separator automatically. Any tokens after a -- are not parsed as options and are returned to the caller via the Leftovers property. This simplifies the common call-site: you can call ParseCommandLine and then inspect Parser.Leftovers to forward any remaining arguments.

Examples:

var
  Parser: TArgParser;
  leftovers: TStringDynArray;
begin
  Parser.Init;
  try
    Parser.AddBoolean('v','verbose','Enable verbose');
    Parser.ParseCommandLine;
    leftovers := Parser.Leftovers; // tokens after `--`, if any
  finally
    Parser.Done;
  end;
end;

Important: the parser no longer prints help or exits during parsing. The presence of -h/--help sets the built-in help flag; after calling ParseCommandLine your program should check Parser.HasError and Parser.GetBoolean('help') and then call Parser.ShowUsage or Parser.ShowHelp and exit if appropriate. This prevents the parser from freeing internal resources unexpectedly while your program continues running.

Additional notes

  • Boolean negation: long boolean options also support a --no-<name> form to explicitly set a boolean flag to False. Example: --no-verbose.
  • Positional arguments: AddPositional creates ordered (positional) arguments. Use the optional NArgs parameter to control how many tokens a positional consumes:
    • NArgs = 0 (default): single token
    • NArgs = -1: greedy mode (consume all remaining tokens until next option or end)
    • Note: Values >0 are accepted but currently behave as 0 (single token)
  • AllowMultiple / GetAll*: For options that can appear multiple times (for example --tag a --tag b), use the GetAll* helpers (e.g., GetAllString, GetAllArray) to retrieve every occurrence in the order parsed.

For deeper details and examples, see the Beginner's Guide and the Cheat Sheet.

📖 System Requirements

  • Compiler: FPC 3.2.2+
  • IDE: Lazarus 4.0+ (recommended, for running the examples and tests)
  • Platforms: Windows, Linux (cross-platform by design)
  • Dependencies: None. Uses only standard FPC RTL units.

📦 Installation

  1. Copy both src/ArgParser.pas and src/ArgTokenizer.pas into your project folder, and add ArgParser to uses.
  2. Compile with FPC:
fpc MyProgram.pas

📚 API Reference

For detailed documentation on all available procedures and functions, please see the Beginner's Guide and the Cheat Sheet.

✅ Testing

  1. Open the TestRunner.lpi using Lazarus IDE
  2. Compile the project
  3. Run the Test Runner:
cd tests
./TestRunner.exe -a --format=plain

Note: v0.4.0 introduced a dedicated ArgTokenizer unit and focused tokenizer unit tests (tests/ArgTokenizer.Test.pas) to validate token shapes and normalization rules.

What's new in v0.7.0

  • Code Simplification: Refactored internal implementation to reduce complexity and remove duplicate code patterns without losing any functionality.
  • Helper Functions: Introduced helper functions for common operations like TArgValue initialization and array management to reduce repetitive code.
  • Cleaner Type Parsing: Split the complex ParseValue method into focused type-specific parsing functions for better maintainability.
  • Simplified Tokenizer: Extracted helper functions in ArgTokenizer to improve code readability and reduce complexity.
  • Streamlined Methods: Consolidated duplicate initialization patterns in AddXXX methods and simplified array operations throughout the codebase.
  • Improved Error Messages: Fixed misleading error messages for missing required positional arguments to follow standard CLI conventions.

Note (v0.7.0): This release contains internal simplifications, refactoring, and improved error messaging. All public APIs remain unchanged and fully backward compatible.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

⚖️ License

This project is licensed under the MIT License - see the LICENSE.md file for details.

🙏 Acknowledgments

About

A lightweight, record-based command-line argument parser for Free Pascal. `ArgParser-FP` is designed for small to medium console applications, offering a clean API to handle arguments with minimal setup.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Languages