ascii-chat 0.8.38
Real-time terminal-based video chat with ASCII art conversion
Loading...
Searching...
No Matches
core.c
Go to the documentation of this file.
1
14#include <ascii-chat/options/registry/common.h>
15#include <ascii-chat/options/registry/core.h>
16#include <ascii-chat/options/registry.h>
17#include <string.h>
18
24 static bool initialized = false;
25 if (initialized) {
26 return;
27 }
28
29 size_t offset = 0;
30 for (int i = 0; g_category_builders[i].entries != NULL; i++) {
31 // Count entries in this category (until sentinel terminator)
32 size_t count = 0;
33 for (const registry_entry_t *e = g_category_builders[i].entries; e->long_name != NULL; e++) {
34 count++;
35 }
36
37 // Copy category entries (count already excludes sentinel)
38 if (offset + count <= 2048) {
39 memcpy(&g_options_registry[offset], g_category_builders[i].entries, count * sizeof(registry_entry_t));
40 offset += count;
41 }
42 }
43
44 // Add final null terminator
45 if (offset < 2048) {
46 g_options_registry[offset] = (registry_entry_t){.long_name = NULL,
47 .short_name = '\0',
48 .type = OPTION_TYPE_BOOL,
49 .offset = 0,
50 .default_value = NULL,
51 .default_value_size = 0,
52 .help_text = NULL,
53 .group = NULL,
54 .required = false,
55 .env_var_name = NULL,
56 .validate_fn = NULL,
57 .parse_fn = NULL,
58 .owns_memory = false,
59 .optional_arg = false,
60 .mode_bitmask = OPTION_MODE_NONE,
61 .metadata = {0}};
62 }
63
64 initialized = true;
65}
66
71asciichat_error_t registry_validate_unique_options(void) {
72 // Check for duplicate long options
73 for (size_t i = 0; g_options_registry[i].long_name != NULL; i++) {
74 const char *long_name = g_options_registry[i].long_name;
75 if (!long_name || long_name[0] == '\0') {
76 continue; // Skip empty long names
77 }
78
79 for (size_t j = i + 1; g_options_registry[j].long_name != NULL; j++) {
80 if (strcmp(g_options_registry[j].long_name, long_name) == 0) {
81 return SET_ERRNO(ERROR_CONFIG, "Duplicate long option '--%s' at registry indices %zu and %zu", long_name, i, j);
82 }
83 }
84 }
85
86 // Check for duplicate short options (skip if '\0')
87 for (size_t i = 0; g_options_registry[i].long_name != NULL; i++) {
88 char short_name = g_options_registry[i].short_name;
89 if (short_name == '\0') {
90 continue; // Skip if no short option
91 }
92
93 for (size_t j = i + 1; g_options_registry[j].long_name != NULL; j++) {
94 if (g_options_registry[j].short_name == short_name) {
95 return SET_ERRNO(ERROR_CONFIG,
96 "Duplicate short option '-%c' for '--%s' and '--%s' at registry indices %zu and %zu",
97 short_name, g_options_registry[i].long_name, g_options_registry[j].long_name, i, j);
98 }
99 }
100 }
101
102 return ASCIICHAT_OK;
103}
104
110
111 if (g_registry_size == 0) {
112 for (size_t i = 0; g_options_registry[i].long_name != NULL; i++) {
114 }
115 // Validate that all options have unique short and long names
117 // DEPRECATED: Metadata is now initialized compile-time in registry entries
118 // registry_populate_metadata_for_critical_options();
120 }
121}
122
127const registry_entry_t *registry_find_entry_by_name(const char *long_name) {
128 if (!long_name) {
129 SET_ERRNO(ERROR_INVALID_PARAM, "Long name is NULL");
130 return NULL;
131 }
132
133 for (size_t i = 0; g_options_registry[i].long_name != NULL; i++) {
134 if (strcmp(g_options_registry[i].long_name, long_name) == 0) {
135 return &g_options_registry[i];
136 }
137 }
138 return NULL;
139}
140
145const registry_entry_t *registry_find_entry_by_short(char short_name) {
146 if (short_name == '\0') {
147 return NULL;
148 }
149
150 for (size_t i = 0; g_options_registry[i].long_name != NULL; i++) {
151 if (g_options_registry[i].short_name == short_name) {
152 return &g_options_registry[i];
153 }
154 }
155 return NULL;
156}
157
161option_descriptor_t registry_entry_to_descriptor(const registry_entry_t *entry) {
162 option_descriptor_t desc = {0};
163 if (entry) {
164 desc.long_name = entry->long_name;
165 desc.short_name = entry->short_name;
166 desc.type = entry->type;
167 desc.offset = entry->offset;
168 desc.help_text = entry->help_text;
169 desc.group = entry->group;
170 desc.arg_placeholder = entry->arg_placeholder;
171 desc.hide_from_mode_help = false;
172 // Hide discovery service options from binary-level help (they're for discovery-service mode only)
173 desc.hide_from_binary_help = (entry->mode_bitmask == OPTION_MODE_DISCOVERY_SVC);
174 desc.default_value = entry->default_value;
175 desc.required = entry->required;
176 desc.env_var_name = entry->env_var_name;
177 desc.validate = entry->validate_fn;
178 desc.parse_fn = entry->parse_fn;
179 desc.action_fn = NULL;
180 desc.owns_memory = entry->owns_memory;
181 desc.optional_arg = entry->optional_arg;
182 desc.mode_bitmask = entry->mode_bitmask;
183 desc.metadata = entry->metadata;
184 desc.mode_default_getter = entry->mode_default_getter;
185 }
186 return desc;
187}
188
200bool registry_entry_applies_to_mode(const registry_entry_t *entry, asciichat_mode_t mode, bool for_binary_help) {
201 if (!entry) {
202 SET_ERRNO(ERROR_INVALID_PARAM, "Entry is NULL");
203 return false;
204 }
205
206 // Hardcoded list of options to hide from binary help (matches builder.c line 752)
207 // These are options that have hide_from_binary_help=true set in builder.c
208 const char *hidden_from_binary[] = {NULL};
209
210 // When for_binary_help is true (i.e., for 'ascii-chat --help'),
211 // we want to show all options that apply to any mode, plus binary-level options.
212 if (for_binary_help) {
213 // Check if this option is explicitly hidden from binary help
214 for (int i = 0; hidden_from_binary[i] != NULL; i++) {
215 if (strcmp(entry->long_name, hidden_from_binary[i]) == 0) {
216 return false; // Hidden from binary help
217 }
218 }
219
220 // An option applies if its mode_bitmask has any bit set for any valid mode.
221 // OPTION_MODE_ALL is a bitmask of all modes (including OPTION_MODE_BINARY).
222 return (entry->mode_bitmask & OPTION_MODE_ALL) != 0;
223 }
224
225 // For mode-specific help, show only options for that mode.
226 // Do not show binary options here unless it also specifically applies to the mode.
227 if (mode < 0 || mode > MODE_DISCOVERY) {
228 return false;
229 }
230 option_mode_bitmask_t mode_bit = (1 << mode);
231
232 // Check if it's a binary option. If so, only show if it also explicitly applies to this mode.
233 if ((entry->mode_bitmask & OPTION_MODE_BINARY) && !(entry->mode_bitmask & mode_bit)) {
234 return false; // Binary options not shown in mode-specific help unless also mode-specific
235 }
236
237 return (entry->mode_bitmask & mode_bit) != 0;
238}
option_descriptor_t registry_entry_to_descriptor(const registry_entry_t *entry)
Convert registry entry to option descriptor.
Definition core.c:161
void registry_init_from_builders(void)
Initialize registry from category builders Populates g_options_registry by concatenating all category...
Definition core.c:23
asciichat_error_t registry_validate_unique_options(void)
Validate that no short or long options appear more than once in the registry.
Definition core.c:71
const registry_entry_t * registry_find_entry_by_name(const char *long_name)
Get a registry entry by long name.
Definition core.c:127
bool registry_entry_applies_to_mode(const registry_entry_t *entry, asciichat_mode_t mode, bool for_binary_help)
Check if an option applies to the given mode for display purposes.
Definition core.c:200
const registry_entry_t * registry_find_entry_by_short(char short_name)
Get a registry entry by short name.
Definition core.c:145
void registry_init_size(void)
Initialize registry size and metadata.
Definition core.c:108
bool initialized
Definition mmap.c:38
registry_entry_t g_options_registry[2048]
Definition registry.c:35
bool g_metadata_populated
Definition registry.c:38
category_builder_t g_category_builders[]
Definition registry.c:26
size_t g_registry_size
Definition registry.c:37