ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
builder.h File Reference

Options builder API for flexible command-line option configuration. More...

Go to the source code of this file.

Data Structures

struct  option_descriptor_t
 Option descriptor. More...
 
struct  option_dependency_t
 Option dependency. More...
 
struct  positional_arg_descriptor_t
 Positional argument descriptor. More...
 
struct  options_config_t
 Options configuration. More...
 
struct  options_builder_t
 Options builder. More...
 

Enumerations

enum  option_type_t {
  OPTION_TYPE_BOOL , OPTION_TYPE_INT , OPTION_TYPE_STRING , OPTION_TYPE_DOUBLE ,
  OPTION_TYPE_CALLBACK , OPTION_TYPE_ACTION
}
 Option value types. More...
 
enum  dependency_type_t { DEPENDENCY_REQUIRES , DEPENDENCY_CONFLICTS , DEPENDENCY_IMPLIES }
 Option dependency types. More...
 

Functions

options_builder_toptions_builder_create (size_t struct_size)
 Create empty options builder.
 
options_builder_toptions_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_toptions_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 *options_struct, char **error_msg))
 Add integer option.
 
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 *options_struct, char **error_msg))
 Add string option.
 
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 *options_struct, char **error_msg))
 Add double/float option.
 
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 *arg, void *dest, char **error_msg), const char *help_text, const char *group, bool required, const char *env_var_name)
 Add option with custom callback parser.
 
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 *arg, void *dest, char **error_msg), const char *help_text, const char *group, bool required, const char *env_var_name, bool optional_arg)
 Add option with custom callback parser that supports optional arguments.
 
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_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, int(*parse_fn)(const char *arg, void *config, char **remaining, int num_remaining, char **error_msg))
 Add positional argument descriptor.
 
asciichat_error_t options_config_parse_positional (const options_config_t *config, int remaining_argc, char **remaining_argv, void *options_struct)
 Parse positional arguments.
 
const options_config_toptions_preset_binary (const char *program_name, const char *description)
 Get binary-level options preset.
 
const options_config_toptions_preset_server (const char *program_name, const char *description)
 Get server mode options preset.
 
const options_config_toptions_preset_client (const char *program_name, const char *description)
 Get client mode options preset.
 
const options_config_toptions_preset_mirror (const char *program_name, const char *description)
 Get mirror mode options preset.
 
const options_config_toptions_preset_acds (const char *program_name, const char *description)
 Get acds mode options preset.
 
asciichat_error_t options_config_set_defaults (const options_config_t *config, void *options_struct)
 Set default values in options struct.
 
asciichat_error_t options_config_parse (const options_config_t *config, int argc, char **argv, void *options_struct, 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.
 
void options_config_print_usage (const options_config_t *config, FILE *stream)
 Print usage/help text.
 
void options_config_cleanup (const options_config_t *config, void *options_struct)
 Clean up memory owned by options struct.
 

Detailed Description

Options builder API for flexible command-line option configuration.

This module provides a builder pattern for constructing option configurations that can be used by library consumers to create custom tools based on ascii-chat modes or build entirely custom option sets from scratch.

Features:

  • Three-tier parsing (binary → mode → mode-specific)
  • Required fields with environment variable fallbacks
  • Option dependencies (REQUIRES, CONFLICTS, IMPLIES)
  • Cross-field validation (validators receive full options struct)
  • Automatic string memory management (auto-strdup, cleanup)
  • Grouped help output
  • Preset configs for server/client/mirror/acds modes

Usage Pattern:

  1. Create builder (from scratch or preset)
  2. Add options with builder functions
  3. Add dependencies if needed
  4. Build immutable config
  5. Parse command line into options struct
  6. Validate (required, dependencies, custom)
  7. Use options in application
  8. Cleanup memory before exit
Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
December 2025

Definition in file builder.h.

Enumeration Type Documentation

◆ dependency_type_t

Option dependency types.

Defines relationships between options.

Enumerator
DEPENDENCY_REQUIRES 

If A is set, B must be set.

DEPENDENCY_CONFLICTS 

If A is set, B must NOT be set.

DEPENDENCY_IMPLIES 

If A is set, B defaults to true/enabled.

Definition at line 59 of file builder.h.

59 {
dependency_type_t
Option dependency types.
Definition builder.h:59
@ DEPENDENCY_IMPLIES
If A is set, B defaults to true/enabled.
Definition builder.h:62
@ DEPENDENCY_CONFLICTS
If A is set, B must NOT be set.
Definition builder.h:61
@ DEPENDENCY_REQUIRES
If A is set, B must be set.
Definition builder.h:60

◆ option_type_t

Option value types.

Defines the type of value an option accepts.

Enumerator
OPTION_TYPE_BOOL 

Boolean flag (–flag, no value)

OPTION_TYPE_INT 

Integer value (–count 42)

OPTION_TYPE_STRING 

String value (–name foo)

OPTION_TYPE_DOUBLE 

Floating point (–ratio 1.5)

OPTION_TYPE_CALLBACK 

Custom parser function.

OPTION_TYPE_ACTION 

Action that executes and may exit (–list-webcams, etc.)

Definition at line 45 of file builder.h.

45 {
option_type_t
Option value types.
Definition builder.h:45
@ OPTION_TYPE_INT
Integer value (–count 42)
Definition builder.h:47
@ OPTION_TYPE_DOUBLE
Floating point (–ratio 1.5)
Definition builder.h:49
@ OPTION_TYPE_STRING
String value (–name foo)
Definition builder.h:48
@ OPTION_TYPE_ACTION
Action that executes and may exit (–list-webcams, etc.)
Definition builder.h:51
@ OPTION_TYPE_CALLBACK
Custom parser function.
Definition builder.h:50
@ OPTION_TYPE_BOOL
Boolean flag (–flag, no value)
Definition builder.h:46

Function Documentation

◆ 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 532 of file builder.c.

533 {
534 ensure_descriptor_capacity(builder);
535
536 option_descriptor_t desc = {.long_name = long_name,
537 .short_name = short_name,
538 .type = OPTION_TYPE_ACTION,
539 .offset = 0, // Actions don't store values
540 .help_text = help_text,
541 .group = group,
542 .default_value = NULL,
543 .required = false, // Actions are never required
544 .env_var_name = NULL,
545 .validate = NULL,
546 .parse_fn = NULL,
547 .action_fn = action_fn,
548 .owns_memory = false};
549
550 builder->descriptors[builder->num_descriptors++] = desc;
551}
Option descriptor.
Definition builder.h:70
const char * long_name
Long option name (e.g., "port")
Definition builder.h:72
option_descriptor_t * descriptors
Dynamic array of descriptors.
Definition builder.h:193
size_t num_descriptors
Current count.
Definition builder.h:194

References options_builder_t::descriptors, option_descriptor_t::long_name, options_builder_t::num_descriptors, and OPTION_TYPE_ACTION.

Referenced by options_preset_acds(), options_preset_client(), options_preset_mirror(), and options_preset_server().

◆ 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 344 of file builder.c.

346 {
347 ensure_descriptor_capacity(builder);
348
349 static bool default_vals[2] = {false, true};
350
351 option_descriptor_t desc = {.long_name = long_name,
352 .short_name = short_name,
353 .type = OPTION_TYPE_BOOL,
354 .offset = offset,
355 .help_text = help_text,
356 .group = group,
357 .default_value = &default_vals[default_value ? 1 : 0],
358 .required = required,
359 .env_var_name = env_var_name,
360 .validate = NULL,
361 .parse_fn = NULL,
362 .owns_memory = false};
363
364 builder->descriptors[builder->num_descriptors++] = desc;
365}

References options_builder_t::descriptors, option_descriptor_t::long_name, options_builder_t::num_descriptors, and OPTION_TYPE_BOOL.

Referenced by options_preset_acds(), options_preset_binary(), options_preset_client(), and options_preset_server().

◆ 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 *arg, void *dest, char **error_msg)  parse_fn,
const char *  help_text,
const char *  group,
bool  required,
const char *  env_var_name 
)

Add option with custom callback parser.

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)

◆ 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 *arg, void *dest, char **error_msg)  parse_fn,
const char *  help_text,
const char *  group,
bool  required,
const char *  env_var_name,
bool  optional_arg 
)

Add option with custom callback parser that supports optional arguments.

Allows the callback to receive NULL if no argument is provided (when next arg is a flag).

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 (receives NULL if arg not provided)
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 for this callback

◆ 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 599 of file builder.c.

599 {
600 if (!builder || !dependency)
601 return;
602
603 ensure_dependency_capacity(builder);
604 builder->dependencies[builder->num_dependencies++] = *dependency;
605}
size_t num_dependencies
Current count.
Definition builder.h:198
option_dependency_t * dependencies
Dynamic array of dependencies.
Definition builder.h:197

