ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
builder.c File Reference

Implementation of options builder API. More...

Go to the source code of this file.

Macros

#define asprintf   platform_asprintf
 

Functions

const char * get_option_help_placeholder_str (const option_descriptor_t *desc)
 Get help placeholder string for an option type.
 
int format_option_default_value_str (const option_descriptor_t *desc, char *buf, size_t bufsize)
 Format option default value as a string.
 
bool option_applies_to_mode (const option_descriptor_t *desc, asciichat_mode_t mode, bool for_binary_help)
 Check if an option applies to a specific mode using bitmask.
 
void ensure_descriptor_capacity (options_builder_t *builder)
 Grow descriptor array if needed.
 
void ensure_dependency_capacity (options_builder_t *builder)
 Grow dependency array if needed.
 
void ensure_positional_arg_capacity (options_builder_t *builder)
 Grow positional arg array if needed.
 
const option_descriptor_t * find_option (const options_config_t *config, const char *long_name)
 Find option descriptor by long name.
 
bool is_option_set (const options_config_t *config, const void *options_struct, const char *option_name)
 Check if an option is set (has non-default value)
 
options_builder_t * options_builder_create (size_t struct_size)
 Create empty options builder.
 
options_builder_t * options_builder_from_preset (const options_config_t *preset)
 Create builder from preset config.
 
void options_builder_destroy (options_builder_t *builder)
 Free options builder.
 
options_config_t * options_builder_build (options_builder_t *builder)
 Build immutable options config.
 
void options_config_destroy (options_config_t *config)
 Free options config.
 
void options_builder_add_bool (options_builder_t *builder, const char *long_name, char short_name, size_t offset, bool default_value, const char *help_text, const char *group, bool required, const char *env_var_name)
 Add boolean flag option.
 
void options_builder_add_int (options_builder_t *builder, const char *long_name, char short_name, size_t offset, int default_value, const char *help_text, const char *group, bool required, const char *env_var_name, bool(*validate)(const void *, char **))
 
void options_builder_add_int_with_metadata (options_builder_t *builder, const char *long_name, char short_name, size_t offset, int default_value, const char *help_text, const char *group, bool required, const char *env_var_name, bool(*validate)(const void *options_struct, char **error_msg), const option_metadata_t *metadata)
 Add integer option with metadata (for numeric ranges and examples)
 
void options_builder_add_string (options_builder_t *builder, const char *long_name, char short_name, size_t offset, const char *default_value, const char *help_text, const char *group, bool required, const char *env_var_name, bool(*validate)(const void *, char **))
 
void options_builder_add_double (options_builder_t *builder, const char *long_name, char short_name, size_t offset, double default_value, const char *help_text, const char *group, bool required, const char *env_var_name, bool(*validate)(const void *, char **), bool optional_arg)
 
void options_builder_add_double_with_metadata (options_builder_t *builder, const char *long_name, char short_name, size_t offset, double default_value, const char *help_text, const char *group, bool required, const char *env_var_name, bool(*validate)(const void *, char **), const option_metadata_t *metadata, bool optional_arg)
 
void options_builder_add_callback (options_builder_t *builder, const char *long_name, char short_name, size_t offset, const void *default_value, size_t value_size, bool(*parse_fn)(const char *, void *, char **), const char *help_text, const char *group, bool required, const char *env_var_name)
 
void options_builder_add_callback_optional (options_builder_t *builder, const char *long_name, char short_name, size_t offset, const void *default_value, size_t value_size, bool(*parse_fn)(const char *, void *, char **), const char *help_text, const char *group, bool required, const char *env_var_name, bool optional_arg)
 Add callback option with optional argument support.
 
void options_builder_add_callback_with_metadata (options_builder_t *builder, const char *long_name, char short_name, size_t offset, const void *default_value, size_t value_size, bool(*parse_fn)(const char *, void *, char **), const char *help_text, const char *group, bool required, const char *env_var_name, bool optional_arg, const option_metadata_t *metadata)
 
void options_builder_add_action (options_builder_t *builder, const char *long_name, char short_name, void(*action_fn)(void), const char *help_text, const char *group)
 Add action option (executes action and may exit)
 
void options_builder_add_descriptor (options_builder_t *builder, const option_descriptor_t *descriptor)
 Add full option descriptor (advanced)
 
void options_builder_set_mode_bitmask (options_builder_t *builder, option_mode_bitmask_t mode_bitmask)
 Set mode bitmask on the last added option descriptor.
 
void options_builder_set_arg_placeholder (options_builder_t *builder, const char *arg_placeholder)
 Set custom argument placeholder on the last added option descriptor.
 
void options_builder_set_enum_values (options_builder_t *builder, const char *option_name, const char **values, const char **descriptions)
 Set enum values with descriptions for an option.
 
void options_builder_set_numeric_range (options_builder_t *builder, const char *option_name, int min, int max, int step)
 Set numeric range for an option.
 
void options_builder_set_examples (options_builder_t *builder, const char *option_name, const char **examples)
 Set example values for an option.
 
void options_builder_set_input_type (options_builder_t *builder, const char *option_name, option_input_type_t input_type)
 Set input type for an option.
 
void options_builder_mark_as_list (options_builder_t *builder, const char *option_name)
 Mark option as accepting multiple values.
 
void options_builder_set_default_value_display (options_builder_t *builder, const char *option_name, const char *default_value)
 Set default value string in metadata.
 
void options_builder_add_dependency_requires (options_builder_t *builder, const char *option_name, const char *depends_on, const char *error_message)
 Add dependency: if option_name is set, depends_on must be set.
 
void options_builder_add_dependency_conflicts (options_builder_t *builder, const char *option_name, const char *conflicts_with, const char *error_message)
 Add anti-dependency: if option_name is set, conflicts_with must NOT be set.
 
void options_builder_add_dependency_implies (options_builder_t *builder, const char *option_name, const char *implies, const char *error_message)
 Add implication: if option_name is set, implies defaults to true.
 
void options_builder_add_dependency (options_builder_t *builder, const option_dependency_t *dependency)
 Add full dependency (advanced)
 
void options_builder_mark_binary_only (options_builder_t *builder, const char *option_name)
 Mark an option as binary-level only (hide from mode-specific help)
 
void options_builder_add_positional (options_builder_t *builder, const char *name, const char *help_text, bool required, const char *section_heading, const char **examples, size_t num_examples, option_mode_bitmask_t mode_bitmask, int(*parse_fn)(const char *arg, void *config, char **remaining, int num_remaining, char **error_msg))
 Add positional argument descriptor.
 
void options_builder_add_usage (options_builder_t *builder, const char *mode, const char *positional, bool show_options, const char *description)
 Add usage line descriptor.
 
void options_builder_add_example (options_builder_t *builder, uint32_t mode_bitmask, const char *args, const char *description, bool owns_args)
 Add example descriptor.
 
void options_builder_add_example_utility (options_builder_t *builder, uint32_t mode_bitmask, const char *args, const char *description, bool is_utility_command)
 Add an example with utility command support.
 
void options_builder_add_mode (options_builder_t *builder, const char *name, const char *description)
 Add mode descriptor.
 
void options_builder_add_custom_section (options_builder_t *builder, const char *heading, const char *content, option_mode_bitmask_t mode_bitmask)
 Add a custom help section.
 
asciichat_error_t options_config_parse_positional (const options_config_t *config, int remaining_argc, char **remaining_argv, void *options_struct)
 Parse positional arguments.
 
asciichat_error_t options_config_set_defaults (const options_config_t *config, void *options_struct)
 Set default values in options struct.
 
const option_descriptor_t * find_option_descriptor (const options_config_t *config, const char *opt_name)
 Find option descriptor by short or long name.
 
asciichat_error_t options_config_parse (const options_config_t *config, int argc, char **argv, void *options_struct, option_mode_bitmask_t detected_mode, int *remaining_argc, char ***remaining_argv)
 Parse command-line arguments.
 
asciichat_error_t options_config_validate (const options_config_t *config, const void *options_struct, char **error_message)
 Validate options struct.
 

Detailed Description

Implementation of options builder API.

Definition in file builder.c.

Macro Definition Documentation

◆ asprintf

#define asprintf   platform_asprintf

Definition at line 24 of file builder.c.

Function Documentation

◆ ensure_dependency_capacity()

void ensure_dependency_capacity ( options_builder_t *  builder)

Grow dependency array if needed.

Definition at line 230 of file builder.c.

230 {
231 if (builder->num_dependencies >= builder->dependency_capacity) {
232 size_t new_capacity = builder->dependency_capacity * 2;
233 option_dependency_t *new_dependencies =
234 SAFE_REALLOC(builder->dependencies, new_capacity * sizeof(option_dependency_t), option_dependency_t *);
235 if (!new_dependencies) {
236 log_fatal("Failed to reallocate dependencies array");
237 return;
238 }
239 builder->dependencies = new_dependencies;
240 builder->dependency_capacity = new_capacity;
241 }
242}
#define SAFE_REALLOC(ptr, size, cast)
Definition common.h:284
#define log_fatal(...)
Log a FATAL message.
Definition log/log.h:599
Option dependency.
Definition builder.h:331
size_t num_dependencies
Current count.
Definition builder.h:447
size_t dependency_capacity
Allocated capacity.
Definition builder.h:448
option_dependency_t * dependencies
Dynamic array of dependencies.
Definition builder.h:446

References options_builder_t::dependencies, options_builder_t::dependency_capacity, log_fatal, options_builder_t::num_dependencies, and SAFE_REALLOC.

Referenced by options_builder_add_dependency(), options_builder_add_dependency_conflicts(), options_builder_add_dependency_implies(), and options_builder_add_dependency_requires().

◆ ensure_descriptor_capacity()

void ensure_descriptor_capacity ( options_builder_t *  builder)

Grow descriptor array if needed.

Definition at line 213 of file builder.c.

213 {
214 if (builder->num_descriptors >= builder->descriptor_capacity) {
215 size_t new_capacity = builder->descriptor_capacity * 2;
216 option_descriptor_t *new_descriptors =
217 SAFE_REALLOC(builder->descriptors, new_capacity * sizeof(option_descriptor_t), option_descriptor_t *);
218 if (!new_descriptors) {
219 log_fatal("Failed to reallocate descriptors array");
220 return;
221 }
222 builder->descriptors = new_descriptors;
223 builder->descriptor_capacity = new_capacity;
224 }
225}
Option descriptor.
Definition builder.h:241
size_t descriptor_capacity
Allocated capacity.
Definition builder.h:444
option_descriptor_t * descriptors
Dynamic array of descriptors.
Definition builder.h:442
size_t num_descriptors
Current count.
Definition builder.h:443

References options_builder_t::descriptor_capacity, options_builder_t::descriptors, log_fatal, options_builder_t::num_descriptors, and SAFE_REALLOC.

Referenced by options_builder_add_action(), options_builder_add_bool(), options_builder_add_callback(), options_builder_add_callback_optional(), options_builder_add_callback_with_metadata(), options_builder_add_descriptor(), options_builder_add_double(), options_builder_add_double_with_metadata(), options_builder_add_int(), options_builder_add_int_with_metadata(), and options_builder_add_string().

◆ ensure_positional_arg_capacity()

void ensure_positional_arg_capacity ( options_builder_t *  builder)

Grow positional arg array if needed.

Definition at line 247 of file builder.c.

247 {
248 if (builder->num_positional_args >= builder->positional_arg_capacity) {
249 size_t new_capacity = builder->positional_arg_capacity * 2;
250 if (new_capacity == 0)
251 new_capacity = INITIAL_POSITIONAL_ARG_CAPACITY;
252
255 if (!new_positional) {
256 log_fatal("Failed to reallocate positional_args array");
257 return;
258 }
259 builder->positional_args = new_positional;
260 builder->positional_arg_capacity = new_capacity;
261 }
262}
#define INITIAL_POSITIONAL_ARG_CAPACITY
positional_arg_descriptor_t * positional_args
Dynamic array of positional args.
Definition builder.h:450
size_t num_positional_args
Current count.
Definition builder.h:451
size_t positional_arg_capacity
Allocated capacity.
Definition builder.h:452
Positional argument descriptor.
Definition builder.h:357

References INITIAL_POSITIONAL_ARG_CAPACITY, log_fatal, options_builder_t::num_positional_args, options_builder_t::positional_arg_capacity, options_builder_t::positional_args, and SAFE_REALLOC.

Referenced by options_builder_add_positional().

◆ find_option()

const option_descriptor_t * find_option ( const options_config_t *  config,
const char *  long_name 
)

Find option descriptor by long name.

Definition at line 344 of file builder.c.

344 {
345 for (size_t i = 0; i < config->num_descriptors; i++) {
346 if (strcmp(config->descriptors[i].long_name, long_name) == 0) {
347 return &config->descriptors[i];
348 }
349 }
350 return NULL;
351}
const char * long_name
Long option name (e.g., "port")
Definition builder.h:243
option_descriptor_t * descriptors
Array of option descriptors.
Definition builder.h:402
size_t num_descriptors
Number of descriptors.
Definition builder.h:403

References options_config_t::descriptors, option_descriptor_t::long_name, and options_config_t::num_descriptors.

