uboot/cmd/setexpr.c
<<
>>
Prefs
   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
  17static 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 */
  67static 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
  81static 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 */
 129static 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 = env_get(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 env_set()) :  %s\n", data);
 286
 287        printf("%s=%s\n", name, data);
 288
 289        return env_set(name, data);
 290}
 291#endif
 292
 293static 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                env_set_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        env_set_hex(argv[1], value);
 374
 375        return 0;
 376}
 377
 378U_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