This is the single source of truth for all options. Each option has a mode_bitmask indicating which modes it applies to. The config includes all options, and validation happens after parsing based on detected mode.
51 {
53 if (!b) {
54 SET_ERRNO(ERROR_MEMORY, "Failed to create options builder");
55 return NULL;
56 }
57
58 b->program_name = program_name ? program_name : "ascii-chat";
59 b->description = description ? description : "Video chat in your terminal";
60
61
63 if (err != ASCIICHAT_OK) {
65 SET_ERRNO(err, "Failed to add all options to builder");
66 return NULL;
67 }
68
69
70
71
72
73
74
75 static char session_buf1[SESSION_STRING_BUFFER_SIZE];
76 static char session_buf2[SESSION_STRING_BUFFER_SIZE];
77 static char session_buf3[SESSION_STRING_BUFFER_SIZE];
78 static char session_buf4[SESSION_STRING_BUFFER_SIZE];
79 static char session_buf5[SESSION_STRING_BUFFER_SIZE];
80 static char session_buf6[SESSION_STRING_BUFFER_SIZE];
81 static char session_buf7[SESSION_STRING_BUFFER_SIZE];
82 static char session_buf8[SESSION_STRING_BUFFER_SIZE];
83 static char session_buf9[SESSION_STRING_BUFFER_SIZE];
84 static char session_buf10[SESSION_STRING_BUFFER_SIZE];
85
86
87 char *example_session_string1 = "adjective-noun-noun";
88 char *example_session_string2 = "adjective-noun-noun";
89 char *example_session_string3 = "adjective-noun-noun";
90 char *example_session_string4 = "adjective-noun-noun";
91 char *example_session_string5 = "adjective-noun-noun";
92 char *example_session_string6 = "adjective-noun-noun";
93 char *example_session_string7 = "adjective-noun-noun";
94 char *example_session_string8 = "adjective-noun-noun";
95 char *example_session_string9 = "adjective-noun-noun";
96 char *example_session_string10 = "adjective-noun-noun";
97
98
100 if (session_buf1[0] != '\0') {
101 example_session_string1 = session_buf1;
102 }
104 if (session_buf2[0] != '\0') {
105 example_session_string2 = session_buf2;
106 }
108 if (session_buf3[0] != '\0') {
109 example_session_string3 = session_buf3;
110 }
112 if (session_buf4[0] != '\0') {
113 example_session_string4 = session_buf4;
114 }
116 if (session_buf5[0] != '\0') {
117 example_session_string5 = session_buf5;
118 }
120 if (session_buf6[0] != '\0') {
121 example_session_string6 = session_buf6;
122 }
124 if (session_buf7[0] != '\0') {
125 example_session_string7 = session_buf7;
126 }
128 if (session_buf8[0] != '\0') {
129 example_session_string8 = session_buf8;
130 }
132 if (session_buf9[0] != '\0') {
133 example_session_string9 = session_buf9;
134 }
136 if (session_buf10[0] != '\0') {
137 example_session_string10 = session_buf10;
138 }
139
140
141
142 static char example_buf1[SESSION_STRING_BUFFER_SIZE];
143 static char example_buf2[SESSION_STRING_BUFFER_SIZE];
144 static char example_buf3[SESSION_STRING_BUFFER_SIZE];
145 static char example_buf4[SESSION_STRING_BUFFER_SIZE];
146 static char example_buf5[SESSION_STRING_BUFFER_SIZE];
147 static char example_buf6[SESSION_STRING_BUFFER_SIZE];
148 static char example_buf7[SESSION_STRING_BUFFER_SIZE];
149 static char example_buf8[SESSION_STRING_BUFFER_SIZE];
150 static char example_buf9[SESSION_STRING_BUFFER_SIZE];
151 static char example_buf10[SESSION_STRING_BUFFER_SIZE];
152
153 safe_snprintf(example_buf1,
sizeof(example_buf1),
"%s", example_session_string1);
154 safe_snprintf(example_buf2,
sizeof(example_buf2),
"%s --discovery-service discovery.example.com",
155 example_session_string2);
156 safe_snprintf(example_buf3,
sizeof(example_buf3),
"%s -f video.mp4", example_session_string3);
157 safe_snprintf(example_buf4,
sizeof(example_buf4),
"%s --url 'https://youtu.be/7ynHVGCehoM'", example_session_string4);
158 safe_snprintf(example_buf5,
sizeof(example_buf5),
"%s -f '-'", example_session_string5);
159 safe_snprintf(example_buf6,
sizeof(example_buf6),
"%s --palette-chars '@%%#*+=-:. '", example_session_string6);
160 safe_snprintf(example_buf7,
sizeof(example_buf7),
"%s", example_session_string7);
161 safe_snprintf(example_buf8,
sizeof(example_buf8),
"%s", example_session_string8);
162 safe_snprintf(example_buf9,
sizeof(example_buf9),
"%s", example_session_string9);
163 safe_snprintf(example_buf10,
sizeof(example_buf10),
"%s --matrix --color-filter rainbow", example_session_string10);
164
165
166 static const char *client_examples[] = {"localhost",
167 "ascii-chat.com",
168 "0.0.0.0",
169 "::",
170 "192.168.1.1:8080",
171 "[2001:db8::42]:27224",
172 "233.27.48.203:27224",
173 "62fb:759e:2bce:21d7:9e5d:13f8:3c11:5084:27224",
174 "ws://example.com:8080",
175 "wss://secure.example.com:443"};
176
177
178 static const char *discovery_examples[] = {"(empty) start new session", (const char *)example_buf7,
179 (const char *)example_buf8, (const char *)example_buf9,
180 (const char *)example_buf10};
182 b, "session-string", "(optional) Random three words in format adjective-noun-noun that connect you to a call.",
183 false, "POSITIONAL ARGUMENTS", discovery_examples, ARRAY_SIZE(discovery_examples), OPTION_MODE_DISCOVERY,
185
186
187 static const char *server_examples[] = {"localhost",
188 "ascii-chat.com",
189 "0.0.0.0",
190 "::",
191 "234.50.188.236",
192 "9631:54e7:5b5c:80dc:0f62:1f01:7ccf:5512",
193 "105.137.19.11 3a08:7276:ccb4:7b31:e934:5330:9b3a:9598",
194 "::1 192.168.1.100"};
196 "(optional) 0-2 addresses for a server to bind to, one IPv4 and the other IPv6.",
197 false, "POSITIONAL ARGUMENTS", server_examples, ARRAY_SIZE(server_examples),
199
201 "POSITIONAL ARGUMENTS", client_examples, ARRAY_SIZE(client_examples),
203
204
209 "Start server (can specify 0-2 bind addresses, one IPv4 and the other IPv6)");
213 "Start discovery service (can specify 0-2 bind addresses, one IPv4 and the other IPv6)");
214
215
220 true);
223 "Join session and stream media from stdin (cat file.mov | ascii-chat ... -f '-')", true);
225 true);
226
227
231 "0.0.0.0 ::", "Start on all IPv4 and IPv6 interfaces (dual-stack)", false);
233
234
236 "Start with identity key and discovery registration", false);
237
238
240 "Stream from YouTube URL (also supports RTSP, HTTP, and HTTPS URLs)", false);
242 "Stream Ludwig from videogames on Twitch", false);
245 "Custom palette characters to use. UTF-8 is allowed.", false);
247 b, OPTION_MODE_CLIENT_LIKE, "--snapshot",
248 "Print ascii art for --snapshot-delay's value of seconds then print the last frame and exit. "
249 "In snapshot mode, --width, --height, and --color are NOT autodetected when piping stdin in or redirecting "
250 "output.",
251 false);
253 "Apply cyan color filter and cool palette", false);
254
255
258 false);
260 "Connect with custom display options", false);
261
262
264 b, OPTION_MODE_MIRROR, NULL,
265 "View the webcam or files or URLs as ASCII art. Like client mode but without network connectivity or a server.",
266 false);
269 "View webcam with green monochromatic color filter", false);
271 "Matrix rain effect with rainbow colors cycling over 3.5s", false);
273 "Stream media from stdin (cat file.gif | ascii-chat mirror -f '-')", false);
275 "Stream .avi from stdin, looped, seeking to 00:30", true);
277 "Start playback at exactly 22:10 (also works with --url)", false);
279 "Print a single frame from a YouTube video at exactly 5:12 and exit", false);
281 "Capture single ASCII frame to clipboard (macOS) and file", false);
283 "View ASCII frame from clipboard (macOS)", true);
284
285
287 "Enforce identity verification for all parties", false);
288
289
294
295
297 "Available in ascii-chat client, mirror, and discovery modes. "
298 "While rendering, press '?' to display a keyboard shortcuts help menu showing:\n"
299 " - Available keybindings (?, Space, arrows, m, c, f, r)\n"
300 " - Current settings (volume, color mode, audio status, etc.)",
301 OPTION_MODE_CLIENT_LIKE);
302
303
305 b, "ENVIRONMENT",
306 "All command-line flags that accept values have corresponding environment variables.\n"
307 " Format: ASCII_CHAT_<FLAG_NAME> where FLAG_NAME is uppercase with hyphens replaced by underscores\n"
308 " Example: --color-filter maps to ASCII_CHAT_COLOR_FILTER\n"
309 "\n"
310 " Configuration precedence (lowest to highest):\n"
311 " 1. Config file values (~/.ascii-chat/config.toml)\n"
312 " 2. Environment variables (ASCII_CHAT_*)\n"
313 " 3. Command-line flags (--flag-name)\n"
314 "\n"
315 " Additional environment variables are documented in the ascii-chat(1) man page.",
316 OPTION_MODE_ALL);
317
318
319
320
322 "Option --url cannot be used with --file (--url takes priority)");
324 b, "url", "loop", "Option --url cannot be used with --loop (network streams cannot be looped)");
325
327
329 "Cannot use --no-compress with --compression-level");
330
332 "Cannot use both --encode-audio and --no-encode-audio");
333
335 "Option --snapshot-delay requires --snapshot");
337
340 return config;
341}
void options_builder_add_usage(options_builder_t *builder, const char *mode, const char *positional, bool show_options, const char *description)
void options_builder_add_example(options_builder_t *builder, uint32_t mode_bitmask, const char *args, const char *description, bool owns_args)
void options_builder_add_dependency_requires(options_builder_t *builder, const char *option_name, const char *depends_on, const char *error_message)
void options_builder_add_positional(options_builder_t *builder, const char *name, const char *help_text, bool required, const char *section_heading, const char **examples, size_t num_examples, option_mode_bitmask_t mode_bitmask, int(*parse_fn)(const char *arg, void *config, char **remaining, int num_remaining, char **error_msg))
void options_builder_add_dependency_conflicts(options_builder_t *builder, const char *option_name, const char *conflicts_with, const char *error_message)
void options_builder_add_mode(options_builder_t *builder, const char *name, const char *description)
void options_builder_add_custom_section(options_builder_t *builder, const char *heading, const char *content, option_mode_bitmask_t mode_bitmask)
void options_builder_destroy(options_builder_t *builder)
options_config_t * options_builder_build(options_builder_t *builder)
void options_builder_add_example_utility(options_builder_t *builder, uint32_t mode_bitmask, const char *args, const char *description, bool is_utility_command)
Add an example with utility command support.
options_builder_t * options_builder_create(size_t struct_size)
asciichat_error_t acds_string_generate(char *output, size_t output_size)
int parse_server_bind_address(const char *arg, void *config, char **remaining, int num_remaining, char **error_msg)
Parse server bind address positional argument.
int parse_client_address(const char *arg, void *config, char **remaining, int num_remaining, char **error_msg)
Parse client address positional argument.
asciichat_error_t options_registry_add_all_to_builder(options_builder_t *builder)
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.