ascii-chat 0.11.33
Video chat in your terminal
Loading...
Searching...
No Matches
common.h File Reference

Common utilities and helpers for option parsing across all modes. More...

Go to the source code of this file.

Macros

#define OPTIONS_COMMON_H
 

Functions

const char * find_similar_option (const char *unknown_opt, const struct option *options)
 Find a similar option name for typo suggestions.
 
const char * format_available_modes (option_mode_bitmask_t mode_bitmask)
 Format all available modes for an option as comma-separated list.
 
int strtoint_safe (const char *str)
 Safely parse string to integer with validation.
 
char * validate_required_argument (const char *optarg, char *argbuf, size_t argbuf_size, const char *option_name, asciichat_mode_t mode)
 Validate and retrieve required argument for an option.
 
bool validate_positive_int_opt (const char *value_str, int *out_value, const char *param_name)
 Validate a positive integer value.
 
bool validate_port_opt (const char *value_str, uint16_t *out_port)
 Validate port number (1-65535)
 
bool validate_fps_opt (const char *value_str, int *out_fps)
 Validate FPS value (1-144)
 
bool validate_webcam_index (const char *value_str, unsigned short int *out_index)
 Validate webcam index using the common device index validator.
 
asciichat_error_t validate_options_and_report (const void *config, const void *opts)
 Validate options and report errors to stderr.
 
asciichat_error_t detect_default_ssh_key (char *key_path, size_t path_size)
 Detect default SSH key path for the current user.
 
char * strip_equals_prefix (const char *opt_value, char *buffer, size_t buffer_size)
 Strip equals sign prefix from option argument.
 
char * get_required_argument (const char *opt_value, char *buffer, size_t buffer_size, const char *option_name, asciichat_mode_t mode)
 Handle required arguments with consistent error messages.
 
char * read_password_from_stdin (const char *prompt)
 Read password from stdin with prompt.
 
asciichat_error_t parse_color_mode_option (const char *value_str, options_t *opts)
 Parse –color-mode option and set opts->color_mode.
 
asciichat_error_t parse_render_mode_option (const char *value_str, options_t *opts)
 Parse –render-mode option and set opts->render_mode.
 
asciichat_error_t parse_palette_option (const char *value_str, options_t *opts)
 Parse –palette option and set opt_palette_type.
 
asciichat_error_t parse_palette_chars_option (const char *value_str, options_t *opts)
 Parse –palette-chars option and set opt_palette_custom.
 
asciichat_error_t parse_width_option (const char *value_str, options_t *opts)
 Parse –width option and set opts->width.
 
asciichat_error_t parse_height_option (const char *value_str, options_t *opts)
 Parse –height option and set opts->height.
 
asciichat_error_t parse_webcam_index_option (const char *value_str, options_t *opts)
 Parse –webcam-index option and set opts->webcam_index.
 
asciichat_error_t parse_snapshot_delay_option (const char *value_str, options_t *opts)
 Parse –snapshot-delay option and set opts->snapshot_delay.
 
asciichat_error_t parse_log_level_option (const char *value_str, options_t *opts)
 Parse –log-level option and set opt_log_level.
 
void update_dimensions_for_full_height (options_t *opts)
 Update dimensions for full-height mode.
 
void update_dimensions_to_terminal_size (options_t *opts)
 Update dimensions to current terminal size.
 
void print_project_links (FILE *desc)
 Print project links with link emoji and colored styling.
 

Detailed Description

Common utilities and helpers for option parsing across all modes.

This module provides shared utilities used by the entire options system:

  • Validators for numeric ranges, file existence, formats (IP, port, etc.)
  • String parsing helpers (safe integer conversion, color mode parsing, etc.)
  • Terminal dimension management functions
  • Option lookup and typo suggestion (Levenshtein distance)
  • SSH key detection and defaults

Design Philosophy:

  • Single Responsibility: Each validator handles one specific type of validation
  • Consistent Error Reporting: All validators provide helpful error messages
  • No Side Effects: Validators are pure functions (no global state modification)
  • Reusability: These functions are used by registry, builder, and parsers modules
  • Cross-Cutting Concerns: Handles validation needs for all modes uniformly

Validator Functions:

Return conventions:

  • Numeric validators: Return parsed value on success, INT_MIN/-1 on error
  • Boolean validators: Return true/false with error message on failure
  • String validators: Validate format, write to output buffer

Typical Usage:

// Validate port number
uint16_t port;
if (!validate_port_opt("8080", &port)) {
fprintf(stderr, "Invalid port: 8080\\n");
return false;
}
// Parse color mode from string
if (err != ASCIICHAT_OK) {
fprintf(stderr, "Unknown color mode\\n");
return false;
}
// Find similar option if user misspelled
const char *suggestion = find_similar_option("prot", all_options);
if (suggestion) {
fprintf(stderr, "Did you mean: --%s?\\n", suggestion);
}
unsigned short uint16_t
Definition common.h:57
asciichat_error_t
Error and exit codes - unified status values (0-255)
Definition error_codes.h:49
@ ASCIICHAT_OK
Definition error_codes.h:51
const char * find_similar_option(const char *unknown_opt, const struct option *options)
Find a similar option name for typo suggestions.
bool validate_port_opt(const char *value_str, uint16_t *out_port)
Validate port number (1-65535)
asciichat_error_t parse_color_mode_option(const char *value_str, options_t *opts)
Parse –color-mode option and set opts->color_mode.

Option Parsing Helpers:

Display Option Parsers:

Terminal Functions:

Cryptography Helpers:

See also
options.h - Main Options Module module
registry.h - Central registry of all Options Module
builder.h - Builder API using these validators
validation.h - Additional Validation Helpers functions
Author
Zachary Fogg me@zf.nosp@m.o.gg
Date
January 2026

Definition in file options/common.h.

Macro Definition Documentation

◆ OPTIONS_COMMON_H

#define OPTIONS_COMMON_H

Definition at line 91 of file options/common.h.

Function Documentation

◆ detect_default_ssh_key()

asciichat_error_t detect_default_ssh_key ( char *  key_path,
size_t  path_size 
)

Detect default SSH key path for the current user.

Checks if ~/.ssh/id_ed25519 exists and is a regular file. Only supports Ed25519 keys (modern, secure, fast).

