]> Git Repo - J-u-boot.git/blob - common/cli_getch.c
spl: Convert semihosting to spl_load
[J-u-boot.git] / common / cli_getch.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2000
4  * Wolfgang Denk, DENX Software Engineering, [email protected].
5  *
6  * Copyright 2022 Google LLC
7  */
8
9 #include <common.h>
10 #include <cli.h>
11
12 /**
13  * enum cli_esc_state_t - indicates what to do with an escape character
14  *
15  * @ESC_REJECT: Invalid escape sequence, so the esc_save[] characters are
16  *      returned from each subsequent call to cli_ch_esc()
17  * @ESC_SAVE: Character should be saved in esc_save until we have another one
18  * @ESC_CONVERTED: Escape sequence has been completed and the resulting
19  *      character is available
20  */
21 enum cli_esc_state_t {
22         ESC_REJECT,
23         ESC_SAVE,
24         ESC_CONVERTED
25 };
26
27 void cli_ch_init(struct cli_ch_state *cch)
28 {
29         memset(cch, '\0', sizeof(*cch));
30 }
31
32 /**
33  * cli_ch_esc() - Process a character in an ongoing escape sequence
34  *
35  * @cch: State information
36  * @ichar: Character to process
37  * @actp: Returns the action to take
38  * Returns: Output character if *actp is ESC_CONVERTED, else 0
39  */
40 static int cli_ch_esc(struct cli_ch_state *cch, int ichar,
41                       enum cli_esc_state_t *actp)
42 {
43         enum cli_esc_state_t act = ESC_REJECT;
44
45         switch (cch->esc_len) {
46         case 1:
47                 if (ichar == '[' || ichar == 'O')
48                         act = ESC_SAVE;
49                 else
50                         act = ESC_CONVERTED;
51                 break;
52         case 2:
53                 switch (ichar) {
54                 case 'D':       /* <- key */
55                         ichar = CTL_CH('b');
56                         act = ESC_CONVERTED;
57                         break;  /* pass off to ^B handler */
58                 case 'C':       /* -> key */
59                         ichar = CTL_CH('f');
60                         act = ESC_CONVERTED;
61                         break;  /* pass off to ^F handler */
62                 case 'H':       /* Home key */
63                         ichar = CTL_CH('a');
64                         act = ESC_CONVERTED;
65                         break;  /* pass off to ^A handler */
66                 case 'F':       /* End key */
67                         ichar = CTL_CH('e');
68                         act = ESC_CONVERTED;
69                         break;  /* pass off to ^E handler */
70                 case 'A':       /* up arrow */
71                         ichar = CTL_CH('p');
72                         act = ESC_CONVERTED;
73                         break;  /* pass off to ^P handler */
74                 case 'B':       /* down arrow */
75                         ichar = CTL_CH('n');
76                         act = ESC_CONVERTED;
77                         break;  /* pass off to ^N handler */
78                 case '1':
79                 case '2':
80                 case '3':
81                 case '4':
82                 case '7':
83                 case '8':
84                         if (cch->esc_save[1] == '[') {
85                                 /* see if next character is ~ */
86                                 act = ESC_SAVE;
87                         }
88                         break;
89                 }
90                 break;
91         case 3:
92                 switch (ichar) {
93                 case '~':
94                         switch (cch->esc_save[2]) {
95                         case '3':       /* Delete key */
96                                 ichar = CTL_CH('d');
97                                 act = ESC_CONVERTED;
98                                 break;  /* pass to ^D handler */
99                         case '1':       /* Home key */
100                         case '7':
101                                 ichar = CTL_CH('a');
102                                 act = ESC_CONVERTED;
103                                 break;  /* pass to ^A handler */
104                         case '4':       /* End key */
105                         case '8':
106                                 ichar = CTL_CH('e');
107                                 act = ESC_CONVERTED;
108                                 break;  /* pass to ^E handler */
109                         }
110                         break;
111                 case '0':
112                         if (cch->esc_save[2] == '2')
113                                 act = ESC_SAVE;
114                         break;
115                 }
116                 break;
117         case 4:
118                 switch (ichar) {
119                 case '0':
120                 case '1':
121                         act = ESC_SAVE;
122                         break;          /* bracketed paste */
123                 }
124                 break;
125         case 5:
126                 if (ichar == '~') {     /* bracketed paste */
127                         ichar = 0;
128                         act = ESC_CONVERTED;
129                 }
130         }
131
132         *actp = act;
133
134         return ichar;
135 }
136
137 int cli_ch_process(struct cli_ch_state *cch, int ichar)
138 {
139         /*
140          * ichar=0x0 when error occurs in U-Boot getchar() or when the caller
141          * wants to check if there are more characters saved in the escape
142          * sequence
143          */
144         if (!ichar) {
145                 if (cch->emitting) {
146                         if (cch->emit_upto < cch->esc_len)
147                                 return cch->esc_save[cch->emit_upto++];
148                         cch->emit_upto = 0;
149                         cch->emitting = false;
150                         cch->esc_len = 0;
151                 }
152                 return 0;
153         } else if (ichar == -ETIMEDOUT) {
154                 /*
155                  * If we are in an escape sequence but nothing has followed the
156                  * Escape character, then the user probably just pressed the
157                  * Escape key. Return it and clear the sequence.
158                  */
159                 if (cch->esc_len) {
160                         cch->esc_len = 0;
161                         return '\e';
162                 }
163
164                 /* Otherwise there is nothing to return */
165                 return 0;
166         }
167
168         if (ichar == '\n' || ichar == '\r')
169                 return '\n';
170
171         /* handle standard linux xterm esc sequences for arrow key, etc. */
172         if (cch->esc_len != 0) {
173                 enum cli_esc_state_t act;
174
175                 ichar = cli_ch_esc(cch, ichar, &act);
176
177                 switch (act) {
178                 case ESC_SAVE:
179                         /* save this character and return nothing */
180                         cch->esc_save[cch->esc_len++] = ichar;
181                         ichar = 0;
182                         break;
183                 case ESC_REJECT:
184                         /*
185                          * invalid escape sequence, start returning the
186                          * characters in it
187                          */
188                         cch->esc_save[cch->esc_len++] = ichar;
189                         ichar = cch->esc_save[cch->emit_upto++];
190                         cch->emitting = true;
191                         return ichar;
192                 case ESC_CONVERTED:
193                         /* valid escape sequence, return the resulting char */
194                         cch->esc_len = 0;
195                         break;
196                 }
197         }
198
199         if (ichar == '\e') {
200                 if (!cch->esc_len) {
201                         cch->esc_save[cch->esc_len] = ichar;
202                         cch->esc_len = 1;
203                 } else {
204                         puts("impossible condition #876\n");
205                         cch->esc_len = 0;
206                 }
207                 return 0;
208         }
209
210         return ichar;
211 }
This page took 0.038081 seconds and 4 git commands to generate.