References options_builder_t::dependencies, 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 577 of file builder.c.

578 {
579 ensure_dependency_capacity(builder);
580
581 option_dependency_t dep = {.option_name = option_name,
582 .type = DEPENDENCY_CONFLICTS,
583 .depends_on = conflicts_with,
584 .error_message = error_message};
585
586 builder->dependencies[builder->num_dependencies++] = dep;
587}
Option dependency.
Definition builder.h:110
const char * option_name
The option that has the dependency.
Definition builder.h:111

References options_builder_t::dependencies, DEPENDENCY_CONFLICTS, options_builder_t::num_dependencies, and option_dependency_t::option_name.

Referenced by options_preset_client(), and options_preset_server().

◆ 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 589 of file builder.c.

590 {
591 ensure_dependency_capacity(builder);
592
593 option_dependency_t dep = {
594 .option_name = option_name, .type = DEPENDENCY_IMPLIES, .depends_on = implies, .error_message = error_message};
595
596 builder->dependencies[builder->num_dependencies++] = dep;
597}

References options_builder_t::dependencies, DEPENDENCY_IMPLIES, 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 565 of file builder.c.

566 {
567 ensure_dependency_capacity(builder);
568
569 option_dependency_t dep = {.option_name = option_name,
570 .type = DEPENDENCY_REQUIRES,
571 .depends_on = depends_on,
572 .error_message = error_message};
573
574 builder->dependencies[builder->num_dependencies++] = dep;
575}

References options_builder_t::dependencies, DEPENDENCY_REQUIRES, options_builder_t::num_dependencies, and option_dependency_t::option_name.

Referenced by options_preset_client(), and options_preset_mirror().

◆ 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 553 of file builder.c.

553 {
554 if (!builder || !descriptor)
555 return;
556
557 ensure_descriptor_capacity(builder);
558 builder->descriptors[builder->num_descriptors++] = *descriptor;
559}

References options_builder_t::descriptors, and options_builder_t::num_descriptors.

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 *options_struct, char **error_msg)  validate 
)

Add double/float option.

Parameters
builderBuilder to add to
long_nameLong option name
short_nameShort option char (or '\0')
offsetoffsetof(struct, field)
default_valueDefault value
help_textHelp description
groupGroup name for help
requiredIf true, option must be provided
env_var_nameEnvironment variable fallback (or NULL)
validateValidator function receiving full struct (or NULL)

◆ 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 *options_struct, char **error_msg)  validate 
)

Add integer option.

Parameters
builderBuilder to add to
long_nameLong option name
short_nameShort option char (or '\0')
offsetoffsetof(struct, field)
default_valueDefault value
help_textHelp description
groupGroup name for help
requiredIf true, option must be provided
env_var_nameEnvironment variable fallback (or NULL)
validateValidator function receiving full struct (or NULL)

◆ 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,
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, int(*parse_fn)(const char *arg, void *config, char **remaining, int num_remaining, char **error_msg))
Add positional argument descriptor.
Definition builder.c:627

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
parse_fnCustom parser (receives arg, config, remaining args, error_msg) Returns number of args consumed (usually 1), or -1 on error

Definition at line 627 of file builder.c.

630 {
631 if (!builder || !name || !parse_fn)
632 return;
633
634 ensure_positional_arg_capacity(builder);
635
636 positional_arg_descriptor_t pos_arg = {.name = name,
637 .help_text = help_text,
638 .required = required,
639 .section_heading = section_heading,
640 .examples = examples,
641 .num_examples = num_examples,
642 .parse_fn = parse_fn};
643
644 builder->positional_args[builder->num_positional_args++] = pos_arg;
645}
positional_arg_descriptor_t * positional_args
Dynamic array of positional args.
Definition builder.h:201
size_t num_positional_args
Current count.
Definition builder.h:202
Positional argument descriptor.
Definition builder.h:136
const char * name
Name for help text (e.g., "address", "bind-addr")
Definition builder.h:137

References positional_arg_descriptor_t::name, options_builder_t::num_positional_args, and options_builder_t::positional_args.

Referenced by options_builder_from_preset(), options_preset_acds(), options_preset_client(), and options_preset_server().

◆ 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 *options_struct, char **error_msg)  validate 
)

Add string option.

Strings are automatically strdup'd during parsing and freed during cleanup.

