This is an automated email from the ASF dual-hosted git repository. ccollins pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
The following commit(s) were added to refs/heads/master by this push: new 6f459fc util/scfg: Simple config lib on top of sys/config 6f459fc is described below commit 6f459fcb9f42d886768c6dcf81159337b5d2fcd8 Author: Christopher Collins <ccoll...@apache.org> AuthorDate: Fri Feb 7 11:19:51 2020 -0800 util/scfg: Simple config lib on top of sys/config --- util/scfg/include/scfg/scfg.h | 101 +++++++++++++++++ util/scfg/pkg.yml | 23 ++++ util/scfg/src/scfg.c | 257 ++++++++++++++++++++++++++++++++++++++++++ util/scfg/syscfg.yml | 24 ++++ 4 files changed, 405 insertions(+) diff --git a/util/scfg/include/scfg/scfg.h b/util/scfg/include/scfg/scfg.h new file mode 100644 index 0000000..caa64b7 --- /dev/null +++ b/util/scfg/include/scfg/scfg.h @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_SCFG_ +#define H_SCFG_ + +#include "config/config.h" + +struct scfg_setting { + /** The name of the setting. */ + const char *name; + + /** Points to the RAM replica of the setting value. */ + void *val; + + /** + * Only needed for string settings. Indicates the maximum length this + * setting's value can by. + */ + int max_len; + + /** This setting's data data. One of the CONF_[...] constants. */ + uint8_t type; + + /** + * Whether this setting contains private data. If true, the value is + * hidden in config dump output. + */ + bool private; +}; + +struct scfg_group { + /*** Public */ + /** This array must be terminated with an `{ 0 }` entry. */ + const struct scfg_setting *settings; + + /*** Private */ + struct conf_handler handler; +}; + +/** + * Persists a single setting. + * + * @param group The group that the setting belongs to. + * @param setting The setting to save. + * + * @return 0 on success; SYS_E[...] code on failure. + */ +int scfg_save_setting(const struct scfg_group *group, + const struct scfg_setting *setting); + +/** + * Persists the setting with the specified name. + * + * @param group The group that the setting belongs to. + * @param setting_name The name of the setting to save. + * + * @return 0 on success; SYS_E[...] code on failure. + */ +int scfg_save_name(const struct scfg_group *group, const char *setting_name); + +/** + * Persists the setting whose value is stored in the specified variable. The + * specified value address should be the same one that was specified in the + * `scfg_setting` definition. + * + * @param group The group that the setting belongs to. + * @param val The address of the setting's value variable. + * + * @return 0 on success; SYS_E[...] code on failure. + */ +int scfg_save_val(const struct scfg_group *group, const void *val); + +/** + * Registers a group of configuration settings. The group's public members + * must be populated before this function is called. + * + * @param group The group to register + * @param name The name of the settings group. + * + * @return 0 on success; SYS_E[...] code on failure. + */ +int scfg_register(struct scfg_group *group, char *name); + +#endif diff --git a/util/scfg/pkg.yml b/util/scfg/pkg.yml new file mode 100644 index 0000000..b0299f7 --- /dev/null +++ b/util/scfg/pkg.yml @@ -0,0 +1,23 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: util/scfg +pkg.description: Simple persistent configuration +pkg.deps: + - "@apache-mynewt-core/sys/config" diff --git a/util/scfg/src/scfg.c b/util/scfg/src/scfg.c new file mode 100644 index 0000000..347d5d7 --- /dev/null +++ b/util/scfg/src/scfg.c @@ -0,0 +1,257 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include "os/mynewt.h" +#include "scfg/scfg.h" + +/* "+ 1" to account for null terminator. */ +#define SCFG_SETTING_ID_BUF_SIZE (MYNEWT_VAL(SCFG_SETTING_ID_MAX_LEN) + 1) + +#define SCFG_NUM_STR_BUF_SIZE (sizeof "18446744073709551615") + +#define SCFG_FOREACH_SETTING(group, s) \ + for (s = (group)->settings; s->name != NULL; s++) + +static void +scfg_setting_id(const char *group_name, const char *setting_name, char *buf) +{ + int setting_len; + int group_len; + int off; + + group_len = strlen(group_name); + setting_len = strlen(setting_name); + + /* <group>/<setting> */ + assert(group_len + 1 + setting_len < SCFG_SETTING_ID_BUF_SIZE); + + off = 0; + + memcpy(&buf[off], group_name, group_len); + off += group_len; + + buf[off] = '/'; + off++; + + memcpy(&buf[off], setting_name, setting_len); + off += setting_len; + + buf[off] = '\0'; +} + +static struct scfg_setting * +scfg_find_setting_by_name(const struct scfg_group *group, + const char *setting_name) +{ + const struct scfg_setting *setting; + + SCFG_FOREACH_SETTING(group, setting) { + if (strcmp(setting->name, setting_name) == 0) { + /* Cast away const. */ + return (struct scfg_setting *)setting; + } + } + + return NULL; +} + +static struct scfg_setting * +scfg_find_setting_by_val(const struct scfg_group *group, const void *val) +{ + const struct scfg_setting *setting; + + SCFG_FOREACH_SETTING(group, setting) { + if (setting->val == val) { + /* Cast away const. */ + return (struct scfg_setting *)setting; + } + } + + return NULL; +} + +/** + * Conf get handler. Converts a setting's underlying variable to a string. + */ +static char * +scfg_handler_get(int argc, char **argv, char *buf, int max_len, void *arg) +{ + const struct scfg_setting *setting; + struct scfg_group *group; + + group = arg; + + if (argc < 1) { + return NULL; + } + + setting = scfg_find_setting_by_name(group, argv[0]); + if (setting == NULL) { + return NULL; + } + + return conf_str_from_value(setting->type, setting->val, buf, max_len); +} + +/** + * Conf set handler. Converts from a string-representation and writes the + * result to the setting's underlying variable. + */ +static int +scfg_handler_set(int argc, char **argv, char *val, void *arg) +{ + const struct scfg_setting *setting; + struct scfg_group *group; + int rc; + + group = arg; + + if (argc < 1) { + return SYS_EINVAL; + } + + setting = scfg_find_setting_by_name(group, argv[0]); + if (setting == NULL) { + return SYS_ENOENT; + } + + rc = conf_value_from_str(val, setting->type, setting->val, + setting->max_len); + if (rc != 0) { + return os_error_to_sys(rc); + } + + return 0; +} + +static int +scfg_handler_export(void (*func)(char *name, char *val), + enum conf_export_tgt tgt, void *arg) +{ + const struct scfg_setting *setting; + struct scfg_group *group; + char id_buf[SCFG_SETTING_ID_BUF_SIZE]; + char val_buf[SCFG_NUM_STR_BUF_SIZE]; + char *val; + + group = arg; + + SCFG_FOREACH_SETTING(group, setting) { + scfg_setting_id(group->handler.ch_name, setting->name, id_buf); + if (setting->private) { + val = "<set>"; + } else { + val = conf_str_from_value(setting->type, setting->val, + val_buf, sizeof val_buf); + } + func(id_buf, val); + } + + return 0; +} + +int +scfg_save_setting(const struct scfg_group *group, + const struct scfg_setting *setting) +{ + char id_buf[SCFG_SETTING_ID_BUF_SIZE]; + char val_buf[SCFG_NUM_STR_BUF_SIZE]; + char *val; + int rc; + + val = conf_str_from_value(setting->type, setting->val, + val_buf, sizeof val_buf); + if (val == NULL) { + return SYS_EUNKNOWN; + } + + scfg_setting_id(group->handler.ch_name, setting->name, id_buf); + + rc = conf_save_one(id_buf, val); + if (rc != 0) { + return os_error_to_sys(rc); + } + + return 0; +} + +int +scfg_save_name(const struct scfg_group *group, const char *setting_name) +{ + const struct scfg_setting *setting; + + setting = scfg_find_setting_by_name(group, setting_name); + if (setting == NULL) { + return SYS_ENOENT; + } + + return scfg_save_setting(group, setting); +} + +int +scfg_save_val(const struct scfg_group *group, const void *val) +{ + const struct scfg_setting *setting; + + setting = scfg_find_setting_by_val(group, val); + if (setting == NULL) { + return SYS_ENOENT; + } + + return scfg_save_setting(group, setting); +} + +int +scfg_register(struct scfg_group *group, char *name) +{ + const struct scfg_setting *setting; + int rc; + + SCFG_FOREACH_SETTING(group, setting) { + switch (setting->type) { + case CONF_INT8: + case CONF_INT16: + case CONF_INT32: + case CONF_INT64: + case CONF_STRING: + case CONF_BOOL: + break; + + default: + /* We don't know how to (de)serialize the other data types. */ + return SYS_EINVAL; + } + } + + group->handler = (struct conf_handler) { + .ch_name = name, + .ch_get_ext = scfg_handler_get, + .ch_set_ext = scfg_handler_set, + .ch_export_ext = scfg_handler_export, + .ch_arg = group, + .ch_ext = true, + }; + + rc = conf_register(&group->handler); + if (rc != 0) { + return os_error_to_sys(rc); + } + + return 0; +} diff --git a/util/scfg/syscfg.yml b/util/scfg/syscfg.yml new file mode 100644 index 0000000..e4326d1 --- /dev/null +++ b/util/scfg/syscfg.yml @@ -0,0 +1,24 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +syscfg.defs: + SCFG_SETTING_ID_MAX_LEN: + description: > + The maximum length of a setting ID. A setting ID has the form + `<group>/<name>`. Note: This is the number of *text* characters; + the null terminator is accounted for separately. + value: 64