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
30const 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
54static 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
189U_BOOT_CMD(
190	test,	CONFIG_SYS_MAXARGS,	1,	do_test,
191	"minimal test like /bin/sh",
192	"[args..]"
193);
194
195static int do_false(struct cmd_tbl *cmdtp, int flag, int argc,
196		    char *const argv[])
197{
198	return 1;
199}
200
201U_BOOT_CMD(
202	false,	CONFIG_SYS_MAXARGS,	1,	do_false,
203	"do nothing, unsuccessfully",
204	NULL
205);
206
207static int do_true(struct cmd_tbl *cmdtp, int flag, int argc,
208		   char *const argv[])
209{
210	return 0;
211}
212
213U_BOOT_CMD(
214	true,	CONFIG_SYS_MAXARGS,	1,	do_true,
215	"do nothing, successfully",
216	NULL
217);
218