ascii-chat 0.6.0
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
options/common.c
Go to the documentation of this file.
1
10#include "options/common.h"
11
12#include "asciichat_errno.h"
13#include "common.h"
14#include "log/logging.h"
15#include "options/levenshtein.h"
16#include "options/validation.h"
17#include "platform/terminal.h"
18#include "util/parsing.h"
19#include "util/password.h"
20#include "util/path.h"
21
22#ifdef _WIN32
23#include <io.h>
24#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
25#else
26#include <unistd.h>
27#endif
28
29#include <limits.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33#include <sys/stat.h>
34
35// ============================================================================
36// Helper Functions
37// ============================================================================
38
39// Find the most similar option name to an unknown option
40// Returns the best matching option name, or NULL if no good match found
41// Note: Uses LEVENSHTEIN_SUGGESTION_THRESHOLD from levenshtein.h
42const char *find_similar_option(const char *unknown_opt, const struct option *options) {
43 if (!unknown_opt || !options) {
44 return NULL;
45 }
46
47 const char *best_match = NULL;
48 size_t best_distance = SIZE_MAX;
49
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) {
53 best_distance = dist;
54 best_match = options[i].name;
55 }
56 }
57
58 // Only suggest if the distance is within our threshold
59 if (best_distance <= LEVENSHTEIN_SUGGESTION_THRESHOLD) {
60 return best_match;
61 }
62
63 return NULL;
64}
65
66// Safely parse string to integer with validation
67int strtoint_safe(const char *str) {
68 if (!str || *str == '\0') {
69 return INT_MIN; // Error: NULL or empty string
70 }
71
72 int32_t result = 0;
73 // Use safe parsing utility with full int32 range validation
74 if (parse_int32(str, &result, INT_MIN, INT_MAX) != ASCIICHAT_OK) {
75 return INT_MIN; // Error: invalid input or out of range
76 }
77
78 return (int)result;
79}
80
81// Forward declaration for get_required_argument (defined later in file)
82char *get_required_argument(const char *opt_value, char *buffer, size_t buffer_size, const char *option_name,
83 asciichat_mode_t mode);
84
85// Validate and retrieve required argument for an option
86char *validate_required_argument(const char *optarg, char *argbuf, size_t argbuf_size, const char *option_name,
87 asciichat_mode_t mode) {
88 char *value = get_required_argument(optarg, argbuf, argbuf_size, option_name, mode);
89 if (!value) {
90 (void)option_error_invalid();
91 }
92 return value;
93}
94
95// Validate a positive integer value (internal option parsing helper)
96bool validate_positive_int_opt(const char *value_str, int *out_value, const char *param_name) {
97 if (!value_str || !out_value) {
98 return false;
99 }
100
101 int val = strtoint_safe(value_str);
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);
104 return false;
105 }
106
107 *out_value = val;
108 return true;
109}
110
111// Validate port number (1-65535) (internal option parsing helper)
112bool validate_port_opt(const char *value_str, uint16_t *out_port) {
113 if (!value_str || !out_port) {
114 return false;
115 }
116
117 // Use safe integer parsing with range validation
118 if (parse_port(value_str, out_port) != ASCIICHAT_OK) {
119 (void)fprintf(stderr, "Invalid port value '%s'. Port must be a number between 1 and 65535.\n", value_str);
120 return false;
121 }
122
123 return true;
124}
125
126// Validate FPS value (1-144) (internal option parsing helper)
127bool validate_fps_opt(const char *value_str, int *out_fps) {
128 if (!value_str || !out_fps) {
129 return false;
130 }
131
132 int fps_val = strtoint_safe(value_str);
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);
135 return false;
136 }
137
138 *out_fps = fps_val;
139 return true;
140}
141
142// Validate webcam index using the common device index validator
143bool validate_webcam_index(const char *value_str, unsigned short int *out_index) {
144 if (!value_str || !out_index) {
145 return false;
146 }
147
148 char error_msg[256];
149 int parsed_index = validate_opt_device_index(value_str, error_msg, sizeof(error_msg));
150 if (parsed_index == INT_MIN) {
151 (void)fprintf(stderr, "Invalid webcam index: %s\n", error_msg);
152 return false;
153 }
154 // Webcam index doesn't support -1 (default), must be >= 0
155 if (parsed_index < 0) {
156 (void)fprintf(stderr, "Invalid webcam index '%s'. Webcam index must be a non-negative integer.\n", value_str);
157 return false;
158 }
159
160 *out_index = (unsigned short int)parsed_index;
161 return true;
162}
163
164// Detect default SSH key path for the current user
165asciichat_error_t detect_default_ssh_key(char *key_path, size_t path_size) {
166 // Use expand_path utility to resolve ~/.ssh/id_ed25519
167 char *full_path = expand_path("~/.ssh/id_ed25519");
168 if (!full_path) {
169 return SET_ERRNO(ERROR_CONFIG, "Could not expand SSH key path");
170 }
171
172 // Check if the Ed25519 private key file exists
173 struct stat st;
174 bool found = (stat(full_path, &st) == 0 && S_ISREG(st.st_mode));
175
176 if (found) {
177 SAFE_SNPRINTF(key_path, path_size, "%s", full_path);
178 log_debug("Found default SSH key: %s", full_path);
179 SAFE_FREE(full_path);
180 return ASCIICHAT_OK;
181 }
182
183 (void)fprintf(stderr, "No Ed25519 SSH key found at %s\n", full_path);
184 SAFE_FREE(full_path);
185 return SET_ERRNO(
187 "Only Ed25519 keys are supported (modern, secure, fast). Generate a new key with: ssh-keygen -t ed25519");
188}
189
190// ============================================================================
191// Argument Processing Helpers
192// ============================================================================
193
194// Helper function to strip equals sign from optarg if present
195char *strip_equals_prefix(const char *opt_value, char *buffer, size_t buffer_size) {
196 if (!opt_value)
197 return NULL;
198
199 SAFE_SNPRINTF(buffer, buffer_size, "%s", opt_value);
200 char *value_str = buffer;
201 if (value_str[0] == '=') {
202 value_str++; // Skip the equals sign
203 }
204
205 // Return NULL for empty strings (treat as missing argument)
206 if (strlen(value_str) == 0) {
207 return NULL;
208 }
209
210 return value_str;
211}
212
213// Helper function to handle required arguments with consistent error messages
214// Returns NULL on error (caller should check and return error code)
215char *get_required_argument(const char *opt_value, char *buffer, size_t buffer_size, const char *option_name,
216 asciichat_mode_t mode) {
217 // Check if opt_value is NULL or empty
218 if (!opt_value || strlen(opt_value) == 0) {
219 goto error;
220 }
221
222 // Check if getopt_long returned the option name itself as the argument
223 // This happens when a long option requiring an argument is at the end of argv
224 if (opt_value && option_name && strcmp(opt_value, option_name) == 0) {
225 goto error;
226 }
227
228 // Process the argument normally
229 char *value_str = strip_equals_prefix(opt_value, buffer, buffer_size);
230 if (!value_str) {
231 goto error;
232 }
233
234 return value_str;
235
236error:
237 (void)fprintf(stderr, "%s: option '--%s' requires an argument\n",
238 mode == MODE_SERVER ? "server" : (mode == MODE_MIRROR ? "mirror" : "client"), option_name);
239 (void)fflush(stderr);
240 return NULL; // Signal error to caller
241}
242
243// Read password from stdin with prompt (returns allocated string or NULL on error)
244char *read_password_from_stdin(const char *prompt) {
245 char *password_buf = SAFE_MALLOC(PASSWORD_MAX_LEN, char *);
246 if (!password_buf) {
247 return NULL;
248 }
249
250 if (prompt_password_simple(prompt, password_buf, PASSWORD_MAX_LEN) != 0) {
251 SAFE_FREE(password_buf);
252 return NULL;
253 }
254
255 return password_buf; // Caller must free
256}
257
258// ============================================================================
259// Global Variable Definitions
260// ============================================================================
261
264
265// Track if --port was explicitly set via command-line flag (for mutual exclusion validation)
267
270
271// Server options
272ASCIICHAT_API int opt_max_clients = 10; // Maximum concurrent clients (min 1, max 32)
273
274// Network performance options
275ASCIICHAT_API int opt_compression_level = 1; // zstd compression level (min 1, max 9, default 1)
276ASCIICHAT_API bool opt_no_compress = false; // Disable compression entirely (default: false)
277ASCIICHAT_API bool opt_encode_audio = true; // Enable Opus audio encoding (default: true)
278
279// Client reconnection options
280ASCIICHAT_API int opt_reconnect_attempts = -1; // Number of reconnection attempts (0=off, -1=unlimited/auto)
281
282ASCIICHAT_API unsigned short int opt_webcam_index = 0;
283
285
286ASCIICHAT_API bool opt_test_pattern = false; // Use test pattern instead of real webcam
287ASCIICHAT_API bool opt_no_audio_mixer = false; // Disable audio mixer (debug only)
288
289// Terminal color mode and capability options
292ASCIICHAT_API unsigned short int opt_show_capabilities = 0; // Don't show capabilities by default
293ASCIICHAT_API unsigned short int opt_force_utf8 = 0; // Don't force UTF-8 by default
294
295ASCIICHAT_API unsigned short int opt_audio_enabled = 0;
296ASCIICHAT_API int opt_microphone_index = -1; // -1 means use default microphone
297ASCIICHAT_API int opt_speakers_index = -1; // -1 means use default speakers
299ASCIICHAT_API unsigned short int opt_audio_no_playback = 0; // Disable speaker playback for debugging
300
301// Allow stretching/shrinking without preserving aspect ratio when set via -s/--stretch
302ASCIICHAT_API unsigned short int opt_stretch = 0;
303
304// Disable console logging when set via -q/--quiet (logs only to file)
305ASCIICHAT_API unsigned short int opt_quiet = 0;
306
307// Verbose logging level - each -V increases verbosity (decreases log level threshold)
308ASCIICHAT_API unsigned short int opt_verbose_level = 0;
309
310// Enable snapshot mode when set via --snapshot (client only - capture one frame and exit)
311ASCIICHAT_API unsigned short int opt_snapshot_mode = 0;
312
313// Snapshot delay in seconds (float) - default 3.0 for webcam warmup
315
316// Strip ANSI escape sequences from output
317ASCIICHAT_API unsigned short int opt_strip_ansi = 0;
318
319// Log file path for file logging (empty string means no file logging)
321
322// Log level for console and file output
323#ifdef NDEBUG
325#else
327#endif
328
329// Encryption options
330ASCIICHAT_API unsigned short int opt_encrypt_enabled = 0; // Enable AES encryption via --encrypt
331ASCIICHAT_API char opt_encrypt_key[OPTIONS_BUFF_SIZE] = ""; // SSH/GPG key file from --key (file-based only)
332ASCIICHAT_API char opt_password[OPTIONS_BUFF_SIZE] = ""; // Password string from --password
333ASCIICHAT_API char opt_encrypt_keyfile[OPTIONS_BUFF_SIZE] = ""; // Key file path from --keyfile
334
335// New crypto options (Phase 2)
336ASCIICHAT_API unsigned short int opt_no_encrypt = 0; // Disable encryption (opt-out)
337ASCIICHAT_API char opt_server_key[OPTIONS_BUFF_SIZE] = ""; // Expected server public key (client only)
338ASCIICHAT_API char opt_client_keys[OPTIONS_BUFF_SIZE] = ""; // Allowed client keys (server only)
339
340// Palette options
342ASCIICHAT_API char opt_palette_custom[256] = ""; // Custom palette characters
343ASCIICHAT_API bool opt_palette_custom_set = false; // True if custom palette was set
344
345// Default weights; must add up to 1.0
346const float weight_red = 0.2989f;
347const float weight_green = 0.5866f;
348const float weight_blue = 0.1145f;
349
350// Color channel lookup tables (used by image.c for palette precomputation)
351// Size must match ASCII_LUMINANCE_LEVELS (256) from ascii.h
352unsigned short int RED[256];
353unsigned short int GREEN[256];
354unsigned short int BLUE[256];
355unsigned short int GRAY[256];
356
357// ============================================================================
358// Shared Option Parsers (Client + Mirror Common Options)
359// ============================================================================
360
362 if (!value_str || !opts) {
363 return ERROR_INVALID_PARAM;
364 }
365
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) {
376 } else {
377 (void)fprintf(stderr, "Error: Invalid color mode '%s'. Valid modes: auto, none, 16, 256, truecolor\n", value_str);
378 return ERROR_INVALID_PARAM;
379 }
380
381 return ASCIICHAT_OK;
382}
383
385 if (!value_str || !opts) {
386 return ERROR_INVALID_PARAM;
387 }
388
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) {
395 } else {
396 (void)fprintf(stderr, "Error: Invalid render mode '%s'. Valid modes: foreground, background, half-block\n",
397 value_str);
398 return ERROR_INVALID_PARAM;
399 }
400
401 return ASCIICHAT_OK;
402}
403
404asciichat_error_t parse_palette_option(const char *value_str, options_t *opts) {
405 if (!value_str || !opts) {
406 return ERROR_INVALID_PARAM;
407 }
408
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) {
421 } else {
422 (void)fprintf(stderr, "Invalid palette '%s'. Valid palettes: standard, blocks, digital, minimal, cool, custom\n",
423 value_str);
424 return ERROR_INVALID_PARAM;
425 }
426
427 return ASCIICHAT_OK;
428}
429
431 if (!value_str || !opts) {
432 return ERROR_INVALID_PARAM;
433 }
434
435 if (strlen(value_str) >= sizeof(opts->palette_custom)) {
436 (void)fprintf(stderr, "Invalid palette-chars: too long (%zu chars, max %zu)\n", strlen(value_str),
437 sizeof(opts->palette_custom) - 1);
438 return ERROR_INVALID_PARAM;
439 }
440
441 SAFE_STRNCPY(opts->palette_custom, value_str, sizeof(opts->palette_custom));
442 opts->palette_custom[sizeof(opts->palette_custom) - 1] = '\0';
443 opts->palette_custom_set = true;
445
446 return ASCIICHAT_OK;
447}
448
449asciichat_error_t parse_width_option(const char *value_str, options_t *opts) {
450 if (!opts) {
451 return ERROR_INVALID_PARAM;
452 }
453
454 int width_val;
455 if (!validate_positive_int_opt(value_str, &width_val, "width")) {
456 return ERROR_INVALID_PARAM;
457 }
458
459 opts->width = (unsigned short int)width_val;
460 opts->auto_width = false;
461
462 return ASCIICHAT_OK;
463}
464
465asciichat_error_t parse_height_option(const char *value_str, options_t *opts) {
466 if (!opts) {
467 return ERROR_INVALID_PARAM;
468 }
469
470 int height_val;
471 if (!validate_positive_int_opt(value_str, &height_val, "height")) {
472 return ERROR_INVALID_PARAM;
473 }
474
475 opts->height = (unsigned short int)height_val;
476 opts->auto_height = false;
477
478 return ASCIICHAT_OK;
479}
480
482 if (!opts) {
483 return ERROR_INVALID_PARAM;
484 }
485
486 unsigned short int index_val;
487 if (!validate_webcam_index(value_str, &index_val)) {
488 return ERROR_INVALID_PARAM;
489 }
490
491 opts->webcam_index = index_val;
492
493 return ASCIICHAT_OK;
494}
495
497 if (!value_str || !opts) {
498 return ERROR_INVALID_PARAM;
499 }
500
501 char *endptr;
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);
505 return ERROR_INVALID_PARAM;
506 }
507
508 opts->snapshot_delay = delay;
509
510 return ASCIICHAT_OK;
511}
512
514 if (!opts) {
515 return ERROR_INVALID_PARAM;
516 }
517
518 char error_msg[256];
519 int log_level = validate_opt_log_level(value_str, error_msg, sizeof(error_msg));
520
521 if (log_level == -1) {
522 (void)fprintf(stderr, "Error: %s\n", error_msg);
523 return ERROR_INVALID_PARAM;
524 }
525
526 opts->log_level = (log_level_t)log_level;
527
528 return ASCIICHAT_OK;
529}
530
531// ============================================================================
532// Terminal Dimension Utilities
533// ============================================================================
534
536 if (!opts) {
537 return;
538 }
539
540 unsigned short int term_width, term_height;
541
542 // Note: Logging is not available during options_init, so we can't use log_debug here
543 asciichat_error_t result = get_terminal_size(&term_width, &term_height);
544 if (result == ASCIICHAT_OK) {
545 // If both dimensions are auto, set height to terminal height and let
546 // aspect_ratio calculate width
547 if (opts->auto_height && opts->auto_width) {
548 opts->height = term_height;
549 opts->width = term_width; // Also set width when both are auto
550 }
551 // If only height is auto, use full terminal height
552 else if (opts->auto_height) {
553 opts->height = term_height;
554 }
555 // If only width is auto, use full terminal width
556 else if (opts->auto_width) {
557 opts->width = term_width;
558 }
559 } else {
560 // Terminal size detection failed, but we can still continue with defaults
561 }
562}
563
565 if (!opts) {
566 return;
567 }
568
569 unsigned short int term_width, term_height;
570 // Get current terminal size (get_terminal_size already handles ioctl first, then $COLUMNS/$LINES fallback)
571 asciichat_error_t terminal_result = get_terminal_size(&term_width, &term_height);
572 if (terminal_result == ASCIICHAT_OK) {
573 if (opts->auto_width) {
574 opts->width = term_width;
575 }
576 if (opts->auto_height) {
577 opts->height = term_height;
578 }
579 log_debug("After update_dimensions_to_terminal_size: width=%d, height=%d", opts->width, opts->height);
580 } else {
581 // Terminal detection failed - keep the default values set in options_init()
582 log_debug(
583 "Failed to get terminal size in update_dimensions_to_terminal_size, keeping defaults: width=%d, height=%d",
584 opts->width, opts->height);
585 }
586}
587
588// ============================================================================
589// Generic Usage Function (Dispatches to Mode-Specific Functions)
590// ============================================================================
591
592void usage(FILE *desc, asciichat_mode_t mode) {
593 switch (mode) {
594 case MODE_SERVER:
595 usage_server(desc);
596 break;
597 case MODE_CLIENT:
598 usage_client(desc);
599 break;
600 case MODE_MIRROR:
601 usage_mirror(desc);
602 break;
603 case MODE_ACDS:
604 usage_acds(desc);
605 break;
606 default:
607 (void)fprintf(desc, "Unknown mode\n");
608 break;
609 }
610}
⚠️‼️ Error and/or exit() when things go bad.
unsigned short uint16_t
Definition common.h:57
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:358
#define SAFE_FREE(ptr)
Definition common.h:320
#define SAFE_MALLOC(size, cast)
Definition common.h:208
#define SAFE_SNPRINTF(buffer, buffer_size,...)
Definition common.h:412
#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)
Definition error_codes.h:46
@ ERROR_CRYPTO_KEY
Definition error_codes.h:89
@ ASCIICHAT_OK
Definition error_codes.h:48
@ ERROR_CONFIG
Definition error_codes.h:54
@ ERROR_INVALID_PARAM
log_level_t
Logging levels enumeration.
Definition log/logging.h:59
#define log_debug(...)
Log a DEBUG message.
@ LOG_INFO
Definition log/logging.h:62
@ LOG_DEBUG
Definition log/logging.h:61
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:422
void usage_mirror(FILE *desc)
Print mirror mode usage/help text.
Definition mirror.c:71
unsigned short int GRAY[256]
Grayscale lookup table.
#define COLOR_MODE_16_COLOR
16-color mode (full name)
Definition options.h:159
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)
Definition options.h:161
#define COLOR_MODE_TRUECOLOR
24-bit truecolor mode
Definition options.h:162
asciichat_mode_t
Mode type for options parsing.
Definition options.h:426
#define COLOR_MODE_AUTO
Backward compatibility aliases for color mode enum values.
Definition options.h:156
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.
const float weight_red
#define OPTIONS_BUFF_SIZE
Buffer size for option string values.
Definition options.h:176
void usage_acds(FILE *desc)
Print ACDS usage information.
Definition acds.c:109
#define COLOR_MODE_NONE
Monochrome mode.
Definition options.h:157
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.
Definition levenshtein.h:29
#define OPT_HEIGHT_DEFAULT
Default terminal height in characters.
Definition options.h:198
unsigned short int GREEN[256]
Green channel lookup table.
#define SNAPSHOT_DELAY_DEFAULT
Default snapshot delay in seconds.
Definition options.h:212
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.
Definition validation.c:190
size_t levenshtein(const char *a, const char *b)
Calculate Levenshtein distance between two strings.
Definition levenshtein.c:72
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.
Definition options.h:187
@ MODE_CLIENT
Client mode - network client options.
Definition options.h:428
@ MODE_ACDS
Discovery service mode - session management and WebRTC signaling.
Definition options.h:430
@ MODE_SERVER
Server mode - network server options.
Definition options.h:427
@ MODE_MIRROR
Mirror mode - local webcam viewing (no network)
Definition options.h:429
palette_type_t
Built-in palette type enumeration.
Definition palette.h:84
@ PALETTE_BLOCKS
Unicode block characters: " ░░▒▒▓▓██".
Definition palette.h:88
@ PALETTE_CUSTOM
User-defined via –palette-chars.
Definition palette.h:96
@ PALETTE_COOL
Ascending blocks: " ▁▂▃▄▅▆▇█".
Definition palette.h:94
@ PALETTE_STANDARD
Standard ASCII palette: " ...',;:clodxkO0KXNWM".
Definition palette.h:86
@ PALETTE_DIGITAL
Digital/glitch aesthetic: " -=≡≣▰▱◼".
Definition palette.h:90
@ PALETTE_MINIMAL
Simple ASCII: " .-+*#".
Definition palette.h:92
render_mode_t
Render mode preferences.
Definition terminal.h:467
#define ASCIICHAT_API
Export symbols on Unix platforms (Linux, macOS)
Definition api.h:82
terminal_color_mode_t
Terminal color support levels.
Definition terminal.h:424
asciichat_error_t get_terminal_size(unsigned short int *width, unsigned short int *height)
Get terminal size with multiple fallback methods.
@ RENDER_MODE_FOREGROUND
Foreground colors only (text color)
Definition terminal.h:469
@ RENDER_MODE_BACKGROUND
Background colors (block colors)
Definition terminal.h:471
@ RENDER_MODE_HALF_BLOCK
Unicode half-block characters (mixed foreground/background)
Definition terminal.h:473
char * expand_path(const char *path)
Expand path with tilde (~) support.
Definition path.c:183
#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:46
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.
Definition parsing.c:240
asciichat_error_t parse_port(const char *str, uint16_t *out_port)
Parse port number (1-65535) from string.
Definition parsing.c:221
🔍 Safe Parsing Utilities
Password prompting utilities with secure input and formatting.
📂 Path Manipulation Utilities
Consolidated options structure.
Definition options.h:439
terminal_color_mode_t color_mode
Color mode (auto/none/16/256/truecolor)
Definition options.h:507
unsigned short int webcam_index
Webcam device index (0 = first)
Definition options.h:499
unsigned short int width
Terminal width in characters.
Definition options.h:454
bool auto_height
Auto-detect height from terminal.
Definition options.h:457
log_level_t log_level
Log level threshold.
Definition options.h:536
char palette_custom[256]
Custom palette characters.
Definition options.h:582
unsigned short int height
Terminal height in characters.
Definition options.h:455
bool palette_custom_set
True if custom palette was set.
Definition options.h:583
render_mode_t render_mode
Render mode (foreground/background/half-block)
Definition options.h:508
double snapshot_delay
Snapshot delay in seconds.
Definition options.h:533
palette_type_t palette_type
Selected palette type.
Definition options.h:581
bool auto_width
Auto-detect width from terminal.
Definition options.h:456
🖥️ Cross-platform terminal interface for ascii-chat
Common SIMD utilities and structures.