1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2000-2009
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  */
6 
7 #include <command.h>
8 #include <fs.h>
9 #include <log.h>
10 #include <slre.h>
11 #include <vsprintf.h>
12 #include <linux/string.h>
13 
14 #define OP_INVALID	0
15 #define OP_NOT		1
16 #define OP_OR		2
17 #define OP_AND		3
18 #define OP_STR_EMPTY	4
19 #define OP_STR_NEMPTY	5
20 #define OP_STR_EQ	6
21 #define OP_STR_NEQ	7
22 #define OP_STR_LT	8
23 #define OP_STR_GT	9
24 #define OP_INT_EQ	10
25 #define OP_INT_NEQ	11
26 #define OP_INT_LT	12
27 #define OP_INT_LE	13
28 #define OP_INT_GT	14
29 #define OP_INT_GE	15
30 #define OP_FILE_EXISTS	16
31 #define OP_REGEX	17
32 
33 const struct {
34 	int arg;
35 	const char *str;
36 	int op;
37 	int adv;
38 } op_adv[] = {
39 	{1, "=", OP_STR_EQ, 3},
40 	{1, "!=", OP_STR_NEQ, 3},
41 	{1, "<", OP_STR_LT, 3},
42 	{1, ">", OP_STR_GT, 3},
43 	{1, "-eq", OP_INT_EQ, 3},
44 	{1, "-ne", OP_INT_NEQ, 3},
45 	{1, "-lt", OP_INT_LT, 3},
46 	{1, "-le", OP_INT_LE, 3},
47 	{1, "-gt", OP_INT_GT, 3},
48 	{1, "-ge", OP_INT_GE, 3},
49 	{0, "!", OP_NOT, 1},
50 	{0, "-o", OP_OR, 1},
51 	{0, "-a", OP_AND, 1},
52 	{0, "-z", OP_STR_EMPTY, 2},
53 	{0, "-n", OP_STR_NEMPTY, 2},
54 	{0, "-e", OP_FILE_EXISTS, 4},
55 #ifdef CONFIG_REGEX
56 	{1, "=~", OP_REGEX, 3},
57 #endif
58 };
59 
do_test(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])60 static int do_test(struct cmd_tbl *cmdtp, int flag, int argc,
61 		   char *const argv[])
62 {
63 	char * const *ap;
64 	int i, op, left, adv, expr, last_expr, last_unop, last_binop;
65 
66 	/* args? */
67 	if (argc < 3)
68 		return 1;
69 
70 #ifdef DEBUG
71 	{
72 		debug("test(%d):", argc);
73 		left = 1;
74 		while (argv[left])
75 			debug(" '%s'", argv[left++]);
76 	}
77 #endif
78 
79 	left = argc - 1;
80 	ap = argv + 1;
81 	expr = 0;
82 	last_unop = OP_INVALID;
83 	last_binop = OP_INVALID;
84 	last_expr = -1;
85 	while (left > 0) {
86 		for (i = 0; i < ARRAY_SIZE(op_adv); i++) {
87 			if (left <= op_adv[i].arg)
88 				continue;
89 			if (!strcmp(ap[op_adv[i].arg], op_adv[i].str)) {
90 				op = op_adv[i].op;
91 				adv = op_adv[i].adv;
92 				break;
93 			}
94 		}
95 		if (i == ARRAY_SIZE(op_adv)) {
96 			expr = 1;
97 			break;
98 		}
99 		if (left < adv) {
100 			expr = 1;
101 			break;
102 		}
103 
104 		switch (op) {
105 		case OP_STR_EMPTY:
106 			expr = strlen(ap[1]) == 0 ? 1 : 0;
107 			break;
108 		case OP_STR_NEMPTY:
109 			expr = strlen(ap[1]) == 0 ? 0 : 1;
110 			break;
111 		case OP_STR_EQ:
112 			expr = strcmp(ap[0], ap[2]) == 0;
113 			break;
114 		case OP_STR_NEQ:
115 			expr = strcmp(ap[0], ap[2]) != 0;
116 			break;
117 		case OP_STR_LT:
118 			expr = strcmp(ap[0], ap[2]) < 0;
119 			break;
120 		case OP_STR_GT:
121 			expr = strcmp(ap[0], ap[2]) > 0;
122 			break;
123 		case OP_INT_EQ:
124 			expr = simple_strtol(ap[0], NULL, 0) ==
125 					simple_strtol(ap[2], NULL, 0);
126 			break;
127 		case OP_INT_NEQ:
128 			expr = simple_strtol(ap[0], NULL, 0) !=
129 					simple_strtol(ap[2], NULL, 0);
130 			break;
131 		case OP_INT_LT:
132 			expr = simple_strtol(ap[0], NULL, 0) <
133 					simple_strtol(ap[2], NULL, 0);
134 			break;
135 		case OP_INT_LE:
136 			expr = simple_strtol(ap[0], NULL, 0) <=
137 					simple_strtol(ap[2], NULL, 0);
138 			break;
139 		case OP_INT_GT:
140 			expr = simple_strtol(ap[0], NULL, 0) >
141 					simple_strtol(ap[2], NULL, 0);
142 			break;
143 		case OP_INT_GE:
144 			expr = simple_strtol(ap[0], NULL, 0) >=
145 					simple_strtol(ap[2], NULL, 0);
146 			break;
147 		case OP_FILE_EXISTS:
148 			expr = file_exists(ap[1], ap[2], ap[3], FS_TYPE_ANY);
149 			break;
150 #ifdef CONFIG_REGEX
151 		case OP_REGEX: {
152 			struct slre slre;
153 
154 			if (slre_compile(&slre, ap[2]) == 0) {
155 				printf("Error compiling regex: %s\n", slre.err_str);
156 				expr = 0;
157 				break;
158 			}
159 
160 			expr = slre_match(&slre, ap[0], strlen(ap[0]), NULL);
161 			break;
162 		}
163 #endif
164 		}
165 
166 		switch (op) {
167 		case OP_OR:
168 			last_expr = expr;
169 			last_binop = OP_OR;
170 			break;
171 		case OP_AND:
172 			last_expr = expr;
173 			last_binop = OP_AND;
174 			break;
175 		case OP_NOT:
176 			if (last_unop == OP_NOT)
177 				last_unop = OP_INVALID;
178 			else
179 				last_unop = OP_NOT;
180 			break;
181 		default:
182 			if (last_unop == OP_NOT) {
183 				expr = !expr;
184 				last_unop = OP_INVALID;
185 			}
186 
187 			if (last_binop == OP_OR)
188 				expr = last_expr || expr;
189 			else if (last_binop == OP_AND)
190 				expr = last_expr && expr;
191 			last_binop = OP_INVALID;
192 
193 			break;
194 		}
195 
196 		ap += adv; left -= adv;
197 	}
198 
199 	expr = !expr;
200 
201 	debug (": returns %d\n", expr);
202 
203 	return expr;
204 }
205 
206 #undef true
207 #undef false
208 
209 U_BOOT_CMD(
210 	test,	CONFIG_SYS_MAXARGS,	1,	do_test,
211 	"minimal test like /bin/sh",
212 	"[args..]"
213 );
214 
do_false(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])215 static int do_false(struct cmd_tbl *cmdtp, int flag, int argc,
216 		    char *const argv[])
217 {
218 	return 1;
219 }
220 
221 U_BOOT_CMD(
222 	false,	CONFIG_SYS_MAXARGS,	1,	do_false,
223 	"do nothing, unsuccessfully",
224 	NULL
225 );
226 
do_true(struct cmd_tbl * cmdtp,int flag,int argc,char * const argv[])227 static int do_true(struct cmd_tbl *cmdtp, int flag, int argc,
228 		   char *const argv[])
229 {
230 	return 0;
231 }
232 
233 U_BOOT_CMD(
234 	true,	CONFIG_SYS_MAXARGS,	1,	do_true,
235 	"do nothing, successfully",
236 	NULL
237 );
238