Parameters
key_pathBuffer to store detected key path
path_sizeSize of key_path buffer
Returns
ASCIICHAT_OK if found, ERROR_CRYPTO_KEY with helpful message otherwise
Note
Uses expand_path() to resolve tilde (~) in path
Prints message to stderr suggesting key generation if not found

Example:

char key_path[OPTIONS_BUFF_SIZE];
if (detect_default_ssh_key(key_path, sizeof(key_path)) == ASCIICHAT_OK) {
log_debug("Using default SSH key: %s", key_path);
SAFE_SNPRINTF(opt_encrypt_key, OPTIONS_BUFF_SIZE, "%s", key_path);
}
#define SAFE_SNPRINTF(buffer, buffer_size,...)
Definition common.h:492
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:548
#define OPTIONS_BUFF_SIZE
Buffer size for option string values.
asciichat_error_t detect_default_ssh_key(char *key_path, size_t path_size)
Detect default SSH key path for the current user.

Definition at line 262 of file options/common.c.

262 {
263 // Use expand_path utility to resolve ~/.ssh/id_ed25519
264 char *full_path = expand_path("~/.ssh/id_ed25519");
265 if (!full_path) {
266 return SET_ERRNO(ERROR_CONFIG, "Could not expand SSH key path");
267 }
268
269 // Check if the Ed25519 private key file exists
270 struct stat st;
271 bool found = (stat(full_path, &st) == 0 && S_ISREG(st.st_mode));
272
273 if (found) {
274 SAFE_SNPRINTF(key_path, path_size, "%s", full_path);
275 log_debug("Found default SSH key: %s", full_path);
276 SAFE_FREE(full_path);
277 return ASCIICHAT_OK;
278 }
279
280 log_error("No Ed25519 SSH key found at %s", full_path);
281 SAFE_FREE(full_path);
282 return SET_ERRNO(
284 "Only Ed25519 keys are supported (modern, secure, fast). Generate a new key with: ssh-keygen -t ed25519");
285}
#define SAFE_FREE(ptr)
Definition common.h:376
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it, returning the error code.
@ ERROR_CRYPTO_KEY
Definition error_codes.h:97
@ ERROR_CONFIG
Definition error_codes.h:57
#define log_error(...)
Log an ERROR message.
Definition log/log.h:587
char * expand_path(const char *path)
Expand path with tilde (~) support.
Definition path.c:505

References ASCIICHAT_OK, ERROR_CONFIG, ERROR_CRYPTO_KEY, expand_path(), log_debug, log_error, SAFE_FREE, SAFE_SNPRINTF, and SET_ERRNO.

◆ find_similar_option()

const char * find_similar_option ( const char *  unknown_opt,
const struct option *  options 
)

Find a similar option name for typo suggestions.

Uses Levenshtein distance to find the most similar option name from the provided options array. Only suggests options within a reasonable edit distance.

Parameters
unknown_optThe unknown/misspelled option name
optionsArray of valid option structures (must be NULL-terminated)
Returns
Suggested option name, or NULL if no good match found
Note
Uses LEVENSHTEIN_SUGGESTION_THRESHOLD to filter poor matches

Example:

const char *suggestion = find_similar_option("--colr", client_options);
if (suggestion) {
fprintf(stderr, "Did you mean '--%s'?\n", suggestion);
}

Definition at line 38 of file options/common.c.

38 {
39 if (!unknown_opt || !options) {
40 return NULL;
41 }
42
43 const char *best_match = NULL;
44 size_t best_distance = SIZE_MAX;
45
46 for (int i = 0; options[i].name != NULL; i++) {
47 size_t dist = levenshtein(unknown_opt, options[i].name);
48 if (dist < best_distance) {
49 best_distance = dist;
50 best_match = options[i].name;
51 }
52 }
53
54 // Only suggest if the distance is within our threshold
55 if (best_distance <= LEVENSHTEIN_SUGGESTION_THRESHOLD) {
56 return best_match;
57 }
58
59 return NULL;
60}
size_t levenshtein(const char *a, const char *b)
Calculate Levenshtein distance between two strings.
Definition levenshtein.c:74
#define LEVENSHTEIN_SUGGESTION_THRESHOLD
Maximum edit distance to suggest an option.
Definition levenshtein.h:32

References levenshtein(), and LEVENSHTEIN_SUGGESTION_THRESHOLD.

◆ format_available_modes()

const char * format_available_modes ( option_mode_bitmask_t  mode_bitmask)

Format all available modes for an option as comma-separated list.

Converts a mode bitmask to a human-readable comma-separated list of mode names. Used in error messages to show which modes support a given option.

Parameters
mode_bitmaskBitmask of modes (OPTION_MODE_SERVER | OPTION_MODE_CLIENT, etc.)
Returns
Formatted string like "server, client, mirror" or "global options"
Note
Returns pointer to static buffer - not thread-safe

Example:

const char *modes = format_available_modes(bitmask);
// modes == "server, client"
option_mode_bitmask_t
Option mode bitmask.
@ OPTION_MODE_CLIENT
Client mode (bit 1)
@ OPTION_MODE_SERVER
Server mode (bit 0)
const char * format_available_modes(option_mode_bitmask_t mode_bitmask)
Format all available modes for an option as comma-separated list.

Definition at line 64 of file options/common.c.