Referenced by is_option_set().

◆ find_option_descriptor()

const option_descriptor_t * find_option_descriptor ( const options_config_t *  config,
const char *  opt_name 
)

Find option descriptor by short or long name.

Definition at line 1490 of file builder.c.

1490 {
1491 if (!opt_name || opt_name[0] == '\0')
1492 return NULL;
1493
1494 // Handle short options: -x (single dash, single char)
1495 if (opt_name[0] == '-' && opt_name[1] != '-' && opt_name[1] != '\0') {
1496 // This is a short option like -x
1497 char short_char = opt_name[1];
1498 for (size_t i = 0; i < config->num_descriptors; i++) {
1499 if (config->descriptors[i].short_name == short_char) {
1500 return &config->descriptors[i];
1501 }
1502 }
1503 // Short option not found
1504 return NULL;
1505 }
1506
1507 // Handle long options: --name (double dash)
1508 if (opt_name[0] == '-' && opt_name[1] == '-' && opt_name[2] != '\0') {
1509 const char *long_name = opt_name + 2; // Skip the '--'
1510 for (size_t i = 0; i < config->num_descriptors; i++) {
1511 if (strcmp(config->descriptors[i].long_name, long_name) == 0) {
1512 return &config->descriptors[i];
1513 }
1514 }
1515 // Long option not found
1516 return NULL;
1517 }
1518
1519 // Not a recognized option format
1520 return NULL;
1521}
char short_name
Short option char (e.g., 'p', or '\0' if none)
Definition builder.h:244

References options_config_t::descriptors, option_descriptor_t::long_name, options_config_t::num_descriptors, and option_descriptor_t::short_name.

◆ format_option_default_value_str()

int format_option_default_value_str ( const option_descriptor_t *  desc,
char *  buf,
size_t  bufsize 
)

Format option default value as a string.

Parameters
descOption descriptor
bufOutput buffer
bufsizeSize of buffer
Returns
Number of characters written to buf

Definition at line 83 of file builder.c.

