1 /* 2 * (C) Copyright 2003 3 * Tait Electronics Limited, Christchurch, New Zealand 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 /* 9 * This file provides a shell like 'test' function to return 10 * true/false from an integer or string compare of two memory 11 * locations or a location and a scalar/literal. 12 * A few parts were lifted from bash 'test' command 13 */ 14 15 #include <common.h> 16 #include <config.h> 17 #include <command.h> 18 #include <mapmem.h> 19 20 #include <asm/io.h> 21 22 #define EQ 0 23 #define NE 1 24 #define LT 2 25 #define GT 3 26 #define LE 4 27 #define GE 5 28 29 struct op_tbl_s { 30 char *op; /* operator string */ 31 int opcode; /* internal representation of opcode */ 32 }; 33 34 typedef struct op_tbl_s op_tbl_t; 35 36 static const op_tbl_t op_table [] = { 37 { "-lt", LT }, 38 { "<" , LT }, 39 { "-gt", GT }, 40 { ">" , GT }, 41 { "-eq", EQ }, 42 { "==" , EQ }, 43 { "-ne", NE }, 44 { "!=" , NE }, 45 { "<>" , NE }, 46 { "-ge", GE }, 47 { ">=" , GE }, 48 { "-le", LE }, 49 { "<=" , LE }, 50 }; 51 52 static long evalexp(char *s, int w) 53 { 54 long l = 0; 55 unsigned long addr; 56 void *buf; 57 58 /* if the parameter starts with a * then assume is a pointer to the value we want */ 59 if (s[0] == '*') { 60 addr = simple_strtoul(&s[1], NULL, 16); 61 buf = map_physmem(addr, w, MAP_WRBACK); 62 if (!buf && addr) { 63 puts("Failed to map physical memory\n"); 64 return 0; 65 } 66 switch (w) { 67 case 1: 68 l = (long)(*(u8 *)buf); 69 break; 70 case 2: 71 l = (long)(*(u16 *)buf); 72 break; 73 case 4: 74 l = (long)(*(u32 *)buf); 75 break; 76 } 77 unmap_physmem(buf, w); 78 return l; 79 } else { 80 l = simple_strtoul(s, NULL, 16); 81 } 82 83 /* avoid overflow on mask calculus */ 84 return (w >= sizeof(long)) ? l : (l & ((1UL << (w * 8)) - 1)); 85 } 86 87 static char * evalstr(char *s) 88 { 89 /* if the parameter starts with a * then assume a string pointer else its a literal */ 90 if (s[0] == '*') { 91 return (char *)simple_strtoul(&s[1], NULL, 16); 92 } else if (s[0] == '$') { 93 int i = 2; 94 95 if (s[1] != '{') 96 return NULL; 97 98 while (s[i] != '}') { 99 if (s[i] == 0) 100 return NULL; 101 i++; 102 } 103 s[i] = 0; 104 return getenv((const char *)&s[2]); 105 } else { 106 return s; 107 } 108 } 109 110 static int stringcomp(char *s, char *t, int op) 111 { 112 int p; 113 char *l, *r; 114 115 l = evalstr(s); 116 r = evalstr(t); 117 118 p = strcmp(l, r); 119 switch (op) { 120 case EQ: return (p == 0); 121 case NE: return (p != 0); 122 case LT: return (p < 0); 123 case GT: return (p > 0); 124 case LE: return (p <= 0); 125 case GE: return (p >= 0); 126 } 127 return (0); 128 } 129 130 static int arithcomp (char *s, char *t, int op, int w) 131 { 132 long l, r; 133 134 l = evalexp (s, w); 135 r = evalexp (t, w); 136 137 switch (op) { 138 case EQ: return (l == r); 139 case NE: return (l != r); 140 case LT: return (l < r); 141 case GT: return (l > r); 142 case LE: return (l <= r); 143 case GE: return (l >= r); 144 } 145 return (0); 146 } 147 148 static int binary_test(char *op, char *arg1, char *arg2, int w) 149 { 150 int len, i; 151 const op_tbl_t *optp; 152 153 len = strlen(op); 154 155 for (optp = (op_tbl_t *)&op_table, i = 0; 156 i < ARRAY_SIZE(op_table); 157 optp++, i++) { 158 159 if ((strncmp (op, optp->op, len) == 0) && (len == strlen (optp->op))) { 160 if (w == 0) { 161 return (stringcomp(arg1, arg2, optp->opcode)); 162 } else { 163 return (arithcomp (arg1, arg2, optp->opcode, w)); 164 } 165 } 166 } 167 168 printf("Unknown operator '%s'\n", op); 169 return 0; /* op code not found */ 170 } 171 172 /* command line interface to the shell test */ 173 static int do_itest(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 174 { 175 int value, w; 176 177 /* Validate arguments */ 178 if ((argc != 4)) 179 return CMD_RET_USAGE; 180 181 /* Check for a data width specification. 182 * Defaults to long (4) if no specification. 183 * Uses -2 as 'width' for .s (string) so as not to upset existing code 184 */ 185 switch (w = cmd_get_data_size(argv[0], 4)) { 186 case 1: 187 case 2: 188 case 4: 189 value = binary_test (argv[2], argv[1], argv[3], w); 190 break; 191 case -2: 192 value = binary_test (argv[2], argv[1], argv[3], 0); 193 break; 194 case -1: 195 default: 196 puts("Invalid data width specifier\n"); 197 value = 0; 198 break; 199 } 200 201 return !value; 202 } 203 204 U_BOOT_CMD( 205 itest, 4, 0, do_itest, 206 "return true/false on integer compare", 207 "[.b, .w, .l, .s] [*]value1 <op> [*]value2" 208 ); 209