+ strcpy(data, t);
+
+ if (s == NULL)
+ nlen = 0;
+ else
+ nlen = strlen(s);
+
+ for (loop = 0;; loop++) {
+ struct cap caps[slre.num_caps + 2];
+ char nbuf[SLRE_PATSZ];
+ const char *old;
+ char *np;
+ int i, olen;
+
+ (void) memset(caps, 0, sizeof(caps));
+
+ res = slre_match(&slre, datap, len, caps);
+
+ debug("Result: %d\n", res);
+
+ for (i = 0; i < slre.num_caps; i++) {
+ if (caps[i].len > 0) {
+ debug("Substring %d: [%.*s]\n", i,
+ caps[i].len, caps[i].ptr);
+ }
+ }
+
+ if (res == 0) {
+ if (loop == 0) {
+ printf("%s: No match\n", t);
+ return 1;
+ } else {
+ break;
+ }
+ }
+
+ debug("## MATCH ## %s\n", data);
+
+ if (s == NULL) {
+ printf("%s=%s\n", name, t);
+ return 1;
+ }
+
+ old = caps[0].ptr;
+ olen = caps[0].len;
+
+ if (nlen + 1 >= SLRE_PATSZ) {
+ printf("## error: pattern buffer overflow: have %d, need %d\n",
+ SLRE_BUFSZ, nlen + 1);
+ return 1;
+ }
+ strcpy(nbuf, s);
+
+ debug("## SUBST(1) ## %s\n", nbuf);
+
+ /*
+ * Handle back references
+ *
+ * Support for \0 ... \9, where \0 is the
+ * whole matched pattern (similar to &).
+ *
+ * Implementation is a bit simpleminded as
+ * backrefs are substituted sequentially, one
+ * by one. This will lead to somewhat
+ * unexpected results if the replacement
+ * strings contain any \N strings then then
+ * may get substitued, too. We accept this
+ * restriction for the sake of simplicity.
+ */
+ for (i = 0; i < 10; ++i) {
+ char backref[2] = {
+ '\\',
+ '0',
+ };
+
+ if (caps[i].len == 0)
+ break;
+
+ backref[1] += i;
+
+ debug("## BACKREF %d: replace \"%.*s\" by \"%.*s\" in \"%s\"\n",
+ i,
+ 2, backref,
+ caps[i].len, caps[i].ptr,
+ nbuf);
+
+ for (np = nbuf;;) {
+ char *p = memstr(np, nlen, backref, 2);
+
+ if (p == NULL)
+ break;
+
+ np = substitute(np, &nlen,
+ SLRE_PATSZ,
+ backref, 2,
+ caps[i].ptr, caps[i].len);
+
+ if (np == NULL)
+ return 1;
+ }
+ }
+ debug("## SUBST(2) ## %s\n", nbuf);
+
+ datap = substitute(datap, &len, SLRE_BUFSZ,
+ old, olen,
+ nbuf, nlen);
+
+ if (datap == NULL)
+ return 1;
+
+ debug("## REMAINDER: %s\n", datap);
+
+ debug("## RESULT: %s\n", data);
+
+ if (!global)
+ break;
+ }
+ debug("## FINAL (now setenv()) : %s\n", data);
+
+ printf("%s=%s\n", name, data);
+
+ return setenv(name, data);
+}
+#endif
+
+static int do_setexpr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+ ulong a, b;
+ ulong value;
+ int w;
+
+ /*
+ * We take 3, 5, or 6 arguments:
+ * 3 : setexpr name value
+ * 5 : setexpr name val1 op val2
+ * setexpr name [g]sub r s
+ * 6 : setexpr name [g]sub r s t
+ */
+
+ /* > 6 already tested by max command args */
+ if ((argc < 3) || (argc == 4))
+ return CMD_RET_USAGE;
+
+ w = cmd_get_data_size(argv[0], 4);
+
+ a = get_arg(argv[2], w);
+
+ /* plain assignment: "setexpr name value" */
+ if (argc == 3) {
+ setenv_hex(argv[1], a);
+ return 0;
+ }
+
+ /* 5 or 6 args (6 args only with [g]sub) */
+#ifdef CONFIG_REGEX
+ /*
+ * rexep handling: "setexpr name [g]sub r s [t]"
+ * with 5 args, "t" will be NULL
+ */
+ if (strcmp(argv[2], "gsub") == 0)
+ return regex_sub(argv[1], argv[3], argv[4], argv[5], 1);
+
+ if (strcmp(argv[2], "sub") == 0)
+ return regex_sub(argv[1], argv[3], argv[4], argv[5], 0);
+#endif
+
+ /* standard operators: "setexpr name val1 op val2" */
+ if (argc != 5)
+ return CMD_RET_USAGE;
+
+ if (strlen(argv[3]) != 1)
+ return CMD_RET_USAGE;
+
+ b = get_arg(argv[4], w);