83 {
84 if (!desc || !buf || bufsize == 0) {
85 return 0;
86 }
87
88 // For callback options with enums, look up the enum string by matching the default value
89 if (desc->type == OPTION_TYPE_CALLBACK && desc->metadata.enum_values && desc->default_value) {
90 int default_int_val = 0;
91 memcpy(&default_int_val, desc->default_value, sizeof(int));
92
93 // Try to find matching enum value
94 if (desc->metadata.enum_integer_values) {
95 for (size_t i = 0; desc->metadata.enum_values[i] != NULL; i++) {
96 if (desc->metadata.enum_integer_values[i] == default_int_val) {
97 return safe_snprintf(buf, bufsize, "%s", desc->metadata.enum_values[i]);
98 }
99 }
100 } else {
101 // Fallback: assume sequential 0-based indices if integer values not provided
102 // Count enum values to check bounds
103 size_t enum_count = 0;
104 while (desc->metadata.enum_values[enum_count] != NULL) {
105 enum_count++;
106 }
107 if (default_int_val >= 0 && (size_t)default_int_val < enum_count) {
108 return safe_snprintf(buf, bufsize, "%s", desc->metadata.enum_values[default_int_val]);
109 }
110 }
111 }
112
113 // For callback options storing numeric types (int/double/float), format them as numbers
114 if (desc->type == OPTION_TYPE_CALLBACK && desc->default_value && desc->metadata.enum_values == NULL) {
115 // Check if this is a numeric callback by looking for numeric_range metadata
116 // Numeric callbacks have min/max range constraints set (max != 0 indicates a range was set)
117 if (desc->metadata.numeric_range.max != 0 || desc->metadata.numeric_range.min != 0) {
118 // This is a numeric callback option - extract and format the value
119 // Determine if it's int or double based on range (int max is 2147483647)
120 double default_double = 0.0;
121 if (desc->metadata.numeric_range.max <= 2147483647.0 && desc->metadata.numeric_range.min >= -2147483648.0) {
122 // Integer-ranged value (like port 1-65535) - stored as int
123 int default_int = 0;
124 memcpy(&default_int, desc->default_value, sizeof(int));
125 default_double = (double)default_int;
126 } else {
127 // Double-ranged value - stored as double
128 memcpy(&default_double, desc->default_value, sizeof(double));
129 }
130
131 // Format with appropriate precision (remove trailing zeros for integers)
132 char formatted[32];
133 safe_snprintf(formatted, sizeof(formatted), "%.1f", default_double);
134
135 // Remove trailing zeros after decimal point
136 char *dot = strchr(formatted, '.');
137 if (dot) {
138 char *end = formatted + strlen(formatted) - 1;
139 while (end > dot && *end == '0') {
140 end--;
141 }
142 if (*end == '.') {
143 *end = '\0';
144 } else {
145 *(end + 1) = '\0';
146 }
147 }
148
149 return safe_snprintf(buf, bufsize, "%s", formatted);
150 }
151 }
152
153 // For callback options with string defaults (no enum, no numeric range)
154 // Treat default_value as a const char* string pointer
155 if (desc->type == OPTION_TYPE_CALLBACK && desc->default_value && desc->metadata.enum_values == NULL &&
156 desc->metadata.numeric_range.max == 0 && desc->metadata.numeric_range.min == 0) {
157 const char *str_default = (const char *)desc->default_value;
158 if (str_default && str_default[0] != '\0') {
159 return safe_snprintf(buf, bufsize, "%s", str_default);
160 }
161 }
162
163 return options_format_default_value(desc->type, desc->default_value, buf, bufsize);
164}
@ OPTION_TYPE_CALLBACK
Custom parser function.
Definition builder.h:166
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.
Definition system.c:148
int options_format_default_value(option_type_t type, const void *default_value, char *buf, size_t bufsize)
Format option default value to string.
const void * default_value
Pointer to default value (or NULL if required)
Definition builder.h:258
option_metadata_t metadata
Metadata for shell completions (enums, ranges, examples, etc.)
Definition builder.h:281
option_type_t type
Value type.
Definition builder.h:247
int max
Maximum value (or 0 if no limit)
Definition builder.h:203
int min
Minimum value (or 0 if no limit)
Definition builder.h:202
const int * enum_integer_values
Actual enum integer values (e.g., {-1, 0, 1, 2, 3} for non-sequential enums)
Definition builder.h:198
const char ** enum_values
Enum value strings (null-terminated, e.g., {"auto", "none", "16", "256", "truecolor",...
Definition builder.h:195
struct option_metadata_t::@19 numeric_range

References option_descriptor_t::default_value, option_metadata_t::enum_integer_values, option_metadata_t::enum_values, option_metadata_t::max, option_descriptor_t::metadata, option_metadata_t::min, option_metadata_t::numeric_range, OPTION_TYPE_CALLBACK, options_format_default_value(), safe_snprintf(), and option_descriptor_t::type.

Referenced by options_config_print_options_sections_with_width(), and options_config_print_usage().

◆ get_option_help_placeholder_str()

const char * get_option_help_placeholder_str ( const option_descriptor_t *  desc)

Get help placeholder string for an option type.

Parameters
descOption descriptor
Returns
Pointer to string literal ("INTEGER", "NUMBER", "STRING", "VALUE", "[BOOLEAN]"), custom placeholder, or empty string

Definition at line 43 of file builder.c.

43 {
44 if (!desc) {
45 return "";
46 }
47 // Check for custom placeholder first
48 if (desc->arg_placeholder != NULL) {
49 return desc->arg_placeholder;
50 }
51
52 // For callback options, check if it's a boolean based on enum values
53 if (desc->type == OPTION_TYPE_CALLBACK && desc->metadata.enum_values) {
54 // Check if enum values contain "true" and "false" (boolean-like)
55 const char *const *values = desc->metadata.enum_values;
56 bool has_true = false, has_false = false;
57
58 for (int i = 0; values[i] != NULL; i++) {
59 if (strcmp(values[i], "true") == 0 || strcmp(values[i], "yes") == 0 || strcmp(values[i], "on") == 0) {
60 has_true = true;
61 }
62 if (strcmp(values[i], "false") == 0 || strcmp(values[i], "no") == 0 || strcmp(values[i], "off") == 0) {
63 has_false = true;
64 }
65 }
66
67 // If it has both true-like and false-like values, it's boolean
68 if (has_true && has_false) {
69 return "BOOLEAN";
70 }
71 }
72
74}
const char * options_get_type_placeholder(option_type_t type)
Get placeholder string for option type.
const char * arg_placeholder
Custom argument placeholder (e.g., "SHELL [FILE]" instead of "STR")
Definition builder.h:253

References option_descriptor_t::arg_placeholder, option_metadata_t::enum_values, option_descriptor_t::metadata, OPTION_TYPE_CALLBACK, options_get_type_placeholder(), and option_descriptor_t::type.

Referenced by options_config_print_options_sections_with_width(), and options_config_print_usage().

◆ is_option_set()

bool is_option_set ( const options_config_t *  config,
const void *  options_struct,
const char *  option_name 
)

Check if an option is set (has non-default value)

Definition at line 356 of file builder.c.

356 {
357 const option_descriptor_t *desc = find_option(config, option_name);
358 if (!desc)
359 return false;
360
361 const char *base = (const char *)options_struct;
362 const void *field = base + desc->offset;
363
364 // Use handler registry to check if option is set
365 if (desc->type >= 0 && desc->type < (int)(NUM_OPTION_TYPES)) {
366 if (g_builder_handlers[desc->type].is_set) {
367 return g_builder_handlers[desc->type].is_set(field, desc);
368 }
369 }
370
371 return false;
372}
const option_descriptor_t * find_option(const options_config_t *config, const char *long_name)
Find option descriptor by long name.
Definition builder.c:344
const option_builder_handler_t g_builder_handlers[]
#define NUM_OPTION_TYPES
bool(* is_set)(const void *field, const option_descriptor_t *desc)
size_t offset
offsetof(struct, field) - where to store value
Definition builder.h:248

References find_option(), g_builder_handlers, option_builder_handler_t::is_set, NUM_OPTION_TYPES, option_descriptor_t::offset, and option_descriptor_t::type.

Referenced by options_config_validate().

◆ option_applies_to_mode()

bool option_applies_to_mode ( const option_descriptor_t *  desc,
asciichat_mode_t  mode,
bool  for_binary_help 
)

Check if an option applies to a specific mode using bitmask.

Parameters
descOption descriptor
modeMode to check (use invalid value like -1 for binary help)
for_binary_helpIf true, show binary options; if false, hide them
Returns
true if option should be shown for this mode

Definition at line 177 of file builder.c.

177 {
178 if (!desc) {
179 SET_ERRNO(ERROR_INVALID_PARAM, "Descriptor is NULL");
180 return false;
181 }
182
183 // When for_binary_help is true (i.e., for 'ascii-chat --help'),
184 // show options that apply to the default mode (DISCOVERY) or binary-level options only.
185 // Don't show mode-specific options for other modes (server, client, mirror, discovery-service).
186 if (for_binary_help) {
187 // Binary-level options or options that apply to discovery mode (the default)
189 return (desc->mode_bitmask & default_modes) != 0 && !desc->hide_from_binary_help;
190 }
191
192 // For mode-specific help (non-discovery modes), show only options for that mode.
193 // Do not show binary options here unless it also specifically applies to the mode.
194 // The 'mode' parameter is the actual mode (e.g., MODE_CLIENT, MODE_SERVER).
195 if (mode < 0 || mode > MODE_DISCOVERY) { // Use MODE_INVALID as upper bound for valid modes
196 return false;
197 }
198 option_mode_bitmask_t mode_bit = (1 << mode);
199
200 // Check if it's a binary option. If so, only show if it also explicitly applies to this mode.
201 if ((desc->mode_bitmask & OPTION_MODE_BINARY) && !(desc->mode_bitmask & mode_bit)) {
202 return false; // Binary options not shown in mode-specific help unless also mode-specific
203 }
204
205 bool applies = (desc->mode_bitmask & mode_bit) != 0;
206
207 return applies && !desc->hide_from_mode_help;
208}
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it, returning the error code.
@ ERROR_INVALID_PARAM
option_mode_bitmask_t
Option mode bitmask.
@ MODE_DISCOVERY
Discovery mode - participant that can dynamically become host.
@ OPTION_MODE_BINARY
Binary-level options (parsed before mode detection)
@ OPTION_MODE_DISCOVERY
Discovery mode (bit 4)
option_mode_bitmask_t mode_bitmask
Which modes this option applies to.
Definition builder.h:278
bool hide_from_mode_help
If true, don't show in mode-specific help (binary-level only)
Definition builder.h:254
bool hide_from_binary_help
If true, don't show in binary-level help (e.g., in release builds)
Definition builder.h:255

References ERROR_INVALID_PARAM, option_descriptor_t::hide_from_binary_help, option_descriptor_t::hide_from_mode_help, option_descriptor_t::mode_bitmask, MODE_DISCOVERY, OPTION_MODE_BINARY, OPTION_MODE_DISCOVERY, and SET_ERRNO.

Referenced by options_config_print_options_sections_with_width(), and options_config_print_usage().

◆ options_builder_add_action()

void options_builder_add_action ( options_builder_t *  builder,
const char *  long_name,
char  short_name,
void(*)(void)  action_fn,
const char *  help_text,
const char *  group 
)

Add action option (executes action and may exit)

Action options execute a callback function when encountered during parsing. The callback may exit the program (e.g., –list-webcams, –version).

Parameters
builderBuilder to add to
long_nameLong option name
short_nameShort option char (or '\0')
action_fnAction callback to execute
help_textHelp description
groupGroup name for help

Definition at line 943 of file builder.c.

944 {
946
947 option_descriptor_t desc = {.long_name = long_name,
948 .short_name = short_name,
949 .type = OPTION_TYPE_ACTION,
950 .offset = 0, // Actions don't store values
951 .help_text = help_text,
952 .group = group,
953 .default_value = NULL,
954 .required = false, // Actions are never required
955 .env_var_name = NULL,
956 .validate = NULL,
957 .parse_fn = NULL,
958 .action_fn = action_fn,
959 .owns_memory = false,
960 .hide_from_mode_help = false,
961 .hide_from_binary_help = false,
962 .mode_bitmask = OPTION_MODE_NONE};
963
964 builder->descriptors[builder->num_descriptors++] = desc;
965
966 // Set hide_from_binary_help after adding (so we can check the option name)
967 if (strcmp(long_name, "create-man-page") == 0) {
968 // Always hide from help and man page (this is a development tool)
969 builder->descriptors[builder->num_descriptors - 1].hide_from_binary_help = true;
970 }
971}
void ensure_descriptor_capacity(options_builder_t *builder)
Grow descriptor array if needed.
Definition builder.c:213
@ OPTION_TYPE_ACTION
Action that executes and may exit (–list-webcams, etc.)
Definition builder.h:167
@ OPTION_MODE_NONE
No modes (invalid)

References options_builder_t::descriptors, ensure_descriptor_capacity(), option_descriptor_t::hide_from_binary_help, option_descriptor_t::long_name, options_builder_t::num_descriptors, OPTION_MODE_NONE, and OPTION_TYPE_ACTION.

Referenced by options_registry_add_all_to_builder().

◆ options_builder_add_bool()

void options_builder_add_bool ( options_builder_t *  builder,
const char *  long_name,
char  short_name,
size_t  offset,
bool  default_value,
const char *  help_text,
const char *  group,
bool  required,
const char *  env_var_name 
)

Add boolean flag option.

Parameters
builderBuilder to add to
long_nameLong option name (e.g., "verbose")
short_nameShort option char (e.g., 'v', or '\0' if none)
offsetoffsetof(struct, field)
default_valueDefault value
help_textHelp description
groupGroup name for help (e.g., "OUTPUT OPTIONS")
requiredIf true, option must be provided
env_var_nameEnvironment variable fallback (or NULL)

Definition at line 657 of file builder.c.

659 {
661
662 static bool default_vals[2] = {false, true};
663
664 option_descriptor_t desc = {.long_name = long_name,
665 .short_name = short_name,
666 .type = OPTION_TYPE_BOOL,
667 .offset = offset,
668 .help_text = help_text,
669 .group = group,
670 .default_value = &default_vals[default_value ? 1 : 0],
671 .required = required,
672 .env_var_name = env_var_name,
673 .mode_bitmask = OPTION_MODE_NONE,
674 .validate = NULL,
675 .parse_fn = NULL,
676 .owns_memory = false};
677
678 builder->descriptors[builder->num_descriptors++] = desc;
679}
@ OPTION_TYPE_BOOL
Boolean flag (–flag, no value)
Definition builder.h:162

References options_builder_t::descriptors, ensure_descriptor_capacity(), option_descriptor_t::long_name, options_builder_t::num_descriptors, OPTION_MODE_NONE, and OPTION_TYPE_BOOL.

Referenced by options_registry_add_all_to_builder().

◆ options_builder_add_callback()

void options_builder_add_callback ( options_builder_t *  builder,
const char *  long_name,
char  short_name,
size_t  offset,
const void *  default_value,
size_t  value_size,
bool(*)(const char *, void *, char **)  parse_fn,
const char *  help_text,
const char *  group,
bool  required,
const char *  env_var_name 
)

Definition at line 849 of file builder.c.

852 {
853 (void)value_size; // Unused parameter
855
856 option_descriptor_t desc = {.long_name = long_name,
857 .short_name = short_name,
858 .type = OPTION_TYPE_CALLBACK,
859 .offset = offset,
860 .help_text = help_text,
861 .group = group,
862 .default_value = default_value,
863 .required = required,
864 .env_var_name = env_var_name,
865 .validate = NULL,
866 .parse_fn = parse_fn,
867 .owns_memory = false,
868 .optional_arg = false,
869 .mode_bitmask = OPTION_MODE_NONE};
870
871 builder->descriptors[builder->num_descriptors++] = desc;
872}

References options_builder_t::descriptors, ensure_descriptor_capacity(), option_descriptor_t::long_name, options_builder_t::num_descriptors, OPTION_MODE_NONE, and OPTION_TYPE_CALLBACK.

◆ options_builder_add_callback_optional()

void options_builder_add_callback_optional ( options_builder_t *  builder,
const char *  long_name,
char  short_name,
size_t  offset,
const void *  default_value,
size_t  value_size,
bool(*)(const char *, void *, char **)  parse_fn,
const char *  help_text,
const char *  group,
bool  required,
const char *  env_var_name,
bool  optional_arg 
)

Add callback option with optional argument support.

Parameters
builderBuilder to add to
long_nameLong option name
short_nameShort option char (or '\0')
offsetoffsetof(struct, field)
default_valuePointer to default value (or NULL)
value_sizesizeof(field_type)
parse_fnCustom parser function
help_textHelp description
groupGroup name for help
requiredIf true, option must be provided
env_var_nameEnvironment variable fallback (or NULL)
optional_argIf true, argument is optional (parser receives NULL if not provided)

Definition at line 890 of file builder.c.

894 {
895 (void)value_size; // Unused parameter
897
898 option_descriptor_t desc = {.long_name = long_name,
899 .short_name = short_name,
900 .type = OPTION_TYPE_CALLBACK,
901 .offset = offset,
902 .help_text = help_text,
903 .group = group,
904 .default_value = default_value,
905 .required = required,
906 .env_var_name = env_var_name,
907 .validate = NULL,
908 .parse_fn = parse_fn,
909 .owns_memory = false,
910 .optional_arg = optional_arg,
911 .mode_bitmask = OPTION_MODE_NONE};
912
913 builder->descriptors[builder->num_descriptors++] = desc;
914}

References options_builder_t::descriptors, ensure_descriptor_capacity(), option_descriptor_t::long_name, options_builder_t::num_descriptors, OPTION_MODE_NONE, and OPTION_TYPE_CALLBACK.

◆ options_builder_add_callback_with_metadata()

void options_builder_add_callback_with_metadata ( options_builder_t *  builder,
const char *  long_name,
char  short_name,
size_t  offset,
const void *  default_value,
size_t  value_size,
bool(*)(const char *, void *, char **)  parse_fn,
const char *  help_text,
const char *  group,
bool  required,
const char *  env_var_name,
bool  optional_arg,
const option_metadata_t *  metadata 
)

Definition at line 916 of file builder.c.

920 {
921 (void)value_size; // Unused parameter
923
924 option_descriptor_t desc = {.long_name = long_name,
925 .short_name = short_name,
926 .type = OPTION_TYPE_CALLBACK,
927 .offset = offset,
928 .help_text = help_text,
929 .group = group,
930 .default_value = default_value,
931 .required = required,
932 .env_var_name = env_var_name,
933 .validate = NULL,
934 .parse_fn = parse_fn,
935 .owns_memory = false,
936 .optional_arg = optional_arg,
937 .mode_bitmask = OPTION_MODE_NONE,
938 .metadata = metadata ? *metadata : (option_metadata_t){0}};
939
940 builder->descriptors[builder->num_descriptors++] = desc;
941}
Metadata for shell completion generation.
Definition builder.h:192

References options_builder_t::descriptors, ensure_descriptor_capacity(), option_descriptor_t::long_name, options_builder_t::num_descriptors, OPTION_MODE_NONE, and OPTION_TYPE_CALLBACK.

Referenced by options_registry_add_all_to_builder().

◆ options_builder_add_custom_section()

void options_builder_add_custom_section ( options_builder_t *  builder,
const char *  heading,
const char *  content,
option_mode_bitmask_t  mode_bitmask 
)

Add a custom help section.

Adds a custom section to help output that appears after EXAMPLES but before OPTIONS.

Parameters
[in]builderOptions builder
[in]headingSection heading (e.g., "INTERACTIVE CONTROLS")
[in]contentSection content
[in]mode_bitmaskWhich modes show this section (use MODE_BITMASK_* constants)

Definition at line 1319 of file builder.c.

1320 {
1321 if (!builder || !heading || !content)
1322 return;
1323
1324 ensure_custom_section_capacity(builder);
1325
1326 custom_section_descriptor_t section = {.heading = heading, .content = content, .mode_bitmask = mode_bitmask};
1327
1328 builder->custom_sections[builder->num_custom_sections++] = section;
1329}
Custom help section descriptor.
Definition builder.h:389
const char * heading
Section heading (e.g., "INTERACTIVE CONTROLS")
Definition builder.h:390
size_t num_custom_sections
Current count.
Definition builder.h:467
custom_section_descriptor_t * custom_sections
Dynamic array of custom sections.
Definition builder.h:466

References options_builder_t::custom_sections, custom_section_descriptor_t::heading, and options_builder_t::num_custom_sections.

Referenced by options_preset_unified().

◆ options_builder_add_dependency()

void options_builder_add_dependency ( options_builder_t *  builder,
const option_dependency_t *  dependency 
)

Add full dependency (advanced)

Parameters
builderBuilder to add to
dependencyDependency to copy

Definition at line 1164 of file builder.c.

1164 {
1165 if (!builder || !dependency)
1166 return;
1167
1169 builder->dependencies[builder->num_dependencies++] = *dependency;
1170}
void ensure_dependency_capacity(options_builder_t *builder)
Grow dependency array if needed.
Definition builder.c:230

References options_builder_t::dependencies, ensure_dependency_capacity(), and options_builder_t::num_dependencies.

Referenced by options_builder_from_preset().

◆ options_builder_add_dependency_conflicts()

void options_builder_add_dependency_conflicts ( options_builder_t *  builder,
const char *  option_name,
const char *  conflicts_with,
const char *  error_message 
)

Add anti-dependency: if option_name is set, conflicts_with must NOT be set.

Parameters
builderBuilder to add to
option_nameOption that has the conflict
conflicts_withOption it conflicts with
error_messageCustom error message (or NULL for default)

Definition at line 1142 of file builder.c.

1143 {
1145
1146 option_dependency_t dep = {.option_name = option_name,
1147 .type = DEPENDENCY_CONFLICTS,
1148 .depends_on = conflicts_with,
1149 .error_message = error_message};
1150
1151 builder->dependencies[builder->num_dependencies++] = dep;
1152}
@ DEPENDENCY_CONFLICTS
If A is set, B must NOT be set.
Definition builder.h:230
const char * option_name
The option that has the dependency.
Definition builder.h:332

References options_builder_t::dependencies, DEPENDENCY_CONFLICTS, ensure_dependency_capacity(), options_builder_t::num_dependencies, and option_dependency_t::option_name.

Referenced by options_preset_unified().

◆ options_builder_add_dependency_implies()

void options_builder_add_dependency_implies ( options_builder_t *  builder,
const char *  option_name,
const char *  implies,
const char *  error_message 
)

Add implication: if option_name is set, implies defaults to true.

Parameters
builderBuilder to add to
option_nameOption that implies another
impliesOption that is implied
error_messageCustom message (rarely used, can be NULL)

Definition at line 1154 of file builder.c.

1155 {
1157
1158 option_dependency_t dep = {
1159 .option_name = option_name, .type = DEPENDENCY_IMPLIES, .depends_on = implies, .error_message = error_message};
1160
1161 builder->dependencies[builder->num_dependencies++] = dep;
1162}
@ DEPENDENCY_IMPLIES
If A is set, B defaults to true/enabled.
Definition builder.h:231

References options_builder_t::dependencies, DEPENDENCY_IMPLIES, ensure_dependency_capacity(), options_builder_t::num_dependencies, and option_dependency_t::option_name.

◆ options_builder_add_dependency_requires()

void options_builder_add_dependency_requires ( options_builder_t *  builder,
const char *  option_name,
const char *  depends_on,
const char *  error_message 
)

Add dependency: if option_name is set, depends_on must be set.

Parameters
builderBuilder to add to
option_nameOption that has the dependency
depends_onOption it depends on
error_messageCustom error message (or NULL for default)

Definition at line 1130 of file builder.c.

1131 {
1133
1134 option_dependency_t dep = {.option_name = option_name,
1135 .type = DEPENDENCY_REQUIRES,
1136 .depends_on = depends_on,
1137 .error_message = error_message};
1138
1139 builder->dependencies[builder->num_dependencies++] = dep;
1140}
@ DEPENDENCY_REQUIRES
If A is set, B must be set.
Definition builder.h:229

References options_builder_t::dependencies, DEPENDENCY_REQUIRES, ensure_dependency_capacity(), options_builder_t::num_dependencies, and option_dependency_t::option_name.

Referenced by options_preset_unified().

◆ options_builder_add_descriptor()

void options_builder_add_descriptor ( options_builder_t *  builder,
const option_descriptor_t *  descriptor 
)

Add full option descriptor (advanced)

Parameters
builderBuilder to add to
descriptorDescriptor to copy

Definition at line 973 of file builder.c.

973 {
974 if (!builder || !descriptor) {
975 SET_ERRNO(ERROR_INVALID_PARAM, "Builder is NULL or descriptor is NULL");
976 return;
977 }
978 return;
979
981 builder->descriptors[builder->num_descriptors++] = *descriptor;
982}

References options_builder_t::descriptors, ensure_descriptor_capacity(), ERROR_INVALID_PARAM, options_builder_t::num_descriptors, and SET_ERRNO.

Referenced by options_builder_from_preset().

◆ options_builder_add_double()

void options_builder_add_double ( options_builder_t *  builder,
const char *  long_name,
char  short_name,
size_t  offset,
double  default_value,
const char *  help_text,
const char *  group,
bool  required,
const char *  env_var_name,
bool(*)(const void *, char **)  validate,
bool  optional_arg 
)

Definition at line 779 of file builder.c.

781 {
783
784 // Increased from 256 to 1024 to support multiple test builders without overflow
785 static double defaults[1024];
786 static size_t num_defaults = 0;
787
788 if (num_defaults >= 1024) {
789 log_error("Too many double options (max 1024)");
790 return;
791 }
792
793 defaults[num_defaults] = default_value;
794
795 option_descriptor_t desc = {.long_name = long_name,
796 .short_name = short_name,
797 .type = OPTION_TYPE_DOUBLE,
798 .offset = offset,
799 .help_text = help_text,
800 .group = group,
801 .default_value = &defaults[num_defaults++],
802 .required = required,
803 .env_var_name = env_var_name,
804 .validate = validate,
805 .parse_fn = NULL,
806 .owns_memory = false,
807 .mode_bitmask = OPTION_MODE_NONE,
808 .optional_arg = optional_arg};
809
810 builder->descriptors[builder->num_descriptors++] = desc;
811}
@ OPTION_TYPE_DOUBLE
Floating point (–ratio 1.5)
Definition builder.h:165
#define log_error(...)
Log an ERROR message.
Definition log/log.h:587

References options_builder_t::descriptors, ensure_descriptor_capacity(), log_error, option_descriptor_t::long_name, options_builder_t::num_descriptors, OPTION_MODE_NONE, and OPTION_TYPE_DOUBLE.

Referenced by options_registry_add_all_to_builder().

◆ options_builder_add_double_with_metadata()

void options_builder_add_double_with_metadata ( options_builder_t *  builder,
const char *  long_name,
char  short_name,
size_t  offset,
double  default_value,
const char *  help_text,
const char *  group,
bool  required,
const char *  env_var_name,
bool(*)(const void *, char **)  validate,
const option_metadata_t *  metadata,
bool  optional_arg 
)

Definition at line 813 of file builder.c.

817 {
819
820 static double defaults[1024];
821 static size_t num_defaults = 0;
822
823 if (num_defaults >= 1024) {
824 log_error("Too many double options (max 1024)");
825 return;
826 }
827
828 defaults[num_defaults] = default_value;
829
830 option_descriptor_t desc = {.long_name = long_name,
831 .short_name = short_name,
832 .type = OPTION_TYPE_DOUBLE,
833 .offset = offset,
834 .help_text = help_text,
835 .group = group,
836 .default_value = &defaults[num_defaults++],
837 .required = required,
838 .env_var_name = env_var_name,
839 .validate = validate,
840 .parse_fn = NULL,
841 .owns_memory = false,
842 .mode_bitmask = OPTION_MODE_NONE,
843 .metadata = metadata ? *metadata : (option_metadata_t){0},
844 .optional_arg = optional_arg};
845
846 builder->descriptors[builder->num_descriptors++] = desc;
847}

References options_builder_t::descriptors, ensure_descriptor_capacity(), log_error, option_descriptor_t::long_name, options_builder_t::num_descriptors, OPTION_MODE_NONE, and OPTION_TYPE_DOUBLE.

Referenced by options_registry_add_all_to_builder().

◆ options_builder_add_example()

void options_builder_add_example ( options_builder_t *  builder,
uint32_t  mode_bitmask,
const char *  args,
const char *  description,
bool  owns_args 
)

Add example descriptor.

Adds an example command to be printed in the EXAMPLES section. Components are colored separately during printing:

  • mode: magenta
  • args: green
Parameters
builderBuilder instance
modeMode name (NULL or "server", "client", "mirror", etc.)
argsArguments (NULL or "example.com", "swift-river-mountain", etc.)
descriptionHelp text for this example

Example:

"Start new session");
options_builder_add_example(b, "server", NULL,
"Run as dedicated server");
options_builder_add_example(b, "client", "example.com",
"Connect to specific server");
void options_builder_add_example(options_builder_t *builder, uint32_t mode_bitmask, const char *args, const char *description, bool owns_args)
Add example descriptor.
Definition builder.c:1255

Add an example to the help output

Parameters
builderBuilder instance
mode_bitmaskBitmask of modes (OPTION_MODE_SERVER | OPTION_MODE_CLIENT, etc.) Use OPTION_MODE_BINARY for binary-level examples
argsArguments (NULL or "example.com", etc.)
descriptionHelp text for this example
owns_argsIf true, duplicate and track the args string

Definition at line 1255 of file builder.c.

1256 {
1257 if (!builder || !description)
1258 return;
1259
1260 ensure_example_capacity(builder);
1261
1262 example_descriptor_t example = {.mode_bitmask = mode_bitmask,
1263 .description = description,
1264 .owns_args_memory = owns_args,
1265 .is_utility_command = false};
1266
1267 if (owns_args) {
1268 // If owning, duplicate the string and track it
1269 char *owned_args = platform_strdup(args);
1270 if (!owned_args) {
1271 log_fatal("Failed to duplicate example args string");
1272 return;
1273 }
1274 example.args = owned_args;
1275 track_owned_string_builder(builder, owned_args);
1276 } else {
1277 example.args = args;
1278 }
1279
1280 builder->examples[builder->num_examples++] = example;
1281}
char * platform_strdup(const char *s)
Duplicate string (strdup replacement)
action_args_t args
Example descriptor for programmatic EXAMPLES generation.
Definition builder.h:310
uint32_t mode_bitmask
Bitmask of modes (OPTION_MODE_SERVER, OPTION_MODE_CLIENT, etc.)
Definition builder.h:311
const char * args
Command-line arguments part of the example.
Definition builder.h:312
example_descriptor_t * examples
Dynamic array of examples.
Definition builder.h:458
size_t num_examples
Current count.
Definition builder.h:459

References example_descriptor_t::args, args, options_builder_t::examples, log_fatal, example_descriptor_t::mode_bitmask, options_builder_t::num_examples, and platform_strdup().

Referenced by options_preset_unified().

◆ options_builder_add_example_utility()

void options_builder_add_example_utility ( options_builder_t *  builder,
uint32_t  mode_bitmask,
const char *  args,
const char *  description,
bool  is_utility_command 
)

Add an example with utility command support.

Allows marking utility commands (like pbpaste, grep, etc.) that shouldn't be prepended with program name in help output.

Definition at line 1289 of file builder.c.

1290 {
1291 if (!builder || !description)
1292 return;
1293
1294 ensure_example_capacity(builder);
1295
1296 example_descriptor_t example = {.mode_bitmask = mode_bitmask,
1297 .description = description,
1298 .owns_args_memory = false,
1299 .is_utility_command = is_utility_command};
1300
1301 if (args) {
1302 example.args = args;
1303 }
1304
1305 builder->examples[builder->num_examples++] = example;
1306}

References example_descriptor_t::args, args, options_builder_t::examples, example_descriptor_t::mode_bitmask, and options_builder_t::num_examples.

Referenced by options_preset_unified().

◆ options_builder_add_int()

void options_builder_add_int ( options_builder_t *  builder,
const char *  long_name,
char  short_name,
size_t  offset,
int  default_value,
const char *  help_text,
const char *  group,
bool  required,
const char *  env_var_name,
bool(*)(const void *, char **)  validate 
)

Definition at line 681 of file builder.c.

683 {
685
686 if (g_int_defaults_counter >= 256) {
687 log_error("Too many int options (max 256)");
688 return;
689 }
690
691 g_int_defaults[g_int_defaults_counter] = default_value;
692
693 option_descriptor_t desc = {.long_name = long_name,
694 .short_name = short_name,
695 .type = OPTION_TYPE_INT,
696 .offset = offset,
697 .help_text = help_text,
698 .group = group,
699 .default_value = &g_int_defaults[g_int_defaults_counter++],
700 .required = required,
701 .env_var_name = env_var_name,
702 .validate = validate,
703 .parse_fn = NULL,
704 .owns_memory = false,
705 .mode_bitmask = OPTION_MODE_NONE};
706
707 builder->descriptors[builder->num_descriptors++] = desc;
708}
@ OPTION_TYPE_INT
Integer value (–count 42)
Definition builder.h:163

References options_builder_t::descriptors, ensure_descriptor_capacity(), log_error, option_descriptor_t::long_name, options_builder_t::num_descriptors, OPTION_MODE_NONE, and OPTION_TYPE_INT.

Referenced by options_registry_add_all_to_builder().

◆ options_builder_add_int_with_metadata()

void options_builder_add_int_with_metadata ( options_builder_t *  builder,
const char *  long_name,
char  short_name,
size_t  offset,
int  default_value,
const char *  help_text,
const char *  group,
bool  required,
const char *  env_var_name,
bool(*)(const void *options_struct, char **error_msg)  validate,
const option_metadata_t *  metadata 
)

Add integer option with metadata (for numeric ranges and examples)

Like options_builder_add_int() but also includes metadata for numeric ranges, examples, and completions.

Parameters
metadataPointer to option_metadata_t with numeric_range, examples, etc. (can be NULL)

Definition at line 710 of file builder.c.

714 {
716
717 if (g_int_defaults_counter >= 256) {
718 log_error("Too many int options (max 256)");
719 return;
720 }
721
722 g_int_defaults[g_int_defaults_counter] = default_value;
723
724 option_descriptor_t desc = {.long_name = long_name,
725 .short_name = short_name,
726 .type = OPTION_TYPE_INT,
727 .offset = offset,
728 .help_text = help_text,
729 .group = group,
730 .default_value = &g_int_defaults[g_int_defaults_counter++],
731 .required = required,
732 .env_var_name = env_var_name,
733 .validate = validate,
734 .parse_fn = NULL,
735 .owns_memory = false,
736 .mode_bitmask = OPTION_MODE_NONE,
737 .metadata = metadata ? *metadata : (option_metadata_t){0}};
738
739 builder->descriptors[builder->num_descriptors++] = desc;
740}

References options_builder_t::descriptors, ensure_descriptor_capacity(), log_error, option_descriptor_t::long_name, options_builder_t::num_descriptors, OPTION_MODE_NONE, and OPTION_TYPE_INT.

Referenced by options_registry_add_all_to_builder().

◆ options_builder_add_mode()

void options_builder_add_mode ( options_builder_t *  builder,
const char *  name,
const char *  description 
)

Add mode descriptor.

Adds a mode to be printed in the MODES section. The mode name is colored magenta during printing.

Parameters
builderBuilder instance
nameMode name (e.g., "server", "client", "mirror")
descriptionMode description

Example:

options_builder_add_mode(b, "server", "Run as multi-client video chat server");
options_builder_add_mode(b, "client", "Run as video chat client (connect to server)");
options_builder_add_mode(b, "mirror", "View local webcam as ASCII art (no server)");
void options_builder_add_mode(options_builder_t *builder, const char *name, const char *description)
Add mode descriptor.
Definition builder.c:1308

Definition at line 1308 of file builder.c.

1308 {
1309 if (!builder || !name || !description)
1310 return;
1311
1312 ensure_mode_capacity(builder);
1313
1314 help_mode_descriptor_t mode = {.name = name, .description = description};
1315
1316 builder->modes[builder->num_modes++] = mode;
1317}
Mode descriptor for programmatic MODES generation (for help output)
Definition builder.h:321
const char * name
Mode name (e.g., "server", "client")
Definition builder.h:322
help_mode_descriptor_t * modes
Dynamic array of modes.
Definition builder.h:462
size_t num_modes
Current count.
Definition builder.h:463

References options_builder_t::modes, help_mode_descriptor_t::name, and options_builder_t::num_modes.

Referenced by options_preset_unified().

◆ options_builder_add_positional()

void options_builder_add_positional ( options_builder_t *  builder,
const char *  name,
const char *  help_text,
bool  required,
const char *  section_heading,
const char **  examples,
size_t  num_examples,
option_mode_bitmask_t  mode_bitmask,
int(*)(const char *arg, void *config, char **remaining, int num_remaining, char **error_msg)  parse_fn 
)

Add positional argument descriptor.

Positional arguments are parsed after getopt finishes, from the remaining argv elements that don't start with '-'. They are parsed in the order they are added to the builder.

Example (client mode):

builder,
"address",
"[address][:port] - Server address (IPv4, IPv6, or hostname) with optional port",
false, // Not required (defaults to localhost)
parse_client_address_arg
);
void options_builder_add_positional(options_builder_t *builder, const char *name, const char *help_text, bool required, const char *section_heading, const char **examples, size_t num_examples, option_mode_bitmask_t mode_bitmask, int(*parse_fn)(const char *arg, void *config, char **remaining, int num_remaining, char **error_msg))
Add positional argument descriptor.
Definition builder.c:1192

