ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
actions.c
Go to the documentation of this file.
1
12
13/* Storage capacities in elements; text buffers include the terminating NUL. */
14#define OPTIONS_PARSING_ACTIONS_SIZE_BUFFER_SIZE 64
15#define OPTIONS_PARSING_ACTIONS_COLORS_BUFFER_SIZE 64
16#define OPTIONS_PARSING_ACTIONS_BITMASK_BUFFER_SIZE 64
17#define OPTIONS_PARSING_ACTIONS_NOTIFICATION_BUFFER_SIZE 1024
18#define OPTIONS_PARSING_ACTIONS_QUESTION_BUFFER_SIZE 4096
19
21
23#include <string.h>
24#include <stddef.h>
25
27#include <ascii-chat/common.h>
29#include <ascii-chat/log/log.h>
36#include <libplatform/terminal.h>
38#include <sys/stat.h>
39#include <ascii-chat/version.h>
44
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48
49// ============================================================================
50// Action Exit Helper
51// ============================================================================
52
60static _Noreturn void action_exit(int code) {
61 fflush(NULL);
62 asciichat_coverage_flush();
63 _Exit(code);
64}
65
66// ============================================================================
67// Deferred Action Tracking System
68// ============================================================================
69
76static struct {
80} g_deferred_action_state = {
81 .action = ACTION_NONE,
82 .args = {0},
83 .has_action = false,
84};
85
87 // Only remember the first action found
88 if (g_deferred_action_state.has_action) {
89 return; // Action already deferred, ignore subsequent actions
90 }
91
92 g_deferred_action_state.action = action;
93 g_deferred_action_state.has_action = true;
94
95 // Copy arguments if provided
96 if (args) {
97 memcpy(&g_deferred_action_state.args, args, sizeof(action_args_t));
98 } else {
99 memset(&g_deferred_action_state.args, 0, sizeof(action_args_t));
100 }
101}
102
104 return g_deferred_action_state.action;
105}
106
108 if (!g_deferred_action_state.has_action) {
109 return NULL;
110 }
111 return &g_deferred_action_state.args;
112}
113
114// ============================================================================
115// Webcam Action
116// ============================================================================
117
119 // Defer execution until after options are fully parsed
121}
122
129static void execute_list_webcams(void) {
130 webcam_device_info_t *devices = NULL;
131 unsigned int device_count = 0;
132
133 asciichat_error_t result = webcam_list_devices(&devices, &device_count);
134 if (result != ASCIICHAT_OK) {
135 log_error("Failed to enumerate webcam devices");
136 action_exit(ERROR_WEBCAM);
137 }
138
139 if (device_count == 0) {
140 log_plain_stdout("No webcam devices found.");
141 } else {
142 log_plain_stdout("Available Webcam Devices:");
143 for (unsigned int i = 0; i < device_count; i++) {
144 log_plain_stdout(" %u %s", devices[i].index, devices[i].name);
145 }
146 }
147
149 action_exit(0);
150}
151
152// ============================================================================
153// Audio Device Actions
154// ============================================================================
155
157 // Defer execution until after options are fully parsed
159}
160
167static void execute_list_microphones(void) {
168 audio_device_info_t *devices = NULL;
169 unsigned int device_count = 0;
170
171 asciichat_error_t result = audio_list_input_devices(&devices, &device_count);
172 if (result != ASCIICHAT_OK) {
173 log_error("Failed to enumerate audio input devices");
174 action_exit(ERROR_AUDIO);
175 }
176
177 if (device_count == 0) {
178 log_plain_stdout("No microphone devices found.");
179 } else {
180 log_plain_stdout("Available Microphone Devices:");
181 for (unsigned int i = 0; i < device_count; i++) {
182 if (devices[i].is_default_input) {
183 log_plain_stdout(" %d %s (default)", devices[i].index, devices[i].name);
184 } else {
185 log_plain_stdout(" %d %s", devices[i].index, devices[i].name);
186 }
187 }
188 }
189
190 audio_free_device_list(devices);
191 action_exit(0);
192}
193
195 // Defer execution until after options are fully parsed
197}
198
205static void execute_list_speakers(void) {
206 audio_device_info_t *devices = NULL;
207 unsigned int device_count = 0;
208
209 asciichat_error_t result = audio_list_output_devices(&devices, &device_count);
210 if (result != ASCIICHAT_OK) {
211 log_error("Failed to enumerate audio output devices");
212 action_exit(ERROR_AUDIO);
213 }
214
215 if (device_count == 0) {
216 log_plain_stdout("No speaker devices found.");
217 } else {
218 log_plain_stdout("Available Speaker Devices:");
219 for (unsigned int i = 0; i < device_count; i++) {
220 if (devices[i].is_default_output) {
221 log_plain_stdout(" %d %s (default)", devices[i].index, devices[i].name);
222 } else {
223 log_plain_stdout(" %d %s", devices[i].index, devices[i].name);
224 }
225 }
226 }
227
228 audio_free_device_list(devices);
229 action_exit(0);
230}
231
232// ============================================================================
233// Terminal Capabilities Action
234// ============================================================================
235
240 terminal_capabilities_t caps;
241 detect_terminal_capabilities_into(options_terminal_settings(), &caps);
242
243 // Determine if we should use colored output
244 bool use_colors = terminal_should_color_output(STDOUT_FILENO, options_terminal_settings());
245
246 // Override color level if colors should not be shown
247 if (!use_colors) {
248 caps.color_level = TERM_COLOR_NONE;
249 caps.color_count = 0;
250 caps.capabilities &= ~((uint32_t)(TERM_CAP_COLOR_TRUE | TERM_CAP_COLOR_256 | TERM_CAP_COLOR_16));
251 }
252
253 // Use detected terminal size (immediate execution doesn't have parsed options yet)
254 terminal_size_t size;
255 terminal_get_size(&size);
256 unsigned short width = size.cols;
257 unsigned short height = size.rows;
258
259 log_color_t label_color = use_colors ? LOG_COLOR_DEBUG : LOG_COLOR_GREY;
260 log_color_t string_color = use_colors ? LOG_COLOR_DEBUG : LOG_COLOR_GREY;
261 log_color_t good_color = use_colors ? LOG_COLOR_INFO : LOG_COLOR_GREY;
262 log_color_t bad_color = use_colors ? LOG_COLOR_ERROR : LOG_COLOR_GREY;
263 log_color_t number_color = use_colors ? LOG_COLOR_DEBUG : LOG_COLOR_GREY;
264
265 printf("%s\n", colored_string(LOG_COLOR_WARN, "Terminal Capabilities:"));
266
268 snprintf(size_buf, sizeof(size_buf), "%ux%u", width, height);
269 printf(" %s: %s\n", colored_string(label_color, "Terminal Size"), colored_string(number_color, size_buf));
270
271 const char *color_level_name = terminal_color_level_name(caps.color_level);
272 log_color_t color_level_color = (caps.color_level == TERM_COLOR_NONE) ? bad_color : string_color;
273 printf(" %s: %s\n", colored_string(label_color, "Color Level"),
274 colored_string(color_level_color, (char *)color_level_name));
275
277 snprintf(colors_buf, sizeof(colors_buf), "%u", caps.color_count);
278 printf(" %s: %s\n", colored_string(label_color, "Max Colors"), colored_string(number_color, colors_buf));
279
280 log_color_t utf8_color = caps.utf8_support ? good_color : bad_color;
281 printf(" %s: %s\n", colored_string(label_color, "UTF-8 Support"),
282 colored_string(utf8_color, (char *)(caps.utf8_support ? "Yes" : "No")));
283
284 const char *render_mode_str = "unknown";
285 if (caps.render_mode == RENDER_MODE_FOREGROUND) {
286 render_mode_str = "foreground";
287 } else if (caps.render_mode == RENDER_MODE_BACKGROUND) {
288 render_mode_str = "background";
289 } else if (caps.render_mode == RENDER_MODE_HALF_BLOCK) {
290 render_mode_str = "half-block";
291 }
292 printf(" %s: %s\n", colored_string(label_color, "Render Mode"),
293 colored_string(string_color, (char *)render_mode_str));
294 printf(" %s: %s\n", colored_string(label_color, "TERM"), colored_string(string_color, (char *)caps.term_type));
295 printf(" %s: %s\n", colored_string(label_color, "COLORTERM"),
296 colored_string(string_color, (char *)(strlen(caps.colorterm) ? caps.colorterm : "(not set)")));
297
298 log_color_t reliable_color = caps.detection_reliable ? good_color : bad_color;
299 printf(" %s: %s\n", colored_string(label_color, "Detection Reliable"),
300 colored_string(reliable_color, (char *)(caps.detection_reliable ? "Yes" : "No")));
301
303 snprintf(bitmask_buf, sizeof(bitmask_buf), "0x%08x", caps.capabilities);
304 printf(" %s: %s\n", colored_string(label_color, "Capabilities Bitmask"), colored_string(number_color, bitmask_buf));
305
306 fflush(stdout);
307 action_exit(0);
308}
309
311 // Defer execution until after options are fully parsed and dimensions updated
312 // This ensures --width and --height flags are properly reflected in the output
314}
315
316// ============================================================================
317// Update Check Action
318// ============================================================================
319
324 printf("Checking for updates...\n");
327 if (err != ASCIICHAT_OK) {
328 printf("\nFailed to check for updates.\n\n");
329 action_exit(1);
330 }
331 if (result.update_available) {
333 update_check_format_notification(&result, notification, sizeof(notification));
334 printf("\n%s\n\n", notification);
335 } else {
336 printf("\nYou are already on the latest version: %s (%.8s)\n\n", result.current_version, result.current_sha);
337 }
338 action_exit(0);
339}
340
342 // Defer execution until after options are fully parsed
344}
345
356static void execute_show_capabilities(void) {
357 terminal_capabilities_t caps;
358 detect_terminal_capabilities_into(options_terminal_settings(), &caps);
359
360 // Determine if we should use colored output
361 bool use_colors = terminal_should_color_output(STDOUT_FILENO, options_terminal_settings());
362
363 // Override color level if colors should not be shown
364 if (!use_colors) {
365 // User requested no colors or output is piped or CLAUDECODE is set
366 caps.color_level = TERM_COLOR_NONE;
367 caps.color_count = 0;
368 caps.capabilities &= ~((uint32_t)(TERM_CAP_COLOR_TRUE | TERM_CAP_COLOR_256 | TERM_CAP_COLOR_16));
369 }
370
371 // Get width and height from parsed options (respects --width and --height flags)
372 const options_t *opts = options_get();
373 unsigned short width = opts ? opts->width : 110;
374 unsigned short height = opts ? opts->height : 70;
375
376 // Color scheme:
377 // - Labels: grey
378 // - Regular string values: blue (DEBUG - cyan/blue)
379 // - Affirmative values (Yes, true): green (INFO)
380 // - Bad/negative values (No, false, error): red (ERROR)
381 // - Numbers and hex: magenta (FATAL)
382 log_color_t label_color = use_colors ? LOG_COLOR_DEBUG : LOG_COLOR_GREY;
383 log_color_t string_color = use_colors ? LOG_COLOR_DEBUG : LOG_COLOR_GREY;
384 log_color_t good_color = use_colors ? LOG_COLOR_INFO : LOG_COLOR_GREY;
385 log_color_t bad_color = use_colors ? LOG_COLOR_ERROR : LOG_COLOR_GREY;
386 log_color_t number_color = use_colors ? LOG_COLOR_DEBUG : LOG_COLOR_GREY;
387
388 printf("%s\n", colored_string(LOG_COLOR_WARN, "Terminal Capabilities:"));
389
391 snprintf(size_buf, sizeof(size_buf), "%ux%u", width, height);
392 printf(" %s: %s\n", colored_string(label_color, "Terminal Size"), colored_string(number_color, size_buf));
393
394 // Color Level: green if good, red if none/bad
395 const char *color_level_name = terminal_color_level_name(caps.color_level);
396 log_color_t color_level_color = (caps.color_level == TERM_COLOR_NONE) ? bad_color : string_color;
397 printf(" %s: %s\n", colored_string(label_color, "Color Level"),
398 colored_string(color_level_color, (char *)color_level_name));
399
401 snprintf(colors_buf, sizeof(colors_buf), "%u", caps.color_count);
402 printf(" %s: %s\n", colored_string(label_color, "Max Colors"), colored_string(number_color, colors_buf));
403
404 // UTF-8: green if Yes, red if No
405 log_color_t utf8_color = caps.utf8_support ? good_color : bad_color;
406 printf(" %s: %s\n", colored_string(label_color, "UTF-8 Support"),
407 colored_string(utf8_color, (char *)(caps.utf8_support ? "Yes" : "No")));
408
409 const char *render_mode_str = "unknown";
410 if (caps.render_mode == RENDER_MODE_FOREGROUND) {
411 render_mode_str = "foreground";
412 } else if (caps.render_mode == RENDER_MODE_BACKGROUND) {
413 render_mode_str = "background";
414 } else if (caps.render_mode == RENDER_MODE_HALF_BLOCK) {
415 render_mode_str = "half-block";
416 }
417 printf(" %s: %s\n", colored_string(label_color, "Render Mode"),
418 colored_string(string_color, (char *)render_mode_str));
419 printf(" %s: %s\n", colored_string(label_color, "TERM"), colored_string(string_color, (char *)caps.term_type));
420 printf(" %s: %s\n", colored_string(label_color, "COLORTERM"),
421 colored_string(string_color, (char *)(strlen(caps.colorterm) ? caps.colorterm : "(not set)")));
422
423 // Detection Reliable: green if Yes, red if No
424 log_color_t reliable_color = caps.detection_reliable ? good_color : bad_color;
425 printf(" %s: %s\n", colored_string(label_color, "Detection Reliable"),
426 colored_string(reliable_color, (char *)(caps.detection_reliable ? "Yes" : "No")));
427
429 snprintf(bitmask_buf, sizeof(bitmask_buf), "0x%08x", caps.capabilities);
430 printf(" %s: %s\n", colored_string(label_color, "Capabilities Bitmask"), colored_string(number_color, bitmask_buf));
431
432 fflush(stdout);
433
434 action_exit(0);
435}
436
437// ============================================================================
438// Version Action
439// ============================================================================
440
442 bool use_colors = terminal_should_color_output(STDOUT_FILENO, options_terminal_settings());
443 if (use_colors) {
444 printf("%s %s (%s, %s)\n", colored_string(LOG_COLOR_WARN, "ascii-chat"),
445 colored_string(LOG_COLOR_INFO, (char *)ASCII_CHAT_VERSION_FULL),
446 colored_string(LOG_COLOR_DEBUG, (char *)ASCII_CHAT_BUILD_TYPE),
447 colored_string(LOG_COLOR_GREY, (char *)ASCII_CHAT_BUILD_DATE));
448 } else {
449 printf("ascii-chat %s (%s, %s)\n", ASCII_CHAT_VERSION_FULL, ASCII_CHAT_BUILD_TYPE, ASCII_CHAT_BUILD_DATE);
450 }
451
452 action_exit(0);
453}
454
455// ============================================================================
456// Help Actions
457// ============================================================================
458
460 usage(stdout, MODE_SERVER);
461 action_exit(0);
462}
463
465 usage(stdout, MODE_CLIENT);
466 action_exit(0);
467}
468
470 usage(stdout, MODE_MIRROR);
471 action_exit(0);
472}
473
476 action_exit(0);
477}
478
480 usage(stdout, MODE_DISCOVERY);
481 action_exit(0);
482}
483
484// ============================================================================
485// Man Page Generation Action
486// ============================================================================
487
488void action_create_manpage(const char *output_path) {
489 // Get binary-level config
490 const options_config_t *config = options_preset_unified(NULL, NULL);
491
492 if (!config) {
493 log_error("Failed to get binary options config");
494 action_exit(ERROR_FILE_OPERATION);
495 }
496
497 // Determine output path: use provided path, or NULL for stdout
498 const char *path_to_use = NULL;
499 if (output_path && strlen(output_path) > 0 && strcmp(output_path, "-") != 0) {
500 // User provided explicit path - use it
501 path_to_use = output_path;
502 } else {
503 // No path or "-" means stdout
504 path_to_use = NULL;
505 }
506
507 // Generate merged man page from embedded or filesystem resources
508 // Resources are loaded automatically based on build type:
509 // - Production (Release): From embedded binary data
510 // - Development (Debug): From filesystem files
512 options_config_generate_manpage_merged(config, "ascii-chat", NULL, path_to_use, "Video chat in your terminal");
513
514 if (err != ASCIICHAT_OK) {
516 if (HAS_ERRNO(&err_ctx)) {
517 log_error("%s", err_ctx.context_message);
518 } else {
519 log_error("Failed to generate man page");
520 }
521 action_exit(ERROR_FILE_OPERATION);
522 }
523
524 if (path_to_use) {
525 log_info("Man page written to: %s", path_to_use);
526 } else {
527 log_info("Man page written to stdout");
528 }
529
530 action_exit(0);
531}
532
533// ============================================================================
534// Config Creation Action
535// ============================================================================
536
537void action_create_config(const char *output_path) {
538 // Build the schema first so config_create_default can generate options from it
539 const options_config_t *unified_config = options_preset_unified(NULL, NULL);
540 if (unified_config) {
541 asciichat_error_t schema_build_result = config_schema_build_from_configs(&unified_config, 1);
542 if (schema_build_result != ASCIICHAT_OK) {
543 // Schema build failed, but continue anyway
544 (void)schema_build_result;
545 }
546 // options_config_destroy(unified_config);
547 }
548
549 const char *config_path = NULL;
550
551 // Determine output path: use provided path, or NULL for stdout
552 if (output_path && strlen(output_path) > 0 && strcmp(output_path, "-") != 0) {
553 // User provided explicit path - use it as-is
554 config_path = output_path;
555 } else {
556 // No path or "-" means stdout
557 config_path = NULL;
558 }
559
560 // Create config with default options
561 asciichat_error_t result = config_create_default(config_path);
562 if (result != ASCIICHAT_OK) {
564 if (HAS_ERRNO(&err_ctx)) {
565 log_error("Error creating config: %s", err_ctx.context_message);
566 } else {
567 log_error("Failed to create config file");
568 }
569 action_exit(ERROR_CONFIG);
570 }
571
572 if (config_path) {
573 log_info("Created default config file at: %s", config_path);
574 } else {
575 log_info("Config written to stdout");
576 }
577 action_exit(0);
578}
579
580// ============================================================================
581// Shell Completions Action
582// ============================================================================
583
584void action_completions(const char *shell_name, const char *output_path) {
585 if (!shell_name || strlen(shell_name) == 0) {
586 log_error("--completions requires shell name (bash, fish, zsh, powershell)");
587 action_exit(ERROR_USAGE);
588 }
589
591 if (format == COMPLETION_FORMAT_UNKNOWN) {
592 log_error("Unknown shell '%s' (supported: bash, fish, zsh, powershell)", shell_name);
593 action_exit(ERROR_USAGE);
594 }
595
596 FILE *output = stdout;
597 bool should_close = false;
598
599 // Determine output: use provided path if given and not "-", otherwise stdout
600 if (output_path && strlen(output_path) > 0 && strcmp(output_path, "-") != 0) {
601 // Check if file already exists and prompt for confirmation
602 struct stat st;
603 if (stat(output_path, &st) == 0) {
604 // File exists - ask user if they want to overwrite
605 log_plain("Completions file already exists: %s", output_path);
606
608 safe_snprintf(question, sizeof(question), "File already exists: %s\n\nOverwrite", output_path);
610 bool overwrite =
611 ui_notice_confirm_kind(UI_PROMPT_COMPLETION_OVERWRITE, UI_NOTICE_WARNING, question, 30); // Default to No
612 if (!overwrite) {
613 log_plain("Completions generation cancelled.");
615 action_exit(errno_peek_since(prompt_scope, &context) && context.code == ERROR_PROMPT_TIMEOUT
617 : 0);
618 }
619
620 log_plain("Overwriting existing completions file...");
621 }
622
623 output = platform_fopen("file_stream", output_path, "w");
624 if (!output) {
625 log_error("Failed to open %s for writing", output_path);
626 action_exit(ERROR_FILE_OPERATION);
627 }
628 should_close = true;
629 }
630
631 asciichat_error_t result = completions_generate_for_shell(format, output);
632
633 if (should_close) {
634 fclose(output);
635 }
636
637 if (result != ASCIICHAT_OK) {
638 log_error("Failed to generate %s completions", completions_get_shell_name(format));
639 action_exit(ERROR_USAGE);
640 }
641
642 // Silently exit - completions are written (either to file or stdout)
643 action_exit(0);
644}
645
652static void execute_check_update(void) {
653 printf("Checking for updates...\n");
654
657
658 if (err != ASCIICHAT_OK) {
660 if (HAS_ERRNO(&ctx)) {
661 fprintf(stderr, "Update check failed: %s\n", ctx.context_message);
662 }
663 action_exit(1);
664 }
665
666 // Display results
667 if (result.update_available) {
669 update_check_format_notification(&result, notification, sizeof(notification));
670 printf("\n%s\n\n", notification);
671 } else {
672 printf("\nYou are already on the latest version: %s (%.8s)\n\n", result.current_version, result.current_sha);
673 }
674
675 action_exit(0);
676}
677
678// ============================================================================
679// Deferred Action Execution
680// ============================================================================
681
684
685 switch (action) {
686 case ACTION_NONE:
687 // No action to execute
688 break;
689
691 execute_list_webcams();
692 break;
693
695 execute_list_microphones();
696 break;
697
699 execute_list_speakers();
700 break;
701
703 execute_show_capabilities();
704 break;
705
707 execute_check_update();
708 break;
709
710 default:
711 log_warn("Unknown deferred action: %d", action);
712 break;
713 }
714}
715
716option_action_fn options_action_callback(const char *name, bool immediate) {
717 static const struct {
718 const char *name;
719 option_action_fn callback;
720 option_action_fn early_callback;
721 } actions[] = {
722 {"list-webcams", action_list_webcams, action_list_webcams},
724 {"list-speakers", action_list_speakers, action_list_speakers},
727 };
728 if (!name)
729 return NULL;
730 for (size_t i = 0; i < sizeof(actions) / sizeof(actions[0]); ++i) {
731 if (strcmp(name, actions[i].name) == 0)
732 return immediate ? actions[i].early_callback : actions[i].callback;
733 }
734 return NULL;
735}
option_action_fn options_action_callback(const char *name, bool immediate)
Definition actions.c:716
void action_check_update_immediate(void)
Execute update check immediately (for early binary-level execution).
Definition actions.c:323
#define OPTIONS_PARSING_ACTIONS_BITMASK_BUFFER_SIZE
Definition actions.c:16
#define OPTIONS_PARSING_ACTIONS_NOTIFICATION_BUFFER_SIZE
Definition actions.c:17
const action_args_t * actions_get_args(void)
Get the arguments for the deferred action.
Definition actions.c:107
void action_check_update(void)
Check for updates and display results.
Definition actions.c:341
deferred_action_t actions_get_deferred(void)
Get the deferred action (if any) that was set.
Definition actions.c:103
void actions_defer(deferred_action_t action, const action_args_t *args)
Set which action to defer until options are fully initialized.
Definition actions.c:86
bool has_action
Definition actions.c:79
void action_help_acds(void)
Show discovery-service mode help and exit.
Definition actions.c:474
void action_show_capabilities(void)
Show terminal capabilities and exit.
Definition actions.c:310
void action_help_server(void)
Show server mode help and exit.
Definition actions.c:459
void action_help_discovery(void)
Show discovery mode help and exit.
Definition actions.c:479
action_args_t args
Definition actions.c:78
#define OPTIONS_PARSING_ACTIONS_COLORS_BUFFER_SIZE
Definition actions.c:15
void action_create_manpage(const char *output_path)
Generate man page template from options builder.
Definition actions.c:488
void action_completions(const char *shell_name, const char *output_path)
Generate shell completions and output to stdout or file.
Definition actions.c:584
deferred_action_t action
Definition actions.c:77
void action_list_microphones(void)
List available microphone devices and exit.
Definition actions.c:156
void action_show_version(void)
Show version information and exit.
Definition actions.c:441
#define OPTIONS_PARSING_ACTIONS_SIZE_BUFFER_SIZE
Definition actions.c:14
void action_help_mirror(void)
Show mirror mode help and exit.
Definition actions.c:469
void action_create_config(const char *output_path)
Create default configuration file and exit.
Definition actions.c:537
void action_list_webcams(void)
List available webcam devices and exit.
Definition actions.c:118
void action_list_speakers(void)
List available speaker devices and exit.
Definition actions.c:194
void action_help_client(void)
Show client mode help and exit.
Definition actions.c:464
void actions_execute_deferred(void)
Execute the deferred action (if any).
Definition actions.c:682
void action_show_capabilities_immediate(void)
Execute show capabilities immediately (for early binary-level execution).
Definition actions.c:239
#define OPTIONS_PARSING_ACTIONS_QUESTION_BUFFER_SIZE
Definition actions.c:18
Action option callbacks for ascii-chat.
deferred_action_t
action args is intentionally a small, concrete record. Fields such as output_path,...
Definition actions.h:18
@ ACTION_CHECK_UPDATE
Definition actions.h:24
@ ACTION_LIST_SPEAKERS
Definition actions.h:22
@ ACTION_LIST_MICROPHONES
Definition actions.h:21
@ ACTION_NONE
Definition actions.h:19
@ ACTION_LIST_WEBCAMS
Definition actions.h:20
@ ACTION_SHOW_CAPABILITIES
Definition actions.h:23
void(* option_action_fn)(void)
Definition actions.h:222
bool errno_peek_since(asciichat_errno_scope_t scope, asciichat_error_context_t *out)
asciichat_errno_scope_t errno_checkpoint(void)
Synchronized per-thread pending error stacks and value snapshots. SET_ERRNO pushes,...
#define HAS_ERRNO(context)
⚙️ Common definitions, error codes, macros, and types shared throughout the application
completion_format_t completions_parse_shell_name(const char *shell_name)
Parse shell name string to completion format.
Definition completions.c:58
asciichat_error_t completions_generate_for_shell(completion_format_t format, FILE *output)
Generate shell completions and write to output stream.
Definition completions.c:24
const char * completions_get_shell_name(completion_format_t format)
Get human-readable shell name for format.
Definition completions.c:43
Auto-generated shell completions from options registry.
completion_format_t
Supported shell completion formats.
Definition completions.h:66
@ COMPLETION_FORMAT_UNKNOWN
Definition completions.h:71
unsigned int height
Definition fft.c:23
unsigned int width
Definition fft.c:23
void audio_free_device_list(audio_device_info_t *devices)
Free device list allocated by audio_list_input_devices/audio_list_output_devices.
asciichat_error_t audio_list_input_devices(audio_device_info_t **out_devices, unsigned int *out_count)
List available audio input devices (microphones).
asciichat_error_t audio_list_output_devices(audio_device_info_t **out_devices, unsigned int *out_count)
List available audio output devices (speakers).
unsigned int uint32_t
Definition common.h:62
asciichat_error_t config_create_default(const char *config_path)
Create default configuration file with all default values.
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ERROR_PROMPT_TIMEOUT
@ ERROR_AUDIO
Definition error_codes.h:62
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_CONFIG
Definition error_codes.h:52
@ ERROR_FILE_OPERATION
@ ERROR_USAGE
Definition error_codes.h:48
@ ERROR_WEBCAM
Definition error_codes.h:59
#define log_warn(...)
Log a WARN message.
Definition log/log.h:621
log_color_t
Color enum for logging - indexes into color arrays.
Definition log/log.h:147
#define log_error(...)
Log an ERROR message.
Definition log/log.h:634
#define log_plain_stdout(...)
Plain logging to stdout with newline.
Definition log/log.h:679
#define log_info(...)
Log an INFO message.
Definition log/log.h:608
#define log_plain(...)
Plain logging - writes to both log file and stderr without timestamps or log levels.
Definition log/log.h:665
@ LOG_COLOR_GREY
Definition log/log.h:154
@ LOG_COLOR_ERROR
Definition log/log.h:152
@ LOG_COLOR_DEBUG
Definition log/log.h:149
@ LOG_COLOR_INFO
Definition log/log.h:150
@ LOG_COLOR_WARN
Definition log/log.h:151
asciichat_error_t update_check_perform(update_check_result_t *result)
Check for updates from GitHub releases API.
void update_check_format_notification(const update_check_result_t *result, char *buffer, size_t buffer_size)
Format update notification message.
struct options_state options_t
Immutable, RCU-published snapshot of the application's runtime configuration.
const options_t * options_get(void)
Get pointer to current options struct (lock-free, thread-safe).
Definition rcu.c:511
void usage(FILE *desc, asciichat_mode_t mode)
Print usage information for a specific mode.
#define options_terminal_settings()
Definition options.h:1296
asciichat_error_t options_config_generate_manpage_merged(const options_config_t *config, const char *program_name, const char *mode_name, const char *output_path, const char *brief_description)
Generate merged man page template preserving manual content.
Definition manpage.c:688
@ MODE_CLIENT
Client mode - network client options.
Definition options.h:921
@ MODE_DISCOVERY_SERVICE
Discovery server mode - session management and WebRTC signaling.
Definition options.h:923
@ MODE_SERVER
Server mode - network server options.
Definition options.h:920
@ MODE_MIRROR
Mirror mode - local webcam viewing (no network).
Definition options.h:922
@ MODE_DISCOVERY
Discovery mode - participant that can dynamically become host.
Definition options.h:924
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Platform-safe snprintf wrapper.
const char * colored_string(log_color_t color, const char *text)
Build a colored string for terminal output.
Definition string.c:284
asciichat_error_t webcam_list_devices(webcam_device_info_t **out_devices, unsigned int *out_count)
Enumerate available webcam devices.
void webcam_free_device_list(webcam_device_info_t *devices)
Free device list returned by webcam_list_devices().
🔊 Audio Capture and Playback Interface for ascii-chat
📝 Logging API with multiple log levels and terminal output control
Man page template generation from options builder.
bool ui_notice_confirm_kind(ui_prompt_kind_t kind, ui_notice_severity_t severity, const char *text, unsigned timeout_seconds)
Definition notice.c:498
@ UI_NOTICE_WARNING
Definition notice.h:11
TOML configuration file support for ascii-chat.
📂 Path Manipulation Utilities
options_config_t * options_preset_unified(const char *program_name, const char *description)
Build unified options config with ALL options (binary + all modes).
Definition presets.c:58
Preset option configurations for ascii-chat modes.
static bool size_t index
Definition queries.h:8
asciichat_error_t config_schema_build_from_configs(const options_config_t **configs, size_t num_configs)
Build schema dynamically from options builder configs.
Definition schema.c:252
Schema metadata for config file options.
🔤 String Manipulation and Shell Escaping Utilities
Action argument structure.
Definition actions.h:32
When code needs to work with asciichat errno snapshot, it keeps total, copied here instead of scatter...
Audio device information structure.
Immutable parsing tables produced from an options builder.
Definition builder.h:414
int height
Terminal height in characters (int for OPTION_TYPE_INT compat).
Definition options.h:997
int width
Terminal width in characters (int for OPTION_TYPE_INT compat).
Definition options.h:996
update check result keeps the values that move through the subsystem: update_available,...
char current_sha[41]
Current commit SHA.
char current_version[64]
Current version string.
bool update_available
True if newer version exists.
Webcam device information structure.
Definition webcam.h:88
🔄 Update checker for GitHub releases with DNS connectivity test and cache