Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,18 @@ add_executable(test_integration tests/test_integration.cc)
target_link_libraries(test_integration argparse test_framework)
add_test(NAME test_integration COMMAND test_integration)

add_executable(test_auto_help tests/test_auto_help.cc)
target_link_libraries(test_auto_help argparse test_framework)
add_test(NAME test_auto_help COMMAND test_auto_help)

# Add test runner
add_executable(test_runner tests/test_runner.cc)
target_link_libraries(test_runner test_framework)

# Add a custom target to run all tests
add_custom_target(run_tests
COMMAND ${CMAKE_CTEST_COMMAND} --verbose
DEPENDS test_parser test_parameters test_util test_integration
DEPENDS test_parser test_parameters test_util test_integration test_auto_help
COMMENT "Running all tests"
)

104 changes: 101 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ For other platforms, the library can be compiled using CMake and corresponding b

## Testing

The library includes a comprehensive test suite with 44 test cases covering all functionality:
The library includes a comprehensive test suite with 51 test cases covering all functionality:

### Running Tests

Expand All @@ -48,6 +48,7 @@ make run_tests
./test_parameters # Parameter type tests (12 tests)
./test_util # Utility function tests (8 tests)
./test_integration # Integration tests (7 tests)
./test_auto_help # Auto-help feature tests (7 tests)
```

### Test Coverage
Expand All @@ -58,19 +59,106 @@ The test suite covers:
- **Parameter Tests**: All parameter types (NONE, INTEGER, STRING, FLOAT), required parameters, edge cases
- **Utility Tests**: Parameter factory functions, memory management, default behaviors
- **Integration Tests**: Complex real-world scenarios, mixed parameter usage, comprehensive error handling
- **Auto-Help Tests**: Automatic help display, backward compatibility, configuration options

All tests pass with 100% success rate, ensuring reliable functionality across all supported use cases.

## Usage

### Auto-Help Feature (Default Behavior)

The library now includes automatic help handling enabled by default. This provides a simplified, more user-friendly experience:

- **Automatic help display**: When `-h` or `--help` is provided, help is automatically printed and the program exits
- **Automatic error handling**: When parsing fails (unknown parameters, missing values, etc.), an error message and help are automatically displayed, then the program exits
- **Zero boilerplate**: No manual help checking or error handling required

#### Simple Auto-Help Example

```cpp
#include "argparse/parser.h"
#include <iostream>

int main(int argc, char** argv) {
argparse::parser parser;

// Add parameters
parser.add_parameter("h", "help", "Show help message", argparse::parameter_type::NONE);
parser.add_parameter("f", "file", "Input file path", argparse::parameter_type::STRING);
parser.add_parameter("v", "verbose", "Enable verbose output", argparse::parameter_type::NONE);

// Parse automatically handles help and errors
parser.parse(argc, argv);

// Get parameter values (only reached if parsing successful)
std::string filename;
parser.get_parameter_value_to("file", &filename);

bool verbose = false;
parser.get_parameter_value_to("verbose", &verbose);

// Use parsed values
if (verbose) {
std::cout << "Processing file: " << filename << std::endl;
}

return 0;
}
```

**Command line behavior:**
```bash
$ ./app --help
Usage: app [options]
-f, --file Input file path
-h, --help Show help message
-v, --verbose Enable verbose output

$ ./app --unknown
error: unknown parameter unknown
Usage: app [options]
-f, --file Input file path
-h, --help Show help message
-v, --verbose Enable verbose output
```

### Backward Compatibility

For existing code that needs manual control over help and error handling, use `set_auto_help(false)`:

```cpp
argparse::parser parser;
parser.set_auto_help(false); // Disable auto-help for manual control

// ... add parameters ...

if (!parser.parse(argc, argv)) {
std::cerr << "Parse failed!" << std::endl;
std::cout << parser.get_help_message() << std::endl;
return 1;
}

// Manual help checking
bool help = false;
if (parser.get_parameter_value_to("help", &help) && help) {
std::cout << parser.get_help_message() << std::endl;
return 0;
}
```

### Basic Example

### Basic Example (Legacy Manual Approach)

For comparison, here's how you would handle help manually with `set_auto_help(false)`:

```cpp
#include "argparse/parser.h"
#include <iostream>