Example (server mode):

builder,
"bind-addr",
"Bind address (IPv4 or IPv6) - can specify 0-2 addresses",
false, // Not required (defaults to localhost dual-stack)
parse_server_bind_addr
);
Parameters
builderBuilder to add to
nameName for help text (e.g., "address")
help_textDescription for usage message
requiredIf true, this positional arg must be provided
section_headingOptional section heading for examples (e.g., "ADDRESS FORMATS")
examplesOptional array of example strings with descriptions
num_examplesNumber of examples in array
mode_bitmaskWhich modes this positional arg applies to
parse_fnCustom parser (receives arg, config, remaining args, error_msg) Returns number of args consumed (usually 1), or -1 on error

Definition at line 1192 of file builder.c.

1196 {
1197 if (!builder || !name || !parse_fn)
1198 return;
1199
1201
1202 positional_arg_descriptor_t pos_arg = {.name = name,
1203 .help_text = help_text,
1204 .required = required,
1205 .section_heading = section_heading,
1206 .examples = examples,
1207 .num_examples = num_examples,
1208 .mode_bitmask = mode_bitmask,
1209 .parse_fn = parse_fn};
1210
1211 builder->positional_args[builder->num_positional_args++] = pos_arg;
1212}
void ensure_positional_arg_capacity(options_builder_t *builder)
Grow positional arg array if needed.
Definition builder.c:247
const char * name
Name for help text (e.g., "address", "bind-addr")
Definition builder.h:358