64 {
65 static char buffer[256];
66 buffer[0] = '\0';
67
68 bool first = true;
69
70 // Check if it's a global/binary option
71 if (mode_bitmask & OPTION_MODE_BINARY) {
72 SAFE_SNPRINTF(buffer, sizeof(buffer), "global options");
73 return buffer;
74 }
75
76 // Build comma-separated list of modes (ordered: default, client, server, mirror, discovery-service)
77 if (mode_bitmask & OPTION_MODE_DISCOVERY) {
78 safe_snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), "%sdefault", first ? "" : ", ");
79 first = false;
80 }
81 if (mode_bitmask & OPTION_MODE_CLIENT) {
82 safe_snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), "%sclient", first ? "" : ", ");
83 first = false;
84 }
85 if (mode_bitmask & OPTION_MODE_SERVER) {
86 safe_snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), "%sserver", first ? "" : ", ");
87 first = false;
88 }
89 if (mode_bitmask & OPTION_MODE_MIRROR) {
90 safe_snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), "%smirror", first ? "" : ", ");
91 first = false;
92 }
93 if (mode_bitmask & OPTION_MODE_DISCOVERY_SVC) {
94 safe_snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer), "%sdiscovery-service", first ? "" : ", ");
95 first = false;
96 }
97
98 // Fallback if no modes matched
99 if (buffer[0] == '\0') {
100 SAFE_SNPRINTF(buffer, sizeof(buffer), "unknown mode");
101 }
102
103 return buffer;
104}
@ OPTION_MODE_BINARY
Binary-level options (parsed before mode detection)
@ OPTION_MODE_DISCOVERY
Discovery mode (bit 4)
@ OPTION_MODE_MIRROR
Mirror mode (bit 2)
@ OPTION_MODE_DISCOVERY_SVC
Discovery server mode (bit 3)
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.
Definition system.c:148

References OPTION_MODE_BINARY, OPTION_MODE_CLIENT, OPTION_MODE_DISCOVERY, OPTION_MODE_DISCOVERY_SVC, OPTION_MODE_MIRROR, OPTION_MODE_SERVER, SAFE_SNPRINTF, and safe_snprintf().

Referenced by find_similar_option_with_mode().

◆ get_required_argument()

char * get_required_argument ( const char *  opt_value,
char *  buffer,
size_t  buffer_size,
const char *  option_name,
asciichat_mode_t  mode 
)

Handle required arguments with consistent error messages.

Validates that an option has a non-empty argument and processes it. Returns NULL on error with appropriate error message printed.

Handles edge cases:

  • NULL or empty opt_value
  • getopt_long bug where option name is returned as argument
  • Arguments with '=' prefix (GNU-style –option=value)
Parameters
opt_valueArgument value from getopt_long
bufferBuffer for storing processed argument
buffer_sizeSize of buffer
option_nameName of the option (for error messages)
modeCurrent mode (client/server/mirror) for error messages
Returns
Pointer to processed argument string in buffer, or NULL on error
Note
Prints "option '--<name>' requires an argument" to stderr on error
Used internally by validate_required_argument()

Example:

char argbuf[OPTIONS_BUFF_SIZE];
char *value = get_required_argument(optarg, argbuf, sizeof(argbuf), "key", MODE_CLIENT);
if (!value) {
return option_error_invalid();
}
SAFE_SNPRINTF(opt_encrypt_key, OPTIONS_BUFF_SIZE, "%s", value);
@ MODE_CLIENT
Client mode - network client options.
char * get_required_argument(const char *opt_value, char *buffer, size_t buffer_size, const char *option_name, asciichat_mode_t mode)
Handle required arguments with consistent error messages.

Definition at line 312 of file options/common.c.

313 {
314 // Check if opt_value is NULL or empty
315 if (!opt_value || strlen(opt_value) == 0) {
316 goto error;
317 }
318
319 // Check if getopt_long returned the option name itself as the argument
320 // This happens when a long option requiring an argument is at the end of argv
321 if (opt_value && option_name && strcmp(opt_value, option_name) == 0) {
322 goto error;
323 }
324
325 // Process the argument normally
326 char *value_str = strip_equals_prefix(opt_value, buffer, buffer_size);
327 if (!value_str) {
328 goto error;
329 }
330
331 return value_str;
332
333error:
334 (void)0;
335 const char *mode_name = (mode == MODE_SERVER ? "server" : (mode == MODE_MIRROR ? "mirror" : "client"));
336 log_error("%s: option '--%s' requires an argument", mode_name, option_name);
337 return NULL; // Signal error to caller
338}
int buffer_size
Size of circular buffer.
Definition grep.c:90
@ MODE_SERVER
Server mode - network server options.
@ MODE_MIRROR
Mirror mode - local webcam viewing (no network)
char * strip_equals_prefix(const char *opt_value, char *buffer, size_t buffer_size)
Strip equals sign prefix from option argument.

References buffer_size, log_error, MODE_MIRROR, MODE_SERVER, and strip_equals_prefix().

Referenced by validate_required_argument().

◆ parse_color_mode_option()

asciichat_error_t parse_color_mode_option ( const char *  value_str,
options_t *  opts 
)

Parse –color-mode option and set opts->color_mode.

Validates color mode string and sets opts->color_mode field. Accepts: "auto", "none", "mono", "16", "16color", "256", "256color", "truecolor", "24bit"

Parameters
value_strColor mode string from command line
optsOptions struct to update
Returns
ASCIICHAT_OK on success, ERROR_INVALID_PARAM on invalid mode
Note
Prints error message to stderr on failure
Sets opts->color_mode on success

Definition at line 385 of file options/common.c.

385 {
386 if (!value_str || !opts) {
387 return ERROR_INVALID_PARAM;
388 }
389
390 if (strcmp(value_str, "auto") == 0 || strcmp(value_str, "a") == 0) {
392 } else if (strcmp(value_str, "none") == 0 || strcmp(value_str, "mono") == 0) {
394 } else if (strcmp(value_str, "16") == 0 || strcmp(value_str, "16color") == 0 || strcmp(value_str, "ansi") == 0) {
396 } else if (strcmp(value_str, "256") == 0 || strcmp(value_str, "256color") == 0) {
398 } else if (strcmp(value_str, "truecolor") == 0 || strcmp(value_str, "24bit") == 0 || strcmp(value_str, "tc") == 0 ||
399 strcmp(value_str, "rgb") == 0 || strcmp(value_str, "true") == 0) {
401 } else {
402 log_error("Invalid color mode '%s'. Valid modes: auto, none, 16, 256, truecolor", value_str);
403 return ERROR_INVALID_PARAM;
404 }
405
406 return ASCIICHAT_OK;
407}
@ ERROR_INVALID_PARAM
#define COLOR_MODE_16_COLOR
16-color mode (full name)
#define COLOR_MODE_256_COLOR
256-color mode (full name)
#define COLOR_MODE_TRUECOLOR
24-bit truecolor mode
#define COLOR_MODE_AUTO
Backward compatibility aliases for color mode enum values.
#define COLOR_MODE_NONE
Monochrome mode.
terminal_color_mode_t color_mode
Color mode (auto/none/16/256/truecolor)

