242 {
243
244 if (g_dynamic_schema) {
245 SAFE_FREE(g_dynamic_schema);
246 g_dynamic_schema = NULL;
247 g_dynamic_schema_count = 0;
248 }
249
250
251 if (g_dynamic_strings) {
252 for (size_t i = 0; i < g_dynamic_strings_count; i++) {
253 SAFE_FREE(g_dynamic_strings[i]);
254 }
255 SAFE_FREE(g_dynamic_strings);
256 g_dynamic_strings = NULL;
257 g_dynamic_strings_count = 0;
258 g_dynamic_strings_capacity = 0;
259 }
260
261
262
263 const option_descriptor_t *all_descriptors[256] = {0};
264 size_t descriptor_count = 0;
265
266
267 for (size_t cfg_idx = 0; cfg_idx < num_configs; cfg_idx++) {
268 const options_config_t *config = configs[cfg_idx];
269 if (!config) {
270 continue;
271 }
272
273 for (size_t i = 0; i < config->num_descriptors && descriptor_count < 256; i++) {
274 const option_descriptor_t *desc = &config->descriptors[i];
275 if (should_add_descriptor(desc, all_descriptors, descriptor_count)) {
276 all_descriptors[descriptor_count++] = desc;
277 }
278 }
279 }
280
281
282 g_dynamic_schema = SAFE_MALLOC(descriptor_count * sizeof(config_option_metadata_t), config_option_metadata_t *);
283 if (!g_dynamic_schema) {
284 return SET_ERRNO(ERROR_MEMORY, "Failed to allocate dynamic schema");
285 }
286
287
288 g_dynamic_schema_count = 0;
289 char toml_key_buffer[BUFFER_SIZE_SMALL];
290 char cli_flag_buffer[256];
291 char category_buffer[64];
292
293 for (size_t i = 0; i < descriptor_count; i++) {
294 const option_descriptor_t *desc = all_descriptors[i];
295 if (!desc || !desc->long_name || !desc->group) {
296 continue;
297 }
298
299 config_option_metadata_t *meta = &g_dynamic_schema[g_dynamic_schema_count++];
300
301 memset(meta, 0, sizeof(*meta));
302
303
304 meta->type = desc->type;
305
306
307 SAFE_STRNCPY(category_buffer, desc->group, sizeof(category_buffer) - 1);
308 category_buffer[sizeof(category_buffer) - 1] = '\0';
309 str_tolower(category_buffer);
310
311
312
313 if (!generate_toml_key(category_buffer, desc->long_name, toml_key_buffer, sizeof(toml_key_buffer))) {
314 g_dynamic_schema_count--;
315 continue;
316 }
317
318
319 meta->toml_key = store_dynamic_string(toml_key_buffer);
320 meta->category = store_dynamic_string(category_buffer);
321 if (!meta->toml_key || !meta->category) {
322
323 g_dynamic_schema_count--;
324 continue;
325 }
326
327
328 if (generate_cli_flag(desc->long_name, cli_flag_buffer, sizeof(cli_flag_buffer))) {
329 meta->cli_flag = store_dynamic_string(cli_flag_buffer);
330 if (!meta->cli_flag) {
331
332 }
333 } else {
334 meta->cli_flag = NULL;
335 }
336
337
338 meta->context = OPTION_CONTEXT_BOTH;
339 meta->field_offset = desc->offset;
340 meta->field_size = get_field_size(meta->type, desc->offset);
341
342 meta->validate_fn = desc->validate;
343
344 meta->parse_fn = desc->parse_fn;
345 meta->description = desc->help_text;
346
347
348
349 meta->mode_bitmask = desc->mode_bitmask;
350
351
352 meta->mode_default_getter = desc->mode_default_getter;
353
354
355
356 memset(&meta->constraints, 0, sizeof(meta->constraints));
357
358 if (desc && desc->metadata.numeric_range.max > 0) {
359 meta->constraints.int_range.min = desc->metadata.numeric_range.min;
360 meta->constraints.int_range.max = desc->metadata.numeric_range.max;
361 }
362 }
363
364 g_schema_built = true;
365 return ASCIICHAT_OK;
366}