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