References ASCIICHAT_OK, options_state::color_mode, COLOR_MODE_16_COLOR, COLOR_MODE_256_COLOR, COLOR_MODE_AUTO, COLOR_MODE_NONE, COLOR_MODE_TRUECOLOR, ERROR_INVALID_PARAM, and log_error.

◆ parse_height_option()

asciichat_error_t parse_height_option ( const char *  value_str,
options_t *  opts 
)

Parse –height option and set opts->height.

Validates height value and sets opts->height and opts->auto_height fields.

Parameters
value_strHeight value from command line
optsOptions struct to update
Returns
ASCIICHAT_OK on success, ERROR_INVALID_PARAM if invalid
Note
Prints error message to stderr on failure
Sets opts->height and opts->auto_height = false on success

Definition at line 488 of file options/common.c.

488 {
489 if (!opts) {
490 return ERROR_INVALID_PARAM;
491 }
492
493 int height_val;
494 if (!validate_positive_int_opt(value_str, &height_val, "height")) {
495 return ERROR_INVALID_PARAM;
496 }
497
498 opts->height = height_val;
499 opts->auto_height = false;
500
501 return ASCIICHAT_OK;
502}
bool validate_positive_int_opt(const char *value_str, int *out_value, const char *param_name)
Validate a positive integer value.
int height
Terminal height in characters (int for OPTION_TYPE_INT compat)
bool auto_height
Auto-detect height from terminal.

References ASCIICHAT_OK, options_state::auto_height, ERROR_INVALID_PARAM, options_state::height, and validate_positive_int_opt().

◆ parse_log_level_option()

asciichat_error_t parse_log_level_option ( const char *  value_str,
options_t *  opts 
)

Parse –log-level option and set opt_log_level.

Validates log level string and sets global opt_log_level variable. Accepts: "dev", "debug", "info", "warn", "error", "fatal" (case-insensitive)

Parameters
value_strLog level string from command line
Returns
ASCIICHAT_OK on success, ERROR_INVALID_PARAM if invalid
Note
Prints error message to stderr on failure
Sets opt_log_level global variable on success
Uses validate_opt_log_level() from validation.h

Definition at line 536 of file options/common.c.

536 {
537 if (!opts) {
538 return ERROR_INVALID_PARAM;
539 }
540
541 char error_msg[BUFFER_SIZE_SMALL];
542 int log_level = validate_opt_log_level(value_str, error_msg, sizeof(error_msg));
543
544 if (log_level == -1) {
545 log_error("%s", error_msg);
546 return ERROR_INVALID_PARAM;
547 }
548
549 opts->log_level = (log_level_t)log_level;
550
551 return ASCIICHAT_OK;
552}
#define BUFFER_SIZE_SMALL
Small buffer size (256 bytes)
log_level_t
Logging levels enumeration.
Definition types.h:29
int validate_opt_log_level(const char *value_str, char *error_msg, size_t error_msg_size)
Validate log level string.
Definition validation.c:234
log_level_t log_level
Log level threshold.

References ASCIICHAT_OK, BUFFER_SIZE_SMALL, ERROR_INVALID_PARAM, log_error, options_state::log_level, and validate_opt_log_level().

◆ parse_palette_chars_option()

asciichat_error_t parse_palette_chars_option ( const char *  value_str,
options_t *  opts 
)

Parse –palette-chars option and set opt_palette_custom.

Validates custom palette characters and sets global opt_palette_custom, opt_palette_custom_set, and opt_palette_type variables.

Parameters
value_strCustom palette characters from command line
Returns
ASCIICHAT_OK on success, ERROR_INVALID_PARAM if too long
Note
Prints error message to stderr on failure
Sets opt_palette_custom, opt_palette_custom_set, and opt_palette_type on success
Maximum length is 255 characters (sizeof(opt_palette_custom) - 1)

Definition at line 453 of file options/common.c.

453 {
454 if (!value_str || !opts) {
455 return ERROR_INVALID_PARAM;
456 }
457
458 if (strlen(value_str) >= sizeof(opts->palette_custom)) {
459 log_error("Invalid palette-chars: too long (%zu chars, max %zu)", strlen(value_str),
460 sizeof(opts->palette_custom) - 1);
461 return ERROR_INVALID_PARAM;
462 }
463
464 SAFE_STRNCPY(opts->palette_custom, value_str, sizeof(opts->palette_custom));
465 opts->palette_custom[sizeof(opts->palette_custom) - 1] = '\0';
466 opts->palette_custom_set = true;
468
469 return ASCIICHAT_OK;
470}
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:414
@ PALETTE_CUSTOM
User-defined via –palette-chars.
Definition palette.h:98
char palette_custom[256]
Custom palette characters.
bool palette_custom_set
True if custom palette was set.
palette_type_t palette_type
Selected palette type.

References ASCIICHAT_OK, ERROR_INVALID_PARAM, log_error, options_state::palette_custom, PALETTE_CUSTOM, options_state::palette_custom_set, options_state::palette_type, and SAFE_STRNCPY.

◆ parse_palette_option()

asciichat_error_t parse_palette_option ( const char *  value_str,
options_t *  opts 
)

Parse –palette option and set opt_palette_type.

Validates palette type string and sets global opt_palette_type variable. Accepts: "standard", "blocks", "digital", "minimal", "cool", "custom"

Parameters
value_strPalette type string from command line
Returns
ASCIICHAT_OK on success, ERROR_INVALID_PARAM on invalid palette
Note
Prints error message to stderr on failure
Sets opt_palette_type global variable on success

Definition at line 428 of file options/common.c.

