1 // SPDX-License-Identifier: GPL-2.0+
6 * Copyright 2022 Google LLC
12 #include <linux/errno.h>
15 * enum cli_esc_state_t - indicates what to do with an escape character
17 * @ESC_REJECT: Invalid escape sequence, so the esc_save[] characters are
18 * returned from each subsequent call to cli_ch_esc()
19 * @ESC_SAVE: Character should be saved in esc_save until we have another one
20 * @ESC_CONVERTED: Escape sequence has been completed and the resulting
21 * character is available
23 enum cli_esc_state_t {
29 void cli_ch_init(struct cli_ch_state *cch)
31 memset(cch, '\0', sizeof(*cch));
35 * cli_ch_esc() - Process a character in an ongoing escape sequence
37 * @cch: State information
38 * @ichar: Character to process
39 * @actp: Returns the action to take
40 * Returns: Output character if *actp is ESC_CONVERTED, else 0
42 static int cli_ch_esc(struct cli_ch_state *cch, int ichar,
43 enum cli_esc_state_t *actp)
45 enum cli_esc_state_t act = ESC_REJECT;
47 switch (cch->esc_len) {
49 if (ichar == '[' || ichar == 'O')
56 case 'D': /* <- key */
59 break; /* pass off to ^B handler */
60 case 'C': /* -> key */
63 break; /* pass off to ^F handler */
64 case 'H': /* Home key */
67 break; /* pass off to ^A handler */
68 case 'F': /* End key */
71 break; /* pass off to ^E handler */
72 case 'A': /* up arrow */
75 break; /* pass off to ^P handler */
76 case 'B': /* down arrow */
79 break; /* pass off to ^N handler */
86 if (cch->esc_save[1] == '[') {
87 /* see if next character is ~ */
96 switch (cch->esc_save[2]) {
97 case '3': /* Delete key */
100 break; /* pass to ^D handler */
101 case '1': /* Home key */
105 break; /* pass to ^A handler */
106 case '4': /* End key */
110 break; /* pass to ^E handler */
114 if (cch->esc_save[2] == '2')
124 break; /* bracketed paste */
128 if (ichar == '~') { /* bracketed paste */
139 int cli_ch_process(struct cli_ch_state *cch, int ichar)
142 * ichar=0x0 when error occurs in U-Boot getchar() or when the caller
143 * wants to check if there are more characters saved in the escape
148 if (cch->emit_upto < cch->esc_len)
149 return cch->esc_save[cch->emit_upto++];
151 cch->emitting = false;
155 } else if (ichar == -ETIMEDOUT) {
157 * If we are in an escape sequence but nothing has followed the
158 * Escape character, then the user probably just pressed the
159 * Escape key. Return it and clear the sequence.
166 /* Otherwise there is nothing to return */
170 if (ichar == '\n' || ichar == '\r')
173 /* handle standard linux xterm esc sequences for arrow key, etc. */
174 if (cch->esc_len != 0) {
175 enum cli_esc_state_t act;
177 ichar = cli_ch_esc(cch, ichar, &act);
181 /* save this character and return nothing */
182 cch->esc_save[cch->esc_len++] = ichar;
187 * invalid escape sequence, start returning the
190 cch->esc_save[cch->esc_len++] = ichar;
191 ichar = cch->esc_save[cch->emit_upto++];
192 cch->emitting = true;
195 /* valid escape sequence, return the resulting char */
203 cch->esc_save[cch->esc_len] = ichar;
206 puts("impossible condition #876\n");