ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
options/json.c
Go to the documentation of this file.
3#include <ascii-chat/options/builder/internal.h>
4#include <math.h>
5#include <string.h>
6
7static const char *json_type(const registry_entry_t *entry) {
8 if (entry->type == OPTION_TYPE_BOOL)
9 return "boolean";
10 if (entry->type == OPTION_TYPE_INT || !strcmp(entry->long_name, "zalgo"))
11 return "integer";
12 if (entry->type == OPTION_TYPE_DOUBLE || (entry->type == OPTION_TYPE_CALLBACK && !entry->metadata.enum_values &&
13 entry->metadata.numeric_range.max && strcmp(entry->long_name, "seek")))
14 return "number";
15 return "string";
16}
17static asciichat_error_t validate_value(const registry_entry_t *e, yyjson_val *v) {
18 if (!strcmp(e->long_name, "test-pattern")) {
19 if (yyjson_is_bool(v) || (yyjson_is_int(v) && yyjson_get_sint(v) >= 0 && yyjson_get_sint(v) <= 1) ||
20 (yyjson_is_str(v) && (!strcmp(yyjson_get_str(v), "0") || !strcmp(yyjson_get_str(v), "1"))))
21 return ASCIICHAT_OK;
22 return SET_ERRNO(ERROR_INVALID_PARAM, "test-pattern must be boolean, 0 or 1");
23 }
24 const char *type = json_type(e);
25 bool ok = (!strcmp(type, "boolean") && yyjson_is_bool(v)) || (!strcmp(type, "integer") && yyjson_is_int(v)) ||
26 (!strcmp(type, "number") && yyjson_is_num(v)) || (!strcmp(type, "string") && yyjson_is_str(v)) ||
27 (!strcmp(e->long_name, "seek") && yyjson_is_num(v));
28 if (!ok)
29 return SET_ERRNO(ERROR_INVALID_PARAM, "Wrong type for %s", e->long_name);
30 if (yyjson_is_str(v) && (yyjson_get_len(v) > 4096 || strlen(yyjson_get_str(v)) != yyjson_get_len(v)))
31 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid or oversized option %s", e->long_name);
32 if (yyjson_is_num(v) && !isfinite(yyjson_get_num(v)))
33 return SET_ERRNO(ERROR_INVALID_PARAM, "Non-finite option");
34 return ASCIICHAT_OK;
35}
36
37yyjson_mut_val *options_json_schema_for_option(yyjson_mut_doc *d, const char *name) {
38 if (!d || !name) {
39 SET_ERRNO(ERROR_INVALID_PARAM, "Missing option schema argument");
40 return NULL;
41 }
43 if (!e || e->type == OPTION_TYPE_ACTION) {
44 SET_ERRNO(ERROR_INVALID_PARAM, "Unknown value option: %s", name);
45 return NULL;
46 }
47 yyjson_mut_val *v = yyjson_mut_obj(d);
48 yyjson_mut_obj_add_str(d, v, "type", json_type(e));
49 yyjson_mut_obj_add_str(d, v, "description", e->help_text);
50 if (e->metadata.enum_values) {
51 yyjson_mut_val *values = yyjson_mut_arr(d);
52 for (size_t i = 0; e->metadata.enum_values[i]; i++)
53 yyjson_mut_arr_add_str(d, values, e->metadata.enum_values[i]);
54 yyjson_mut_obj_add_val(d, v, "enum", values);
55 }
56 if (!strcmp(name, "test-pattern")) {
57 yyjson_mut_obj_remove_str(v, "type");
58 yyjson_mut_obj_remove_str(v, "enum");
59 yyjson_mut_val *values = yyjson_mut_arr(d);
60 yyjson_mut_arr_add_bool(d, values, true);
61 yyjson_mut_arr_add_bool(d, values, false);
62 yyjson_mut_arr_add_int(d, values, 0);
63 yyjson_mut_arr_add_int(d, values, 1);
64 yyjson_mut_arr_add_str(d, values, "0");
65 yyjson_mut_arr_add_str(d, values, "1");
66 yyjson_mut_obj_add_val(d, v, "enum", values);
67 }
68 if (!strcmp(name, "seek")) {
69 yyjson_mut_obj_remove_str(v, "type");
70 yyjson_mut_val *types = yyjson_mut_arr(d);
71 yyjson_mut_arr_add_str(d, types, "string");
72 yyjson_mut_arr_add_str(d, types, "number");
73 yyjson_mut_obj_add_val(d, v, "type", types);
74 }
75 return v;
76}
77
78asciichat_error_t options_json_parse_value(const char *name, yyjson_val *v, char *output, size_t output_size,
79 bool *omitted) {
80 if (!name || !v || !output || !output_size || !omitted)
81 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing JSON option argument");
82 *omitted = false;
84 if (!e || e->type < 0 || e->type >= NUM_OPTION_TYPES || e->type == OPTION_TYPE_ACTION || e->owns_memory)
85 return SET_ERRNO(ERROR_INVALID_PARAM, "Unsupported value option: %s", name);
86 asciichat_error_t err = validate_value(e, v);
87 if (err != ASCIICHAT_OK)
88 return err;
89 if (yyjson_is_str(v)) {
90 size_t len = yyjson_get_len(v);
91 if (len >= output_size || (e->type == OPTION_TYPE_STRING && e->default_value_size && len >= e->default_value_size))
92 return SET_ERRNO(ERROR_INVALID_PARAM, "Option value too long: %s", name);
93 SAFE_STRNCPY(output, yyjson_get_str(v), output_size);
94 } else if (yyjson_is_bool(v)) {
95 SAFE_SNPRINTF(output, output_size, "%s", yyjson_get_bool(v) ? "true" : "false");
96 } else {
97 SAFE_SNPRINTF(output, output_size, "%.17g", yyjson_get_num(v));
98 }
99 if (!strcmp(name, "test-pattern") && yyjson_is_bool(v)) {
100 if (!yyjson_get_bool(v)) {
101 *omitted = true;
102 return ASCIICHAT_OK;
103 }
104 SAFE_SNPRINTF(output, output_size, "0");
105 }
106 // Use the same registry descriptor and handlers as options_config_parse().
108 options_t *scratch = SAFE_CALLOC(1, sizeof(*scratch), options_t *);
109 err = g_builder_handlers[descriptor.type].apply_cli((char *)scratch + descriptor.offset, output, &descriptor);
110 SAFE_FREE(scratch);
111 return err;
112}
#define SET_ERRNO(code,...)
@ OPTION_TYPE_INT
Integer value (–count 42).
Definition builder.h:168
@ OPTION_TYPE_DOUBLE
Floating point (–ratio 1.5).
Definition builder.h:170
@ OPTION_TYPE_STRING
String value (–name foo).
Definition builder.h:169
@ OPTION_TYPE_ACTION
Action that executes and may exit (–list-webcams, etc.).
Definition builder.h:172
@ OPTION_TYPE_CALLBACK
Custom parser function.
Definition builder.h:171
@ OPTION_TYPE_BOOL
Boolean flag (–flag, no value).
Definition builder.h:167
option_descriptor_t registry_entry_to_descriptor(const registry_entry_t *entry)
Convert registry entry to option descriptor.
Definition core.c:161
const registry_entry_t * registry_find_entry_by_name(const char *long_name)
Get a registry entry by long name.
Definition core.c:127
Internal helper functions and data for registry implementation.
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:423
#define SAFE_FREE(ptr)
Definition common.h:377
#define SAFE_SNPRINTF(buffer, buffer_size,...)
Definition common.h:507
#define SAFE_CALLOC(count, size, cast)
Definition common.h:275
asciichat_error_t
Error and exit codes - unified status values (0-255).
Definition error_codes.h:44
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
struct options_state options_t
Immutable, RCU-published snapshot of the application's runtime configuration.
Registry-backed JSON schemas and conversion through CLI option handlers.
🔢 Mathematical Utility Functions
yyjson_mut_val * options_json_schema_for_option(yyjson_mut_doc *d, const char *name)
asciichat_error_t options_json_parse_value(const char *name, yyjson_val *v, char *output, size_t output_size, bool *omitted)
🔤 String Manipulation and Shell Escaping Utilities
The complete registry entry for one command-line/configuration option.
Definition builder.h:249
size_t offset
offsetof(struct, field) - where to store value
Definition builder.h:256
option_type_t type
Value type.
Definition builder.h:255
int max
Maximum value (or 0 if no limit).
Definition builder.h:208
struct option_metadata_t::@061372117173071240020206164036331043262170062306 numeric_range
const char ** enum_values
Enum value strings (null-terminated, e.g., {"auto", "none", "16", "256", "truecolor",...
Definition builder.h:200
Registry entry - stores option definition with mode bitmask and metadata.
option_type_t type
bool owns_memory
const char * long_name
size_t default_value_size
option_metadata_t metadata
Enum values, numeric ranges, examples.
const char * help_text