428 {
429 if (!value_str || !opts) {
430 return ERROR_INVALID_PARAM;
431 }
432
433 if (strcmp(value_str, "standard") == 0) {
435 } else if (strcmp(value_str, "blocks") == 0) {
437 } else if (strcmp(value_str, "digital") == 0) {
439 } else if (strcmp(value_str, "minimal") == 0) {
441 } else if (strcmp(value_str, "cool") == 0) {
443 } else if (strcmp(value_str, "custom") == 0) {
445 } else {
446 log_error("Invalid palette '%s'. Valid palettes: standard, blocks, digital, minimal, cool, custom", value_str);
447 return ERROR_INVALID_PARAM;
448 }
449
450 return ASCIICHAT_OK;
451}
@ PALETTE_BLOCKS
Unicode block characters: " ░░▒▒▓▓██".
Definition palette.h:90
@ PALETTE_COOL
Ascending blocks: " ▁▂▃▄▅▆▇█".
Definition palette.h:96
@ PALETTE_STANDARD
Standard ASCII palette: " ...',;:clodxkO0KXNWM".
Definition palette.h:88
@ PALETTE_DIGITAL
Digital/glitch aesthetic: " -=≡≣▰▱◼".
Definition palette.h:92
@ PALETTE_MINIMAL
Simple ASCII: " .-+*#".
Definition palette.h:94

References ASCIICHAT_OK, ERROR_INVALID_PARAM, log_error, PALETTE_BLOCKS, PALETTE_COOL, PALETTE_CUSTOM, PALETTE_DIGITAL, PALETTE_MINIMAL, PALETTE_STANDARD, and options_state::palette_type.

◆ parse_render_mode_option()

asciichat_error_t parse_render_mode_option ( const char *  value_str,
options_t *  opts 
)

Parse –render-mode option and set opts->render_mode.

Validates render mode string and sets opts->render_mode field. Accepts: "foreground", "fg", "background", "bg", "half-block", "halfblock"

Parameters
value_strRender mode string from command line
optsOptions struct to update
Returns
ASCIICHAT_OK on success, ERROR_INVALID_PARAM on invalid mode
Note
Prints error message to stderr on failure
Sets opts->render_mode on success

Definition at line 409 of file options/common.c.

409 {
410 if (!value_str || !opts) {
411 return ERROR_INVALID_PARAM;
412 }
413
414 if (strcmp(value_str, "foreground") == 0 || strcmp(value_str, "fg") == 0) {
416 } else if (strcmp(value_str, "background") == 0 || strcmp(value_str, "bg") == 0) {
418 } else if (strcmp(value_str, "half-block") == 0 || strcmp(value_str, "halfblock") == 0) {
420 } else {
421 log_error("Invalid render mode '%s'. Valid modes: foreground, background, half-block", value_str);
422 return ERROR_INVALID_PARAM;
423 }
424
425 return ASCIICHAT_OK;
426}
render_mode_t render_mode
Render mode (foreground/background/half-block)
@ RENDER_MODE_FOREGROUND
Foreground colors only (text color)
Definition terminal.h:664
@ RENDER_MODE_BACKGROUND
Background colors (block colors)
Definition terminal.h:666
@ RENDER_MODE_HALF_BLOCK
Unicode half-block characters (mixed foreground/background)
Definition terminal.h:668

References ASCIICHAT_OK, ERROR_INVALID_PARAM, log_error, options_state::render_mode, RENDER_MODE_BACKGROUND, RENDER_MODE_FOREGROUND, and RENDER_MODE_HALF_BLOCK.

◆ parse_snapshot_delay_option()

asciichat_error_t parse_snapshot_delay_option ( const char *  value_str,
options_t *  opts 
)

Parse –snapshot-delay option and set opts->snapshot_delay.

Validates snapshot delay (non-negative float) and sets opts->snapshot_delay field.

Parameters
value_strSnapshot delay in seconds from command line
optsOptions struct to update
Returns
ASCIICHAT_OK on success, ERROR_INVALID_PARAM if invalid
Note
Prints error message to stderr on failure
Sets opts->snapshot_delay on success

Definition at line 519 of file options/common.c.

519 {
520 if (!value_str || !opts) {
521 return ERROR_INVALID_PARAM;
522 }
523
524 char *endptr;
525 float delay = strtof(value_str, &endptr);
526 if (endptr == value_str || *endptr != '\0' || delay < 0.0f) {
527 log_error("Invalid snapshot delay '%s'. Must be a non-negative number.", value_str);
528 return ERROR_INVALID_PARAM;
529 }
530
531 opts->snapshot_delay = delay;
532
533 return ASCIICHAT_OK;
534}
double snapshot_delay
Snapshot delay in seconds.

References ASCIICHAT_OK, ERROR_INVALID_PARAM, log_error, and options_state::snapshot_delay.

◆ parse_webcam_index_option()

asciichat_error_t parse_webcam_index_option ( const char *  value_str,
options_t *  opts 
)

Parse –webcam-index option and set opts->webcam_index.

Validates webcam index and sets opts->webcam_index field.

Parameters
value_strWebcam index from command line
optsOptions struct to update
Returns
ASCIICHAT_OK on success, ERROR_INVALID_PARAM if invalid
Note
Prints error message to stderr on failure
Sets opts->webcam_index on success

Definition at line 504 of file options/common.c.

504 {
505 if (!opts) {
506 return ERROR_INVALID_PARAM;
507 }
508
509 unsigned short int index_val;
510 if (!validate_webcam_index(value_str, &index_val)) {
511 return ERROR_INVALID_PARAM;
512 }
513
514 opts->webcam_index = index_val;
515
516 return ASCIICHAT_OK;
517}
bool validate_webcam_index(const char *value_str, unsigned short int *out_index)
Validate webcam index using the common device index validator.
int webcam_index
Webcam device index (0 = first)

References ASCIICHAT_OK, ERROR_INVALID_PARAM, validate_webcam_index(), and options_state::webcam_index.

◆ parse_width_option()

asciichat_error_t parse_width_option ( const char *  value_str,
options_t *  opts 
)

Parse –width option and set opts->width.

Validates width value and sets opts->width and opts->auto_width fields.

Parameters
value_strWidth value from command line
optsOptions struct to update
Returns
ASCIICHAT_OK on success, ERROR_INVALID_PARAM if invalid
Note
Prints error message to stderr on failure
Sets opts->width and opts->auto_width = false on success

Definition at line 472 of file options/common.c.

472 {
473 if (!opts) {
474 return ERROR_INVALID_PARAM;
475 }
476
477 int width_val;
478 if (!validate_positive_int_opt(value_str, &width_val, "width")) {
479 return ERROR_INVALID_PARAM;
480 }
481
482 opts->width = width_val;
483 opts->auto_width = false;
484
485 return ASCIICHAT_OK;
486}
int width
Terminal width in characters (int for OPTION_TYPE_INT compat)
bool auto_width
Auto-detect width from terminal.

