12e192b24SSimon Glass /* 22e192b24SSimon Glass * Copyright 2008 Freescale Semiconductor, Inc. 32e192b24SSimon Glass * Copyright 2013 Wolfgang Denk <wd@denx.de> 42e192b24SSimon Glass * 52e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 62e192b24SSimon Glass */ 72e192b24SSimon Glass 82e192b24SSimon Glass /* 92e192b24SSimon Glass * This file provides a shell like 'expr' function to return. 102e192b24SSimon Glass */ 112e192b24SSimon Glass 122e192b24SSimon Glass #include <common.h> 132e192b24SSimon Glass #include <config.h> 142e192b24SSimon Glass #include <command.h> 152e192b24SSimon Glass #include <mapmem.h> 162e192b24SSimon Glass 172e192b24SSimon Glass static ulong get_arg(char *s, int w) 182e192b24SSimon Glass { 192e192b24SSimon Glass /* 202e192b24SSimon Glass * If the parameter starts with a '*' then assume it is a pointer to 212e192b24SSimon Glass * the value we want. 222e192b24SSimon Glass */ 232e192b24SSimon Glass if (s[0] == '*') { 242e192b24SSimon Glass ulong *p; 252e192b24SSimon Glass ulong addr; 262e192b24SSimon Glass ulong val; 272e192b24SSimon Glass 282e192b24SSimon Glass addr = simple_strtoul(&s[1], NULL, 16); 292e192b24SSimon Glass switch (w) { 302e192b24SSimon Glass case 1: 312e192b24SSimon Glass p = map_sysmem(addr, sizeof(uchar)); 322e192b24SSimon Glass val = (ulong)*(uchar *)p; 332e192b24SSimon Glass unmap_sysmem(p); 342e192b24SSimon Glass return val; 352e192b24SSimon Glass case 2: 362e192b24SSimon Glass p = map_sysmem(addr, sizeof(ushort)); 372e192b24SSimon Glass val = (ulong)*(ushort *)p; 382e192b24SSimon Glass unmap_sysmem(p); 392e192b24SSimon Glass return val; 402e192b24SSimon Glass case 4: 412e192b24SSimon Glass default: 422e192b24SSimon Glass p = map_sysmem(addr, sizeof(ulong)); 432e192b24SSimon Glass val = *p; 442e192b24SSimon Glass unmap_sysmem(p); 452e192b24SSimon Glass return val; 462e192b24SSimon Glass } 472e192b24SSimon Glass } else { 482e192b24SSimon Glass return simple_strtoul(s, NULL, 16); 492e192b24SSimon Glass } 502e192b24SSimon Glass } 512e192b24SSimon Glass 522e192b24SSimon Glass #ifdef CONFIG_REGEX 532e192b24SSimon Glass 542e192b24SSimon Glass #include <slre.h> 552e192b24SSimon Glass 562e192b24SSimon Glass #define SLRE_BUFSZ 16384 572e192b24SSimon Glass #define SLRE_PATSZ 4096 582e192b24SSimon Glass 592e192b24SSimon Glass /* 602e192b24SSimon Glass * memstr - Find the first substring in memory 612e192b24SSimon Glass * @s1: The string to be searched 622e192b24SSimon Glass * @s2: The string to search for 632e192b24SSimon Glass * 642e192b24SSimon Glass * Similar to and based on strstr(), 652e192b24SSimon Glass * but strings do not need to be NUL terminated. 662e192b24SSimon Glass */ 672e192b24SSimon Glass static char *memstr(const char *s1, int l1, const char *s2, int l2) 682e192b24SSimon Glass { 692e192b24SSimon Glass if (!l2) 702e192b24SSimon Glass return (char *)s1; 712e192b24SSimon Glass 722e192b24SSimon Glass while (l1 >= l2) { 732e192b24SSimon Glass l1--; 742e192b24SSimon Glass if (!memcmp(s1, s2, l2)) 752e192b24SSimon Glass return (char *)s1; 762e192b24SSimon Glass s1++; 772e192b24SSimon Glass } 782e192b24SSimon Glass return NULL; 792e192b24SSimon Glass } 802e192b24SSimon Glass 812e192b24SSimon Glass static char *substitute(char *string, /* string buffer */ 822e192b24SSimon Glass int *slen, /* current string length */ 832e192b24SSimon Glass int ssize, /* string bufer size */ 842e192b24SSimon Glass const char *old,/* old (replaced) string */ 852e192b24SSimon Glass int olen, /* length of old string */ 862e192b24SSimon Glass const char *new,/* new (replacement) string */ 872e192b24SSimon Glass int nlen) /* length of new string */ 882e192b24SSimon Glass { 892e192b24SSimon Glass char *p = memstr(string, *slen, old, olen); 902e192b24SSimon Glass 912e192b24SSimon Glass if (p == NULL) 922e192b24SSimon Glass return NULL; 932e192b24SSimon Glass 942e192b24SSimon Glass debug("## Match at pos %ld: match len %d, subst len %d\n", 952e192b24SSimon Glass (long)(p - string), olen, nlen); 962e192b24SSimon Glass 972e192b24SSimon Glass /* make sure replacement matches */ 982e192b24SSimon Glass if (*slen + nlen - olen > ssize) { 992e192b24SSimon Glass printf("## error: substitution buffer overflow\n"); 1002e192b24SSimon Glass return NULL; 1012e192b24SSimon Glass } 1022e192b24SSimon Glass 1032e192b24SSimon Glass /* move tail if needed */ 1042e192b24SSimon Glass if (olen != nlen) { 1052e192b24SSimon Glass int tail, len; 1062e192b24SSimon Glass 1072e192b24SSimon Glass len = (olen > nlen) ? olen : nlen; 1082e192b24SSimon Glass 1092e192b24SSimon Glass tail = ssize - (p + len - string); 1102e192b24SSimon Glass 1112e192b24SSimon Glass debug("## tail len %d\n", tail); 1122e192b24SSimon Glass 1132e192b24SSimon Glass memmove(p + nlen, p + olen, tail); 1142e192b24SSimon Glass } 1152e192b24SSimon Glass 1162e192b24SSimon Glass /* insert substitue */ 1172e192b24SSimon Glass memcpy(p, new, nlen); 1182e192b24SSimon Glass 1192e192b24SSimon Glass *slen += nlen - olen; 1202e192b24SSimon Glass 1212e192b24SSimon Glass return p + nlen; 1222e192b24SSimon Glass } 1232e192b24SSimon Glass 1242e192b24SSimon Glass /* 1252e192b24SSimon Glass * Perform regex operations on a environment variable 1262e192b24SSimon Glass * 1272e192b24SSimon Glass * Returns 0 if OK, 1 in case of errors. 1282e192b24SSimon Glass */ 1292e192b24SSimon Glass static int regex_sub(const char *name, 1302e192b24SSimon Glass const char *r, const char *s, const char *t, 1312e192b24SSimon Glass int global) 1322e192b24SSimon Glass { 1332e192b24SSimon Glass struct slre slre; 1342e192b24SSimon Glass char data[SLRE_BUFSZ]; 1352e192b24SSimon Glass char *datap = data; 1362e192b24SSimon Glass const char *value; 1372e192b24SSimon Glass int res, len, nlen, loop; 1382e192b24SSimon Glass 1392e192b24SSimon Glass if (name == NULL) 1402e192b24SSimon Glass return 1; 1412e192b24SSimon Glass 1422e192b24SSimon Glass if (slre_compile(&slre, r) == 0) { 1432e192b24SSimon Glass printf("Error compiling regex: %s\n", slre.err_str); 1442e192b24SSimon Glass return 1; 1452e192b24SSimon Glass } 1462e192b24SSimon Glass 1472e192b24SSimon Glass if (t == NULL) { 1482e192b24SSimon Glass value = getenv(name); 1492e192b24SSimon Glass 1502e192b24SSimon Glass if (value == NULL) { 1512e192b24SSimon Glass printf("## Error: variable \"%s\" not defined\n", name); 1522e192b24SSimon Glass return 1; 1532e192b24SSimon Glass } 1542e192b24SSimon Glass t = value; 1552e192b24SSimon Glass } 1562e192b24SSimon Glass 1572e192b24SSimon Glass debug("REGEX on %s=%s\n", name, t); 1582e192b24SSimon Glass debug("REGEX=\"%s\", SUBST=\"%s\", GLOBAL=%d\n", 1592e192b24SSimon Glass r, s ? s : "<NULL>", global); 1602e192b24SSimon Glass 1612e192b24SSimon Glass len = strlen(t); 1622e192b24SSimon Glass if (len + 1 > SLRE_BUFSZ) { 1632e192b24SSimon Glass printf("## error: subst buffer overflow: have %d, need %d\n", 1642e192b24SSimon Glass SLRE_BUFSZ, len + 1); 1652e192b24SSimon Glass return 1; 1662e192b24SSimon Glass } 1672e192b24SSimon Glass 1682e192b24SSimon Glass strcpy(data, t); 1692e192b24SSimon Glass 1702e192b24SSimon Glass if (s == NULL) 1712e192b24SSimon Glass nlen = 0; 1722e192b24SSimon Glass else 1732e192b24SSimon Glass nlen = strlen(s); 1742e192b24SSimon Glass 1752e192b24SSimon Glass for (loop = 0;; loop++) { 1762e192b24SSimon Glass struct cap caps[slre.num_caps + 2]; 1772e192b24SSimon Glass char nbuf[SLRE_PATSZ]; 1782e192b24SSimon Glass const char *old; 1792e192b24SSimon Glass char *np; 1802e192b24SSimon Glass int i, olen; 1812e192b24SSimon Glass 1822e192b24SSimon Glass (void) memset(caps, 0, sizeof(caps)); 1832e192b24SSimon Glass 1842e192b24SSimon Glass res = slre_match(&slre, datap, len, caps); 1852e192b24SSimon Glass 1862e192b24SSimon Glass debug("Result: %d\n", res); 1872e192b24SSimon Glass 1882e192b24SSimon Glass for (i = 0; i < slre.num_caps; i++) { 1892e192b24SSimon Glass if (caps[i].len > 0) { 1902e192b24SSimon Glass debug("Substring %d: [%.*s]\n", i, 1912e192b24SSimon Glass caps[i].len, caps[i].ptr); 1922e192b24SSimon Glass } 1932e192b24SSimon Glass } 1942e192b24SSimon Glass 1952e192b24SSimon Glass if (res == 0) { 1962e192b24SSimon Glass if (loop == 0) { 1972e192b24SSimon Glass printf("%s: No match\n", t); 1982e192b24SSimon Glass return 1; 1992e192b24SSimon Glass } else { 2002e192b24SSimon Glass break; 2012e192b24SSimon Glass } 2022e192b24SSimon Glass } 2032e192b24SSimon Glass 2042e192b24SSimon Glass debug("## MATCH ## %s\n", data); 2052e192b24SSimon Glass 2062e192b24SSimon Glass if (s == NULL) { 2072e192b24SSimon Glass printf("%s=%s\n", name, t); 2082e192b24SSimon Glass return 1; 2092e192b24SSimon Glass } 2102e192b24SSimon Glass 2112e192b24SSimon Glass old = caps[0].ptr; 2122e192b24SSimon Glass olen = caps[0].len; 2132e192b24SSimon Glass 2142e192b24SSimon Glass if (nlen + 1 >= SLRE_PATSZ) { 2152e192b24SSimon Glass printf("## error: pattern buffer overflow: have %d, need %d\n", 2162e192b24SSimon Glass SLRE_BUFSZ, nlen + 1); 2172e192b24SSimon Glass return 1; 2182e192b24SSimon Glass } 2192e192b24SSimon Glass strcpy(nbuf, s); 2202e192b24SSimon Glass 2212e192b24SSimon Glass debug("## SUBST(1) ## %s\n", nbuf); 2222e192b24SSimon Glass 2232e192b24SSimon Glass /* 2242e192b24SSimon Glass * Handle back references 2252e192b24SSimon Glass * 2262e192b24SSimon Glass * Support for \0 ... \9, where \0 is the 2272e192b24SSimon Glass * whole matched pattern (similar to &). 2282e192b24SSimon Glass * 2292e192b24SSimon Glass * Implementation is a bit simpleminded as 2302e192b24SSimon Glass * backrefs are substituted sequentially, one 2312e192b24SSimon Glass * by one. This will lead to somewhat 2322e192b24SSimon Glass * unexpected results if the replacement 2332e192b24SSimon Glass * strings contain any \N strings then then 2342e192b24SSimon Glass * may get substitued, too. We accept this 2352e192b24SSimon Glass * restriction for the sake of simplicity. 2362e192b24SSimon Glass */ 2372e192b24SSimon Glass for (i = 0; i < 10; ++i) { 2382e192b24SSimon Glass char backref[2] = { 2392e192b24SSimon Glass '\\', 2402e192b24SSimon Glass '0', 2412e192b24SSimon Glass }; 2422e192b24SSimon Glass 2432e192b24SSimon Glass if (caps[i].len == 0) 2442e192b24SSimon Glass break; 2452e192b24SSimon Glass 2462e192b24SSimon Glass backref[1] += i; 2472e192b24SSimon Glass 2482e192b24SSimon Glass debug("## BACKREF %d: replace \"%.*s\" by \"%.*s\" in \"%s\"\n", 2492e192b24SSimon Glass i, 2502e192b24SSimon Glass 2, backref, 2512e192b24SSimon Glass caps[i].len, caps[i].ptr, 2522e192b24SSimon Glass nbuf); 2532e192b24SSimon Glass 2542e192b24SSimon Glass for (np = nbuf;;) { 2552e192b24SSimon Glass char *p = memstr(np, nlen, backref, 2); 2562e192b24SSimon Glass 2572e192b24SSimon Glass if (p == NULL) 2582e192b24SSimon Glass break; 2592e192b24SSimon Glass 2602e192b24SSimon Glass np = substitute(np, &nlen, 2612e192b24SSimon Glass SLRE_PATSZ, 2622e192b24SSimon Glass backref, 2, 2632e192b24SSimon Glass caps[i].ptr, caps[i].len); 2642e192b24SSimon Glass 2652e192b24SSimon Glass if (np == NULL) 2662e192b24SSimon Glass return 1; 2672e192b24SSimon Glass } 2682e192b24SSimon Glass } 2692e192b24SSimon Glass debug("## SUBST(2) ## %s\n", nbuf); 2702e192b24SSimon Glass 2712e192b24SSimon Glass datap = substitute(datap, &len, SLRE_BUFSZ, 2722e192b24SSimon Glass old, olen, 2732e192b24SSimon Glass nbuf, nlen); 2742e192b24SSimon Glass 2752e192b24SSimon Glass if (datap == NULL) 2762e192b24SSimon Glass return 1; 2772e192b24SSimon Glass 2782e192b24SSimon Glass debug("## REMAINDER: %s\n", datap); 2792e192b24SSimon Glass 2802e192b24SSimon Glass debug("## RESULT: %s\n", data); 2812e192b24SSimon Glass 2822e192b24SSimon Glass if (!global) 2832e192b24SSimon Glass break; 2842e192b24SSimon Glass } 285*382bee57SSimon Glass debug("## FINAL (now env_set()) : %s\n", data); 2862e192b24SSimon Glass 2872e192b24SSimon Glass printf("%s=%s\n", name, data); 2882e192b24SSimon Glass 289*382bee57SSimon Glass return env_set(name, data); 2902e192b24SSimon Glass } 2912e192b24SSimon Glass #endif 2922e192b24SSimon Glass 2932e192b24SSimon Glass static int do_setexpr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 2942e192b24SSimon Glass { 2952e192b24SSimon Glass ulong a, b; 2962e192b24SSimon Glass ulong value; 2972e192b24SSimon Glass int w; 2982e192b24SSimon Glass 2992e192b24SSimon Glass /* 3002e192b24SSimon Glass * We take 3, 5, or 6 arguments: 3012e192b24SSimon Glass * 3 : setexpr name value 3022e192b24SSimon Glass * 5 : setexpr name val1 op val2 3032e192b24SSimon Glass * setexpr name [g]sub r s 3042e192b24SSimon Glass * 6 : setexpr name [g]sub r s t 3052e192b24SSimon Glass */ 3062e192b24SSimon Glass 3072e192b24SSimon Glass /* > 6 already tested by max command args */ 3082e192b24SSimon Glass if ((argc < 3) || (argc == 4)) 3092e192b24SSimon Glass return CMD_RET_USAGE; 3102e192b24SSimon Glass 3112e192b24SSimon Glass w = cmd_get_data_size(argv[0], 4); 3122e192b24SSimon Glass 3132e192b24SSimon Glass a = get_arg(argv[2], w); 3142e192b24SSimon Glass 3152e192b24SSimon Glass /* plain assignment: "setexpr name value" */ 3162e192b24SSimon Glass if (argc == 3) { 3172e192b24SSimon Glass setenv_hex(argv[1], a); 3182e192b24SSimon Glass return 0; 3192e192b24SSimon Glass } 3202e192b24SSimon Glass 3212e192b24SSimon Glass /* 5 or 6 args (6 args only with [g]sub) */ 3222e192b24SSimon Glass #ifdef CONFIG_REGEX 3232e192b24SSimon Glass /* 3242e192b24SSimon Glass * rexep handling: "setexpr name [g]sub r s [t]" 3252e192b24SSimon Glass * with 5 args, "t" will be NULL 3262e192b24SSimon Glass */ 3272e192b24SSimon Glass if (strcmp(argv[2], "gsub") == 0) 3282e192b24SSimon Glass return regex_sub(argv[1], argv[3], argv[4], argv[5], 1); 3292e192b24SSimon Glass 3302e192b24SSimon Glass if (strcmp(argv[2], "sub") == 0) 3312e192b24SSimon Glass return regex_sub(argv[1], argv[3], argv[4], argv[5], 0); 3322e192b24SSimon Glass #endif 3332e192b24SSimon Glass 3342e192b24SSimon Glass /* standard operators: "setexpr name val1 op val2" */ 3352e192b24SSimon Glass if (argc != 5) 3362e192b24SSimon Glass return CMD_RET_USAGE; 3372e192b24SSimon Glass 3382e192b24SSimon Glass if (strlen(argv[3]) != 1) 3392e192b24SSimon Glass return CMD_RET_USAGE; 3402e192b24SSimon Glass 3412e192b24SSimon Glass b = get_arg(argv[4], w); 3422e192b24SSimon Glass 3432e192b24SSimon Glass switch (argv[3][0]) { 3442e192b24SSimon Glass case '|': 3452e192b24SSimon Glass value = a | b; 3462e192b24SSimon Glass break; 3472e192b24SSimon Glass case '&': 3482e192b24SSimon Glass value = a & b; 3492e192b24SSimon Glass break; 3502e192b24SSimon Glass case '+': 3512e192b24SSimon Glass value = a + b; 3522e192b24SSimon Glass break; 3532e192b24SSimon Glass case '^': 3542e192b24SSimon Glass value = a ^ b; 3552e192b24SSimon Glass break; 3562e192b24SSimon Glass case '-': 3572e192b24SSimon Glass value = a - b; 3582e192b24SSimon Glass break; 3592e192b24SSimon Glass case '*': 3602e192b24SSimon Glass value = a * b; 3612e192b24SSimon Glass break; 3622e192b24SSimon Glass case '/': 3632e192b24SSimon Glass value = a / b; 3642e192b24SSimon Glass break; 3652e192b24SSimon Glass case '%': 3662e192b24SSimon Glass value = a % b; 3672e192b24SSimon Glass break; 3682e192b24SSimon Glass default: 3692e192b24SSimon Glass printf("invalid op\n"); 3702e192b24SSimon Glass return 1; 3712e192b24SSimon Glass } 3722e192b24SSimon Glass 3732e192b24SSimon Glass setenv_hex(argv[1], value); 3742e192b24SSimon Glass 3752e192b24SSimon Glass return 0; 3762e192b24SSimon Glass } 3772e192b24SSimon Glass 3782e192b24SSimon Glass U_BOOT_CMD( 3792e192b24SSimon Glass setexpr, 6, 0, do_setexpr, 3802e192b24SSimon Glass "set environment variable as the result of eval expression", 3812e192b24SSimon Glass "[.b, .w, .l] name [*]value1 <op> [*]value2\n" 3822e192b24SSimon Glass " - set environment variable 'name' to the result of the evaluated\n" 3832e192b24SSimon Glass " expression specified by <op>. <op> can be &, |, ^, +, -, *, /, %\n" 3842e192b24SSimon Glass " size argument is only meaningful if value1 and/or value2 are\n" 3852e192b24SSimon Glass " memory addresses (*)\n" 3862e192b24SSimon Glass "setexpr[.b, .w, .l] name [*]value\n" 3872e192b24SSimon Glass " - load a value into a variable" 3882e192b24SSimon Glass #ifdef CONFIG_REGEX 3892e192b24SSimon Glass "\n" 3902e192b24SSimon Glass "setexpr name gsub r s [t]\n" 3912e192b24SSimon Glass " - For each substring matching the regular expression <r> in the\n" 3922e192b24SSimon Glass " string <t>, substitute the string <s>. The result is\n" 3932e192b24SSimon Glass " assigned to <name>. If <t> is not supplied, use the old\n" 3942e192b24SSimon Glass " value of <name>\n" 3952e192b24SSimon Glass "setexpr name sub r s [t]\n" 3962e192b24SSimon Glass " - Just like gsub(), but replace only the first matching substring" 3972e192b24SSimon Glass #endif 3982e192b24SSimon Glass ); 399