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