[PATCH 1/3] cmd: setexpr: add fmt format string operation

Roland Gaudig roland.gaudig-oss at weidmueller.com
Mon Jun 28 17:17:48 CEST 2021


From: Roland Gaudig <roland.gaudig at 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.gaudig at 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



More information about the U-Boot mailing list