1*2e192b24SSimon Glass /* 2*2e192b24SSimon Glass * Copyright 2008 Freescale Semiconductor, Inc. 3*2e192b24SSimon Glass * Copyright 2013 Wolfgang Denk <wd@denx.de> 4*2e192b24SSimon Glass * 5*2e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 6*2e192b24SSimon Glass */ 7*2e192b24SSimon Glass 8*2e192b24SSimon Glass /* 9*2e192b24SSimon Glass * This file provides a shell like 'expr' function to return. 10*2e192b24SSimon Glass */ 11*2e192b24SSimon Glass 12*2e192b24SSimon Glass #include <common.h> 13*2e192b24SSimon Glass #include <config.h> 14*2e192b24SSimon Glass #include <command.h> 15*2e192b24SSimon Glass #include <mapmem.h> 16*2e192b24SSimon Glass 17*2e192b24SSimon Glass static ulong get_arg(char *s, int w) 18*2e192b24SSimon Glass { 19*2e192b24SSimon Glass /* 20*2e192b24SSimon Glass * If the parameter starts with a '*' then assume it is a pointer to 21*2e192b24SSimon Glass * the value we want. 22*2e192b24SSimon Glass */ 23*2e192b24SSimon Glass if (s[0] == '*') { 24*2e192b24SSimon Glass ulong *p; 25*2e192b24SSimon Glass ulong addr; 26*2e192b24SSimon Glass ulong val; 27*2e192b24SSimon Glass 28*2e192b24SSimon Glass addr = simple_strtoul(&s[1], NULL, 16); 29*2e192b24SSimon Glass switch (w) { 30*2e192b24SSimon Glass case 1: 31*2e192b24SSimon Glass p = map_sysmem(addr, sizeof(uchar)); 32*2e192b24SSimon Glass val = (ulong)*(uchar *)p; 33*2e192b24SSimon Glass unmap_sysmem(p); 34*2e192b24SSimon Glass return val; 35*2e192b24SSimon Glass case 2: 36*2e192b24SSimon Glass p = map_sysmem(addr, sizeof(ushort)); 37*2e192b24SSimon Glass val = (ulong)*(ushort *)p; 38*2e192b24SSimon Glass unmap_sysmem(p); 39*2e192b24SSimon Glass return val; 40*2e192b24SSimon Glass case 4: 41*2e192b24SSimon Glass default: 42*2e192b24SSimon Glass p = map_sysmem(addr, sizeof(ulong)); 43*2e192b24SSimon Glass val = *p; 44*2e192b24SSimon Glass unmap_sysmem(p); 45*2e192b24SSimon Glass return val; 46*2e192b24SSimon Glass } 47*2e192b24SSimon Glass } else { 48*2e192b24SSimon Glass return simple_strtoul(s, NULL, 16); 49*2e192b24SSimon Glass } 50*2e192b24SSimon Glass } 51*2e192b24SSimon Glass 52*2e192b24SSimon Glass #ifdef CONFIG_REGEX 53*2e192b24SSimon Glass 54*2e192b24SSimon Glass #include <slre.h> 55*2e192b24SSimon Glass 56*2e192b24SSimon Glass #define SLRE_BUFSZ 16384 57*2e192b24SSimon Glass #define SLRE_PATSZ 4096 58*2e192b24SSimon Glass 59*2e192b24SSimon Glass /* 60*2e192b24SSimon Glass * memstr - Find the first substring in memory 61*2e192b24SSimon Glass * @s1: The string to be searched 62*2e192b24SSimon Glass * @s2: The string to search for 63*2e192b24SSimon Glass * 64*2e192b24SSimon Glass * Similar to and based on strstr(), 65*2e192b24SSimon Glass * but strings do not need to be NUL terminated. 66*2e192b24SSimon Glass */ 67*2e192b24SSimon Glass static char *memstr(const char *s1, int l1, const char *s2, int l2) 68*2e192b24SSimon Glass { 69*2e192b24SSimon Glass if (!l2) 70*2e192b24SSimon Glass return (char *)s1; 71*2e192b24SSimon Glass 72*2e192b24SSimon Glass while (l1 >= l2) { 73*2e192b24SSimon Glass l1--; 74*2e192b24SSimon Glass if (!memcmp(s1, s2, l2)) 75*2e192b24SSimon Glass return (char *)s1; 76*2e192b24SSimon Glass s1++; 77*2e192b24SSimon Glass } 78*2e192b24SSimon Glass return NULL; 79*2e192b24SSimon Glass } 80*2e192b24SSimon Glass 81*2e192b24SSimon Glass static char *substitute(char *string, /* string buffer */ 82*2e192b24SSimon Glass int *slen, /* current string length */ 83*2e192b24SSimon Glass int ssize, /* string bufer size */ 84*2e192b24SSimon Glass const char *old,/* old (replaced) string */ 85*2e192b24SSimon Glass int olen, /* length of old string */ 86*2e192b24SSimon Glass const char *new,/* new (replacement) string */ 87*2e192b24SSimon Glass int nlen) /* length of new string */ 88*2e192b24SSimon Glass { 89*2e192b24SSimon Glass char *p = memstr(string, *slen, old, olen); 90*2e192b24SSimon Glass 91*2e192b24SSimon Glass if (p == NULL) 92*2e192b24SSimon Glass return NULL; 93*2e192b24SSimon Glass 94*2e192b24SSimon Glass debug("## Match at pos %ld: match len %d, subst len %d\n", 95*2e192b24SSimon Glass (long)(p - string), olen, nlen); 96*2e192b24SSimon Glass 97*2e192b24SSimon Glass /* make sure replacement matches */ 98*2e192b24SSimon Glass if (*slen + nlen - olen > ssize) { 99*2e192b24SSimon Glass printf("## error: substitution buffer overflow\n"); 100*2e192b24SSimon Glass return NULL; 101*2e192b24SSimon Glass } 102*2e192b24SSimon Glass 103*2e192b24SSimon Glass /* move tail if needed */ 104*2e192b24SSimon Glass if (olen != nlen) { 105*2e192b24SSimon Glass int tail, len; 106*2e192b24SSimon Glass 107*2e192b24SSimon Glass len = (olen > nlen) ? olen : nlen; 108*2e192b24SSimon Glass 109*2e192b24SSimon Glass tail = ssize - (p + len - string); 110*2e192b24SSimon Glass 111*2e192b24SSimon Glass debug("## tail len %d\n", tail); 112*2e192b24SSimon Glass 113*2e192b24SSimon Glass memmove(p + nlen, p + olen, tail); 114*2e192b24SSimon Glass } 115*2e192b24SSimon Glass 116*2e192b24SSimon Glass /* insert substitue */ 117*2e192b24SSimon Glass memcpy(p, new, nlen); 118*2e192b24SSimon Glass 119*2e192b24SSimon Glass *slen += nlen - olen; 120*2e192b24SSimon Glass 121*2e192b24SSimon Glass return p + nlen; 122*2e192b24SSimon Glass } 123*2e192b24SSimon Glass 124*2e192b24SSimon Glass /* 125*2e192b24SSimon Glass * Perform regex operations on a environment variable 126*2e192b24SSimon Glass * 127*2e192b24SSimon Glass * Returns 0 if OK, 1 in case of errors. 128*2e192b24SSimon Glass */ 129*2e192b24SSimon Glass static int regex_sub(const char *name, 130*2e192b24SSimon Glass const char *r, const char *s, const char *t, 131*2e192b24SSimon Glass int global) 132*2e192b24SSimon Glass { 133*2e192b24SSimon Glass struct slre slre; 134*2e192b24SSimon Glass char data[SLRE_BUFSZ]; 135*2e192b24SSimon Glass char *datap = data; 136*2e192b24SSimon Glass const char *value; 137*2e192b24SSimon Glass int res, len, nlen, loop; 138*2e192b24SSimon Glass 139*2e192b24SSimon Glass if (name == NULL) 140*2e192b24SSimon Glass return 1; 141*2e192b24SSimon Glass 142*2e192b24SSimon Glass if (slre_compile(&slre, r) == 0) { 143*2e192b24SSimon Glass printf("Error compiling regex: %s\n", slre.err_str); 144*2e192b24SSimon Glass return 1; 145*2e192b24SSimon Glass } 146*2e192b24SSimon Glass 147*2e192b24SSimon Glass if (t == NULL) { 148*2e192b24SSimon Glass value = getenv(name); 149*2e192b24SSimon Glass 150*2e192b24SSimon Glass if (value == NULL) { 151*2e192b24SSimon Glass printf("## Error: variable \"%s\" not defined\n", name); 152*2e192b24SSimon Glass return 1; 153*2e192b24SSimon Glass } 154*2e192b24SSimon Glass t = value; 155*2e192b24SSimon Glass } 156*2e192b24SSimon Glass 157*2e192b24SSimon Glass debug("REGEX on %s=%s\n", name, t); 158*2e192b24SSimon Glass debug("REGEX=\"%s\", SUBST=\"%s\", GLOBAL=%d\n", 159*2e192b24SSimon Glass r, s ? s : "<NULL>", global); 160*2e192b24SSimon Glass 161*2e192b24SSimon Glass len = strlen(t); 162*2e192b24SSimon Glass if (len + 1 > SLRE_BUFSZ) { 163*2e192b24SSimon Glass printf("## error: subst buffer overflow: have %d, need %d\n", 164*2e192b24SSimon Glass SLRE_BUFSZ, len + 1); 165*2e192b24SSimon Glass return 1; 166*2e192b24SSimon Glass } 167*2e192b24SSimon Glass 168*2e192b24SSimon Glass strcpy(data, t); 169*2e192b24SSimon Glass 170*2e192b24SSimon Glass if (s == NULL) 171*2e192b24SSimon Glass nlen = 0; 172*2e192b24SSimon Glass else 173*2e192b24SSimon Glass nlen = strlen(s); 174*2e192b24SSimon Glass 175*2e192b24SSimon Glass for (loop = 0;; loop++) { 176*2e192b24SSimon Glass struct cap caps[slre.num_caps + 2]; 177*2e192b24SSimon Glass char nbuf[SLRE_PATSZ]; 178*2e192b24SSimon Glass const char *old; 179*2e192b24SSimon Glass char *np; 180*2e192b24SSimon Glass int i, olen; 181*2e192b24SSimon Glass 182*2e192b24SSimon Glass (void) memset(caps, 0, sizeof(caps)); 183*2e192b24SSimon Glass 184*2e192b24SSimon Glass res = slre_match(&slre, datap, len, caps); 185*2e192b24SSimon Glass 186*2e192b24SSimon Glass debug("Result: %d\n", res); 187*2e192b24SSimon Glass 188*2e192b24SSimon Glass for (i = 0; i < slre.num_caps; i++) { 189*2e192b24SSimon Glass if (caps[i].len > 0) { 190*2e192b24SSimon Glass debug("Substring %d: [%.*s]\n", i, 191*2e192b24SSimon Glass caps[i].len, caps[i].ptr); 192*2e192b24SSimon Glass } 193*2e192b24SSimon Glass } 194*2e192b24SSimon Glass 195*2e192b24SSimon Glass if (res == 0) { 196*2e192b24SSimon Glass if (loop == 0) { 197*2e192b24SSimon Glass printf("%s: No match\n", t); 198*2e192b24SSimon Glass return 1; 199*2e192b24SSimon Glass } else { 200*2e192b24SSimon Glass break; 201*2e192b24SSimon Glass } 202*2e192b24SSimon Glass } 203*2e192b24SSimon Glass 204*2e192b24SSimon Glass debug("## MATCH ## %s\n", data); 205*2e192b24SSimon Glass 206*2e192b24SSimon Glass if (s == NULL) { 207*2e192b24SSimon Glass printf("%s=%s\n", name, t); 208*2e192b24SSimon Glass return 1; 209*2e192b24SSimon Glass } 210*2e192b24SSimon Glass 211*2e192b24SSimon Glass old = caps[0].ptr; 212*2e192b24SSimon Glass olen = caps[0].len; 213*2e192b24SSimon Glass 214*2e192b24SSimon Glass if (nlen + 1 >= SLRE_PATSZ) { 215*2e192b24SSimon Glass printf("## error: pattern buffer overflow: have %d, need %d\n", 216*2e192b24SSimon Glass SLRE_BUFSZ, nlen + 1); 217*2e192b24SSimon Glass return 1; 218*2e192b24SSimon Glass } 219*2e192b24SSimon Glass strcpy(nbuf, s); 220*2e192b24SSimon Glass 221*2e192b24SSimon Glass debug("## SUBST(1) ## %s\n", nbuf); 222*2e192b24SSimon Glass 223*2e192b24SSimon Glass /* 224*2e192b24SSimon Glass * Handle back references 225*2e192b24SSimon Glass * 226*2e192b24SSimon Glass * Support for \0 ... \9, where \0 is the 227*2e192b24SSimon Glass * whole matched pattern (similar to &). 228*2e192b24SSimon Glass * 229*2e192b24SSimon Glass * Implementation is a bit simpleminded as 230*2e192b24SSimon Glass * backrefs are substituted sequentially, one 231*2e192b24SSimon Glass * by one. This will lead to somewhat 232*2e192b24SSimon Glass * unexpected results if the replacement 233*2e192b24SSimon Glass * strings contain any \N strings then then 234*2e192b24SSimon Glass * may get substitued, too. We accept this 235*2e192b24SSimon Glass * restriction for the sake of simplicity. 236*2e192b24SSimon Glass */ 237*2e192b24SSimon Glass for (i = 0; i < 10; ++i) { 238*2e192b24SSimon Glass char backref[2] = { 239*2e192b24SSimon Glass '\\', 240*2e192b24SSimon Glass '0', 241*2e192b24SSimon Glass }; 242*2e192b24SSimon Glass 243*2e192b24SSimon Glass if (caps[i].len == 0) 244*2e192b24SSimon Glass break; 245*2e192b24SSimon Glass 246*2e192b24SSimon Glass backref[1] += i; 247*2e192b24SSimon Glass 248*2e192b24SSimon Glass debug("## BACKREF %d: replace \"%.*s\" by \"%.*s\" in \"%s\"\n", 249*2e192b24SSimon Glass i, 250*2e192b24SSimon Glass 2, backref, 251*2e192b24SSimon Glass caps[i].len, caps[i].ptr, 252*2e192b24SSimon Glass nbuf); 253*2e192b24SSimon Glass 254*2e192b24SSimon Glass for (np = nbuf;;) { 255*2e192b24SSimon Glass char *p = memstr(np, nlen, backref, 2); 256*2e192b24SSimon Glass 257*2e192b24SSimon Glass if (p == NULL) 258*2e192b24SSimon Glass break; 259*2e192b24SSimon Glass 260*2e192b24SSimon Glass np = substitute(np, &nlen, 261*2e192b24SSimon Glass SLRE_PATSZ, 262*2e192b24SSimon Glass backref, 2, 263*2e192b24SSimon Glass caps[i].ptr, caps[i].len); 264*2e192b24SSimon Glass 265*2e192b24SSimon Glass if (np == NULL) 266*2e192b24SSimon Glass return 1; 267*2e192b24SSimon Glass } 268*2e192b24SSimon Glass } 269*2e192b24SSimon Glass debug("## SUBST(2) ## %s\n", nbuf); 270*2e192b24SSimon Glass 271*2e192b24SSimon Glass datap = substitute(datap, &len, SLRE_BUFSZ, 272*2e192b24SSimon Glass old, olen, 273*2e192b24SSimon Glass nbuf, nlen); 274*2e192b24SSimon Glass 275*2e192b24SSimon Glass if (datap == NULL) 276*2e192b24SSimon Glass return 1; 277*2e192b24SSimon Glass 278*2e192b24SSimon Glass debug("## REMAINDER: %s\n", datap); 279*2e192b24SSimon Glass 280*2e192b24SSimon Glass debug("## RESULT: %s\n", data); 281*2e192b24SSimon Glass 282*2e192b24SSimon Glass if (!global) 283*2e192b24SSimon Glass break; 284*2e192b24SSimon Glass } 285*2e192b24SSimon Glass debug("## FINAL (now setenv()) : %s\n", data); 286*2e192b24SSimon Glass 287*2e192b24SSimon Glass printf("%s=%s\n", name, data); 288*2e192b24SSimon Glass 289*2e192b24SSimon Glass return setenv(name, data); 290*2e192b24SSimon Glass } 291*2e192b24SSimon Glass #endif 292*2e192b24SSimon Glass 293*2e192b24SSimon Glass static int do_setexpr(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 294*2e192b24SSimon Glass { 295*2e192b24SSimon Glass ulong a, b; 296*2e192b24SSimon Glass ulong value; 297*2e192b24SSimon Glass int w; 298*2e192b24SSimon Glass 299*2e192b24SSimon Glass /* 300*2e192b24SSimon Glass * We take 3, 5, or 6 arguments: 301*2e192b24SSimon Glass * 3 : setexpr name value 302*2e192b24SSimon Glass * 5 : setexpr name val1 op val2 303*2e192b24SSimon Glass * setexpr name [g]sub r s 304*2e192b24SSimon Glass * 6 : setexpr name [g]sub r s t 305*2e192b24SSimon Glass */ 306*2e192b24SSimon Glass 307*2e192b24SSimon Glass /* > 6 already tested by max command args */ 308*2e192b24SSimon Glass if ((argc < 3) || (argc == 4)) 309*2e192b24SSimon Glass return CMD_RET_USAGE; 310*2e192b24SSimon Glass 311*2e192b24SSimon Glass w = cmd_get_data_size(argv[0], 4); 312*2e192b24SSimon Glass 313*2e192b24SSimon Glass a = get_arg(argv[2], w); 314*2e192b24SSimon Glass 315*2e192b24SSimon Glass /* plain assignment: "setexpr name value" */ 316*2e192b24SSimon Glass if (argc == 3) { 317*2e192b24SSimon Glass setenv_hex(argv[1], a); 318*2e192b24SSimon Glass return 0; 319*2e192b24SSimon Glass } 320*2e192b24SSimon Glass 321*2e192b24SSimon Glass /* 5 or 6 args (6 args only with [g]sub) */ 322*2e192b24SSimon Glass #ifdef CONFIG_REGEX 323*2e192b24SSimon Glass /* 324*2e192b24SSimon Glass * rexep handling: "setexpr name [g]sub r s [t]" 325*2e192b24SSimon Glass * with 5 args, "t" will be NULL 326*2e192b24SSimon Glass */ 327*2e192b24SSimon Glass if (strcmp(argv[2], "gsub") == 0) 328*2e192b24SSimon Glass return regex_sub(argv[1], argv[3], argv[4], argv[5], 1); 329*2e192b24SSimon Glass 330*2e192b24SSimon Glass if (strcmp(argv[2], "sub") == 0) 331*2e192b24SSimon Glass return regex_sub(argv[1], argv[3], argv[4], argv[5], 0); 332*2e192b24SSimon Glass #endif 333*2e192b24SSimon Glass 334*2e192b24SSimon Glass /* standard operators: "setexpr name val1 op val2" */ 335*2e192b24SSimon Glass if (argc != 5) 336*2e192b24SSimon Glass return CMD_RET_USAGE; 337*2e192b24SSimon Glass 338*2e192b24SSimon Glass if (strlen(argv[3]) != 1) 339*2e192b24SSimon Glass return CMD_RET_USAGE; 340*2e192b24SSimon Glass 341*2e192b24SSimon Glass b = get_arg(argv[4], w); 342*2e192b24SSimon Glass 343*2e192b24SSimon Glass switch (argv[3][0]) { 344*2e192b24SSimon Glass case '|': 345*2e192b24SSimon Glass value = a | b; 346*2e192b24SSimon Glass break; 347*2e192b24SSimon Glass case '&': 348*2e192b24SSimon Glass value = a & b; 349*2e192b24SSimon Glass break; 350*2e192b24SSimon Glass case '+': 351*2e192b24SSimon Glass value = a + b; 352*2e192b24SSimon Glass break; 353*2e192b24SSimon Glass case '^': 354*2e192b24SSimon Glass value = a ^ b; 355*2e192b24SSimon Glass break; 356*2e192b24SSimon Glass case '-': 357*2e192b24SSimon Glass value = a - b; 358*2e192b24SSimon Glass break; 359*2e192b24SSimon Glass case '*': 360*2e192b24SSimon Glass value = a * b; 361*2e192b24SSimon Glass break; 362*2e192b24SSimon Glass case '/': 363*2e192b24SSimon Glass value = a / b; 364*2e192b24SSimon Glass break; 365*2e192b24SSimon Glass case '%': 366*2e192b24SSimon Glass value = a % b; 367*2e192b24SSimon Glass break; 368*2e192b24SSimon Glass default: 369*2e192b24SSimon Glass printf("invalid op\n"); 370*2e192b24SSimon Glass return 1; 371*2e192b24SSimon Glass } 372*2e192b24SSimon Glass 373*2e192b24SSimon Glass setenv_hex(argv[1], value); 374*2e192b24SSimon Glass 375*2e192b24SSimon Glass return 0; 376*2e192b24SSimon Glass } 377*2e192b24SSimon Glass 378*2e192b24SSimon Glass U_BOOT_CMD( 379*2e192b24SSimon Glass setexpr, 6, 0, do_setexpr, 380*2e192b24SSimon Glass "set environment variable as the result of eval expression", 381*2e192b24SSimon Glass "[.b, .w, .l] name [*]value1 <op> [*]value2\n" 382*2e192b24SSimon Glass " - set environment variable 'name' to the result of the evaluated\n" 383*2e192b24SSimon Glass " expression specified by <op>. <op> can be &, |, ^, +, -, *, /, %\n" 384*2e192b24SSimon Glass " size argument is only meaningful if value1 and/or value2 are\n" 385*2e192b24SSimon Glass " memory addresses (*)\n" 386*2e192b24SSimon Glass "setexpr[.b, .w, .l] name [*]value\n" 387*2e192b24SSimon Glass " - load a value into a variable" 388*2e192b24SSimon Glass #ifdef CONFIG_REGEX 389*2e192b24SSimon Glass "\n" 390*2e192b24SSimon Glass "setexpr name gsub r s [t]\n" 391*2e192b24SSimon Glass " - For each substring matching the regular expression <r> in the\n" 392*2e192b24SSimon Glass " string <t>, substitute the string <s>. The result is\n" 393*2e192b24SSimon Glass " assigned to <name>. If <t> is not supplied, use the old\n" 394*2e192b24SSimon Glass " value of <name>\n" 395*2e192b24SSimon Glass "setexpr name sub r s [t]\n" 396*2e192b24SSimon Glass " - Just like gsub(), but replace only the first matching substring" 397*2e192b24SSimon Glass #endif 398*2e192b24SSimon Glass ); 399