References ASCIICHAT_OK, options_state::auto_width, ERROR_INVALID_PARAM, validate_positive_int_opt(), and options_state::width.

◆ print_project_links()

void print_project_links ( FILE *  desc)

Print project links with link emoji and colored styling.

Parameters
descOutput file stream (typically stdout)

Definition at line 756 of file options/common.c.

756 {
757 if (!desc) {
758 return;
759 }
760
761 (void)fprintf(desc, "🔗 %s\n", colored_string(LOG_COLOR_GREY, "https://ascii-chat.com"));
762 (void)fprintf(desc, "🔗 %s\n", colored_string(LOG_COLOR_GREY, "https://github.com/zfogg/ascii-chat"));
763}
@ LOG_COLOR_GREY
Definition log/log.h:137
const char * colored_string(log_color_t color, const char *text)
Build a colored string for terminal output.

References colored_string(), and LOG_COLOR_GREY.

Referenced by options_print_help_for_mode().

◆ read_password_from_stdin()

char * read_password_from_stdin ( const char *  prompt)

Read password from stdin with prompt.

Parameters
promptPrompt message to display to user
Returns
Allocated password string (caller must free), or NULL on error

Prompts user for password input using prompt_password_simple() from util/password.h. Returns dynamically allocated string that must be freed by caller.

Note
Returns NULL if password input fails or if not running in a TTY.
Caller must use SAFE_FREE() to deallocate returned string.

Definition at line 341 of file options/common.c.

341 {
342 char *password_buf = SAFE_MALLOC(PASSWORD_MAX_LEN, char *);
343 if (!password_buf) {
344 return NULL;
345 }
346
347 if (prompt_password_simple(prompt, password_buf, PASSWORD_MAX_LEN) != 0) {
348 SAFE_FREE(password_buf);
349 return NULL;
350 }
351
352 return password_buf; // Caller must free
353}
#define SAFE_MALLOC(size, cast)
Definition common.h:264
#define PASSWORD_MAX_LEN
Buffer size for password input.
Definition password.h:30
int prompt_password_simple(const char *prompt, char *password, size_t max_len)
Prompt the user for a password with simple formatting.
Definition password.c:70

References PASSWORD_MAX_LEN, prompt_password_simple(), SAFE_FREE, and SAFE_MALLOC.

◆ strip_equals_prefix()

char * strip_equals_prefix ( const char *  opt_value,
char *  buffer,
size_t  buffer_size 
)

Strip equals sign prefix from option argument.

Internal helper that handles GNU-style long options with = syntax (–option=value). Copies argument to buffer and returns pointer past the '=' if present.

Parameters
opt_valueRaw option value from getopt_long
bufferBuffer to store processed value
buffer_sizeSize of buffer
Returns
Pointer to value in buffer (past '=' if present), or NULL if empty
Note
Returns NULL for empty strings after stripping '='
Buffer is always null-terminated via SAFE_SNPRINTF

Example:

char argbuf[OPTIONS_BUFF_SIZE];
char *value = strip_equals_prefix("=1234", argbuf, sizeof(argbuf));
// value points to "1234" in argbuf

Definition at line 292 of file options/common.c.

292 {
293 if (!opt_value)
294 return NULL;
295
296 SAFE_SNPRINTF(buffer, buffer_size, "%s", opt_value);
297 char *value_str = buffer;
298 if (value_str[0] == '=') {
299 value_str++; // Skip the equals sign
300 }
301
302 // Return NULL for empty strings (treat as missing argument)
303 if (strlen(value_str) == 0) {
304 return NULL;
305 }
306
307 return value_str;
308}

References buffer_size, and SAFE_SNPRINTF.

Referenced by get_required_argument().

◆ strtoint_safe()

int strtoint_safe ( const char *  str)

Safely parse string to integer with validation.

Parses a string to integer using parse_int32() with full range checking. Returns INT_MIN on error (NULL input, empty string, invalid format, out of range).

Parameters
strString to parse
Returns
Parsed integer value, or INT_MIN on error
Warning
INT_MIN is used as error sentinel, so cannot represent INT_MIN value

Example:

int val = strtoint_safe(optarg);
if (val == INT_MIN) {
fprintf(stderr, "Invalid integer: %s\n", optarg);
}
int strtoint_safe(const char *str)
Safely parse string to integer with validation.

Definition at line 164 of file options/common.c.

164 {
165 if (!str || *str == '\0') {
166 return INT_MIN; // Error: NULL or empty string
167 }
168
169 int32_t result = 0;
170 // Use safe parsing utility with full int32 range validation
171 if (parse_int32(str, &result, INT_MIN, INT_MAX) != ASCIICHAT_OK) {
172 return INT_MIN; // Error: invalid input or out of range
173 }
174
175 return (int)result;
176}
asciichat_error_t parse_int32(const char *str, int32_t *out_value, int32_t min_value, int32_t max_value)
Parse signed 32-bit integer with range validation.

◆ update_dimensions_for_full_height()

void update_dimensions_for_full_height ( options_t *  opts)

Update dimensions for full-height mode.

Sets opt_height to terminal height when auto-detected. Used during initialization to maximize vertical space usage.

Behavior:

  • Both auto: Set both width and height to terminal size
  • Only height auto: Set height to terminal height
  • Only width auto: Set width to terminal width
  • Neither auto: No change
Note
Does not use log_debug because logging may not be initialized yet
Fails silently if terminal size detection fails (keeps defaults)

Example:

// During options_init():
}
void update_dimensions_for_full_height(options_t *opts)
Update dimensions for full-height mode.
bool auto_height
bool auto_width

Definition at line 606 of file options/common.c.

606 {
607 if (!opts) {
608 return;
609 }
610
611 unsigned short int term_width, term_height;
612
613 // Note: Logging is not available during options_init, so we can't use log_debug here
614 asciichat_error_t result = get_terminal_size(&term_width, &term_height);
615
616 if (result == ASCIICHAT_OK) {
617 // If both dimensions are auto, set height to terminal height and let
618 // aspect_ratio calculate width
619 if (opts->auto_height && opts->auto_width) {
620 opts->height = term_height;
621 opts->width = term_width; // Also set width when both are auto
622 }
623 // If only height is auto, use full terminal height
624 else if (opts->auto_height) {
625 opts->height = term_height;
626 }
627 // If only width is auto, use full terminal width
628 else if (opts->auto_width) {
629 opts->width = term_width;
630 }
631 } else {
632 // Terminal size detection failed, but we can still continue with defaults
633 }
634}
asciichat_error_t get_terminal_size(unsigned short int *width, unsigned short int *height)
Get terminal size with multiple fallback methods.

