Skip to main content

Accessing Values

Learn how to retrieve and use parsed option values in your Argus applications with type-safe access methods.

Core Access Functions

After argus_parse() succeeds, use these functions to access your parsed values:

FunctionPurposeReturns
argus_get()Get option valueargus_value_t union
argus_is_set()Check if option was providedbool
argus_count()Get number of values (collections)size_t

Basic Value Access

Access values using the option's identifier (long name, or short name if no long name):

ARGUS_OPTIONS(
options,
OPTION_FLAG('v', "verbose", HELP("Verbose output")),
OPTION_STRING('o', "output", HELP("Output file")),
OPTION_INT('p', "port", HELP("Port number")),
OPTION_FLOAT('r', "rate", HELP("Processing rate")),
OPTION_BOOL('d', "debug", HELP("Debug mode")),
)

int main(int argc, char **argv)
{
argus_t argus = argus_init(options, "myapp", "1.0.0");
argus_parse(&argus, argc, argv);

// Access by long name (preferred)
bool verbose = argus_get(&argus, "verbose").as_bool;
const char *output = argus_get(&argus, "output").as_string;
int port = argus_get(&argus, "port").as_int;
float rate = argus_get(&argus, "rate").as_float;
bool debug = argus_get(&argus, "debug").as_bool;

printf("Verbose: %s\n", verbose ? "yes" : "no");
printf("Output: %s\n", output);
printf("Port: %d\n", port);
printf("Rate: %.2f\n", rate);

argus_free(&argus);
return 0;
}

Checking If Options Are Set

Use argus_is_set() to distinguish between default values and user-provided values:

ARGUS_OPTIONS(
options,
OPTION_STRING('o', "output", HELP("Output file"), DEFAULT("default.txt")),
OPTION_INT('p', "port", HELP("Port"), DEFAULT(8080)),
POSITIONAL_STRING("input", HELP("Input file")),
)

int main(int argc, char **argv)
{
argus_t argus = argus_init(options, "myapp", "1.0.0");
argus_parse(&argus, argc, argv);

// Always check if user explicitly set the option
if (argus_is_set(&argus, "output"))
printf("User specified output: %s\n", argus_get(&argus, "output").as_string);
else
printf("Using default output: %s\n", argus_get(&argus, "output").as_string);

// Required positionals are always set (or parsing fails)
const char *input = argus_get(&argus, "input").as_string;
printf("Input: %s\n", input);

argus_free(&argus);
return 0;
}
When to use argus_is_set()
  • Optional arguments: Check before accessing to avoid using defaults
  • Conditional logic: Different behavior based on whether user provided the option
  • Validation: Ensure required logic only runs when user provided values
  • Debugging: Log what the user actually specified vs defaults

Array Collections

Access array values using direct access or helper functions:

ARGUS_OPTIONS(
options,
OPTION_ARRAY_STRING('t', "tags", HELP("Tags")),
OPTION_ARRAY_INT('n', "numbers", HELP("Numbers")),
)

int main(int argc, char **argv)
{
argus_t argus = argus_init(options, "myapp", "1.0.0");
argus_parse(&argus, argc, argv);

// Get array count and data
size_t tag_count = argus_count(&argus, "tags");
argus_value_t *tags = argus_get(&argus, "tags").as_array;

printf("Tags (%zu):\n", tag_count);
for (size_t i = 0; i < tag_count; i++)
printf(" %zu: %s\n", i + 1, tags[i].as_string);

// Same for integers
size_t num_count = argus_count(&argus, "numbers");
argus_value_t *numbers = argus_get(&argus, "numbers").as_array;

for (size_t i = 0; i < num_count; i++)
printf("Number %zu: %d\n", i + 1, numbers[i].as_int);

argus_free(&argus);
return 0;
}

Map Collections

Access key-value pairs using direct access or lookup helpers:

ARGUS_OPTIONS(
options,
OPTION_MAP_STRING('e', "env", HELP("Environment variables")),
OPTION_MAP_INT('p', "ports", HELP("Port mappings")),
)

int main(int argc, char **argv)
{
argus_t argus = argus_init(options, "myapp", "1.0.0");
argus_parse(&argus, argc, argv);

// Get map count and data
size_t env_count = argus_count(&argus, "env");
argus_pair_t *env_map = argus_get(&argus, "env").as_map;

printf("Environment variables (%zu):\n", env_count);
for (size_t i = 0; i < env_count; i++)
printf(" %s = %s\n", env_map[i].key, env_map[i].value.as_string);

argus_free(&argus);
return 0;
}

Subcommand Access

In subcommand context, access values using path notation or relative names:

// Subcommand action handler
int add_command(argus_t *argus, void *data)
{
(void)data; // Unused

// Access subcommand options using relative names
const char *file = argus_get(argus, "file").as_string;
bool force = argus_get(argus, "force").as_bool;

// Access global options using absolute path
bool verbose = argus_get(argus, ".verbose").as_bool;

printf("Adding file: %s\n", file);
if (force)
printf(" (forced)\n");
if (verbose)
printf(" (verbose mode)\n");

return 0;
}

ARGUS_OPTIONS(add_options,
HELP_OPTION(),
OPTION_FLAG('f', "force", HELP("Force operation")),
POSITIONAL_STRING("file", HELP("File to add")),
)

ARGUS_OPTIONS(options,
HELP_OPTION(),
OPTION_FLAG('v', "verbose", HELP("Verbose output")),
SUBCOMMAND("add", add_options, HELP("Add a file"), ACTION(add_command)),
)

Custom Types

Access custom handler values through the generic pointer:

typedef struct {
char *host;
int port;
} endpoint_t;

// Custom handler creates endpoint_t structure
int endpoint_handler(argus_t *argus, argus_option_t *option, char *arg)
{
// Parse "host:port" format into endpoint_t
// (implementation details omitted)

endpoint_t *endpoint = malloc(sizeof(endpoint_t));
// ... parse and populate endpoint ...

option->value.as_ptr = endpoint;
option->is_allocated = true;
return ARGUS_SUCCESS;
}

ARGUS_OPTIONS(options,
OPTION_BASE('e', "endpoint", VALUE_TYPE_CUSTOM,
HANDLER(endpoint_handler),
HELP("Server endpoint (host:port)")),
)

int main(int argc, char **argv)
{
argus_t argus = argus_init(options, "myapp", "1.0.0");
argus_parse(&argus, argc, argv);

// Cast generic pointer to your custom type
endpoint_t *endpoint = (endpoint_t*)argus_get(&argus, "endpoint").as_ptr;

if (endpoint) {
printf("Host: %s\n", endpoint->host);
printf("Port: %d\n", endpoint->port);
}

argus_free(&argus);
return 0;
}

Error Handling

Always check parse results before accessing values:

int main(int argc, char **argv)
{
argus_t argus = argus_init(options, "myapp", "1.0.0");

// Parse can fail - always check the result
int status = argus_parse(&argus, argc, argv);
if (status != ARGUS_SUCCESS) {
// Error already printed by argus_parse(), argus_free() is not needed
return status;
}

// Safe to access values after successful parse
bool verbose = argus_get(&argus, "verbose").as_bool;
const char *input = argus_get(&argus, "input").as_string;

// Your application logic here

argus_free(&argus);
return 0;
}

Best Practices

✅ Good Practices

// 1. Always check parse result
if (argus_parse(&argus, argc, argv) != ARGUS_SUCCESS) {
return 1;
}

// 2. Use descriptive variable names
const char *config_file = argus_get(&argus, "config").as_string;
bool enable_debug = argus_get(&argus, "debug").as_bool;

// 3. Check optional values before using
if (argus_is_set(&argus, "output")) {
const char *output = argus_get(&argus, "output").as_string;
// Use output...
}

// 4. Access arrays safely
size_t count = argus_count(&argus, "files");
if (count > 0) {
argus_value_t *files = argus_get(&argus, "files").as_array;
// Process files...
}

❌ Avoid These Patterns

// ❌ Don't ignore parse errors
argus_parse(&argus, argc, argv); // Missing error check
bool verbose = argus_get(&argus, "verbose").as_bool;

// ❌ Don't access without checking count for arrays
argus_value_t *files = argus_get(&argus, "files").as_array;
printf("First file: %s\n", files[0].as_string); // May crash!

// ❌ Don't assume optional values are set
const char *output = argus_get(&argus, "output").as_string;
FILE *f = fopen(output, "w"); // output might be NULL!

Access Patterns Summary

ScenarioMethodExample
Basic typesargus_get().as_typeargus_get(&argus, "port").as_int
Check if setargus_is_set()if (argus_is_set(&argus, "output"))
Array elementsargus_array_get()argus_array_get(&argus, "tags", 0)
Array iterationargus_array_it()while (argus_array_next(&it))
Map lookupargus_map_get()argus_map_get(&argus, "env", "USER")
Map iterationargus_map_it()while (argus_map_next(&it))
Subcommand relativeargus_get()argus_get(argus, "file").as_string
Root from subcommandargus_get() with .argus_get(argus, ".debug").as_bool
Custom typesCast as_ptr(my_type_t*)argus_get().as_ptr

What's Next?

Now that you know how to access values, learn about:

Memory Management

Argus automatically manages memory for all parsed values. Just remember to call argus_free() before your program exits to clean up resources.