References ensure_positional_arg_capacity(), positional_arg_descriptor_t::name, options_builder_t::num_positional_args, and options_builder_t::positional_args.

Referenced by options_builder_from_preset(), and options_preset_unified().

◆ options_builder_add_string()

void options_builder_add_string ( options_builder_t *  builder,
const char *  long_name,
char  short_name,
size_t  offset,
const char *  default_value,
const char *  help_text,
const char *  group,
bool  required,
const char *  env_var_name,
bool(*)(const void *, char **)  validate 
)

Definition at line 742 of file builder.c.

744 {
746
747 // Store default string pointer in static storage to avoid stack-use-after-return
748 // Increased from 256 to 1024 to support multiple test builders without overflow
749 static const char *defaults[1024];
750 static size_t num_defaults = 0;
751
752 const void *default_ptr = NULL;
753 if (default_value) {
754 if (num_defaults >= 1024) {
755 log_error("Too many string options (max 1024)");
756 return;
757 }
758 defaults[num_defaults] = default_value;
759 default_ptr = &defaults[num_defaults++];
760 }
761
762 option_descriptor_t desc = {.long_name = long_name,
763 .short_name = short_name,
764 .type = OPTION_TYPE_STRING,
765 .offset = offset,
766 .help_text = help_text,
767 .group = group,
768 .default_value = default_ptr,
769 .required = required,
770 .env_var_name = env_var_name,
771 .validate = validate,
772 .parse_fn = NULL,
773 .owns_memory = true, // Strings are always owned
774 .mode_bitmask = OPTION_MODE_NONE};
775
776 builder->descriptors[builder->num_descriptors++] = desc;
777}
@ OPTION_TYPE_STRING
String value (–name foo)
Definition builder.h:164

References options_builder_t::descriptors, ensure_descriptor_capacity(), log_error, option_descriptor_t::long_name, options_builder_t::num_descriptors, OPTION_MODE_NONE, and OPTION_TYPE_STRING.

Referenced by options_registry_add_all_to_builder().

◆ options_builder_add_usage()

void options_builder_add_usage ( options_builder_t *  builder,
const char *  mode,
const char *  positional,
bool  show_options,
const char *  description 
)

Add usage line descriptor.

Adds a usage line to be printed in the USAGE section. Components are colored separately during printing:

  • mode: magenta
  • positional: green
  • "[options...]": yellow
Parameters
builderBuilder instance
modeMode name (NULL for binary-level, or "server", "<mode>", etc.)
positionalPositional args (NULL or "[bind-addr]", "<session-string>", etc.)
show_optionsTrue to append "[options...]" or "[mode-options...]"
descriptionHelp text for this usage pattern

Example:

options_builder_add_usage(b, NULL, NULL, true,
"Start a new session");
options_builder_add_usage(b, NULL, "<session-string>", true,
"Join an existing session");
options_builder_add_usage(b, "<mode>", NULL, true,
"Run in a specific mode");
void options_builder_add_usage(options_builder_t *builder, const char *mode, const char *positional, bool show_options, const char *description)
Add usage line descriptor.
Definition builder.c:1242

Definition at line 1242 of file builder.c.

1243 {
1244 if (!builder || !description)
1245 return;
1246
1247 ensure_usage_line_capacity(builder);
1248
1250 .mode = mode, .positional = positional, .show_options = show_options, .description = description};
1251
1252 builder->usage_lines[builder->num_usage_lines++] = usage;
1253}
void usage(FILE *desc, asciichat_mode_t mode)
Print usage information for a specific mode.
size_t num_usage_lines
Current count.
Definition builder.h:455
usage_descriptor_t * usage_lines
Dynamic array of usage lines.
Definition builder.h:454
Usage line descriptor for programmatic USAGE generation.
Definition builder.h:296
const char * mode
NULL or mode name (e.g., "server") or "<mode>" placeholder.
Definition builder.h:297

References usage_descriptor_t::mode, options_builder_t::num_usage_lines, usage(), and options_builder_t::usage_lines.

Referenced by options_preset_unified().

◆ options_builder_build()

options_config_t * options_builder_build ( options_builder_t *  builder)

Build immutable options config.

Creates final config from builder. Builder is NOT consumed - you must still call options_builder_destroy().

Parameters
builderBuilder with options and dependencies
Returns
Immutable config (must be freed with options_config_destroy)

Definition at line 482 of file builder.c.

