| 109 | } |
| 110 | |
| 111 | void cbm_ui_config_load(cbm_ui_config_t *cfg) { |
| 112 | if (!cfg) { |
| 113 | return; |
| 114 | } |
| 115 | cfg->ui_enabled = CBM_UI_DEFAULT_ENABLED; |
| 116 | cfg->ui_port = CBM_UI_DEFAULT_PORT; |
| 117 | |
| 118 | char path[CBM_SZ_1K]; |
| 119 | cbm_ui_config_path(path, (int)sizeof(path)); |
| 120 | |
| 121 | size_t length = 0; |
| 122 | bool opened = false; |
| 123 | char *buffer = config_read_file(path, &length, &opened); |
| 124 | if (!opened) { |
| 125 | /* No config file — auto-enable UI if binary has embedded assets */ |
| 126 | if (CBM_EMBEDDED_FILE_COUNT > 0) { |
| 127 | cfg->ui_enabled = true; |
| 128 | } |
| 129 | return; |
| 130 | } |
| 131 | if (!buffer) { |
| 132 | return; |
| 133 | } |
| 134 | |
| 135 | yyjson_doc *doc = yyjson_read(buffer, length, 0); |
| 136 | free(buffer); |
| 137 | if (!doc) { |
| 138 | cbm_log_warn("ui.config.corrupt", "path", path); |
| 139 | return; /* corrupt JSON → defaults */ |
| 140 | } |
| 141 | |
| 142 | yyjson_val *root = yyjson_doc_get_root(doc); |
| 143 | if (!yyjson_is_obj(root)) { |
| 144 | yyjson_doc_free(doc); |
| 145 | return; |
| 146 | } |
| 147 | |
| 148 | yyjson_val *v_enabled = yyjson_obj_get(root, "ui_enabled"); |
| 149 | if (yyjson_is_bool(v_enabled)) { |
| 150 | cfg->ui_enabled = yyjson_get_bool(v_enabled); |
| 151 | } |
| 152 | |
| 153 | yyjson_val *v_port = yyjson_obj_get(root, "ui_port"); |
| 154 | if (yyjson_is_int(v_port)) { |
| 155 | int64_t port = yyjson_get_int(v_port); |
| 156 | if (port > 0 && port <= 65535) { |
| 157 | cfg->ui_port = (int)port; |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | yyjson_doc_free(doc); |
| 162 | } |
| 163 | |
| 164 | /* ── Save ────────────────────────────────────────────────────── */ |
| 165 |
no test coverage detected