Parameters
builderBuilder to add to
long_nameLong option name
short_nameShort option char (or '\0')
offsetoffsetof(struct, field)
default_valueDefault value (will be strdup'd, or NULL)
help_textHelp description
groupGroup name for help
requiredIf true, option must be provided
env_var_nameEnvironment variable fallback (or NULL)
validateValidator function receiving full struct (or NULL)

◆ 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 265 of file builder.c.

265 {
266 if (!builder) {
267 SET_ERRNO(ERROR_INVALID_PARAM, "Builder is NULL");
268 return NULL;
269 }
270
272 if (!config) {
273 SET_ERRNO(ERROR_MEMORY, "Failed to allocate options config");
274 return NULL;
275 }
276
277 // Allocate and copy descriptors
279 if (!config->descriptors && builder->num_descriptors > 0) {
280 SAFE_FREE(config);
281 SET_ERRNO(ERROR_MEMORY, "Failed to allocate descriptors");
282 return NULL;
283 }
284 memcpy(config->descriptors, builder->descriptors, builder->num_descriptors * sizeof(option_descriptor_t));
285 config->num_descriptors = builder->num_descriptors;
286
287 // Allocate and copy dependencies
289 if (!config->dependencies && builder->num_dependencies > 0) {
290 SAFE_FREE(config->descriptors);
291 SAFE_FREE(config);
292 SET_ERRNO(ERROR_MEMORY, "Failed to allocate dependencies");
293 return NULL;
294 }
295 memcpy(config->dependencies, builder->dependencies, builder->num_dependencies * sizeof(option_dependency_t));
296 config->num_dependencies = builder->num_dependencies;
297
298 // Allocate and copy positional args
299 if (builder->num_positional_args > 0) {
300 config->positional_args =
302 if (!config->positional_args) {
303 SAFE_FREE(config->descriptors);
304 SAFE_FREE(config->dependencies);
305 SAFE_FREE(config);
306 SET_ERRNO(ERROR_MEMORY, "Failed to allocate positional args");
307 return NULL;
308 }
309 memcpy(config->positional_args, builder->positional_args,
311 config->num_positional_args = builder->num_positional_args;
312 } else {
313 config->positional_args = NULL;
314 config->num_positional_args = 0;
315 }
316
317 config->struct_size = builder->struct_size;
318 config->program_name = builder->program_name;
319 config->description = builder->description;
320
321 // Initialize memory management
322 config->owned_strings = NULL;
323 config->num_owned_strings = 0;
324 config->owned_strings_capacity = 0;
325
326 return config;
327}
#define SAFE_FREE(ptr)
Definition common.h:320
#define SAFE_MALLOC(size, cast)
Definition common.h:208
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
@ ERROR_MEMORY
Definition error_codes.h:53
@ ERROR_INVALID_PARAM
const char * program_name
Program name for usage.
Definition builder.h:206
const char * description
Program description for usage.
Definition builder.h:207
size_t struct_size
Target struct size.
Definition builder.h:205
Options configuration.
Definition builder.h:165
positional_arg_descriptor_t * positional_args
Array of positional argument descriptors.
Definition builder.h:172
option_descriptor_t * descriptors
Array of option descriptors.
Definition builder.h:166
option_dependency_t * dependencies
Array of dependencies.
Definition builder.h:169
const char * program_name
For usage header.
Definition builder.h:176
size_t num_positional_args
Number of positional arguments.
Definition builder.h:173
size_t num_descriptors
Number of descriptors.
Definition builder.h:167
char ** owned_strings
Strdup'd strings to free on cleanup.
Definition builder.h:180
size_t owned_strings_capacity
Allocated capacity.
Definition builder.h:182
size_t num_dependencies
Number of dependencies.
Definition builder.h:170
const char * description
For usage header.
Definition builder.h:177
size_t struct_size
sizeof(options_t) for bounds checking
Definition builder.h:175
size_t num_owned_strings
Number of owned strings.
Definition builder.h:181

References 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::num_dependencies, options_builder_t::num_dependencies, options_config_t::num_descriptors, options_builder_t::num_descriptors, options_config_t::num_owned_strings, options_config_t::num_positional_args, options_builder_t::num_positional_args, options_config_t::owned_strings, 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, and options_builder_t::struct_size.

Referenced by options_preset_acds(), options_preset_binary(), options_preset_client(), options_preset_mirror(), and options_preset_server().

◆ 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 184 of file builder.c.

184 {
186 if (!builder) {
187 SET_ERRNO(ERROR_MEMORY, "Failed to allocate options builder");
188 return NULL;
189 }
190
192 if (!builder->descriptors) {
193 free(builder);
194 SET_ERRNO(ERROR_MEMORY, "Failed to allocate descriptors array");
195 return NULL;
196 }
197
199 if (!builder->dependencies) {
200 SAFE_FREE(builder->descriptors);
201 SAFE_FREE(builder);
202 SET_ERRNO(ERROR_MEMORY, "Failed to allocate dependencies array");
203 return NULL;
204 }
205
206 builder->num_descriptors = 0;
208 builder->num_dependencies = 0;
210 builder->positional_args = NULL;
211 builder->num_positional_args = 0;
212 builder->positional_arg_capacity = 0;
213 builder->struct_size = struct_size;
214 builder->program_name = NULL;
215 builder->description = NULL;
216
217 return builder;
218}
#define INITIAL_DEPENDENCY_CAPACITY
Definition builder.c:25
#define INITIAL_DESCRIPTOR_CAPACITY
Definition builder.c:24
Options builder.
Definition builder.h:192
size_t descriptor_capacity
Allocated capacity.
Definition builder.h:195
size_t positional_arg_capacity
Allocated capacity.
Definition builder.h:203
size_t dependency_capacity
Allocated capacity.
Definition builder.h:199

References options_builder_t::dependencies, options_builder_t::dependency_capacity, options_builder_t::description, options_builder_t::descriptor_capacity, options_builder_t::descriptors, ERROR_MEMORY, INITIAL_DEPENDENCY_CAPACITY, INITIAL_DESCRIPTOR_CAPACITY, options_builder_t::num_dependencies, options_builder_t::num_descriptors, options_builder_t::num_positional_args, options_builder_t::positional_arg_capacity, options_builder_t::positional_args, options_builder_t::program_name, SAFE_FREE, SAFE_MALLOC, SET_ERRNO, and options_builder_t::struct_size.

Referenced by options_builder_from_preset(), options_preset_acds(), options_preset_binary(), options_preset_client(), options_preset_mirror(), and options_preset_server().

◆ options_builder_destroy()

void options_builder_destroy ( options_builder_t builder)

Free options builder.

Parameters
builderBuilder to free (can be NULL)

Definition at line 255 of file builder.c.

255 {
256 if (!builder)
257 return;
258
259 SAFE_FREE(builder->descriptors);
260 SAFE_FREE(builder->dependencies);
261 SAFE_FREE(builder->positional_args);
262 SAFE_FREE(builder);
263}

References options_builder_t::dependencies, options_builder_t::descriptors, options_builder_t::positional_args, and SAFE_FREE.

Referenced by options_preset_acds(), options_preset_binary(), options_preset_client(), options_preset_mirror(), and options_preset_server().

◆ 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 220 of file builder.c.

220 {
221 if (!preset) {
222 SET_ERRNO(ERROR_INVALID_PARAM, "Preset config is NULL");
223 return NULL;
224 }
225
227 if (!builder) {
228 return NULL;
229 }
230
231 builder->program_name = preset->program_name;
232 builder->description = preset->description;
233
234 // Copy all descriptors
235 for (size_t i = 0; i < preset->num_descriptors; i++) {
236 options_builder_add_descriptor(builder, &preset->descriptors[i]);
237 }
238
239 // Copy all dependencies
240 for (size_t i = 0; i < preset->num_dependencies; i++) {
241 options_builder_add_dependency(builder, &preset->dependencies[i]);
242 }
243
244 // Copy all positional arguments
245 for (size_t i = 0; i < preset->num_positional_args; i++) {
246 const positional_arg_descriptor_t *pos_arg = &preset->positional_args[i];
247 options_builder_add_positional(builder, pos_arg->name, pos_arg->help_text, pos_arg->required,
248 pos_arg->section_heading, pos_arg->examples, pos_arg->num_examples,
249 pos_arg->parse_fn);
250 }
251
252 return builder;
253}
void options_builder_add_dependency(options_builder_t *builder, const option_dependency_t *dependency)
Add full dependency (advanced)
Definition builder.c:599
void options_builder_add_descriptor(options_builder_t *builder, const option_descriptor_t *descriptor)
Add full option descriptor (advanced)
Definition builder.c:553
options_builder_t * options_builder_create(size_t struct_size)
Create empty options builder.
Definition builder.c:184
const char * section_heading
Section heading for examples (e.g., "ADDRESS FORMATS")
Definition builder.h:142
bool required
If true, this positional arg must be provided.
Definition builder.h:139
const char * help_text
Description for usage message.
Definition builder.h:138
int(* parse_fn)(const char *arg, void *config, char **remaining, int num_remaining, char **error_msg)
Definition builder.h:156
const char ** examples
Array of example strings with descriptions.
Definition builder.h:143
size_t num_examples
Number of examples.
Definition builder.h:144

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::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_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:607
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:399

Definition at line 607 of file builder.c.

607 {
608 if (!builder || !option_name)
609 return;
610
611 // Find the option by name and mark it
612 for (size_t i = 0; i < builder->num_descriptors; i++) {
613 if (strcmp(builder->descriptors[i].long_name, option_name) == 0) {
614 builder->descriptors[i].hide_from_mode_help = true;
615 return;
616 }
617 }
618
619 // Option not found - this is a programming error
620 log_warn("Attempted to mark non-existent option '%s' as binary-only", option_name);
621}
#define log_warn(...)
Log a WARN message.
bool hide_from_mode_help
If true, don't show in mode-specific help (binary-level only)
Definition builder.h:82

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_config_cleanup()

void options_config_cleanup ( const options_config_t config,
void *  options_struct 
)

Clean up memory owned by options struct.

Frees all auto-duplicated strings and sets pointers to NULL. Call this before freeing the options struct.

Parameters
configOptions configuration
options_structOptions struct to clean up

Definition at line 1345 of file builder.c.

1345 {
1346 if (!config || !options_struct)
1347 return;
1348
1349 // Free all owned strings
1350 for (size_t i = 0; i < config->num_owned_strings; i++) {
1351 free(config->owned_strings[i]);
1352 }
1353
1354 // Reset owned strings tracking
1355 ((options_config_t *)config)->num_owned_strings = 0;
1356
1357 // NULL out string fields
1358 char *base = (char *)options_struct;
1359 for (size_t i = 0; i < config->num_descriptors; i++) {
1360 const option_descriptor_t *desc = &config->descriptors[i];
1361 if (desc->type == OPTION_TYPE_STRING && desc->owns_memory) {
1362 char **field = (char **)(base + desc->offset);
1363 *field = NULL;
1364 }
1365 }
1366}
size_t offset
offsetof(struct, field) - where to store value
Definition builder.h:77
bool owns_memory
If true, strings are strdup'd and freed on cleanup.
Definition builder.h:99
option_type_t type
Value type.
Definition builder.h:76

References options_config_t::descriptors, options_config_t::num_descriptors, options_config_t::num_owned_strings, option_descriptor_t::offset, OPTION_TYPE_STRING, options_config_t::owned_strings, option_descriptor_t::owns_memory, and option_descriptor_t::type.

◆ 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_cleanup() for that.

Parameters
configConfig to free (can be NULL)

Definition at line 329 of file builder.c.

329 {
330 if (!config)
331 return;
332
333 SAFE_FREE(config->descriptors);
334 SAFE_FREE(config->dependencies);
335 SAFE_FREE(config->positional_args);
336 SAFE_FREE(config->owned_strings);
337 SAFE_FREE(config);
338}

References options_config_t::dependencies, options_config_t::descriptors, options_config_t::owned_strings, options_config_t::positional_args, and SAFE_FREE.

Referenced by parse_acds_options(), parse_client_options(), parse_mirror_options(), parse_server_options(), usage_acds(), usage_client(), usage_mirror(), and usage_server().

◆ options_config_parse()

asciichat_error_t options_config_parse ( const options_config_t config,
int  argc,
char **  argv,
void *  options_struct,
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 1101 of file builder.c.

1102 {
1103 if (!config || !options_struct) {
1104 return SET_ERRNO(ERROR_INVALID_PARAM, "Config or options struct is NULL");
1105 }
1106
1107 // Use the new unified parser that handles mixed positional and flag arguments
1108 asciichat_error_t result = options_config_parse_unified(config, argc, argv, options_struct);
1109 if (result != ASCIICHAT_OK) {
1110 return result;
1111 }
1112
1113 // Since unified parser handles all arguments, there are no remaining args
1114 // (backward compatibility: set remaining_argc to 0)
1115 if (remaining_argc) {
1116 *remaining_argc = 0;
1117 }
1118 if (remaining_argv) {
1119 *remaining_argv = NULL;
1120 }
1121
1122 return ASCIICHAT_OK;
1123}
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:46
@ ASCIICHAT_OK
Definition error_codes.h:48

References ASCIICHAT_OK, ERROR_INVALID_PARAM, and SET_ERRNO.

Referenced by parse_acds_options(), parse_client_options(), parse_mirror_options(), and parse_server_options().

◆ 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 647 of file builder.c.

648 {
649 if (!config || !options_struct) {
650 return SET_ERRNO(ERROR_INVALID_PARAM, "Config or options struct is NULL");
651 }
652
653 if (remaining_argc < 0 || (remaining_argc > 0 && !remaining_argv)) {
654 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid remaining args");
655 }
656
657 // No positional args defined - but we got some positional arguments
658 if (config->num_positional_args == 0 && remaining_argc > 0) {
659 (void)fprintf(stderr, "Error: Unexpected positional argument '%s'\n", remaining_argv[0]);
660 return ERROR_USAGE;
661 }
662
663 // Check if required positional args are missing
664 for (size_t i = 0; i < config->num_positional_args; i++) {
665 const positional_arg_descriptor_t *pos_arg = &config->positional_args[i];
666 if (pos_arg->required && remaining_argc == 0) {
667 (void)fprintf(stderr, "Error: Missing required positional argument '%s'\n", pos_arg->name);
668 if (pos_arg->help_text) {
669 (void)fprintf(stderr, " %s\n", pos_arg->help_text);
670 }
671 return ERROR_USAGE;
672 }
673 }
674
675 // Parse positional arguments
676 int arg_index = 0;
677 for (size_t i = 0; i < config->num_positional_args && arg_index < remaining_argc; i++) {
678 const positional_arg_descriptor_t *pos_arg = &config->positional_args[i];
679
680 const char *arg = remaining_argv[arg_index];
681 char **remaining = (arg_index + 1 < remaining_argc) ? &remaining_argv[arg_index + 1] : NULL;
682 int num_remaining = remaining_argc - arg_index - 1;
683 char *error_msg = NULL;
684
685 // Call custom parser
686 int consumed = pos_arg->parse_fn(arg, options_struct, remaining, num_remaining, &error_msg);
687
688 if (consumed < 0) {
689 // Parse error
690 if (error_msg) {
691 (void)fprintf(stderr, "Error parsing positional argument '%s': %s\n", pos_arg->name, error_msg);
692 free(error_msg);
693 } else {
694 (void)fprintf(stderr, "Error parsing positional argument '%s': %s\n", pos_arg->name, arg);
695 }
696 return ERROR_USAGE;
697 }
698
699 // Advance by consumed args (usually 1, but can be more for multi-arg parsers)
700 arg_index += consumed;
701 }
702
703 // Check for extra unconsumed positional arguments
704 if (arg_index < remaining_argc) {
705 (void)fprintf(stderr, "Error: Unexpected positional argument '%s'\n", remaining_argv[arg_index]);
706 return ERROR_USAGE;
707 }
708
709 return ASCIICHAT_OK;
710}
@ ERROR_USAGE
Definition error_codes.h:50

References ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_USAGE, positional_arg_descriptor_t::help_text, 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_print_usage()

void options_config_print_usage ( const options_config_t config,
FILE *  stream 
)

Print usage/help text.

Generates formatted help with grouped options.

Parameters
configOptions configuration
streamOutput stream (stdout or stderr)

Definition at line 1236 of file builder.c.

1236 {
1237 if (!config || !stream)
1238 return;
1239
1240 // Print header
1241 if (config->program_name) {
1242 fprintf(stream, "USAGE: %s [OPTIONS]\n\n", config->program_name);
1243 }
1244 if (config->description) {
1245 fprintf(stream, "%s\n\n", config->description);
1246 }
1247
1248 // Group options by group name
1249 const char *current_group = NULL;
1250
1251 for (size_t i = 0; i < config->num_descriptors; i++) {
1252 const option_descriptor_t *desc = &config->descriptors[i];
1253
1254 // Skip binary-level options (they're shown in top-level help only)
1255 if (desc->hide_from_mode_help) {
1256 continue;
1257 }
1258
1259 // Print group header if changed
1260 if (desc->group && (!current_group || strcmp(current_group, desc->group) != 0)) {
1261 fprintf(stream, "\n%s:\n", desc->group);
1262 current_group = desc->group;
1263 }
1264
1265 // Print option
1266 fprintf(stream, " ");
1267 if (desc->short_name) {
1268 fprintf(stream, "-%c, ", desc->short_name);
1269 } else {
1270 fprintf(stream, " ");
1271 }
1272
1273 fprintf(stream, "--%s", desc->long_name);
1274
1275 // Print value placeholder
1276 if (desc->type != OPTION_TYPE_BOOL && desc->type != OPTION_TYPE_ACTION) {
1277 fprintf(stream, " ");
1278 switch (desc->type) {
1279 case OPTION_TYPE_INT:
1280 fprintf(stream, "NUM");
1281 break;
1282 case OPTION_TYPE_STRING:
1283 fprintf(stream, "STR");
1284 break;
1285 case OPTION_TYPE_DOUBLE:
1286 fprintf(stream, "NUM");
1287 break;
1289 fprintf(stream, "VAL");
1290 break;
1291 default:
1292 break;
1293 }
1294 }
1295
1296 // Print description
1297 if (desc->help_text) {
1298 fprintf(stream, " %s", desc->help_text);
1299 }
1300
1301 // Print default if exists
1302 if (desc->default_value && desc->type != OPTION_TYPE_CALLBACK) {
1303 fprintf(stream, " (default: ");
1304 switch (desc->type) {
1305 case OPTION_TYPE_BOOL:
1306 fprintf(stream, "%s", *(const bool *)desc->default_value ? "true" : "false");
1307 break;
1308 case OPTION_TYPE_INT: {
1309 int int_val = 0;
1310 memcpy(&int_val, desc->default_value, sizeof(int));
1311 fprintf(stream, "%d", int_val);
1312 break;
1313 }
1314 case OPTION_TYPE_STRING:
1315 fprintf(stream, "%s", *(const char *const *)desc->default_value);
1316 break;
1317 case OPTION_TYPE_DOUBLE: {
1318 double double_val = 0.0;
1319 memcpy(&double_val, desc->default_value, sizeof(double));
1320 fprintf(stream, "%.2f", double_val);
1321 break;
1322 }
1323 default:
1324 break;
1325 }
1326 fprintf(stream, ")");
1327 }
1328
1329 // Mark as required
1330 if (desc->required) {
1331 fprintf(stream, " [REQUIRED]");
1332 }
1333
1334 // Print env var
1335 if (desc->env_var_name) {
1336 fprintf(stream, " (env: %s)", desc->env_var_name);
1337 }
1338
1339 fprintf(stream, "\n");
1340 }
1341
1342 fprintf(stream, "\n");
1343}
const char * help_text
Description for –help.
Definition builder.h:80
const char * env_var_name
Environment variable fallback (or NULL)
Definition builder.h:87
const char * group
Group name for help sections (e.g., "NETWORK OPTIONS")
Definition builder.h:81
const void * default_value
Pointer to default value (or NULL if required)
Definition builder.h:85
bool required
If true, option must be provided.
Definition builder.h:86
char short_name
Short option char (e.g., 'p', or '\0' if none)
Definition builder.h:73

References option_descriptor_t::default_value, options_config_t::description, options_config_t::descriptors, option_descriptor_t::env_var_name, option_descriptor_t::group, option_descriptor_t::help_text, option_descriptor_t::hide_from_mode_help, option_descriptor_t::long_name, options_config_t::num_descriptors, OPTION_TYPE_ACTION, OPTION_TYPE_BOOL, OPTION_TYPE_CALLBACK, OPTION_TYPE_DOUBLE, OPTION_TYPE_INT, OPTION_TYPE_STRING, options_config_t::program_name, option_descriptor_t::required, option_descriptor_t::short_name, and option_descriptor_t::type.

Referenced by usage_acds(), usage_client(), usage_mirror(), and usage_server().

◆ 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 716 of file builder.c.

716 {
717 if (!config || !options_struct) {
718 return SET_ERRNO(ERROR_INVALID_PARAM, "Config or options struct is NULL");
719 }
720
721 char *base = (char *)options_struct;
722
723 for (size_t i = 0; i < config->num_descriptors; i++) {
724 const option_descriptor_t *desc = &config->descriptors[i];
725 void *field = base + desc->offset;
726
727 // Check environment variable first
728 const char *env_value = NULL;
729 if (desc->env_var_name) {
730 env_value = SAFE_GETENV(desc->env_var_name);
731 }
732
733 switch (desc->type) {
734 case OPTION_TYPE_BOOL: {
735 bool value = false;
736 if (env_value) {
737 // Parse env var as bool
738 value = (strcmp(env_value, "1") == 0 || strcmp(env_value, "true") == 0 || strcmp(env_value, "yes") == 0 ||
739 strcmp(env_value, "on") == 0);
740 } else if (desc->default_value) {
741 value = *(const bool *)desc->default_value;
742 }
743 *(bool *)field = value;
744 break;
745 }
746
747 case OPTION_TYPE_INT: {
748 int value = 0;
749 if (env_value) {
750 // Parse env var as int
751 char *endptr;
752 long parsed = strtol(env_value, &endptr, 10);
753 if (*endptr == '\0' && parsed >= INT_MIN && parsed <= INT_MAX) {
754 value = (int)parsed;
755 }
756 } else if (desc->default_value) {
757 value = *(const int *)desc->default_value;
758 }
759 // Use memcpy to handle potentially misaligned memory safely
760 memcpy(field, &value, sizeof(int));
761 break;
762 }
763
764 case OPTION_TYPE_STRING: {
765 const char *value = NULL;
766 if (env_value) {
767 value = env_value;
768 } else if (desc->default_value) {
769 value = *(const char *const *)desc->default_value;
770 }
771
772 // Copy into fixed-size buffer (same as parsing logic in options_config_parse)
773 // String fields in options_t are char[OPTIONS_BUFF_SIZE] arrays, not pointers
774 if (value && value[0] != '\0') {
775 char *dest = (char *)field;
776 snprintf(dest, OPTIONS_BUFF_SIZE, "%s", value);
777 dest[OPTIONS_BUFF_SIZE - 1] = '\0'; // Ensure null termination
778 }
779 break;
780 }
781
782 case OPTION_TYPE_DOUBLE: {
783 double value = 0.0;
784 if (env_value) {
785 char *endptr;
786 value = strtod(env_value, &endptr);
787 if (*endptr != '\0') {
788 value = 0.0; // Parse failed
789 }
790 } else if (desc->default_value) {
791 value = *(const double *)desc->default_value;
792 }
793 // Use memcpy to handle potentially misaligned memory safely
794 memcpy(field, &value, sizeof(double));
795 break;
796 }
797
799 // Callbacks don't have automatic defaults in set_defaults
800 // Defaults are applied during parsing via the parse_fn callback
801 // Note: value_size is not stored in descriptor, so we can't memcpy safely
802 break;
803
805 // Actions don't store defaults - they execute when encountered
806 break;
807 }
808 }
809
810 return ASCIICHAT_OK;
811}
#define SAFE_GETENV(name)
Definition common.h:378
#define OPTIONS_BUFF_SIZE
Buffer size for option string values.
Definition options.h:176

References ASCIICHAT_OK, option_descriptor_t::default_value, options_config_t::descriptors, option_descriptor_t::env_var_name, ERROR_INVALID_PARAM, options_config_t::num_descriptors, option_descriptor_t::offset, OPTION_TYPE_ACTION, OPTION_TYPE_BOOL, OPTION_TYPE_CALLBACK, OPTION_TYPE_DOUBLE, OPTION_TYPE_INT, OPTION_TYPE_STRING, OPTIONS_BUFF_SIZE, SAFE_GETENV, SET_ERRNO, and option_descriptor_t::type.

Referenced by parse_acds_options(), parse_client_options(), parse_mirror_options(), and parse_server_options().

◆ 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 1125 of file builder.c.

1126 {
1127 if (!config || !options_struct) {
1128 return SET_ERRNO(ERROR_INVALID_PARAM, "Config or options struct is NULL");
1129 }
1130
1131 const char *base = (const char *)options_struct;
1132
1133 // Check required fields
1134 for (size_t i = 0; i < config->num_descriptors; i++) {
1135 const option_descriptor_t *desc = &config->descriptors[i];
1136 if (!desc->required)
1137 continue;
1138
1139 const void *field = base + desc->offset;
1140 bool is_set = false;
1141
1142 switch (desc->type) {
1143 case OPTION_TYPE_BOOL:
1144 is_set = true; // Bools are always set
1145 break;
1146 case OPTION_TYPE_INT:
1147 is_set = true; // Ints are always set
1148 break;
1149 case OPTION_TYPE_STRING:
1150 is_set = (*(const char *const *)field != NULL);
1151 break;
1152 case OPTION_TYPE_DOUBLE:
1153 is_set = true; // Doubles are always set
1154 break;
1156 is_set = (*(const void *const *)field != NULL);
1157 break;
1158 case OPTION_TYPE_ACTION:
1159 is_set = true; // Actions are never required
1160 break;
1161 }
1162
1163 if (!is_set) {
1164 if (error_message) {
1165 if (desc->env_var_name) {
1166 asprintf(error_message, "Required option --%s is not set (set %s env var or use --%s)", desc->long_name,
1167 desc->env_var_name, desc->long_name);
1168 } else {
1169 asprintf(error_message, "Required option --%s is not set", desc->long_name);
1170 }
1171 }
1172 return ERROR_USAGE;
1173 }
1174 }
1175
1176 // Check dependencies
1177 for (size_t i = 0; i < config->num_dependencies; i++) {
1178 const option_dependency_t *dep = &config->dependencies[i];
1179
1180 bool option_is_set = is_option_set(config, options_struct, dep->option_name);
1181 bool depends_is_set = is_option_set(config, options_struct, dep->depends_on);
1182
1183 switch (dep->type) {
1185 if (option_is_set && !depends_is_set) {
1186 if (error_message) {
1187 if (dep->error_message) {
1188 *error_message = strdup(dep->error_message);
1189 } else {
1190 asprintf(error_message, "Option --%s requires --%s to be set", dep->option_name, dep->depends_on);
1191 }
1192 }
1193 return ERROR_USAGE;
1194 }
1195 break;
1196
1198 if (option_is_set && depends_is_set) {
1199 if (error_message) {
1200 if (dep->error_message) {
1201 *error_message = strdup(dep->error_message);
1202 } else {
1203 asprintf(error_message, "Option --%s conflicts with --%s", dep->option_name, dep->depends_on);
1204 }
1205 }
1206 return ERROR_USAGE;
1207 }
1208 break;
1209
1210 case DEPENDENCY_IMPLIES:
1211 // Implies is handled during parsing, not validation
1212 break;
1213 }
1214 }
1215
1216 // Run custom validators
1217 for (size_t i = 0; i < config->num_descriptors; i++) {
1218 const option_descriptor_t *desc = &config->descriptors[i];
1219 if (!desc->validate)
1220 continue;
1221
1222 char *custom_error = NULL;
1223 if (!desc->validate(options_struct, &custom_error)) {
1224 if (error_message) {
1225 *error_message = custom_error;
1226 } else {
1227 free(custom_error);
1228 }
1229 return ERROR_USAGE;
1230 }
1231 }
1232
1233 return ASCIICHAT_OK;
1234}
bool is_set
const char * depends_on
The option it depends on.
Definition builder.h:113
const char * error_message
Custom error message (optional)
Definition builder.h:114
dependency_type_t type
Type of dependency.
Definition builder.h:112
bool(* validate)(const void *options_struct, char **error_msg)
Definition builder.h:90

References ASCIICHAT_OK, 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, is_set, option_descriptor_t::long_name, options_config_t::num_dependencies, options_config_t::num_descriptors, option_descriptor_t::offset, option_dependency_t::option_name, OPTION_TYPE_ACTION, OPTION_TYPE_BOOL, OPTION_TYPE_CALLBACK, OPTION_TYPE_DOUBLE, OPTION_TYPE_INT, OPTION_TYPE_STRING, option_descriptor_t::required, SET_ERRNO, option_descriptor_t::type, option_dependency_t::type, and option_descriptor_t::validate.

◆ options_preset_acds()

const options_config_t * options_preset_acds ( const char *  program_name,
const char *  description 
)

Get acds mode options preset.

Parameters
program_nameOptional program name (defaults to "ascii-chat acds")
descriptionOptional program description (defaults to "ASCII Chat Discovery Service")
Returns
Preset config (caller must free after use)

Definition at line 571 of file presets.c.

571 {
572 // Note: Each call creates a new config (no static caching) since program_name/description vary
574 if (!b)
575 return NULL;
576
577 b->program_name = program_name ? program_name : "ascii-chat discovery service";
578 b->description = description ? description : "session management and WebRTC signaling";
579
580 // Help and version
581 options_builder_add_bool(b, "help", 'h', offsetof(options_t, help), false, "Show this help", "GENERAL", false, NULL);
582
583 // Network options
584 // Note: Bind addresses are specified via positional arguments, not flags
585 add_port_option(b, "27225", "ACDS_PORT");
586
587 // ACDS-specific options
588 options_builder_add_string(b, "key", 'k', offsetof(options_t, acds_key_path), "",
589 "Path to ACDS identity key file (default: ~/.ascii-chat/acds_identity)", "ACDS", false,
590 "ACDS_KEY_PATH", NULL);
591
592 options_builder_add_string(b, "database", 'd', offsetof(options_t, acds_database_path), "",
593 "Path to ACDS database file (default: ~/.ascii-chat/acds.db)", "ACDS", false,
594 "ACDS_DATABASE_PATH", NULL);
595
596 // Logging options (binary-level, work before or after mode name)
597 // Note: ACDS uses partial logging options due to short name conflicts with identity verification options
598 options_builder_add_string(b, "log-file", 'L', offsetof(options_t, log_file), "", "Redirect logs to FILE", "LOGGING",
599 false, "ASCII_CHAT_LOG_FILE", NULL);
600
601 options_builder_add_callback(b, "log-level", '\0', offsetof(options_t, log_level), &(log_level_t){LOG_INFO},
603 "Set log level: dev, debug, info, warn, error, fatal", "LOGGING", false, NULL);
604
605 // Encryption options (shared with client and server)
606 options_builder_add_bool(b, "encrypt", 'E', offsetof(options_t, encrypt_enabled), false, "Enable encryption",
607 "SECURITY", false, NULL);
608
609 options_builder_add_string(b, "key", 'K', offsetof(options_t, encrypt_key), "", "SSH/GPG key file path", "SECURITY",
610 false, "ASCII_CHAT_KEY", NULL);
611
612 options_builder_add_string(b, "password", '\0', offsetof(options_t, password), "",
613 "Shared password for authentication", "SECURITY", false, "ASCII_CHAT_PASSWORD", NULL);
614
615 options_builder_add_string(b, "keyfile", 'F', offsetof(options_t, encrypt_keyfile), "", "Alternative key file path",
616 "SECURITY", false, NULL, NULL);
617
618 options_builder_add_bool(b, "no-encrypt", '\0', offsetof(options_t, no_encrypt), false, "Disable encryption",
619 "SECURITY", false, NULL);
620
621 // Identity verification options
622 options_builder_add_bool(b, "require-server-identity", 'S', offsetof(options_t, require_server_identity), false,
623 "Require servers to provide signed Ed25519 identity when creating sessions", "SECURITY",
624 false, NULL);
625
626 options_builder_add_bool(b, "require-client-identity", 'C', offsetof(options_t, require_client_identity), false,
627 "Require clients to provide signed Ed25519 identity when joining sessions", "SECURITY",
628 false, NULL);
629
630 options_builder_add_bool(b, "require-server-verify", 'V', offsetof(options_t, require_server_verify), false,
631 "ACDS policy: require servers to verify client identity during handshake", "SECURITY", false,
632 NULL);
633
634 options_builder_add_bool(b, "require-client-verify", 'c', offsetof(options_t, require_client_verify), false,
635 "ACDS policy: require clients to verify server identity during handshake", "SECURITY", false,
636 NULL);
637
638 // WebRTC connectivity options
639 options_builder_add_string(b, "stun-servers", '\0', offsetof(options_t, stun_servers),
640 "stun:stun.ascii-chat.com:3478,stun:stun.l.google.com:19302",
641 "Comma-separated list of STUN server URLs", "WEBRTC", false, "ASCII_CHAT_STUN_SERVERS",
642 NULL);
643
644 options_builder_add_string(b, "turn-servers", '\0', offsetof(options_t, turn_servers),
645 "turn:turn.ascii-chat.com:3478", "Comma-separated list of TURN server URLs", "WEBRTC",
646 false, "ASCII_CHAT_TURN_SERVERS", NULL);
647
648 options_builder_add_string(b, "turn-username", '\0', offsetof(options_t, turn_username), "ascii",
649 "Username for TURN server authentication", "WEBRTC", false, "ASCII_CHAT_TURN_USERNAME",
650 NULL);
651
652 options_builder_add_string(b, "turn-credential", '\0', offsetof(options_t, turn_credential),
653 "0aa9917b4dad1b01631e87a32b875e09", "Credential/password for TURN server authentication",
654 "WEBRTC", false, "ASCII_CHAT_TURN_CREDENTIAL", NULL);
655
656 options_builder_add_string(b, "turn-secret", '\0', offsetof(options_t, turn_secret), "",
657 "Shared secret for dynamic TURN credential generation (HMAC-SHA1)", "WEBRTC", false,
658 "ASCII_CHAT_TURN_SECRET", NULL);
659
660 options_builder_add_bool(b, "upnp", '\0', offsetof(options_t, enable_upnp), true,
661 "Enable UPnP/NAT-PMP for automatic port mapping (enables direct TCP for most home users)",
662 "WEBRTC", false, "ASCII_CHAT_UPNP");
663
664 options_builder_add_bool(b, "no-upnp", '\0', offsetof(options_t, no_upnp), false,
665 "Disable UPnP/NAT-PMP port mapping (requires manual port forwarding)", "WEBRTC", false,
666 NULL);
667
668 // Action options (execute and exit)
669 options_builder_add_action(b, "version", 'v', action_show_version, "Show version information and exit", "ACTIONS");
670
671 // Positional arguments: 0-2 bind addresses (IPv4 and/or IPv6)
672 options_builder_add_positional(b, "bind-address", "IPv4 or IPv6 bind address (can specify 0-2 addresses)",
673 false, // Not required (defaults to localhost)
674 "BIND ADDRESS FORMATS", g_server_bind_address_examples,
675 sizeof(g_server_bind_address_examples) / sizeof(g_server_bind_address_examples[0]),
677
678 const options_config_t *config = options_builder_build(b);
680 return config;
681}
void action_show_version(void)
Show version information and exit.
Definition actions.c:153
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)
Definition builder.c:532
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.
Definition builder.c:344
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)
Definition builder.c:467
void options_builder_destroy(options_builder_t *builder)
Free options builder.
Definition builder.c:255
options_config_t * options_builder_build(options_builder_t *builder)
Build immutable options config.
Definition builder.c:265
log_level_t
Logging levels enumeration.
Definition log/logging.h:59
#define log_file(...)
File-only logging - writes to log file only, no stderr output.
@ LOG_INFO
Definition log/logging.h:62
int parse_server_bind_address(const char *arg, void *config, char **remaining, int num_remaining, char **error_msg)
Parse server bind address positional argument.
Definition parsers.c:306
bool parse_log_level(const char *arg, void *dest, char **error_msg)
Parse log level option.
Definition parsers.c:233
Consolidated options structure.
Definition options.h:439

References action_show_version(), options_builder_t::description, log_file, LOG_INFO, options_builder_add_action(), options_builder_add_bool(), options_builder_add_callback(), options_builder_add_positional(), options_builder_add_string(), options_builder_build(), options_builder_create(), options_builder_destroy(), parse_log_level(), parse_server_bind_address(), and options_builder_t::program_name.

Referenced by parse_acds_options(), and usage_acds().

◆ options_preset_binary()

const options_config_t * options_preset_binary ( const char *  program_name,
const char *  description 
)

Get binary-level options preset.

Binary options are parsed BEFORE mode selection. Includes: –help, –version, –log-file, –log-level, etc.

Parameters
program_nameOptional program name (defaults to "ascii-chat")
descriptionOptional program description
Returns
Preset config (caller must free after use)

Definition at line 273 of file presets.c.

273 {
274 // Note: Each call creates a new config (no static caching) since program_name/description vary
276 if (!b)
277 return NULL;
278
279 b->program_name = program_name ? program_name : "ascii-chat";
280 b->description = description ? description : "Video chat in your terminal";
281
282 // Help and version
283 options_builder_add_bool(b, "help", '\0', offsetof(options_t, help), false, "Show this help", "GENERAL", false, NULL);
284
285 options_builder_add_bool(b, "version", '\0', offsetof(options_t, version), false, "Show version information",
286 "GENERAL", false, NULL);
287
288 // Add logging options
289 add_binary_logging_options(b);
290
291 const options_config_t *config = options_builder_build(b);
293 return config;
294}

References options_builder_t::description, options_builder_add_bool(), options_builder_build(), options_builder_create(), options_builder_destroy(), and options_builder_t::program_name.

◆ options_preset_client()

const options_config_t * options_preset_client ( const char *  program_name,
const char *  description 
)

Get client mode options preset.

Parameters
program_nameOptional program name (defaults to "ascii-chat client")
descriptionOptional program description (defaults to "Connect to ascii-chat server")
Returns
Preset config (caller must free after use)

Definition at line 398 of file presets.c.

398 {
399 // Note: Each call creates a new config (no static caching) since program_name/description vary
401 if (!b)
402 return NULL;
403
404 b->program_name = program_name ? program_name : "ascii-chat client";
405 b->description = description ? description : "Connect to ascii-chat server";
406
407 // Network options
408 // Note: Server address and port are specified via positional argument [address][:port], not flags
409 add_port_option(b, OPT_PORT_DEFAULT, "ASCII_CHAT_PORT");
410
411 options_builder_add_int(b, "reconnect", 'r', offsetof(options_t, reconnect_attempts), OPT_RECONNECT_ATTEMPTS_DEFAULT,
412 "Reconnection attempts (-1=infinite)", "NETWORK", false, NULL, NULL);
413
414 options_builder_add_bool(b, "scan", '\0', offsetof(options_t, lan_discovery), false,
415 "Scan for ASCII-Chat servers on local network (mDNS)", "NETWORK", false, NULL);
416
417 // Terminal dimensions, webcam, display, and snapshot options (shared with mirror)
418 add_terminal_dimension_options(b);
419 add_webcam_options(b);
420 add_display_options(b);
421 add_snapshot_options(b);
422
423 // Audio options
424 options_builder_add_bool(b, "audio", 'A', offsetof(options_t, audio_enabled), false, "Enable audio streaming",
425 "AUDIO", false, NULL);
426
427 options_builder_add_int(b, "microphone-index", '\0', offsetof(options_t, microphone_index),
428 OPT_MICROPHONE_INDEX_DEFAULT, "Microphone device index (-1=default)", "AUDIO", false, NULL,
429 NULL);
430
431 options_builder_add_int(b, "speakers-index", '\0', offsetof(options_t, speakers_index), OPT_SPEAKERS_INDEX_DEFAULT,
432 "Speakers device index (-1=default)", "AUDIO", false, NULL, NULL);
433
434 options_builder_add_bool(b, "audio-analysis", '\0', offsetof(options_t, audio_analysis_enabled), false,
435 "Enable audio analysis (debug)", "AUDIO", false, NULL);
436
437 options_builder_add_bool(b, "no-audio-playback", '\0', offsetof(options_t, audio_no_playback), false,
438 "Disable speaker playback (debug)", "AUDIO", false, NULL);
439
440 // Compression and audio encoding options (shared with server)
441 add_compression_options(b);
442
443 // ACDS Discovery options (shared with server)
444 add_acds_discovery_options(b);
445
446 // WebRTC Connection Strategy Options (Phase 3 fallback control)
447 options_builder_add_bool(b, "prefer-webrtc", '\0', offsetof(options_t, prefer_webrtc), false,
448 "Try WebRTC before Direct TCP (useful when Direct TCP fails)", "NETWORK", false, NULL);
449
450 options_builder_add_bool(b, "no-webrtc", '\0', offsetof(options_t, no_webrtc), false,
451 "Disable WebRTC, use Direct TCP only", "NETWORK", false, NULL);
452
453 options_builder_add_bool(b, "webrtc-skip-stun", '\0', offsetof(options_t, webrtc_skip_stun), false,
454 "Skip WebRTC+STUN stage, go straight to TURN relay", "NETWORK", false, NULL);
455
456 options_builder_add_bool(b, "webrtc-disable-turn", '\0', offsetof(options_t, webrtc_disable_turn), false,
457 "Disable WebRTC+TURN relay, use STUN only", "NETWORK", false, NULL);
458
459 // WebRTC Server Configuration (for testing/debugging - production uses ACDS)
460 // Note: In production, ACDS provides these automatically via SESSION_JOINED response
461 options_builder_add_string(b, "stun-servers", '\0', offsetof(options_t, stun_servers), "",
462 "Comma-separated STUN server URLs (debug/test only - ACDS provides in production)",
463 "WEBRTC", false, "ASCII_CHAT_STUN_SERVERS", NULL);
464
465 options_builder_add_string(b, "turn-servers", '\0', offsetof(options_t, turn_servers), "",
466 "Comma-separated TURN server URLs (debug/test only - ACDS provides in production)",
467 "WEBRTC", false, "ASCII_CHAT_TURN_SERVERS", NULL);
468
469 options_builder_add_string(b, "turn-username", '\0', offsetof(options_t, turn_username), "",
470 "TURN authentication username (debug/test only - ACDS provides in production)", "WEBRTC",
471 false, "ASCII_CHAT_TURN_USERNAME", NULL);
472
473 options_builder_add_string(b, "turn-credential", '\0', offsetof(options_t, turn_credential), "",
474 "TURN authentication credential (debug/test only - ACDS provides in production)", "WEBRTC",
475 false, "ASCII_CHAT_TURN_CREDENTIAL", NULL);
476
477 // Security options (common with server, plus client-specific server-key)
478 add_crypto_common_options(b);
479
480 options_builder_add_string(b, "server-key", '\0', offsetof(options_t, server_key), "", "Expected server public key",
481 "SECURITY", false, NULL, NULL);
482
483 options_builder_add_bool(b, "acds-insecure", '\0', offsetof(options_t, acds_insecure), false,
484 "Skip server key verification (MITM-vulnerable, requires explicit opt-in)", "SECURITY",
485 false, NULL);
486
487 // Add binary-level logging options (--log-file, --log-level, -V, -q)
488 // These work before or after the mode name
489 add_binary_logging_options(b);
490
491 // Dependencies
492 options_builder_add_dependency_requires(b, "snapshot-delay", "snapshot",
493 "Option --snapshot-delay requires --snapshot");
494 options_builder_add_dependency_conflicts(b, "no-compress", "compression-level",
495 "Cannot use --no-compress with --compression-level");
496 options_builder_add_dependency_conflicts(b, "encode-audio", "no-encode-audio",
497 "Cannot use both --encode-audio and --no-encode-audio");
498
499 // Action options (execute and exit)
500 options_builder_add_action(b, "help", 'h', action_help_client, "Show this help message and exit", "ACTIONS");
501
502 options_builder_add_action(b, "list-webcams", '\0', action_list_webcams, "List available webcam devices and exit",
503 "ACTIONS");
504
505 options_builder_add_action(b, "list-microphones", '\0', action_list_microphones,
506 "List available microphone devices and exit", "ACTIONS");
507
508 options_builder_add_action(b, "list-speakers", '\0', action_list_speakers, "List available speaker devices and exit",
509 "ACTIONS");
510
511 options_builder_add_action(b, "show-capabilities", '\0', action_show_capabilities,
512 "Show terminal capabilities and exit", "ACTIONS");
513
514 // Positional argument: [address][:port]
516 b, "address", "[address][:port] - Server address (IPv4, IPv6, or hostname) with optional port",
517 false, // Not required (defaults to localhost:27224)
518 "ADDRESS FORMATS", g_client_address_examples,
519 sizeof(g_client_address_examples) / sizeof(g_client_address_examples[0]), parse_client_address);
520
521 const options_config_t *config = options_builder_build(b);
523 return config;
524}
void action_show_capabilities(void)
Show terminal capabilities and exit.
Definition actions.c:118
void action_list_microphones(void)
List available microphone devices and exit.
Definition actions.c:58
void action_list_webcams(void)
List available webcam devices and exit.
Definition actions.c:30
void action_list_speakers(void)
List available speaker devices and exit.
Definition actions.c:86
void action_help_client(void)
Show client mode help and exit.
Definition actions.c:198
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.
Definition builder.c:565
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.
Definition builder.c:577
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 **))
Definition builder.c:367
#define OPT_MICROPHONE_INDEX_DEFAULT
Default microphone device index (-1 means system default)
Definition options.h:237
#define OPT_RECONNECT_ATTEMPTS_DEFAULT
Default reconnect attempts (-1 means auto/infinite)
Definition options.h:243
#define OPT_PORT_DEFAULT
Default TCP port for client/server communication.
Definition options.h:216
#define OPT_SPEAKERS_INDEX_DEFAULT
Default speakers device index (-1 means system default)
Definition options.h:240
int parse_client_address(const char *arg, void *config, char **remaining, int num_remaining, char **error_msg)
Parse client address positional argument.
Definition parsers.c:393

