cli: hush_modern: Enable loops
[pandora-u-boot.git] / common / cli_hush_modern.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * This file defines the compilation unit for the new hush shell version.  The
4  * actual implementation from upstream BusyBox can be found in
5  * `cli_hush_upstream.c` which is included at the end of this file.
6  *
7  * This "wrapper" technique is used to keep the changes to the upstream version
8  * as minmal as possible.  Instead, all defines and redefines necessary are done
9  * here, outside the upstream sources.  This will hopefully make upgrades to
10  * newer revisions much easier.
11  *
12  * Copyright (c) 2021, Harald Seiler, DENX Software Engineering, hws@denx.de
13  */
14
15 #include <common.h>         /* readline */
16 #include <env.h>
17 #include <malloc.h>         /* malloc, free, realloc*/
18 #include <linux/ctype.h>    /* isalpha, isdigit */
19 #include <console.h>
20 #include <bootretry.h>
21 #include <cli.h>
22 #include <cli_hush.h>
23 #include <command.h>        /* find_cmd */
24 #include <asm/global_data.h>
25
26 /*
27  * BusyBox Version: UPDATE THIS WHEN PULLING NEW UPSTREAM REVISION!
28  */
29 #define BB_VER                  "1.34.0.git37460f5daff9"
30
31 /*
32  * Define hush features by the names used upstream.
33  */
34 #define ENABLE_HUSH_INTERACTIVE 1
35 #define ENABLE_FEATURE_EDITING  1
36 #define ENABLE_HUSH_IF          1
37 #define ENABLE_HUSH_LOOPS       1
38 /* No MMU in U-Boot */
39 #define BB_MMU                  0
40 #define USE_FOR_NOMMU(...)      __VA_ARGS__
41 #define USE_FOR_MMU(...)
42
43 /*
44  * Size-saving "small" ints (arch-dependent)
45  */
46 #if CONFIG_IS_ENABLED(X86) || CONFIG_IS_ENABLED(X86_64) || CONFIG_IS_ENABLED(MIPS)
47 /* add other arches which benefit from this... */
48 typedef signed char smallint;
49 typedef unsigned char smalluint;
50 #else
51 /* for arches where byte accesses generate larger code: */
52 typedef int smallint;
53 typedef unsigned smalluint;
54 #endif
55
56 /*
57  * Alignment defines used by BusyBox.
58  */
59 #define ALIGN1                  __attribute__((aligned(1)))
60 #define ALIGN2                  __attribute__((aligned(2)))
61 #define ALIGN4                  __attribute__((aligned(4)))
62 #define ALIGN8                  __attribute__((aligned(8)))
63 #define ALIGN_PTR               __attribute__((aligned(sizeof(void*))))
64
65 /*
66  * Miscellaneous compiler/platform defines.
67  */
68 #define FAST_FUNC /* not used in U-Boot */
69 #define UNUSED_PARAM            __always_unused
70 #define ALWAYS_INLINE           __always_inline
71 #define NOINLINE                noinline
72
73 /*
74  * Defines to provide equivalents to what libc/BusyBox defines.
75  */
76 #define EOF                     (-1)
77 #define EXIT_SUCCESS            0
78 #define EXIT_FAILURE            1
79
80 /*
81  * Stubs to provide libc/BusyBox functions based on U-Boot equivalents where it
82  * makes sense.
83  */
84 #define utoa                    simple_itoa
85
86 static void __noreturn xfunc_die(void)
87 {
88         panic("HUSH died!");
89 }
90
91 #define bb_error_msg_and_die(format, ...) do { \
92 panic("HUSH: " format, __VA_ARGS__); \
93 } while (0);
94
95 #define bb_simple_error_msg_and_die(msg) do { \
96 panic_str("HUSH: " msg); \
97 } while (0);
98
99 /* fdprintf() is used for debug output. */
100 static int __maybe_unused fdprintf(int fd, const char *format, ...)
101 {
102         va_list args;
103         uint i;
104
105         assert(fd == 2);
106
107         va_start(args, format);
108         i = vprintf(format, args);
109         va_end(args);
110
111         return i;
112 }
113
114 static void bb_verror_msg(const char *s, va_list p, const char* strerr)
115 {
116         /* TODO: what to do with strerr arg? */
117         vprintf(s, p);
118 }
119
120 static void bb_error_msg(const char *s, ...)
121 {
122         va_list p;
123
124         va_start(p, s);
125         bb_verror_msg(s, p, NULL);
126         va_end(p);
127 }
128
129 static void bb_simple_error_msg(const char *s)
130 {
131         bb_error_msg("%s", s);
132 }
133
134 static void *xmalloc(size_t size)
135 {
136         void *p = NULL;
137         if (!(p = malloc(size)))
138                 panic("out of memory");
139         return p;
140 }
141
142 static void *xzalloc(size_t size)
143 {
144         void *p = xmalloc(size);
145         memset(p, 0, size);
146         return p;
147 }
148
149 static void *xrealloc(void *ptr, size_t size)
150 {
151         void *p = NULL;
152         if (!(p = realloc(ptr, size)))
153                 panic("out of memory");
154         return p;
155 }
156
157 static void *xmemdup(const void *s, int n)
158 {
159         return memcpy(xmalloc(n), s, n);
160 }
161
162 #define xstrdup         strdup
163 #define xstrndup        strndup
164
165 static void *mempcpy(void *dest, const void *src, size_t len)
166 {
167         return memcpy(dest, src, len) + len;
168 }
169
170 /* Like strcpy but can copy overlapping strings. */
171 static void overlapping_strcpy(char *dst, const char *src)
172 {
173         /*
174          * Cheap optimization for dst == src case -
175          * better to have it here than in many callers.
176          */
177         if (dst != src) {
178                 while ((*dst = *src) != '\0') {
179                         dst++;
180                         src++;
181                 }
182         }
183 }
184
185 static char* skip_whitespace(const char *s)
186 {
187         /*
188          * In POSIX/C locale (the only locale we care about: do we REALLY want
189          * to allow Unicode whitespace in, say, .conf files? nuts!)
190          * isspace is only these chars: "\t\n\v\f\r" and space.
191          * "\t\n\v\f\r" happen to have ASCII codes 9,10,11,12,13.
192          * Use that.
193          */
194         while (*s == ' ' || (unsigned char)(*s - 9) <= (13 - 9))
195                 s++;
196
197         return (char *) s;
198 }
199
200 static char* skip_non_whitespace(const char *s)
201 {
202         while (*s != '\0' && *s != ' ' && (unsigned char)(*s - 9) > (13 - 9))
203                 s++;
204
205         return (char *) s;
206 }
207
208 #define is_name(c)      ((c) == '_' || isalpha((unsigned char)(c)))
209 #define is_in_name(c)   ((c) == '_' || isalnum((unsigned char)(c)))
210
211 static const char* endofname(const char *name)
212 {
213         if (!is_name(*name))
214                 return name;
215         while (*++name) {
216                 if (!is_in_name(*name))
217                         break;
218         }
219         return name;
220 }
221
222 /**
223  * list_size() - returns the number of elements in char ** before NULL.
224  *
225  * Argument must contain NULL to signalize its end.
226  *
227  * @list The list to count the number of element.
228  * @return The number of element in list.
229  */
230 static size_t list_size(char **list)
231 {
232         size_t size;
233
234         for (size = 0; list[size] != NULL; size++);
235
236         return size;
237 }
238
239 struct in_str;
240 static int u_boot_cli_readline(struct in_str *i);
241
242 struct in_str;
243 static int u_boot_cli_readline(struct in_str *i);
244
245 /*
246  * BusyBox globals which are needed for hush.
247  */
248 static uint8_t xfunc_error_retval;
249
250 static const char defifsvar[] __aligned(1) = "IFS= \t\n";
251 #define defifs (defifsvar + 4)
252
253 /* This define is used to check if exit command was called. */
254 #define EXIT_RET_CODE -2
255
256 /*
257  * This define is used for changes that need be done directly in the upstream
258  * sources still. Ideally, its use should be minimized as much as possible.
259  */
260 #define __U_BOOT__
261
262 /*
263  *
264  * +-- Include of the upstream sources --+ *
265  * V                                     V
266  */
267 #include "cli_hush_upstream.c"
268 /*
269  * A                                     A
270  * +-- Include of the upstream sources --+ *
271  *
272  */
273
274 int u_boot_hush_start_modern(void)
275 {
276         INIT_G();
277         return 0;
278 }
279
280 static int u_boot_cli_readline(struct in_str *i)
281 {
282         char *prompt;
283         char __maybe_unused *ps_prompt = NULL;
284
285         if (!G.promptmode)
286                 prompt = CONFIG_SYS_PROMPT;
287 #ifdef CONFIG_SYS_PROMPT_HUSH_PS2
288         else
289                 prompt = CONFIG_SYS_PROMPT_HUSH_PS2;
290 #else
291         /* TODO: default value? */
292         #error "SYS_PROMPT_HUSH_PS2 is not defined!"
293 #endif
294
295         if (CONFIG_IS_ENABLED(CMDLINE_PS_SUPPORT)) {
296                 if (!G.promptmode)
297                         ps_prompt = env_get("PS1");
298                 else
299                         ps_prompt = env_get("PS2");
300
301                 if (ps_prompt)
302                         prompt = ps_prompt;
303         }
304
305         return cli_readline(prompt);
306 }