"Das U-Boot" Source Tree
at master 213 lines 4.7 kB view raw
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2000 4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 5 * 6 * Copyright 2022 Google LLC 7 */ 8 9#include <cli.h> 10#include <stdio.h> 11#include <string.h> 12#include <linux/errno.h> 13 14/** 15 * enum cli_esc_state_t - indicates what to do with an escape character 16 * 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 22 */ 23enum cli_esc_state_t { 24 ESC_REJECT, 25 ESC_SAVE, 26 ESC_CONVERTED 27}; 28 29void cli_ch_init(struct cli_ch_state *cch) 30{ 31 memset(cch, '\0', sizeof(*cch)); 32} 33 34/** 35 * cli_ch_esc() - Process a character in an ongoing escape sequence 36 * 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 41 */ 42static int cli_ch_esc(struct cli_ch_state *cch, int ichar, 43 enum cli_esc_state_t *actp) 44{ 45 enum cli_esc_state_t act = ESC_REJECT; 46 47 switch (cch->esc_len) { 48 case 1: 49 if (ichar == '[' || ichar == 'O') 50 act = ESC_SAVE; 51 else 52 act = ESC_CONVERTED; 53 break; 54 case 2: 55 switch (ichar) { 56 case 'D': /* <- key */ 57 ichar = CTL_CH('b'); 58 act = ESC_CONVERTED; 59 break; /* pass off to ^B handler */ 60 case 'C': /* -> key */ 61 ichar = CTL_CH('f'); 62 act = ESC_CONVERTED; 63 break; /* pass off to ^F handler */ 64 case 'H': /* Home key */ 65 ichar = CTL_CH('a'); 66 act = ESC_CONVERTED; 67 break; /* pass off to ^A handler */ 68 case 'F': /* End key */ 69 ichar = CTL_CH('e'); 70 act = ESC_CONVERTED; 71 break; /* pass off to ^E handler */ 72 case 'A': /* up arrow */ 73 ichar = CTL_CH('p'); 74 act = ESC_CONVERTED; 75 break; /* pass off to ^P handler */ 76 case 'B': /* down arrow */ 77 ichar = CTL_CH('n'); 78 act = ESC_CONVERTED; 79 break; /* pass off to ^N handler */ 80 case '1': 81 case '2': 82 case '3': 83 case '4': 84 case '7': 85 case '8': 86 if (cch->esc_save[1] == '[') { 87 /* see if next character is ~ */ 88 act = ESC_SAVE; 89 } 90 break; 91 } 92 break; 93 case 3: 94 switch (ichar) { 95 case '~': 96 switch (cch->esc_save[2]) { 97 case '3': /* Delete key */ 98 ichar = CTL_CH('d'); 99 act = ESC_CONVERTED; 100 break; /* pass to ^D handler */ 101 case '1': /* Home key */ 102 case '7': 103 ichar = CTL_CH('a'); 104 act = ESC_CONVERTED; 105 break; /* pass to ^A handler */ 106 case '4': /* End key */ 107 case '8': 108 ichar = CTL_CH('e'); 109 act = ESC_CONVERTED; 110 break; /* pass to ^E handler */ 111 } 112 break; 113 case '0': 114 if (cch->esc_save[2] == '2') 115 act = ESC_SAVE; 116 break; 117 } 118 break; 119 case 4: 120 switch (ichar) { 121 case '0': 122 case '1': 123 act = ESC_SAVE; 124 break; /* bracketed paste */ 125 } 126 break; 127 case 5: 128 if (ichar == '~') { /* bracketed paste */ 129 ichar = 0; 130 act = ESC_CONVERTED; 131 } 132 } 133 134 *actp = act; 135 136 return ichar; 137} 138 139int cli_ch_process(struct cli_ch_state *cch, int ichar) 140{ 141 /* 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 144 * sequence 145 */ 146 if (!ichar) { 147 if (cch->emitting) { 148 if (cch->emit_upto < cch->esc_len) 149 return cch->esc_save[cch->emit_upto++]; 150 cch->emit_upto = 0; 151 cch->emitting = false; 152 cch->esc_len = 0; 153 } 154 return 0; 155 } else if (ichar == -ETIMEDOUT) { 156 /* 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. 160 */ 161 if (cch->esc_len) { 162 cch->esc_len = 0; 163 return '\e'; 164 } 165 166 /* Otherwise there is nothing to return */ 167 return 0; 168 } 169 170 if (ichar == '\n' || ichar == '\r') 171 return '\n'; 172 173 /* handle standard linux xterm esc sequences for arrow key, etc. */ 174 if (cch->esc_len != 0) { 175 enum cli_esc_state_t act; 176 177 ichar = cli_ch_esc(cch, ichar, &act); 178 179 switch (act) { 180 case ESC_SAVE: 181 /* save this character and return nothing */ 182 cch->esc_save[cch->esc_len++] = ichar; 183 ichar = 0; 184 break; 185 case ESC_REJECT: 186 /* 187 * invalid escape sequence, start returning the 188 * characters in it 189 */ 190 cch->esc_save[cch->esc_len++] = ichar; 191 ichar = cch->esc_save[cch->emit_upto++]; 192 cch->emitting = true; 193 return ichar; 194 case ESC_CONVERTED: 195 /* valid escape sequence, return the resulting char */ 196 cch->esc_len = 0; 197 break; 198 } 199 } 200 201 if (ichar == '\e') { 202 if (!cch->esc_len) { 203 cch->esc_save[cch->esc_len] = ichar; 204 cch->esc_len = 1; 205 } else { 206 puts("impossible condition #876\n"); 207 cch->esc_len = 0; 208 } 209 return 0; 210 } 211 212 return ichar; 213}