References action_help_client(), action_list_microphones(), action_list_speakers(), action_list_webcams(), action_show_capabilities(), options_builder_t::description, OPT_MICROPHONE_INDEX_DEFAULT, OPT_PORT_DEFAULT, OPT_RECONNECT_ATTEMPTS_DEFAULT, OPT_SPEAKERS_INDEX_DEFAULT, options_builder_add_action(), options_builder_add_bool(), options_builder_add_dependency_conflicts(), options_builder_add_dependency_requires(), options_builder_add_int(), options_builder_add_positional(), options_builder_add_string(), options_builder_build(), options_builder_create(), options_builder_destroy(), parse_client_address(), and options_builder_t::program_name.

Referenced by parse_client_options(), and usage_client().

◆ options_preset_mirror()

const options_config_t * options_preset_mirror ( const char *  program_name,
const char *  description 
)

Get mirror mode options preset.

Parameters
program_nameOptional program name (defaults to "ascii-chat mirror")
descriptionOptional program description (defaults to "Local webcam viewing (no network)")
Returns
Preset config (caller must free after use)

Definition at line 530 of file presets.c.

530 {
531 // Note: Each call creates a new config (no static caching) since program_name/description vary
533 if (!b)
534 return NULL;
535
536 b->program_name = program_name ? program_name : "ascii-chat mirror";
537 b->description = description ? description : "Local webcam viewing (no network)";
538
539 // Terminal dimensions, webcam, display, and snapshot options (shared with client)
540 add_terminal_dimension_options(b);
541 add_webcam_options(b);
542 add_display_options(b);
543 add_snapshot_options(b);
544
545 // Add binary-level logging options (--log-file, --log-level, -V, -q)
546 // These work before or after the mode name
547 add_binary_logging_options(b);
548
549 // Dependencies
550 options_builder_add_dependency_requires(b, "snapshot-delay", "snapshot",
551 "Option --snapshot-delay requires --snapshot");
552
553 // Action options (execute and exit)
554 options_builder_add_action(b, "help", 'h', action_help_mirror, "Show this help message and exit", "ACTIONS");
555
556 options_builder_add_action(b, "list-webcams", '\0', action_list_webcams, "List available webcam devices and exit",
557 "ACTIONS");
558
559 options_builder_add_action(b, "show-capabilities", '\0', action_show_capabilities,
560 "Show terminal capabilities and exit", "ACTIONS");
561
562 const options_config_t *config = options_builder_build(b);
564 return config;
565}
void action_help_mirror(void)
Show mirror mode help and exit.
Definition actions.c:204