◆ update_dimensions_to_terminal_size()

void update_dimensions_to_terminal_size ( options_t *  opts)

Update dimensions to current terminal size.

Updates opt_width and opt_height to current terminal size for auto-detected dimensions. Used after logging is initialized (can use log_debug).

Behavior:

  • auto_width: Set width to terminal width
  • auto_height: Set height to terminal height
  • Neither: No change
Note
Logs debug messages about dimension updates
Logs debug message if terminal size detection fails

Example:

// After logging initialization:
log_info("Terminal dimensions: %dx%d", opt_width, opt_height);
#define log_info(...)
Log an INFO message.
Definition log/log.h:561
void update_dimensions_to_terminal_size(options_t *opts)
Update dimensions to current terminal size.

Definition at line 636 of file options/common.c.

636 {
637 if (!opts) {
638 return;
639 }
640
641 unsigned short int term_width, term_height;
642 // Get current terminal size (get_terminal_size already handles ioctl first, then $COLUMNS/$LINES fallback)
643 asciichat_error_t terminal_result = get_terminal_size(&term_width, &term_height);
644 if (terminal_result == ASCIICHAT_OK) {
645 // Use INFO level so this is visible without -v flag (important for debugging dimension issues)
646 log_dev("Terminal size detected: %ux%u (auto_width=%d, auto_height=%d)", term_width, term_height, opts->auto_width,
647 opts->auto_height);
648 if (opts->auto_width) {
649 opts->width = term_width;
650 log_debug("Auto-width: set width to %u", opts->width);
651 }
652 if (opts->auto_height) {
653 opts->height = term_height;
654 log_debug("Auto-height: set height to %u", opts->height);
655 }
656 log_debug("Final dimensions: %ux%u", opts->width, opts->height);
657 } else {
658 // Terminal detection failed - keep the default values set in options_init()
659 log_warn("TERMINAL_DETECT_FAIL: Could not detect terminal size, using defaults: %ux%u", opts->width, opts->height);
660 }
661}
#define log_warn(...)
Log a WARN message.
Definition log/log.h:574
#define log_dev(...)
Log a DEV message (most verbose, development only)
Definition log/log.h:534

◆ validate_fps_opt()

bool validate_fps_opt ( const char *  value_str,
int *  out_fps 
)

Validate FPS value (1-144)

Internal option parsing helper that validates FPS is in reasonable range. Range chosen to support 1 FPS (slideshows) to 144 FPS (high refresh monitors).

Parameters
value_strString to validate
out_fpsOutput parameter for validated FPS
Returns
true if valid, false otherwise

Example:

int fps;
if (!validate_fps_opt(optarg, &fps)) {
return option_error_invalid();
}
opt_fps = fps;
bool validate_fps_opt(const char *value_str, int *out_fps)
Validate FPS value (1-144)

Definition at line 224 of file options/common.c.

224 {
225 if (!value_str || !out_fps) {
226 return false;
227 }
228
229 int fps_val = strtoint_safe(value_str);
230 if (fps_val == INT_MIN || fps_val < 1 || fps_val > 144) {
231 log_error("Invalid FPS value '%s'. FPS must be between 1 and 144.", value_str);
232 return false;
233 }
234
235 *out_fps = fps_val;
236 return true;
237}

References log_error, and strtoint_safe().

◆ validate_options_and_report()

asciichat_error_t validate_options_and_report ( const void *  config,
const void *  opts 
)

Validate options and report errors to stderr.

Calls options_config_validate() and handles error message display and cleanup. Validates all option dependencies, conflicts, and custom validators.

Parameters
configOptions configuration (opaque pointer, defined in builder.h)
optsOptions struct to validate
Returns
ASCIICHAT_OK if valid, error code otherwise
Note
Prints error message to stderr if validation fails
Frees error message internally

Example:

if (result != ASCIICHAT_OK) {
return result;
}
void options_config_destroy(options_config_t *config)
Free options config.
Definition builder.c:631
asciichat_error_t validate_options_and_report(const void *config, const void *opts)
Validate options and report errors to stderr.

Definition at line 718 of file options/common.c.

718 {
719 if (!config || !opts) {
720 return SET_ERRNO(ERROR_INVALID_PARAM, "Config or options is NULL");
721 }
722
723 char *error_message = NULL;
724 // Cast opaque config pointer to actual type
725 const options_config_t *config_typed = (const options_config_t *)config;
726 const options_t *options = (const options_t *)opts;
727 if (options->webrtc_relay_only && options->detected_mode == MODE_CLIENT) {
728 return SET_ERRNO(ERROR_INVALID_PARAM, "Relay only requires discovery mode; connect using a session name");
729 }
730 if (options->webrtc_relay_only && options->detected_mode == MODE_SERVER && !options->discovery) {
731 return SET_ERRNO(ERROR_INVALID_PARAM, "Server relay only requires --discovery");
732 }
733 if (options->webrtc_relay_only && (options->no_webrtc || options->webrtc_disable_turn)) {
734 return SET_ERRNO(ERROR_INVALID_PARAM, "--webrtc-relay-only conflicts with --no-webrtc or --webrtc-disable-turn");
735 }
736 if ((options->turn_username[0] != '\0') != (options->turn_credential[0] != '\0')) {
737 return SET_ERRNO(ERROR_INVALID_PARAM, "Provide both --turn-username and --turn-credential, or leave both blank");
738 }
739 if (strlen(options->turn_username) > 127 || strlen(options->turn_credential) > 127) {
740 return SET_ERRNO(ERROR_INVALID_PARAM, "TURN username and credential must each fit 127 bytes");
741 }
742 asciichat_error_t result = options_config_validate(config_typed, opts, &error_message);
743 if (result != ASCIICHAT_OK) {
744 if (error_message) {
745 log_error("%s", error_message);
746 free(error_message);
747 }
748 }
749 return result;
750}
asciichat_error_t options_config_validate(const options_config_t *config, const void *options_struct, char **error_message)
Validate options struct.
Definition builder.c:1840
Options configuration.
Definition builder.h:401
Consolidated options structure.
bool discovery
Enable discovery session registration (default: false)
bool webrtc_relay_only
–webrtc-relay-only: Require TURN relay candidates
asciichat_mode_t detected_mode
Mode detected from command-line arguments.
bool no_webrtc
–no-webrtc: Disable WebRTC, use Direct TCP only
bool webrtc_disable_turn
–webrtc-disable-turn: Disable Stage 3 (TURN), use STUN only
char turn_credential[256]
ACDS: Credential/password for TURN authentication.
char turn_username[256]
ACDS: Username for TURN authentication.

