24#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
43 if (!unknown_opt || !options) {
47 const char *best_match = NULL;
48 size_t best_distance = SIZE_MAX;
50 for (
int i = 0; options[i].name != NULL; i++) {
51 size_t dist =
levenshtein(unknown_opt, options[i].name);
52 if (dist < best_distance) {
54 best_match = options[i].name;
68 if (!str || *str ==
'\0') {
82char *
get_required_argument(
const char *opt_value,
char *buffer,
size_t buffer_size,
const char *option_name,
90 (void)option_error_invalid();
97 if (!value_str || !out_value) {
102 if (val == INT_MIN || val <= 0) {
103 (void)fprintf(stderr,
"Invalid %s value '%s'. %s must be a positive integer.\n", param_name, value_str, param_name);
113 if (!value_str || !out_port) {
119 (void)fprintf(stderr,
"Invalid port value '%s'. Port must be a number between 1 and 65535.\n", value_str);
128 if (!value_str || !out_fps) {
133 if (fps_val == INT_MIN || fps_val < 1 || fps_val > 144) {
134 (void)fprintf(stderr,
"Invalid FPS value '%s'. FPS must be between 1 and 144.\n", value_str);
144 if (!value_str || !out_index) {
150 if (parsed_index == INT_MIN) {
151 (void)fprintf(stderr,
"Invalid webcam index: %s\n", error_msg);
155 if (parsed_index < 0) {
156 (void)fprintf(stderr,
"Invalid webcam index '%s'. Webcam index must be a non-negative integer.\n", value_str);
160 *out_index = (
unsigned short int)parsed_index;
167 char *full_path =
expand_path(
"~/.ssh/id_ed25519");
174 bool found = (stat(full_path, &st) == 0 && S_ISREG(st.st_mode));
178 log_debug(
"Found default SSH key: %s", full_path);
183 (void)fprintf(stderr,
"No Ed25519 SSH key found at %s\n", full_path);
187 "Only Ed25519 keys are supported (modern, secure, fast). Generate a new key with: ssh-keygen -t ed25519");
200 char *value_str = buffer;
201 if (value_str[0] ==
'=') {
206 if (strlen(value_str) == 0) {
218 if (!opt_value || strlen(opt_value) == 0) {
224 if (opt_value && option_name && strcmp(opt_value, option_name) == 0) {
237 (void)fprintf(stderr,
"%s: option '--%s' requires an argument\n",
239 (void)fflush(stderr);
352unsigned short int RED[256];
362 if (!value_str || !opts) {
366 if (strcmp(value_str,
"auto") == 0) {
368 }
else if (strcmp(value_str,
"none") == 0 || strcmp(value_str,
"mono") == 0) {
370 }
else if (strcmp(value_str,
"16") == 0 || strcmp(value_str,
"16color") == 0) {
372 }
else if (strcmp(value_str,
"256") == 0 || strcmp(value_str,
"256color") == 0) {
374 }
else if (strcmp(value_str,
"truecolor") == 0 || strcmp(value_str,
"24bit") == 0) {
377 (void)fprintf(stderr,
"Error: Invalid color mode '%s'. Valid modes: auto, none, 16, 256, truecolor\n", value_str);
385 if (!value_str || !opts) {
389 if (strcmp(value_str,
"foreground") == 0 || strcmp(value_str,
"fg") == 0) {
391 }
else if (strcmp(value_str,
"background") == 0 || strcmp(value_str,
"bg") == 0) {
393 }
else if (strcmp(value_str,
"half-block") == 0 || strcmp(value_str,
"halfblock") == 0) {
396 (void)fprintf(stderr,
"Error: Invalid render mode '%s'. Valid modes: foreground, background, half-block\n",
405 if (!value_str || !opts) {
409 if (strcmp(value_str,
"standard") == 0) {
411 }
else if (strcmp(value_str,
"blocks") == 0) {
413 }
else if (strcmp(value_str,
"digital") == 0) {
415 }
else if (strcmp(value_str,
"minimal") == 0) {
417 }
else if (strcmp(value_str,
"cool") == 0) {
419 }
else if (strcmp(value_str,
"custom") == 0) {
422 (void)fprintf(stderr,
"Invalid palette '%s'. Valid palettes: standard, blocks, digital, minimal, cool, custom\n",
431 if (!value_str || !opts) {
436 (void)fprintf(stderr,
"Invalid palette-chars: too long (%zu chars, max %zu)\n", strlen(value_str),
459 opts->
width = (
unsigned short int)width_val;
475 opts->
height = (
unsigned short int)height_val;
486 unsigned short int index_val;
497 if (!value_str || !opts) {
502 float delay = strtof(value_str, &endptr);
503 if (endptr == value_str || *endptr !=
'\0' || delay < 0.0f) {
504 (void)fprintf(stderr,
"Invalid snapshot delay '%s'. Must be a non-negative number.\n", value_str);
521 if (log_level == -1) {
522 (void)fprintf(stderr,
"Error: %s\n", error_msg);
540 unsigned short int term_width, term_height;
548 opts->
height = term_height;
549 opts->
width = term_width;
553 opts->
height = term_height;
557 opts->
width = term_width;
569 unsigned short int term_width, term_height;
574 opts->
width = term_width;
577 opts->
height = term_height;
579 log_debug(
"After update_dimensions_to_terminal_size: width=%d, height=%d", opts->
width, opts->
height);
583 "Failed to get terminal size in update_dimensions_to_terminal_size, keeping defaults: width=%d, height=%d",
607 (void)fprintf(desc,
"Unknown mode\n");
⚠️‼️ Error and/or exit() when things go bad.
#define SAFE_STRNCPY(dst, src, size)
#define SAFE_MALLOC(size, cast)
#define SAFE_SNPRINTF(buffer, buffer_size,...)
#define SET_ERRNO(code, context_msg,...)
Set error code with custom context message and log it.
asciichat_error_t
Error and exit codes - unified status values (0-255)
log_level_t
Logging levels enumeration.
#define log_debug(...)
Log a DEBUG message.
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)
void usage_mirror(FILE *desc)
Print mirror mode usage/help text.
unsigned short int GRAY[256]
Grayscale lookup table.
#define COLOR_MODE_16_COLOR
16-color mode (full name)
void usage_client(FILE *desc)
Print client mode usage/help text.
unsigned short int BLUE[256]
Blue channel lookup table.
#define COLOR_MODE_256_COLOR
256-color mode (full name)
#define COLOR_MODE_TRUECOLOR
24-bit truecolor mode
asciichat_mode_t
Mode type for options parsing.
#define COLOR_MODE_AUTO
Backward compatibility aliases for color mode enum values.
void usage_server(FILE *desc)
Print server usage information.
int strtoint_safe(const char *str)
Safely parse string to integer with validation.
void update_dimensions_to_terminal_size(options_t *opts)
Update dimensions to current terminal size.
const float weight_blue
Blue weight for luminance calculation.
#define OPTIONS_BUFF_SIZE
Buffer size for option string values.
void usage_acds(FILE *desc)
Print ACDS usage information.
#define COLOR_MODE_NONE
Monochrome mode.
void usage(FILE *desc, asciichat_mode_t mode)
Print usage information for client, server, or mirror mode.
#define LEVENSHTEIN_SUGGESTION_THRESHOLD
Maximum edit distance to suggest an option.
#define OPT_HEIGHT_DEFAULT
Default terminal height in characters.
unsigned short int GREEN[256]
Green channel lookup table.
#define SNAPSHOT_DELAY_DEFAULT
Default snapshot delay in seconds.
const float weight_green
Green weight for luminance calculation.
int validate_opt_log_level(const char *value_str, char *error_msg, size_t error_msg_size)
Validate log level string.
size_t levenshtein(const char *a, const char *b)
Calculate Levenshtein distance between two strings.
unsigned short int RED[256]
Red channel lookup table.
void update_dimensions_for_full_height(options_t *opts)
Update dimensions for full-height mode.
#define OPT_WIDTH_DEFAULT
Default terminal width in characters.
@ MODE_CLIENT
Client mode - network client options.
@ MODE_ACDS
Discovery service mode - session management and WebRTC signaling.
@ MODE_SERVER
Server mode - network server options.
@ MODE_MIRROR
Mirror mode - local webcam viewing (no network)
palette_type_t
Built-in palette type enumeration.
@ PALETTE_BLOCKS
Unicode block characters: " ░░▒▒▓▓██".
@ PALETTE_CUSTOM
User-defined via –palette-chars.
@ PALETTE_COOL
Ascending blocks: " ▁▂▃▄▅▆▇█".
@ PALETTE_STANDARD
Standard ASCII palette: " ...',;:clodxkO0KXNWM".
@ PALETTE_DIGITAL
Digital/glitch aesthetic: " -=≡≣▰▱◼".
@ PALETTE_MINIMAL
Simple ASCII: " .-+*#".
char * expand_path(const char *path)
Expand path with tilde (~) support.
#define PASSWORD_MAX_LEN
Buffer size for password input.
int prompt_password_simple(const char *prompt, char *password, size_t max_len)
Prompt the user for a password with simple formatting.
Levenshtein distance algorithm for fuzzy string matching.
Application limits and constraints.
📝 Logging API with multiple log levels and terminal output control
char * strip_equals_prefix(const char *opt_value, char *buffer, size_t buffer_size)
Strip equals sign prefix from option argument.
ASCIICHAT_API unsigned short int opt_verbose_level
ASCIICHAT_API int opt_max_clients
ASCIICHAT_API char opt_address[OPTIONS_BUFF_SIZE]
ASCIICHAT_API unsigned short int opt_show_capabilities
ASCIICHAT_API unsigned short int opt_audio_analysis_enabled
ASCIICHAT_API unsigned short int opt_encrypt_enabled
ASCIICHAT_API bool opt_webcam_flip
ASCIICHAT_API bool auto_width
ASCIICHAT_API float opt_snapshot_delay
ASCIICHAT_API bool opt_palette_custom_set
ASCIICHAT_API int opt_reconnect_attempts
ASCIICHAT_API int opt_speakers_index
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.
ASCIICHAT_API unsigned short int opt_height
ASCIICHAT_API char opt_port[OPTIONS_BUFF_SIZE]
ASCIICHAT_API palette_type_t opt_palette_type
ASCIICHAT_API unsigned short int opt_strip_ansi
ASCIICHAT_API char opt_encrypt_key[OPTIONS_BUFF_SIZE]
const char * find_similar_option(const char *unknown_opt, const struct option *options)
Find a similar option name for typo suggestions.
ASCIICHAT_API int opt_microphone_index
ASCIICHAT_API bool opt_no_compress
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_width_option(const char *value_str, options_t *opts)
Parse –width option and set opts->width.
ASCIICHAT_API int opt_compression_level
ASCIICHAT_API terminal_color_mode_t opt_color_mode
ASCIICHAT_API char opt_server_key[OPTIONS_BUFF_SIZE]
asciichat_error_t detect_default_ssh_key(char *key_path, size_t path_size)
Detect default SSH key path for the current user.
ASCIICHAT_API char opt_palette_custom[256]
ASCIICHAT_API unsigned short int opt_width
ASCIICHAT_API char opt_encrypt_keyfile[OPTIONS_BUFF_SIZE]
char * read_password_from_stdin(const char *prompt)
Read password from stdin with prompt.
bool validate_port_opt(const char *value_str, uint16_t *out_port)
Validate port number (1-65535)
ASCIICHAT_API render_mode_t opt_render_mode
ASCIICHAT_API bool opt_test_pattern
asciichat_error_t parse_height_option(const char *value_str, options_t *opts)
Parse –height option and set opts->height.
ASCIICHAT_API char opt_address6[OPTIONS_BUFF_SIZE]
bool validate_fps_opt(const char *value_str, int *out_fps)
Validate FPS value (1-144)
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_palette_option(const char *value_str, options_t *opts)
Parse –palette option and set opt_palette_type.
ASCIICHAT_API bool auto_height
ASCIICHAT_API unsigned short int opt_audio_no_playback
ASCIICHAT_API log_level_t opt_log_level
asciichat_error_t parse_log_level_option(const char *value_str, options_t *opts)
Parse –log-level option and set opt_log_level.
ASCIICHAT_API char opt_log_file[OPTIONS_BUFF_SIZE]
ASCIICHAT_API char opt_client_keys[OPTIONS_BUFF_SIZE]
ASCIICHAT_API unsigned short int opt_force_utf8
bool validate_positive_int_opt(const char *value_str, int *out_value, const char *param_name)
Validate a positive integer value.
ASCIICHAT_API char opt_password[OPTIONS_BUFF_SIZE]
ASCIICHAT_API unsigned short int opt_audio_enabled
asciichat_error_t parse_color_mode_option(const char *value_str, options_t *opts)
Parse –color-mode option and set opts->color_mode.
ASCIICHAT_API bool opt_no_audio_mixer
ASCIICHAT_API bool opt_encode_audio
ASCIICHAT_API unsigned short int opt_snapshot_mode
ASCIICHAT_API unsigned short int opt_stretch
ASCIICHAT_API unsigned short int opt_quiet
ASCIICHAT_API unsigned short int opt_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.
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.
asciichat_error_t parse_webcam_index_option(const char *value_str, options_t *opts)
Parse –webcam-index option and set opts->webcam_index.
bool port_explicitly_set_via_flag
bool validate_webcam_index(const char *value_str, unsigned short int *out_index)
Validate webcam index using the common device index validator.
ASCIICHAT_API unsigned short int opt_no_encrypt
Common utilities and helpers for option parsing.
Validation functions for options parsing.
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.
asciichat_error_t parse_port(const char *str, uint16_t *out_port)
Parse port number (1-65535) from string.
Password prompting utilities with secure input and formatting.
📂 Path Manipulation Utilities
Consolidated options structure.
terminal_color_mode_t color_mode
Color mode (auto/none/16/256/truecolor)
unsigned short int webcam_index
Webcam device index (0 = first)
unsigned short int width
Terminal width in characters.
bool auto_height
Auto-detect height from terminal.
log_level_t log_level
Log level threshold.
char palette_custom[256]
Custom palette characters.
unsigned short int height
Terminal height in characters.
bool palette_custom_set
True if custom palette was set.
render_mode_t render_mode
Render mode (foreground/background/half-block)
double snapshot_delay
Snapshot delay in seconds.
palette_type_t palette_type
Selected palette type.
bool auto_width
Auto-detect width from terminal.
🖥️ Cross-platform terminal interface for ascii-chat
Common SIMD utilities and structures.