| /* |
| * Copyright (c) 2018 Nordic Semiconductor ASA |
| * Copyright (c) 2015 Runtime Inc |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdio.h> |
| #include <stdbool.h> |
| #include <errno.h> |
| |
| #include "settings/settings.h" |
| #include "settings_priv.h" |
| #include <zephyr/types.h> |
| |
| #include <logging/log.h> |
| LOG_MODULE_REGISTER(settings, CONFIG_SETTINGS_LOG_LEVEL); |
| |
| sys_slist_t settings_handlers; |
| |
| static u8_t settings_cmd_inited; |
| |
| static struct settings_handler *settings_handler_lookup(char *name); |
| void settings_store_init(void); |
| |
| void settings_init(void) |
| { |
| if (!settings_cmd_inited) { |
| sys_slist_init(&settings_handlers); |
| settings_store_init(); |
| |
| settings_cmd_inited = 1U; |
| } |
| } |
| |
| int settings_register(struct settings_handler *handler) |
| { |
| if (settings_handler_lookup(handler->name)) { |
| return -EEXIST; |
| } |
| sys_slist_prepend(&settings_handlers, &handler->node); |
| |
| return 0; |
| } |
| |
| /* |
| * Find settings_handler based on name. |
| */ |
| static struct settings_handler *settings_handler_lookup(char *name) |
| { |
| struct settings_handler *ch; |
| |
| SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) { |
| if (!strcmp(name, ch->name)) { |
| return ch; |
| } |
| } |
| return NULL; |
| } |
| |
| /* |
| * Separate string into argv array. |
| */ |
| int settings_parse_name(char *name, int *name_argc, char *name_argv[]) |
| { |
| int i = 0; |
| |
| while (name) { |
| name_argv[i++] = name; |
| |
| while (1) { |
| if (*name == '\0') { |
| name = NULL; |
| break; |
| } |
| |
| if (*name == *SETTINGS_NAME_SEPARATOR) { |
| *name = '\0'; |
| name++; |
| break; |
| } |
| name++; |
| } |
| } |
| |
| *name_argc = i; |
| |
| return 0; |
| } |
| |
| static struct settings_handler *settings_parse_and_lookup(char *name, |
| int *name_argc, |
| char *name_argv[]) |
| { |
| int rc; |
| |
| rc = settings_parse_name(name, name_argc, name_argv); |
| if (rc) { |
| return NULL; |
| } |
| return settings_handler_lookup(name_argv[0]); |
| } |
| |
| int settings_set_value_priv(char *name, void *val_read_cb_ctx, off_t off, |
| u8_t is_runtime) |
| { |
| int name_argc; |
| char *name_argv[SETTINGS_MAX_DIR_DEPTH]; |
| struct settings_handler *ch; |
| struct read_value_cb_ctx value_ctx; |
| |
| ch = settings_parse_and_lookup(name, &name_argc, name_argv); |
| if (!ch) { |
| return -EINVAL; |
| } |
| |
| value_ctx.read_cb_ctx = val_read_cb_ctx; |
| value_ctx.off = off; |
| value_ctx.runtime = is_runtime; |
| |
| return ch->h_set(name_argc - 1, &name_argv[1], (void *)&value_ctx); |
| } |
| |
| /* API */ |
| int settings_set_value(char *name, void *val_str, size_t len) |
| { |
| struct runtime_value_ctx rt_ctx; |
| |
| rt_ctx.p_value = val_str; |
| rt_ctx.size = len; |
| |
| return settings_set_value_priv(name, &rt_ctx, 0, 1); |
| } |
| |
| /* API */ |
| int settings_val_read_cb(void *value_ctx, void *buf, size_t len) |
| { |
| struct read_value_cb_ctx *value_context = value_ctx; |
| size_t len_read; |
| int rc; |
| struct runtime_value_ctx *rt_ctx; |
| |
| if (value_context->runtime) { |
| rt_ctx = value_context->read_cb_ctx; |
| len_read = MIN(len, rt_ctx->size); |
| memcpy(buf, rt_ctx->p_value, len_read); |
| return len_read; |
| } else { |
| rc = settings_line_val_read(value_context->off, 0, buf, len, |
| &len_read, |
| value_context->read_cb_ctx); |
| } |
| |
| if (rc == 0) { |
| return len_read; |
| } |
| |
| return rc; |
| } |
| |
| /* API */ |
| size_t settings_val_get_len_cb(void *value_ctx) |
| { |
| struct read_value_cb_ctx *value_context = value_ctx; |
| struct runtime_value_ctx *rt_ctx; |
| |
| if (value_context->runtime) { |
| rt_ctx = value_context->read_cb_ctx; |
| return rt_ctx->size; |
| } else { |
| return settings_line_val_get_len(value_context->off, |
| value_context->read_cb_ctx); |
| } |
| } |
| |
| /* |
| * Get value in printable string form. If value is not string, the value |
| * will be filled in *buf. |
| * Return value will be pointer to beginning of that buffer, |
| * except for string it will pointer to beginning of string. |
| */ |
| int settings_get_value(char *name, char *buf, int buf_len) |
| { |
| int name_argc; |
| char *name_argv[SETTINGS_MAX_DIR_DEPTH]; |
| struct settings_handler *ch; |
| |
| ch = settings_parse_and_lookup(name, &name_argc, name_argv); |
| if (!ch) { |
| return -EINVAL; |
| } |
| |
| if (!ch->h_get) { |
| return -EINVAL; |
| } |
| return ch->h_get(name_argc - 1, &name_argv[1], buf, buf_len); |
| } |
| |
| int settings_commit(char *name) |
| { |
| int name_argc; |
| char *name_argv[SETTINGS_MAX_DIR_DEPTH]; |
| struct settings_handler *ch; |
| int rc; |
| int rc2; |
| |
| if (name) { |
| ch = settings_parse_and_lookup(name, &name_argc, name_argv); |
| if (!ch) { |
| return -EINVAL; |
| } |
| if (ch->h_commit) { |
| return ch->h_commit(); |
| } else { |
| return 0; |
| } |
| } else { |
| rc = 0; |
| SYS_SLIST_FOR_EACH_CONTAINER(&settings_handlers, ch, node) { |
| if (ch->h_commit) { |
| rc2 = ch->h_commit(); |
| if (!rc) { |
| rc = rc2; |
| } |
| } |
| } |
| return rc; |
| } |
| } |