482 {
483 if (!builder) {
484 SET_ERRNO(ERROR_INVALID_PARAM, "Builder is NULL");
485 return NULL;
486 }
487
489 if (!config) {
490 SET_ERRNO(ERROR_MEMORY, "Failed to allocate options config");
491 return NULL;
492 }
493
494 // Allocate and copy descriptors
496 if (!config->descriptors && builder->num_descriptors > 0) {
497 SAFE_FREE(config);
498 SET_ERRNO(ERROR_MEMORY, "Failed to allocate descriptors");
499 return NULL;
500 }
501 memcpy(config->descriptors, builder->descriptors, builder->num_descriptors * sizeof(option_descriptor_t));
502 config->num_descriptors = builder->num_descriptors;
503
504 // Allocate and copy dependencies
506 if (!config->dependencies && builder->num_dependencies > 0) {
507 SAFE_FREE(config->descriptors);
508 SAFE_FREE(config);
509 SET_ERRNO(ERROR_MEMORY, "Failed to allocate dependencies");
510 return NULL;
511 }
512 memcpy(config->dependencies, builder->dependencies, builder->num_dependencies * sizeof(option_dependency_t));
513 config->num_dependencies = builder->num_dependencies;
514
515 // Allocate and copy positional args
516 if (builder->num_positional_args > 0) {
517 config->positional_args =
519 if (!config->positional_args) {
520 SAFE_FREE(config->descriptors);
521 SAFE_FREE(config->dependencies);
522 SAFE_FREE(config);
523 SET_ERRNO(ERROR_MEMORY, "Failed to allocate positional args");
524 return NULL;
525 }
526 memcpy(config->positional_args, builder->positional_args,
528 config->num_positional_args = builder->num_positional_args;
529 } else {
530 config->positional_args = NULL;
531 config->num_positional_args = 0;
532 }
533
534 // Allocate and copy usage lines
535 if (builder->num_usage_lines > 0) {
537 if (!config->usage_lines) {
538 SAFE_FREE(config->descriptors);
539 SAFE_FREE(config->dependencies);
540 SAFE_FREE(config->positional_args);
541 SAFE_FREE(config);
542 SET_ERRNO(ERROR_MEMORY, "Failed to allocate usage lines");
543 return NULL;
544 }
545 memcpy(config->usage_lines, builder->usage_lines, builder->num_usage_lines * sizeof(usage_descriptor_t));
546 config->num_usage_lines = builder->num_usage_lines;
547 } else {
548 config->usage_lines = NULL;
549 config->num_usage_lines = 0;
550 }
551
552 // Allocate and copy examples
553 if (builder->num_examples > 0) {
555 if (!config->examples) {
556 SAFE_FREE(config->descriptors);
557 SAFE_FREE(config->dependencies);
558 SAFE_FREE(config->positional_args);
559 SAFE_FREE(config->usage_lines);
560 SAFE_FREE(config);
561 SET_ERRNO(ERROR_MEMORY, "Failed to allocate examples");
562 return NULL;
563 }
564 memcpy(config->examples, builder->examples, builder->num_examples * sizeof(example_descriptor_t));
565 config->num_examples = builder->num_examples;
566 } else {
567 config->examples = NULL;
568 config->num_examples = 0;
569 }
570
571 // Allocate and copy modes
572 if (builder->num_modes > 0) {
574 if (!config->modes) {
575 SAFE_FREE(config->descriptors);
576 SAFE_FREE(config->dependencies);
577 SAFE_FREE(config->positional_args);
578 SAFE_FREE(config->usage_lines);
579 SAFE_FREE(config->examples);
580 SAFE_FREE(config);
581 SET_ERRNO(ERROR_MEMORY, "Failed to allocate modes");
582 return NULL;
583 }
584 memcpy(config->modes, builder->modes, builder->num_modes * sizeof(help_mode_descriptor_t));
585 config->num_modes = builder->num_modes;
586 } else {
587 config->modes = NULL;
588 config->num_modes = 0;
589 }
590
591 // Allocate and copy custom sections
592 if (builder->num_custom_sections > 0) {
593 config->custom_sections =
595 if (!config->custom_sections) {
596 SAFE_FREE(config->descriptors);
597 SAFE_FREE(config->dependencies);
598 SAFE_FREE(config->positional_args);
599 SAFE_FREE(config->usage_lines);
600 SAFE_FREE(config->examples);
601 SAFE_FREE(config->modes);
602 SAFE_FREE(config);
603 SET_ERRNO(ERROR_MEMORY, "Failed to allocate custom sections");
604 return NULL;
605 }
606 memcpy(config->custom_sections, builder->custom_sections,
608 config->num_custom_sections = builder->num_custom_sections;
609 } else {
610 config->custom_sections = NULL;
611 config->num_custom_sections = 0;
612 }
613
614 config->struct_size = builder->struct_size;
615 config->program_name = builder->program_name;
616 config->description = builder->description;
617
618 // Initialize memory management
619 config->owned_strings = builder->owned_strings_builder;
622
623 // Clear builder's ownership so it doesn't free them
624 builder->owned_strings_builder = NULL;
625 builder->num_owned_strings_builder = 0;
627
628 return config;
629}
#define SAFE_FREE(ptr)
Definition common.h:376
#define SAFE_MALLOC(size, cast)
Definition common.h:264
@ ERROR_MEMORY
Definition error_codes.h:56
size_t owned_strings_builder_capacity
Definition builder.h:477
const char * program_name
Definition builder.h:471
const char * description
Definition builder.h:472
char ** owned_strings_builder
Definition builder.h:475
size_t num_owned_strings_builder
Definition builder.h:476
size_t struct_size
Definition builder.h:470
Options configuration.
Definition builder.h:401
positional_arg_descriptor_t * positional_args
Array of positional argument descriptors.
Definition builder.h:408
size_t num_custom_sections
Number of custom sections.
Definition builder.h:426
size_t num_usage_lines
Number of usage lines.
Definition builder.h:417
option_dependency_t * dependencies
Array of dependencies.
Definition builder.h:405
custom_section_descriptor_t * custom_sections
Array of custom help sections.
Definition builder.h:425
size_t num_modes
Number of modes.
Definition builder.h:423
const char * program_name
For usage header.
Definition builder.h:412
size_t num_positional_args
Number of positional arguments.
Definition builder.h:409
char ** owned_strings
Strdup'd strings to free on cleanup.
Definition builder.h:429
size_t owned_strings_capacity
Allocated capacity.
Definition builder.h:431
size_t num_examples
Number of examples.
Definition builder.h:420
size_t num_dependencies
Number of dependencies.
Definition builder.h:406
const char * description
For usage header.
Definition builder.h:413
help_mode_descriptor_t * modes
Array of mode descriptors.
Definition builder.h:422
usage_descriptor_t * usage_lines
Array of usage line descriptors.
Definition builder.h:416
example_descriptor_t * examples
Array of example descriptors.
Definition builder.h:419
size_t struct_size
sizeof(options_t) for bounds checking
Definition builder.h:411
size_t num_owned_strings
Number of owned strings.
Definition builder.h:430

References options_config_t::custom_sections, options_builder_t::custom_sections, options_config_t::dependencies, options_builder_t::dependencies, options_config_t::description, options_builder_t::description, options_config_t::descriptors, options_builder_t::descriptors, ERROR_INVALID_PARAM, ERROR_MEMORY, options_config_t::examples, options_builder_t::examples, options_config_t::modes, options_builder_t::modes, options_config_t::num_custom_sections, options_builder_t::num_custom_sections, options_config_t::num_dependencies, options_builder_t::num_dependencies, options_config_t::num_descriptors, options_builder_t::num_descriptors, options_config_t::num_examples, options_builder_t::num_examples, options_config_t::num_modes, options_builder_t::num_modes, options_config_t::num_owned_strings, options_builder_t::num_owned_strings_builder, options_config_t::num_positional_args, options_builder_t::num_positional_args, options_config_t::num_usage_lines, options_builder_t::num_usage_lines, options_config_t::owned_strings, options_builder_t::owned_strings_builder, options_builder_t::owned_strings_builder_capacity, options_config_t::owned_strings_capacity, options_config_t::positional_args, options_builder_t::positional_args, options_config_t::program_name, options_builder_t::program_name, SAFE_FREE, SAFE_MALLOC, SET_ERRNO, options_config_t::struct_size, options_builder_t::struct_size, options_config_t::usage_lines, and options_builder_t::usage_lines.

Referenced by options_builder_generate_manpage_template(), and options_preset_unified().

◆ options_builder_create()

options_builder_t * options_builder_create ( size_t  struct_size)

Create empty options builder.

Parameters
struct_sizesizeof(your_options_t) for the target options struct
Returns
New builder (must be freed with options_builder_destroy)

Definition at line 378 of file builder.c.

378 {
379 // Reset int defaults counter for new builder
380 g_int_defaults_counter = 0;
381
383 if (!builder) {
384 SET_ERRNO(ERROR_MEMORY, "Failed to allocate options builder");
385 return NULL;
386 }
387
389 if (!builder->descriptors) {
390 free(builder);
391 SET_ERRNO(ERROR_MEMORY, "Failed to allocate descriptors array");
392 return NULL;
393 }
394
396 if (!builder->dependencies) {
397 SAFE_FREE(builder->descriptors);
398 SAFE_FREE(builder);
399 SET_ERRNO(ERROR_MEMORY, "Failed to allocate dependencies array");
400 return NULL;
401 }
402
403 builder->num_descriptors = 0;
405 builder->num_dependencies = 0;
407 builder->positional_args = NULL;
408 builder->num_positional_args = 0;
409 builder->positional_arg_capacity = 0;
410 builder->usage_lines = NULL;
411 builder->num_usage_lines = 0;
412 builder->usage_line_capacity = 0;
413 builder->examples = NULL;
414 builder->num_examples = 0;
415 builder->example_capacity = 0;
416 builder->modes = NULL;
417 builder->num_modes = 0;
418 builder->mode_capacity = 0;
419 builder->custom_sections = NULL;
420 builder->num_custom_sections = 0;
421 builder->custom_section_capacity = 0;
422 builder->struct_size = struct_size;
423 builder->program_name = NULL;
424 builder->description = NULL;
425 builder->owned_strings_builder = NULL;
426 builder->num_owned_strings_builder = 0;
428
429 return builder;
430}
#define INITIAL_DEPENDENCY_CAPACITY
#define INITIAL_DESCRIPTOR_CAPACITY
Options builder.
Definition builder.h:441
size_t mode_capacity
Allocated capacity.
Definition builder.h:464
size_t example_capacity
Allocated capacity.
Definition builder.h:460
size_t custom_section_capacity
Allocated capacity.
Definition builder.h:468
size_t usage_line_capacity
Allocated capacity.
Definition builder.h:456

References options_builder_t::custom_section_capacity, options_builder_t::custom_sections, options_builder_t::dependencies, options_builder_t::dependency_capacity, options_builder_t::description, options_builder_t::descriptor_capacity, options_builder_t::descriptors, ERROR_MEMORY, options_builder_t::example_capacity, options_builder_t::examples, INITIAL_DEPENDENCY_CAPACITY, INITIAL_DESCRIPTOR_CAPACITY, options_builder_t::mode_capacity, options_builder_t::modes, options_builder_t::num_custom_sections, options_builder_t::num_dependencies, options_builder_t::num_descriptors, options_builder_t::num_examples, options_builder_t::num_modes, options_builder_t::num_owned_strings_builder, options_builder_t::num_positional_args, options_builder_t::num_usage_lines, options_builder_t::owned_strings_builder, options_builder_t::owned_strings_builder_capacity, options_builder_t::positional_arg_capacity, options_builder_t::positional_args, options_builder_t::program_name, SAFE_FREE, SAFE_MALLOC, SET_ERRNO, options_builder_t::struct_size, options_builder_t::usage_line_capacity, and options_builder_t::usage_lines.

Referenced by options_builder_from_preset(), and options_preset_unified().

◆ options_builder_destroy()

void options_builder_destroy ( options_builder_t *  builder)

Free options builder.

Parameters
builderBuilder to free (can be NULL)

Definition at line 467 of file builder.c.

467 {
468 if (!builder)
469 return;
470
471 SAFE_FREE(builder->descriptors);
472 SAFE_FREE(builder->dependencies);
473 SAFE_FREE(builder->positional_args);
474 SAFE_FREE(builder->usage_lines);
475 SAFE_FREE(builder->examples);
476 SAFE_FREE(builder->modes);
477 SAFE_FREE(builder->custom_sections);
478 SAFE_FREE(builder->owned_strings_builder); // Free the builder's owned strings
479 SAFE_FREE(builder);
480}

References options_builder_t::custom_sections, options_builder_t::dependencies, options_builder_t::descriptors, options_builder_t::examples, options_builder_t::modes, options_builder_t::owned_strings_builder, options_builder_t::positional_args, SAFE_FREE, and options_builder_t::usage_lines.

Referenced by options_preset_unified().

◆ options_builder_from_preset()

options_builder_t * options_builder_from_preset ( const options_config_t *  preset)

Create builder from preset config.

Copies all descriptors and dependencies from the preset.

Parameters
presetPreset configuration to copy
Returns
New builder (must be freed with options_builder_destroy)

Definition at line 432 of file builder.c.

432 {
433 if (!preset) {
434 SET_ERRNO(ERROR_INVALID_PARAM, "Preset config is NULL");
435 return NULL;
436 }
437
439 if (!builder) {
440 return NULL;
441 }
442
443 builder->program_name = preset->program_name;
444 builder->description = preset->description;
445
446 // Copy all descriptors
447 for (size_t i = 0; i < preset->num_descriptors; i++) {
448 options_builder_add_descriptor(builder, &preset->descriptors[i]);
449 }
450
451 // Copy all dependencies
452 for (size_t i = 0; i < preset->num_dependencies; i++) {
453 options_builder_add_dependency(builder, &preset->dependencies[i]);
454 }
455
456 // Copy all positional arguments
457 for (size_t i = 0; i < preset->num_positional_args; i++) {
458 const positional_arg_descriptor_t *pos_arg = &preset->positional_args[i];
459 options_builder_add_positional(builder, pos_arg->name, pos_arg->help_text, pos_arg->required,
460 pos_arg->section_heading, pos_arg->examples, pos_arg->num_examples,
461 pos_arg->mode_bitmask, pos_arg->parse_fn);
462 }
463
464 return builder;
465}
void options_builder_add_dependency(options_builder_t *builder, const option_dependency_t *dependency)
Add full dependency (advanced)
Definition builder.c:1164
void options_builder_add_descriptor(options_builder_t *builder, const option_descriptor_t *descriptor)
Add full option descriptor (advanced)
Definition builder.c:973
options_builder_t * options_builder_create(size_t struct_size)
Create empty options builder.
Definition builder.c:378
const char * section_heading
Section heading for examples (e.g., "ADDRESS FORMATS")
Definition builder.h:363
bool required
If true, this positional arg must be provided.
Definition builder.h:360
const char * help_text
Description for usage message.
Definition builder.h:359
int(* parse_fn)(const char *arg, void *config, char **remaining, int num_remaining, char **error_msg)
Definition builder.h:377
option_mode_bitmask_t mode_bitmask
Which modes this positional arg applies to.
Definition builder.h:380
const char ** examples
Array of example strings with descriptions.
Definition builder.h:364
size_t num_examples
Number of examples.
Definition builder.h:365

References options_config_t::dependencies, options_config_t::description, options_builder_t::description, options_config_t::descriptors, ERROR_INVALID_PARAM, positional_arg_descriptor_t::examples, positional_arg_descriptor_t::help_text, positional_arg_descriptor_t::mode_bitmask, positional_arg_descriptor_t::name, options_config_t::num_dependencies, options_config_t::num_descriptors, positional_arg_descriptor_t::num_examples, options_config_t::num_positional_args, options_builder_add_dependency(), options_builder_add_descriptor(), options_builder_add_positional(), options_builder_create(), positional_arg_descriptor_t::parse_fn, options_config_t::positional_args, options_config_t::program_name, options_builder_t::program_name, positional_arg_descriptor_t::required, positional_arg_descriptor_t::section_heading, SET_ERRNO, and options_config_t::struct_size.

◆ options_builder_mark_as_list()

void options_builder_mark_as_list ( options_builder_t *  builder,
const char *  option_name 
)

Mark option as accepting multiple values.

Indicates the option accepts comma-separated or space-separated values.

Parameters
builderOptions builder
option_nameLong name of option to mark

Example:

options_builder_mark_as_list(builder, "stun-servers"); // Accepts comma-separated URLs
void options_builder_mark_as_list(options_builder_t *builder, const char *option_name)
Mark option as accepting multiple values.
Definition builder.c:1093

Definition at line 1093 of file builder.c.

1093 {
1094 if (!builder || !option_name) {
1095 SET_ERRNO(ERROR_INVALID_PARAM, "Builder or option_name is NULL");
1096 return;
1097 }
1098
1099 int idx = find_descriptor_in_builder(builder, option_name);
1100 if (idx < 0) {
1101 SET_ERRNO(ERROR_INVALID_PARAM, "Option '%s' not found in builder", option_name);
1102 return;
1103 }
1104
1105 option_descriptor_t *desc = &builder->descriptors[idx];
1106 desc->metadata.is_list = true;
1107}
bool is_list
If true, option accepts multiple comma-separated or space-separated values.
Definition builder.h:217

References options_builder_t::descriptors, ERROR_INVALID_PARAM, option_metadata_t::is_list, option_descriptor_t::metadata, and SET_ERRNO.

◆ options_builder_mark_binary_only()

void options_builder_mark_binary_only ( options_builder_t *  builder,
const char *  option_name 
)

Mark an option as binary-level only (hide from mode-specific help)

Binary-level options are still parsed by mode-specific parsers (so they work anywhere in the command line), but they don't appear in mode-specific –help. They should only be documented in the top-level binary help.

Parameters
builderBuilder containing the option
option_nameLong name of the option to mark

Example:

options_builder_add_string(b, "log-file", 'L', ...);
void options_builder_mark_binary_only(options_builder_t *builder, const char *option_name)
Mark an option as binary-level only (hide from mode-specific help)
Definition builder.c:1172
void options_builder_add_string(options_builder_t *builder, const char *long_name, char short_name, size_t offset, const char *default_value, const char *help_text, const char *group, bool required, const char *env_var_name, bool(*validate)(const void *, char **))
Definition builder.c:742

Definition at line 1172 of file builder.c.

1172 {
1173 if (!builder || !option_name)
1174 return;
1175
1176 // Find the option by name and mark it
1177 for (size_t i = 0; i < builder->num_descriptors; i++) {
1178 if (strcmp(builder->descriptors[i].long_name, option_name) == 0) {
1179 builder->descriptors[i].hide_from_mode_help = true;
1180 return;
1181 }
1182 }
1183
1184 // Option not found - this is a programming error
1185 log_warn("Attempted to mark non-existent option '%s' as binary-only", option_name);
1186}
#define log_warn(...)
Log a WARN message.
Definition log/log.h:574

References options_builder_t::descriptors, option_descriptor_t::hide_from_mode_help, log_warn, option_descriptor_t::long_name, and options_builder_t::num_descriptors.

◆ options_builder_set_arg_placeholder()

void options_builder_set_arg_placeholder ( options_builder_t *  builder,
const char *  arg_placeholder 
)

Set custom argument placeholder on the last added option descriptor.

Sets the arg_placeholder field on the most recently added option descriptor. This allows customizing the placeholder text shown in help (e.g., "SHELL [FILE]" instead of "STR").

Parameters
builderOptions builder
arg_placeholderCustom placeholder text (e.g., "SHELL [FILE]"), or NULL to use type-based placeholder

Definition at line 992 of file builder.c.

992 {
993 if (!builder || builder->num_descriptors == 0) {
994 SET_ERRNO(ERROR_INVALID_STATE, "Builder is NULL or has no descriptors");
995 return;
996 }
997 builder->descriptors[builder->num_descriptors - 1].arg_placeholder = arg_placeholder;
998}
@ ERROR_INVALID_STATE

References option_descriptor_t::arg_placeholder, options_builder_t::descriptors, ERROR_INVALID_STATE, options_builder_t::num_descriptors, and SET_ERRNO.

Referenced by options_registry_add_all_to_builder().

◆ options_builder_set_default_value_display()

void options_builder_set_default_value_display ( options_builder_t *  builder,
const char *  option_name,
const char *  default_value 
)

Set default value string in metadata.

Sets the default value string for display in completions (informational, separate from the descriptor's default_value which is used for parsing).

Parameters
builderOptions builder
option_nameLong name of option to set metadata for
default_valueDefault value as string for display

Definition at line 1109 of file builder.c.

1110 {
1111 if (!builder || !option_name) {
1112 SET_ERRNO(ERROR_INVALID_PARAM, "Builder or option_name is NULL");
1113 return;
1114 }
1115
1116 int idx = find_descriptor_in_builder(builder, option_name);
1117 if (idx < 0) {
1118 SET_ERRNO(ERROR_INVALID_PARAM, "Option '%s' not found in builder", option_name);
1119 return;
1120 }
1121
1122 option_descriptor_t *desc = &builder->descriptors[idx];
1123 desc->metadata.default_value = default_value;
1124}
const char * default_value
Default value as string for display.
Definition builder.h:211

References option_metadata_t::default_value, options_builder_t::descriptors, ERROR_INVALID_PARAM, option_descriptor_t::metadata, and SET_ERRNO.

◆ options_builder_set_enum_values()

void options_builder_set_enum_values ( options_builder_t *  builder,
const char *  option_name,
const char **  values,
const char **  descriptions 
)

Set enum values with descriptions for an option.

Populates the metadata with enum values and descriptions for shell completion. Both arrays must have the same length.

Parameters
builderOptions builder
option_nameLong name of option to set metadata for
valuesArray of enum value strings (e.g., {"auto", "none", "16", "256", "truecolor"})
descriptionsArray of descriptions parallel to values
countNumber of values/descriptions

Example:

const char *color_values[] = {"auto", "none", "16", "256", "truecolor"};
const char *color_descs[] = {
"Auto-detect from terminal",
"Monochrome only",
"16 colors (ANSI)",
"256 colors (xterm)",
"24-bit truecolor (modern terminals)"
};
options_builder_set_enum_values(builder, "color-mode", color_values, color_descs, 5);
void options_builder_set_enum_values(options_builder_t *builder, const char *option_name, const char **values, const char **descriptions)
Set enum values with descriptions for an option.
Definition builder.c:1022
void options_builder_set_input_type(options_builder_t *builder, const char *option_name, option_input_type_t input_type)
Set input type for an option.
Definition builder.c:1076
@ OPTION_INPUT_ENUM
Choose from fixed set of enum values.
Definition builder.h:178

Definition at line 1022 of file builder.c.

1023 {
1024 if (!builder || !option_name || !values || !descriptions) {
1025 SET_ERRNO(ERROR_INVALID_PARAM, "Builder or arguments are NULL");
1026 return;
1027 }
1028
1029 int idx = find_descriptor_in_builder(builder, option_name);
1030 if (idx < 0) {
1031 SET_ERRNO(ERROR_INVALID_PARAM, "Option '%s' not found in builder", option_name);
1032 return;
1033 }
1034
1035 option_descriptor_t *desc = &builder->descriptors[idx];
1036 desc->metadata.enum_values = values;
1037 desc->metadata.enum_descriptions = descriptions;
1038}
const char ** enum_descriptions
Descriptions parallel to enum_values (null-terminated, e.g., "Auto-detect from terminal")
Definition builder.h:197

References options_builder_t::descriptors, option_metadata_t::enum_descriptions, option_metadata_t::enum_values, ERROR_INVALID_PARAM, option_descriptor_t::metadata, and SET_ERRNO.

◆ options_builder_set_examples()

void options_builder_set_examples ( options_builder_t *  builder,
const char *  option_name,
const char **  examples 
)

Set example values for an option.

Provides example values or command invocations for help display and completion suggestions.

Parameters
builderOptions builder
option_nameLong name of option to set metadata for
examplesArray of example strings (must be null-terminated, may be values or full commands)

Example:

const char *fps_examples[] = {"30", "60", "144", NULL};
options_builder_set_examples(builder, "fps", fps_examples);
void options_builder_set_examples(options_builder_t *builder, const char *option_name, const char **examples)
Set example values for an option.
Definition builder.c:1059

Definition at line 1059 of file builder.c.

1059 {
1060 if (!builder || !option_name || !examples) {
1061 SET_ERRNO(ERROR_INVALID_PARAM, "Builder or arguments are NULL");
1062 return;
1063 }
1064
1065 int idx = find_descriptor_in_builder(builder, option_name);
1066 if (idx < 0) {
1067 SET_ERRNO(ERROR_INVALID_PARAM, "Option '%s' not found in builder", option_name);
1068 return;
1069 }
1070
1071 option_descriptor_t *desc = &builder->descriptors[idx];
1072 desc->metadata.examples = examples;
1073 // Note: examples array must be null-terminated
1074}
const char ** examples
Example values or command invocations (null-terminated array)
Definition builder.h:208

References options_builder_t::descriptors, ERROR_INVALID_PARAM, option_metadata_t::examples, option_descriptor_t::metadata, and SET_ERRNO.

◆ options_builder_set_input_type()

void options_builder_set_input_type ( options_builder_t *  builder,
const char *  option_name,
option_input_type_t  input_type 
)

Set input type for an option.

Specifies what kind of input the option expects (enum, numeric, filepath, etc.) for generating appropriate shell completions.

Parameters
builderOptions builder
option_nameLong name of option to set metadata for
input_typeThe input type (OPTION_INPUT_ENUM, OPTION_INPUT_NUMERIC, etc.)

Example:

@ OPTION_INPUT_FILEPATH
File path completion.
Definition builder.h:181

Definition at line 1076 of file builder.c.

1077 {
1078 if (!builder || !option_name) {
1079 SET_ERRNO(ERROR_INVALID_PARAM, "Builder or option_name is NULL");
1080 return;
1081 }
1082
1083 int idx = find_descriptor_in_builder(builder, option_name);
1084 if (idx < 0) {
1085 SET_ERRNO(ERROR_INVALID_PARAM, "Option '%s' not found in builder", option_name);
1086 return;
1087 }
1088
1089 option_descriptor_t *desc = &builder->descriptors[idx];
1090 desc->metadata.input_type = input_type;
1091}
option_input_type_t input_type
What kind of input this option expects.
Definition builder.h:214

References options_builder_t::descriptors, ERROR_INVALID_PARAM, option_metadata_t::input_type, option_descriptor_t::metadata, and SET_ERRNO.

◆ options_builder_set_mode_bitmask()

void options_builder_set_mode_bitmask ( options_builder_t *  builder,
option_mode_bitmask_t  mode_bitmask 
)

Set mode bitmask on the last added option descriptor.

Sets the mode_bitmask field on the most recently added option descriptor. This allows setting mode applicability after adding an option.

Parameters
builderOptions builder
mode_bitmaskBitmask indicating which modes this option applies to

Definition at line 984 of file builder.c.

984 {
985 if (!builder || builder->num_descriptors == 0) {
986 SET_ERRNO(ERROR_INVALID_STATE, "Builder is NULL or has no descriptors");
987 return;
988 }
989 builder->descriptors[builder->num_descriptors - 1].mode_bitmask = mode_bitmask;
990}

References options_builder_t::descriptors, ERROR_INVALID_STATE, option_descriptor_t::mode_bitmask, options_builder_t::num_descriptors, and SET_ERRNO.

Referenced by options_registry_add_all_to_builder().

◆ options_builder_set_numeric_range()

void options_builder_set_numeric_range ( options_builder_t *  builder,
const char *  option_name,
int  min,
int  max,
int  step 
)

Set numeric range for an option.

Specifies minimum, maximum, and optional step for numeric input completions.

Parameters
builderOptions builder
option_nameLong name of option to set metadata for
minMinimum value (0 = no limit)
maxMaximum value (0 = no limit)
stepStep size (0 = continuous, no step)

Example:

options_builder_set_numeric_range(builder, "compression-level", 1, 9, 1);
void options_builder_set_numeric_range(options_builder_t *builder, const char *option_name, int min, int max, int step)
Set numeric range for an option.
Definition builder.c:1040
@ OPTION_INPUT_NUMERIC
Numeric value with optional min/max/step.
Definition builder.h:179

Definition at line 1040 of file builder.c.

1041 {
1042 if (!builder || !option_name) {
1043 SET_ERRNO(ERROR_INVALID_PARAM, "Builder or option_name is NULL");
1044 return;
1045 }
1046
1047 int idx = find_descriptor_in_builder(builder, option_name);
1048 if (idx < 0) {
1049 SET_ERRNO(ERROR_INVALID_PARAM, "Option '%s' not found in builder", option_name);
1050 return;
1051 }
1052
1053 option_descriptor_t *desc = &builder->descriptors[idx];
1054 desc->metadata.numeric_range.min = min;
1055 desc->metadata.numeric_range.max = max;
1056 desc->metadata.numeric_range.step = step;
1057}
int step
Step size (0 = no step, continuous)
Definition builder.h:204

References options_builder_t::descriptors, ERROR_INVALID_PARAM, option_metadata_t::max, option_descriptor_t::metadata, option_metadata_t::min, option_metadata_t::numeric_range, SET_ERRNO, and option_metadata_t::step.

◆ options_config_destroy()

void options_config_destroy ( options_config_t *  config)

Free options config.

Frees the config structure. Does NOT free strings in the options struct - use options_config_destroy() for that.

Parameters
configConfig to free (can be NULL)

Definition at line 631 of file builder.c.

631 {
632 if (!config)
633 return;
634
635 SAFE_FREE(config->descriptors);
636 SAFE_FREE(config->dependencies);
637 SAFE_FREE(config->positional_args);
638 SAFE_FREE(config->usage_lines);
639 SAFE_FREE(config->examples);
640 SAFE_FREE(config->modes);
641 SAFE_FREE(config->custom_sections);
642
643 // Free all owned strings before freeing the array
644 // Use SAFE_FREE because platform_strdup uses SAFE_MALLOC (mimalloc on Windows)
645 for (size_t i = 0; i < config->num_owned_strings; i++) {
646 SAFE_FREE(config->owned_strings[i]);
647 }
648 SAFE_FREE(config->owned_strings);
649
650 SAFE_FREE(config);
651}

References options_config_t::custom_sections, options_config_t::dependencies, options_config_t::descriptors, options_config_t::examples, options_config_t::modes, options_config_t::num_owned_strings, options_config_t::owned_strings, options_config_t::positional_args, SAFE_FREE, and options_config_t::usage_lines.

Referenced by config_create_default(), options_init(), and usage().

◆ options_config_parse()

asciichat_error_t options_config_parse ( const options_config_t *  config,
int  argc,
char **  argv,
void *  options_struct,
option_mode_bitmask_t  detected_mode,
int *  remaining_argc,
char ***  remaining_argv 
)

Parse command-line arguments.

Parses argv using the option descriptors. Strings are automatically strdup'd. Environment variables are checked for missing options.

Parameters
configOptions configuration
argcArgument count
argvArgument vector
options_structOptions struct to fill
remaining_argcOptional: receives count of non-option args
remaining_argvOptional: receives array of non-option args
Returns
ASCIICHAT_OK on success, ERROR_USAGE on parse errors

Definition at line 1815 of file builder.c.

1817 {
1818 if (!config || !options_struct) {
1819 return SET_ERRNO(ERROR_INVALID_PARAM, "Config or options struct is NULL");
1820 }
1821
1822 // Use the new unified parser that handles mixed positional and flag arguments
1823 asciichat_error_t result = options_config_parse_unified(config, argc, argv, options_struct, detected_mode);
1824 if (result != ASCIICHAT_OK) {
1825 return result;
1826 }
1827
1828 // Since unified parser handles all arguments, there are no remaining args
1829 // (backward compatibility: set remaining_argc to 0)
1830 if (remaining_argc) {
1831 *remaining_argc = 0;
1832 }
1833 if (remaining_argv) {
1834 *remaining_argv = NULL;
1835 }
1836
1837 return ASCIICHAT_OK;
1838}
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:49
@ ASCIICHAT_OK
Definition error_codes.h:51

References ASCIICHAT_OK, ERROR_INVALID_PARAM, and SET_ERRNO.

Referenced by options_init().

◆ options_config_parse_positional()

asciichat_error_t options_config_parse_positional ( const options_config_t *  config,
int  remaining_argc,
char **  remaining_argv,
void *  options_struct 
)

Parse positional arguments.

Parses positional arguments from remaining_argv after getopt processing. Calls each positional arg descriptor's parse_fn in order.

This is called automatically by options_config_parse(), but can also be called separately if you want custom control over the parsing flow.

Parameters
configOptions configuration
remaining_argcCount of remaining args
remaining_argvArray of remaining args
options_structOptions struct to fill
Returns
ASCIICHAT_OK on success, ERROR_USAGE on parse errors

Definition at line 1331 of file builder.c.

1332 {
1333 if (!config || !options_struct) {
1334 return SET_ERRNO(ERROR_INVALID_PARAM, "Config or options struct is NULL");
1335 }
1336
1337 if (remaining_argc < 0 || (remaining_argc > 0 && !remaining_argv)) {
1338 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid remaining args");
1339 }
1340
1341 // No positional args defined - but we got some positional arguments
1342 if (config->num_positional_args == 0 && remaining_argc > 0) {
1343 log_error("Error: Unexpected positional argument '%s'", remaining_argv[0]);
1344 return ERROR_USAGE;
1345 }
1346
1347 // Check if required positional args are missing
1348 for (size_t i = 0; i < config->num_positional_args; i++) {
1349 const positional_arg_descriptor_t *pos_arg = &config->positional_args[i];
1350 if (pos_arg->required && remaining_argc == 0) {
1351 log_error("Error: Missing required positional argument '%s'", pos_arg->name);
1352 if (pos_arg->help_text) {
1353 log_error(" %s", pos_arg->help_text);
1354 }
1355 return ERROR_USAGE;
1356 }
1357 }
1358
1359 // Parse positional arguments
1360 int arg_index = 0;
1361 for (size_t i = 0; i < config->num_positional_args && arg_index < remaining_argc; i++) {
1362 const positional_arg_descriptor_t *pos_arg = &config->positional_args[i];
1363
1364 const char *arg = remaining_argv[arg_index];
1365 char **remaining = (arg_index + 1 < remaining_argc) ? &remaining_argv[arg_index + 1] : NULL;
1366 int num_remaining = remaining_argc - arg_index - 1;
1367 char *error_msg = NULL;
1368
1369 // Call custom parser
1370 int consumed = pos_arg->parse_fn(arg, options_struct, remaining, num_remaining, &error_msg);
1371
1372 if (consumed < 0) {
1373 // Parse error
1374 if (error_msg) {
1375 log_error("Error parsing positional argument '%s': %s", pos_arg->name, error_msg);
1376 free(error_msg);
1377 } else {
1378 log_error("Error parsing positional argument '%s': %s", pos_arg->name, arg);
1379 }
1380 return ERROR_USAGE;
1381 }
1382
1383 // Advance by consumed args (usually 1, but can be more for multi-arg parsers)
1384 arg_index += consumed;
1385 }
1386
1387 // Check for extra unconsumed positional arguments
1388 if (arg_index < remaining_argc) {
1389 log_error("Error: Unexpected positional argument '%s'", remaining_argv[arg_index]);
1390 return ERROR_USAGE;
1391 }
1392
1393 return ASCIICHAT_OK;
1394}
@ ERROR_USAGE
Definition error_codes.h:53

References ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_USAGE, positional_arg_descriptor_t::help_text, log_error, positional_arg_descriptor_t::name, options_config_t::num_positional_args, positional_arg_descriptor_t::parse_fn, options_config_t::positional_args, positional_arg_descriptor_t::required, and SET_ERRNO.

◆ options_config_set_defaults()

asciichat_error_t options_config_set_defaults ( const options_config_t *  config,
void *  options_struct 
)

Set default values in options struct.

Sets defaults from descriptors, checking environment variables for options with env_var_name set.

Parameters
configOptions configuration
options_structOptions struct to initialize
Returns
ASCIICHAT_OK on success, error code on failure

Definition at line 1400 of file builder.c.

1400 {
1401 if (!config || !options_struct) {
1402 return SET_ERRNO(ERROR_INVALID_PARAM, "Config or options struct is NULL");
1403 }
1404
1405 char *base = (char *)options_struct;
1406
1407 for (size_t i = 0; i < config->num_descriptors; i++) {
1408 const option_descriptor_t *desc = &config->descriptors[i];
1409 void *field = base + desc->offset;
1410
1411 // Check environment variable first (primary)
1412 const char *env_value = NULL;
1413 if (desc->env_var_name) {
1414 env_value = SAFE_GETENV(desc->env_var_name);
1415 }
1416 // Check shorter alias names as fallback if primary not set
1417 if (!env_value) {
1418 if (desc->env_var_name && strcmp(desc->env_var_name, "ASCII_CHAT_PORT") == 0) {
1419 env_value = SAFE_GETENV("PORT");
1420 } else if (desc->env_var_name && strcmp(desc->env_var_name, "ASCII_CHAT_WEBSOCKET_PORT") == 0) {
1421 env_value = SAFE_GETENV("WS_PORT");
1422 }
1423 }
1424
1425 // Use handler registry to apply environment variables and defaults
1426 if (desc->type >= 0 && desc->type < (int)(NUM_OPTION_TYPES)) {
1427 if (g_builder_handlers[desc->type].apply_env) {
1428 g_builder_handlers[desc->type].apply_env(field, env_value, desc);
1429 }
1430 } else if (desc->type == OPTION_TYPE_CALLBACK && desc->parse_fn && desc->default_value) {
1431 // Special handling for callbacks with parse_fn
1432 char *error_msg = NULL;
1433 desc->parse_fn(NULL, field, &error_msg);
1434 if (error_msg) {
1435 free(error_msg);
1436 }
1437 }
1438 }
1439
1440 return ASCIICHAT_OK;
1441}
#define SAFE_GETENV(name)
Definition common.h:434
void(* apply_env)(void *field, const char *env_value, const option_descriptor_t *desc)
const char * env_var_name
Environment variable fallback (or NULL)
Definition builder.h:260
bool(* parse_fn)(const char *arg, void *dest, char **error_msg)
Definition builder.h:266

References option_builder_handler_t::apply_env, ASCIICHAT_OK, option_descriptor_t::default_value, options_config_t::descriptors, option_descriptor_t::env_var_name, ERROR_INVALID_PARAM, g_builder_handlers, options_config_t::num_descriptors, NUM_OPTION_TYPES, option_descriptor_t::offset, OPTION_TYPE_CALLBACK, option_descriptor_t::parse_fn, SAFE_GETENV, SET_ERRNO, and option_descriptor_t::type.

Referenced by options_init().

◆ options_config_validate()

asciichat_error_t options_config_validate ( const options_config_t *  config,
const void *  options_struct,
char **  error_message 
)

Validate options struct.

Checks:

  • Required fields are set
  • Dependencies are satisfied
  • Custom validators pass
Parameters
configOptions configuration
options_structOptions struct to validate
error_messageOptional: receives detailed error message (must free)
Returns
ASCIICHAT_OK if valid, error code otherwise

Definition at line 1840 of file builder.c.

1841 {
1842 if (!config || !options_struct) {
1843 return SET_ERRNO(ERROR_INVALID_PARAM, "Config or options struct is NULL");
1844 }
1845
1846 const char *base = (const char *)options_struct;
1847
1848 // Check required fields
1849 for (size_t i = 0; i < config->num_descriptors; i++) {
1850 const option_descriptor_t *desc = &config->descriptors[i];
1851 if (!desc->required)
1852 continue;
1853
1854 const void *field = base + desc->offset;
1855 // Use handler registry to check if option is set (for required field validation)
1856 bool is_set = true;
1857 if (desc->type >= 0 && desc->type < (int)(NUM_OPTION_TYPES)) {
1858 if (g_builder_handlers[desc->type].is_set) {
1859 is_set = g_builder_handlers[desc->type].is_set(field, desc);
1860 }
1861 }
1862
1863 if (!is_set) {
1864 if (error_message) {
1865 int asprintf_result;
1866 if (desc->env_var_name) {
1867 asprintf_result = asprintf(error_message, "Required option --%s is not set (set %s env var or use --%s)",
1868 desc->long_name, desc->env_var_name, desc->long_name);
1869 } else {
1870 asprintf_result = asprintf(error_message, "Required option --%s is not set", desc->long_name);
1871 }
1872 if (asprintf_result < 0) {
1873 log_error("Failed to format error message for missing required option --%s", desc->long_name);
1874 *error_message = NULL;
1875 }
1876 }
1877 return ERROR_USAGE;
1878 }
1879 }
1880
1881 // Check dependencies
1882 for (size_t i = 0; i < config->num_dependencies; i++) {
1883 const option_dependency_t *dep = &config->dependencies[i];
1884
1885 bool option_is_set = is_option_set(config, options_struct, dep->option_name);
1886 bool depends_is_set = is_option_set(config, options_struct, dep->depends_on);
1887
1888 switch (dep->type) {
1890 if (option_is_set && !depends_is_set) {
1891 if (error_message) {
1892 if (dep->error_message) {
1893 *error_message = platform_strdup(dep->error_message);
1894 } else {
1895 int asprintf_result =
1896 asprintf(error_message, "Option --%s requires --%s to be set", dep->option_name, dep->depends_on);
1897 if (asprintf_result < 0) {
1898 log_error("Failed to format error message for option dependency: --%s requires --%s", dep->option_name,
1899 dep->depends_on);
1900 *error_message = NULL;
1901 }
1902 }
1903 }
1904 return ERROR_USAGE;
1905 }
1906 break;
1907
1909 if (option_is_set && depends_is_set) {
1910 if (error_message) {
1911 if (dep->error_message) {
1912 *error_message = platform_strdup(dep->error_message);
1913 } else {
1914 int asprintf_result =
1915 asprintf(error_message, "Option --%s conflicts with --%s", dep->option_name, dep->depends_on);
1916 if (asprintf_result < 0) {
1917 log_error("Failed to format error message for option conflict: --%s conflicts with --%s",
1918 dep->option_name, dep->depends_on);
1919 *error_message = NULL;
1920 }
1921 }
1922 }
1923 return ERROR_USAGE;
1924 }
1925 break;
1926
1927 case DEPENDENCY_IMPLIES:
1928 // Implies is handled during parsing, not validation
1929 break;
1930 }
1931 }
1932
1933 // Run custom validators
1934 for (size_t i = 0; i < config->num_descriptors; i++) {
1935 const option_descriptor_t *desc = &config->descriptors[i];
1936 if (!desc->validate)
1937 continue;
1938
1939 char *custom_error = NULL;
1940 if (!desc->validate(options_struct, &custom_error)) {
1941 if (error_message) {
1942 *error_message = custom_error;
1943 } else {
1944 free(custom_error);
1945 }
1946 return ERROR_USAGE;
1947 }
1948 }
1949
1950 // Cross-field validation: Check for conflicting color options
1951 // Cannot use --color with --color-mode none
1952 const options_t *opts = (const options_t *)options_struct;
1953 if (opts->color && opts->color_mode == TERM_COLOR_NONE) {
1954 if (error_message) {
1955 int asprintf_result =
1956 asprintf(error_message, "Option --color cannot be used with --color-mode=none (conflicting color settings)");
1957 if (asprintf_result < 0) {
1958 log_error("Failed to format error message for color option conflict");
1959 *error_message = NULL;
1960 }
1961 }
1962 return ERROR_USAGE;
1963 }
1964
1965 return ASCIICHAT_OK;
1966}
bool is_option_set(const options_config_t *config, const void *options_struct, const char *option_name)
Check if an option is set (has non-default value)
Definition builder.c:356
#define asprintf
Definition builder.c:24
bool is_set
const char * depends_on
The option it depends on.
Definition builder.h:334
const char * error_message
Custom error message (optional)
Definition builder.h:335
dependency_type_t type
Type of dependency.
Definition builder.h:333
bool(* validate)(const void *options_struct, char **error_msg)
Definition builder.h:263
bool required
If true, option must be provided.
Definition builder.h:259
Consolidated options structure.
terminal_color_mode_t color_mode
Color mode (auto/none/16/256/truecolor)
int color
Color setting (COLOR_SETTING_AUTO/TRUE/FALSE)
@ TERM_COLOR_NONE
No color support (monochrome terminal)
Definition terminal.h:582

References ASCIICHAT_OK, asprintf, options_state::color, options_state::color_mode, options_config_t::dependencies, DEPENDENCY_CONFLICTS, DEPENDENCY_IMPLIES, DEPENDENCY_REQUIRES, option_dependency_t::depends_on, options_config_t::descriptors, option_descriptor_t::env_var_name, ERROR_INVALID_PARAM, option_dependency_t::error_message, ERROR_USAGE, g_builder_handlers, is_option_set(), option_builder_handler_t::is_set, is_set, log_error, option_descriptor_t::long_name, options_config_t::num_dependencies, options_config_t::num_descriptors, NUM_OPTION_TYPES, option_descriptor_t::offset, option_dependency_t::option_name, platform_strdup(), option_descriptor_t::required, SET_ERRNO, TERM_COLOR_NONE, option_descriptor_t::type, option_dependency_t::type, and option_descriptor_t::validate.

Referenced by validate_options_and_report().