int main(int argc, char** argv) {
argparse::parser parser;
parser.set_auto_help(false); // Disable auto-help for manual control

// Add parameters
parser.add_parameter("h", "help", "Show help message", argparse::parameter_type::NONE);
Expand All @@ -79,7 +167,11 @@ int main(int argc, char** argv) {
parser.add_parameter("n", "number", "Number of iterations", argparse::parameter_type::INTEGER);

// Parse command line
parser.parse(argc, argv);
if (!parser.parse(argc, argv)) {
std::cerr << "Failed to parse arguments!" << std::endl;
std::cout << parser.get_help_message() << std::endl;
return 1;
}

// Check for help
bool help = false;
Expand Down Expand Up @@ -116,7 +208,13 @@ int main(int argc, char** argv) {

### Additional Examples

See `example/src/example.cc` for a basic usage example, or refer to the comprehensive test suite in the `tests/` directory for advanced usage patterns.
The `example/` directory contains demonstration programs:

- `example_auto_help.cc`: Shows the new default auto-help behavior
- `example_manual_help.cc`: Shows backward-compatible manual help handling
- Basic usage patterns can also be found in `example/src/example.cc`

For comprehensive usage patterns, refer to the test suite in the `tests/` directory.

For more complex usage examples, see main.cc in [scatk](https://github.com/helium729/scatk).

45 changes: 45 additions & 0 deletions example/src/example_auto_help.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "argparse/parser.h"
#include <iostream>

int main(int argc, char** argv)
{
argparse::parser parser;

// Add parameters
parser.add_parameter("h", "help", "Show this help message", argparse::parameter_type::NONE);
parser.add_parameter("f", "file", "Input file path", argparse::parameter_type::STRING, false, "input.txt");
parser.add_parameter("v", "verbose", "Enable verbose output", argparse::parameter_type::NONE);
parser.add_parameter("n", "number", "A number parameter", argparse::parameter_type::INTEGER, false, "42");

// Parse arguments
// Note: With auto-help enabled (default), help will be automatically printed and program will exit
// when -h/--help is used or when parsing fails (unknown parameters, missing values, etc.)
bool parse_success = parser.parse(argc, argv);

if (parse_success) {
std::cout << "Arguments parsed successfully!" << std::endl;

// Get parameter values
std::string file_value;
if (parser.get_parameter_value_to("file", &file_value)) {
std::cout << "File: " << file_value << std::endl;
}

bool verbose_value = false;
if (parser.get_parameter_value_to("verbose", &verbose_value) && verbose_value) {
std::cout << "Verbose mode enabled" << std::endl;
}

int number_value;
if (parser.get_parameter_value_to("number", &number_value)) {
std::cout << "Number: " << number_value << std::endl;
}
} else {
// This should not be reached when auto-help is enabled (default)
// because parse errors will automatically print help and exit
std::cout << "Parse failed!" << std::endl;
return 1;
}

return 0;
}
46 changes: 46 additions & 0 deletions example/src/example_manual_help.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#include "argparse/parser.h"
#include <iostream>

int main(int argc, char** argv)
{
argparse::parser parser;

// Disable auto-help for manual control (backward compatibility)
parser.set_auto_help(false);

// Add parameters
parser.add_parameter("h", "help", "Show this help message", argparse::parameter_type::NONE);
parser.add_parameter("f", "file", "Input file path", argparse::parameter_type::STRING, false, "input.txt");
parser.add_parameter("v", "verbose", "Enable verbose output", argparse::parameter_type::NONE);

// Parse arguments
bool parse_success = parser.parse(argc, argv);

if (!parse_success) {
std::cerr << "Failed to parse arguments!" << std::endl;
std::cout << parser.get_help_message() << std::endl;
return 1;
}

// Check if help was requested
bool help = false;
if (parser.get_parameter_value_to("h", &help) && help) {
std::cout << parser.get_help_message() << std::endl;
return 0;
}

std::cout << "Arguments parsed successfully!" << std::endl;

// Get parameter values
std::string file_value;
if (parser.get_parameter_value_to("file", &file_value)) {
std::cout << "File: " << file_value << std::endl;
}

bool verbose_value = false;
if (parser.get_parameter_value_to("verbose", &verbose_value) && verbose_value) {
std::cout << "Verbose mode enabled" << std::endl;
}

return 0;
}
54 changes: 31 additions & 23 deletions include/argparse/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,37 @@
namespace argparse
{

class parser
{
public:
parser();
virtual ~parser();

void add_parameter(std::string short_name, std::string name, std::string description, parameter_type type=NONE, bool required=false, std::string default_value=std::string(""));

std::string get_help_message();

bool parse(std::vector<std::string> args);
bool parse(int argc, char** argv);

bool get_parameter_value_to(std::string flag, void* value_buf);


private:
std::map<std::string, parameter*> parameters;
std::string program_name;

std::map<std::string, std::string> short_name_query;
std::map<std::string, std::string> name_query;

class parser
{
public:
parser();
virtual ~parser();

void add_parameter(std::string short_name, std::string name, std::string description, parameter_type type=NONE, bool required=false, std::string default_value=std::string(""));

std::string get_help_message();

bool parse(std::vector<std::string> args);
bool parse(int argc, char** argv);

bool get_parameter_value_to(std::string flag, void* value_buf);

// Auto-help configuration
void set_auto_help(bool enable);

private:
std::map<std::string, parameter*> parameters;
std::string program_name;

std::map<std::string, std::string> short_name_query;
std::map<std::string, std::string> name_query;

bool auto_help_enabled;

// Helper methods for auto-help
bool is_help_requested();
void print_help_and_exit();

};
}

Expand Down
Loading