References ASCIICHAT_OK, options_state::detected_mode, options_state::discovery, ERROR_INVALID_PARAM, log_error, MODE_CLIENT, MODE_SERVER, options_state::no_webrtc, options_config_validate(), SET_ERRNO, options_state::turn_credential, options_state::turn_username, options_state::webrtc_disable_turn, and options_state::webrtc_relay_only.

Referenced by options_init().

◆ validate_port_opt()

bool validate_port_opt ( const char *  value_str,
uint16_t *  out_port 
)

Validate port number (1-65535)

Internal option parsing helper that validates a port number is in valid range. Uses parse_port() for robust validation.

Parameters
value_strString to validate
out_portOutput parameter for validated port
Returns
true if valid, false otherwise

Example:

uint16_t port;
if (!validate_port_opt(optarg, &port)) {
return option_error_invalid();
}
opt_port = port;

Definition at line 209 of file options/common.c.

209 {
210 if (!value_str || !out_port) {
211 return false;
212 }
213
214 // Use safe integer parsing with range validation
215 if (parse_port(value_str, out_port) != ASCIICHAT_OK) {
216 log_error("Invalid port value '%s'. Port must be a number between 1 and 65535.", value_str);
217 return false;
218 }
219
220 return true;
221}
asciichat_error_t parse_port(const char *str, uint16_t *out_port)
Parse port number (1-65535) from string.

References ASCIICHAT_OK, log_error, and parse_port().

◆ validate_positive_int_opt()

bool validate_positive_int_opt ( const char *  value_str,
int *  out_value,
const char *  param_name 
)

Validate a positive integer value.

Internal option parsing helper that validates a string represents a positive integer (> 0). Prints error message on failure.

Parameters
value_strString to validate
out_valueOutput parameter for validated integer
param_nameParameter name for error messages
Returns
true if valid, false otherwise

Example:

int fps;
if (!validate_positive_int_opt(optarg, &fps, "FPS")) {
return option_error_invalid();
}

Definition at line 193 of file options/common.c.

193 {
194 if (!value_str || !out_value) {
195 return false;
196 }
197
198 int val = strtoint_safe(value_str);
199 if (val == INT_MIN || val <= 0) {
200 log_error("Invalid %s value '%s'. %s must be a positive integer.", param_name, value_str, param_name);
201 return false;
202 }
203
204 *out_value = val;
205 return true;
206}

References log_error, and strtoint_safe().

Referenced by parse_height_option(), and parse_width_option().

◆ validate_required_argument()

char * validate_required_argument ( const char *  optarg,
char *  argbuf,
size_t  argbuf_size,
const char *  option_name,
asciichat_mode_t  mode 
)

Validate and retrieve required argument for an option.

Wrapper around get_required_argument() that also sets error code on failure. Used for options that must have an argument.

Parameters
optargArgument value from getopt_long
argbufBuffer for storing processed argument
argbuf_sizeSize of argbuf
option_nameName of the option (for error messages)
modeCurrent mode (client/server/mirror) for error messages
Returns
Pointer to processed argument string in argbuf, or NULL on error
Note
On error, prints message to stderr and calls option_error_invalid()

Example:

char argbuf[OPTIONS_BUFF_SIZE];
char *value = validate_required_argument(optarg, argbuf, sizeof(argbuf), "port", MODE_CLIENT);
if (!value) {
return option_error_invalid();
}
char * validate_required_argument(const char *optarg, char *argbuf, size_t argbuf_size, const char *option_name, asciichat_mode_t mode)
Validate and retrieve required argument for an option.

Definition at line 183 of file options/common.c.

184 {
185 char *value = get_required_argument(optarg, argbuf, argbuf_size, option_name, mode);
186 if (!value) {
187 (void)option_error_invalid();
188 }
189 return value;
190}

References get_required_argument().

◆ validate_webcam_index()

bool validate_webcam_index ( const char *  value_str,
unsigned short int *  out_index 
)

Validate webcam index using the common device index validator.

Validates webcam index is a non-negative integer. Unlike audio device indices, webcam indices do not support -1 (default).

Parameters
value_strString to validate
out_indexOutput parameter for validated index
Returns
true if valid, false otherwise

Example:

unsigned short int webcam_idx;
if (!validate_webcam_index(optarg, &webcam_idx)) {
return option_error_invalid();
}
opt_webcam_index = webcam_idx;

Definition at line 240 of file options/common.c.

240 {
241 if (!value_str || !out_index) {
242 return false;
243 }
244
245 char error_msg[BUFFER_SIZE_SMALL];
246 int parsed_index = validate_opt_device_index(value_str, error_msg, sizeof(error_msg));
247 if (parsed_index == INT_MIN) {
248 log_error("Invalid webcam index: %s", error_msg);
249 return false;
250 }
251 // Webcam index doesn't support -1 (default), must be >= 0
252 if (parsed_index < 0) {
253 log_error("Invalid webcam index '%s'. Webcam index must be a non-negative integer.", value_str);
254 return false;
255 }
256
257 *out_index = (unsigned short int)parsed_index;
258 return true;
259}
int validate_opt_device_index(const char *value_str, char *error_msg, size_t error_msg_size)
Validate device index (-1 for default, 0+ for specific device)
Definition validation.c:456

References BUFFER_SIZE_SMALL, log_error, and validate_opt_device_index().

Referenced by parse_webcam_index_option().