References action_help_mirror(), action_list_webcams(), action_show_capabilities(), options_builder_t::description, options_builder_add_action(), options_builder_add_dependency_requires(), options_builder_build(), options_builder_create(), options_builder_destroy(), and options_builder_t::program_name.

Referenced by parse_mirror_options(), and usage_mirror().

◆ options_preset_server()

const options_config_t * options_preset_server ( const char *  program_name,
const char *  description 
)

Get server mode options preset.

Parameters
program_nameOptional program name (defaults to "ascii-chat server")
descriptionOptional program description (defaults to "Start ascii-chat server")
Returns
Preset config (caller must free after use)

Definition at line 300 of file presets.c.

300 {
301 // Note: Each call creates a new config (no static caching) since program_name/description vary
303 if (!b)
304 return NULL;
305
306 b->program_name = program_name ? program_name : "ascii-chat server";
307 b->description = description ? description : "Start ascii-chat server";
308
309 // Network options
310 // Note: Server bind addresses are positional arguments only, not flags
311 add_port_option(b, OPT_PORT_DEFAULT, "ASCII_CHAT_PORT");
312
313 options_builder_add_int(b, "max-clients", '\0', offsetof(options_t, max_clients), OPT_MAX_CLIENTS_DEFAULT,
314 "Maximum concurrent clients", "NETWORK", false, "ASCII_CHAT_MAX_CLIENTS", NULL);
315
316 // Compression and audio encoding options (shared with client)
317 add_compression_options(b);
318
319 options_builder_add_bool(b, "no-audio-mixer", '\0', offsetof(options_t, no_audio_mixer), false,
320 "Disable audio mixer (debug)", "PERFORMANCE", false, NULL);
321
322 // Security options (common with client, plus server-specific client-keys and no-encrypt)
323 add_crypto_common_options(b);
324
325 options_builder_add_string(b, "client-keys", '\0', offsetof(options_t, client_keys), "",
326 "Allowed client keys whitelist", "SECURITY", false, NULL, NULL);
327
328 options_builder_add_bool(b, "acds-expose-ip", '\0', offsetof(options_t, acds_expose_ip), false,
329 "Explicitly allow public IP disclosure in ACDS sessions (requires ACDS, opt-in only)",
330 "SECURITY", false, NULL);
331
332 options_builder_add_bool(b, "no-encrypt", '\0', offsetof(options_t, no_encrypt), false, "Disable encryption",
333 "SECURITY", false, NULL);
334
335 // ACDS Session Registration
336 options_builder_add_bool(b, "acds", '\0', offsetof(options_t, acds), false,
337 "Enable ACDS session registration (requires --key or --password or --acds-expose-ip)",
338 "DISCOVERY", false, NULL);
339
340 // ACDS Discovery options (shared with client)
341 add_acds_discovery_options(b);
342
343 options_builder_add_bool(b, "upnp", '\0', offsetof(options_t, enable_upnp), true,
344 "Enable UPnP/NAT-PMP for automatic port mapping (enables direct TCP for most home users)",
345 "DISCOVERY", false, "ASCII_CHAT_UPNP");
346
347 options_builder_add_bool(b, "no-upnp", '\0', offsetof(options_t, no_upnp), false,
348 "Disable UPnP/NAT-PMP port mapping (requires manual port forwarding)", "DISCOVERY", false,
349 NULL);
350
351 options_builder_add_bool(b, "no-mdns-advertise", '\0', offsetof(options_t, no_mdns_advertise), false,
352 "Disable mDNS service advertisement on local network (LAN discovery won't find this server)",
353 "DISCOVERY", false, NULL);
354
355 // Add binary-level logging options (--log-file, --log-level, -V, -q)
356 // These work before or after the mode name
357 add_binary_logging_options(b);
358
359 // Dependencies
360 options_builder_add_dependency_conflicts(b, "no-encrypt", "encrypt", "Cannot use --no-encrypt with --encrypt");
361 options_builder_add_dependency_conflicts(b, "no-encrypt", "key", "Cannot use --no-encrypt with --key");
362 options_builder_add_dependency_conflicts(b, "no-encrypt", "password", "Cannot use --no-encrypt with --password");
363 options_builder_add_dependency_conflicts(b, "no-compress", "compression-level",
364 "Cannot use --no-compress with --compression-level");
365 options_builder_add_dependency_conflicts(b, "encode-audio", "no-encode-audio",
366 "Cannot use both --encode-audio and --no-encode-audio");
367
368 // Action options (execute and exit)
369 options_builder_add_action(b, "help", 'h', action_help_server, "Show this help message and exit", "ACTIONS");
370
371 options_builder_add_action(b, "list-webcams", '\0', action_list_webcams, "List available webcam devices and exit",
372 "ACTIONS");
373
374 options_builder_add_action(b, "list-microphones", '\0', action_list_microphones,
375 "List available microphone devices and exit", "ACTIONS");
376
377 options_builder_add_action(b, "list-speakers", '\0', action_list_speakers, "List available speaker devices and exit",
378 "ACTIONS");
379
380 options_builder_add_action(b, "version", 'V', action_show_version, "Show version information and exit", "ACTIONS");
381
382 // Positional arguments: 0-2 bind addresses (IPv4 and/or IPv6)
383 options_builder_add_positional(b, "bind-address", "IPv4 or IPv6 bind address (can specify 0-2 addresses)",
384 false, // Not required (defaults to localhost)
385 "BIND ADDRESS FORMATS", g_server_bind_address_examples,
386 sizeof(g_server_bind_address_examples) / sizeof(g_server_bind_address_examples[0]),
388
389 const options_config_t *config = options_builder_build(b);
391 return config;
392}
void action_help_server(void)
Show server mode help and exit.
Definition actions.c:192
#define OPT_MAX_CLIENTS_DEFAULT
Default maximum concurrent clients (server only)
Definition options.h:225

References action_help_server(), action_list_microphones(), action_list_speakers(), action_list_webcams(), action_show_version(), options_builder_t::description, OPT_MAX_CLIENTS_DEFAULT, OPT_PORT_DEFAULT, options_builder_add_action(), options_builder_add_bool(), options_builder_add_dependency_conflicts(), options_builder_add_int(), options_builder_add_positional(), options_builder_add_string(), options_builder_build(), options_builder_create(), options_builder_destroy(), parse_server_bind_address(), and options_builder_t::program_name.

Referenced by parse_server_options(), and usage_server().