DeterministicESPAsyncWebServer v6.28.0
Zero-allocation, bounded-execution async HTTP server for ESP32
Loading...
Searching...
No Matches
config_io.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file config_io.cpp
6 * @brief Schema-driven config export / restore over the config store.
7 *
8 * Delegates value storage to services/config_store (which has a host in-memory
9 * backend), so the whole serialize / parse round-trip is host-tested.
10 */
11
13
14#if DETWS_ENABLE_CONFIG_IO
15
18#include <stdio.h>
19#include <string.h>
20
21namespace
22{
23constexpr size_t VAL_MAX = 128; // export/import value field cap
24constexpr size_t KEY_MAX = 16; // NVS key cap (15 + null)
25
26// Look up a key in the schema; write its DetwsCfgType to *out and return true, or return false if absent.
27bool field_type(const DetwsCfgField *fields, size_t n, const char *key, DetwsCfgType *out)
28{
29 for (size_t i = 0; i < n; i++)
30 if (fields[i].key && strcmp(fields[i].key, key) == 0)
31 {
32 *out = fields[i].type;
33 return true;
34 }
35 return false;
36}
37
38// Append "<key>=<val>\n" to out at *pos, overflow-safe. Returns false on overflow.
39bool append_kv(char *out, size_t cap, size_t *pos, const char *key, const char *val)
40{
41 size_t kn = strnlen(key, cap + 1), vn = strnlen(val, cap + 1);
42 size_t need = kn + 1 + vn + 1; // key '=' val '\n'
43 if (*pos + need >= cap) // keep room for the null terminator
44 return false;
45 memcpy(out + *pos, key, kn);
46 *pos += kn;
47 out[(*pos)++] = '=';
48 memcpy(out + *pos, val, vn);
49 *pos += vn;
50 out[(*pos)++] = '\n';
51 out[*pos] = '\0';
52 return true;
53}
54} // namespace
55
56int detws_config_export(const char *ns, const DetwsCfgField *fields, size_t n, char *out, size_t cap)
57{
58 if (!out || cap == 0)
59 return 0;
60 out[0] = '\0';
61 if (!fields || !detws_config_begin(ns))
62 return 0;
63
64 size_t pos = 0;
65 for (size_t i = 0; i < n; i++)
66 {
67 char val[VAL_MAX];
68 if (fields[i].type == DetwsCfgType::DETWS_CFG_U32)
69 snprintf(val, sizeof(val), "%u", (unsigned)detws_config_get_u32(fields[i].key, 0));
70 else
71 detws_config_get_str(fields[i].key, val, sizeof(val), "");
72
73 if (!append_kv(out, cap, &pos, fields[i].key, val))
74 {
75 out[0] = '\0';
76 return 0; // fail closed on overflow
77 }
78 }
79 return (int)pos;
80}
81
82// Set one key=val pair against the field table; returns true iff a matching field was found and its
83// setter accepted the value. Extracted so the import loop stays flat (one dispatch, no nested type switch).
84static bool config_apply_field(const DetwsCfgField *fields, size_t n, const char *key, const char *val)
85{
86 DetwsCfgType t;
87 if (!field_type(fields, n, key, &t))
88 return false;
89 if (t == DetwsCfgType::DETWS_CFG_U32)
90 return detws_config_set_u32(key, (uint32_t)det_strtoul(val, nullptr));
91 if (t == DetwsCfgType::DETWS_CFG_STR)
92 return detws_config_set_str(key, val);
93 return false;
94}
95
96int detws_config_import(const char *ns, const DetwsCfgField *fields, size_t n, const char *text, size_t len)
97{
98 if (!text || !fields || !detws_config_begin(ns))
99 return 0;
100
101 int count = 0;
102 size_t i = 0;
103 while (i < len)
104 {
105 // Find the end of this line.
106 size_t eol = i;
107 while (eol < len && text[eol] != '\n')
108 eol++;
109
110 // Split the line on the first '='.
111 size_t eq = i;
112 while (eq < eol && text[eq] != '=')
113 eq++;
114
115 if (eq >= eol) // no '=' on this line
116 {
117 i = eol + 1;
118 continue;
119 }
120 size_t klen = eq - i;
121 size_t vlen = eol - (eq + 1);
122 if (klen > 0 && klen < KEY_MAX && vlen < VAL_MAX)
123 {
124 char key[KEY_MAX];
125 char val[VAL_MAX];
126 memcpy(key, text + i, klen);
127 key[klen] = '\0';
128 memcpy(val, text + eq + 1, vlen);
129 val[vlen] = '\0';
130 if (config_apply_field(fields, n, key, val))
131 count++;
132 }
133 i = eol + 1; // skip the newline
134 }
135 return count;
136}
137
138#endif // DETWS_ENABLE_CONFIG_IO
Schema-driven config export / restore (DETWS_ENABLE_CONFIG_IO).
Typed NVS configuration store (DETWS_ENABLE_CONFIG_STORE).
Tiny no-stdlib base-10 number parsers (strtol/strtoul/strtof replacements).
unsigned long det_strtoul(const char *s, const char **end)
Parse a base-10 unsigned long; sets end past the digits (or to s).
Definition numparse.h:50