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

Reply via email to