From: Roland Gaudig <roland.gau...@weidmueller.com> Add format string "fmt" operation to the setexpr command which converts the input value according the format string specification and stores the result into the variable named name.
Signed-off-by: Roland Gaudig <roland.gau...@weidmueller.com> --- cmd/setexpr.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 1 deletion(-) diff --git a/cmd/setexpr.c b/cmd/setexpr.c index e828be3970..b69cbab3dd 100644 --- a/cmd/setexpr.c +++ b/cmd/setexpr.c @@ -11,12 +11,15 @@ #include <common.h> #include <config.h> #include <command.h> +#include <ctype.h> #include <env.h> #include <log.h> #include <malloc.h> #include <mapmem.h> #include <linux/sizes.h> +#define MAX_STR_LEN 128 + /** * struct expr_arg: Holds an argument to an expression * @@ -361,6 +364,95 @@ static int regex_sub_var(const char *name, const char *r, const char *s, } #endif +/** + * setexpr_fmt_spec_search() - Search for format specifier + * + * This function searches the intput string for the first occurrence of a + * format specifier which starts with a %. Double % are ignored. + * + * @format: C like format string to search + * @return: Pointer to found format specifier, NULL in case none is found + */ +static char *setexpr_fmt_spec_search(char *format) +{ + while (*format != '\0') { + if (*format == '%') { + switch (*(format + 1)) { + case '%': + /* found '%%', not a format specifier, skip. */ + format++; + break; + case '\0': + /* found '%' at end of string, + * incomplete format specifier. + */ + return NULL; + default: + /* looks like a format specifier */ + return format; + } + } + format++; + } + + return NULL; +} + +/** + * setexpr_fmt() - Implements the setexpr <name> fmt command + * + * This function implements the setexpr <name> fmt <format> <value> command. + * + * @name: Name of the environment variable to save the evaluated expression in + * @format: C like format string + * @value: Input value to be converted + * @return: 0 if OK, 1 on error + */ +static int setexpr_fmt(char *name, char *format, char *value) +{ + struct expr_arg aval; + int data_size; + char str[MAX_STR_LEN]; + int fmt_len = strlen(format); + + if (fmt_len < 2) { + printf("Error: missing format string"); + return CMD_RET_FAILURE; + } + + /* Search format specifier */ + char *first = setexpr_fmt_spec_search(format); + + /* Exactly one format specifier is required */ + if (!first || setexpr_fmt_spec_search(first + 1)) { + printf("Error: exactly one format specifier is required\n"); + return CMD_RET_FAILURE; + } + + /* Search type field of format specifier */ + while (*first && !isalpha(*first)) + first++; + + /* Test if type is supported */ + if (!strchr("diouxX", *first)) { + printf("Error: format type not supported\n"); + return CMD_RET_FAILURE; + } + + data_size = cmd_get_data_size(value, 4); + + if (data_size == CMD_DATA_SIZE_STR) { + free(aval.sval); + return CMD_RET_FAILURE; + } + + if (get_arg(value, data_size, &aval)) + return CMD_RET_FAILURE; + + snprintf(str, sizeof(str), format, aval.ival); + return env_set(name, str); +} + static int do_setexpr(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -374,6 +466,7 @@ static int do_setexpr(struct cmd_tbl *cmdtp, int flag, int argc, * 3 : setexpr name value * 5 : setexpr name val1 op val2 * setexpr name [g]sub r s + * setexpr name fmt format value * 6 : setexpr name [g]sub r s t */ @@ -398,6 +491,10 @@ static int do_setexpr(struct cmd_tbl *cmdtp, int flag, int argc, return ret; } + /* format string assignment: "setexpr name fmt %d value" */ + if (strcmp(argv[2], "fmt") == 0) + return setexpr_fmt(argv[1], argv[3], argv[4]); + /* 5 or 6 args (6 args only with [g]sub) */ #ifdef CONFIG_REGEX /* @@ -504,7 +601,10 @@ U_BOOT_CMD( " size argument is only meaningful if value1 and/or value2 are\n" " memory addresses (*)\n" "setexpr[.b, .w, .l] name [*]value\n" - " - load a value into a variable" + " - load a value into a variable\n" + "setexpr name fmt <format> [*]value\n" + " - set environment variable 'name' to the result of the C like\n" + " format string evaluation of [*]value.\n" #ifdef CONFIG_REGEX "\n" "setexpr name gsub r s [t]\n" -- 2.25.1