mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-30 19:48:19 +00:00 
			
		
		
		
	As part of bringing the master branch back in to next, we need to allow for all of these changes to exist here. Reported-by: Jonas Karlman <jonas@kwiboo.se> Signed-off-by: Tom Rini <trini@konsulko.com>
		
			
				
	
	
		
			214 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  * (C) Copyright 2000
 | |
|  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 | |
|  *
 | |
|  * Copyright 2022 Google LLC
 | |
|  */
 | |
| 
 | |
| #include <cli.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <linux/errno.h>
 | |
| 
 | |
| /**
 | |
|  * enum cli_esc_state_t - indicates what to do with an escape character
 | |
|  *
 | |
|  * @ESC_REJECT: Invalid escape sequence, so the esc_save[] characters are
 | |
|  *	returned from each subsequent call to cli_ch_esc()
 | |
|  * @ESC_SAVE: Character should be saved in esc_save until we have another one
 | |
|  * @ESC_CONVERTED: Escape sequence has been completed and the resulting
 | |
|  *	character is available
 | |
|  */
 | |
| enum cli_esc_state_t {
 | |
| 	ESC_REJECT,
 | |
| 	ESC_SAVE,
 | |
| 	ESC_CONVERTED
 | |
| };
 | |
| 
 | |
| void cli_ch_init(struct cli_ch_state *cch)
 | |
| {
 | |
| 	memset(cch, '\0', sizeof(*cch));
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * cli_ch_esc() - Process a character in an ongoing escape sequence
 | |
|  *
 | |
|  * @cch: State information
 | |
|  * @ichar: Character to process
 | |
|  * @actp: Returns the action to take
 | |
|  * Returns: Output character if *actp is ESC_CONVERTED, else 0
 | |
|  */
 | |
| static int cli_ch_esc(struct cli_ch_state *cch, int ichar,
 | |
| 		      enum cli_esc_state_t *actp)
 | |
| {
 | |
| 	enum cli_esc_state_t act = ESC_REJECT;
 | |
| 
 | |
| 	switch (cch->esc_len) {
 | |
| 	case 1:
 | |
| 		if (ichar == '[' || ichar == 'O')
 | |
| 			act = ESC_SAVE;
 | |
| 		else
 | |
| 			act = ESC_CONVERTED;
 | |
| 		break;
 | |
| 	case 2:
 | |
| 		switch (ichar) {
 | |
| 		case 'D':	/* <- key */
 | |
| 			ichar = CTL_CH('b');
 | |
| 			act = ESC_CONVERTED;
 | |
| 			break;	/* pass off to ^B handler */
 | |
| 		case 'C':	/* -> key */
 | |
| 			ichar = CTL_CH('f');
 | |
| 			act = ESC_CONVERTED;
 | |
| 			break;	/* pass off to ^F handler */
 | |
| 		case 'H':	/* Home key */
 | |
| 			ichar = CTL_CH('a');
 | |
| 			act = ESC_CONVERTED;
 | |
| 			break;	/* pass off to ^A handler */
 | |
| 		case 'F':	/* End key */
 | |
| 			ichar = CTL_CH('e');
 | |
| 			act = ESC_CONVERTED;
 | |
| 			break;	/* pass off to ^E handler */
 | |
| 		case 'A':	/* up arrow */
 | |
| 			ichar = CTL_CH('p');
 | |
| 			act = ESC_CONVERTED;
 | |
| 			break;	/* pass off to ^P handler */
 | |
| 		case 'B':	/* down arrow */
 | |
| 			ichar = CTL_CH('n');
 | |
| 			act = ESC_CONVERTED;
 | |
| 			break;	/* pass off to ^N handler */
 | |
| 		case '1':
 | |
| 		case '2':
 | |
| 		case '3':
 | |
| 		case '4':
 | |
| 		case '7':
 | |
| 		case '8':
 | |
| 			if (cch->esc_save[1] == '[') {
 | |
| 				/* see if next character is ~ */
 | |
| 				act = ESC_SAVE;
 | |
| 			}
 | |
| 			break;
 | |
| 		}
 | |
| 		break;
 | |
| 	case 3:
 | |
| 		switch (ichar) {
 | |
| 		case '~':
 | |
| 			switch (cch->esc_save[2]) {
 | |
| 			case '3':	/* Delete key */
 | |
| 				ichar = CTL_CH('d');
 | |
| 				act = ESC_CONVERTED;
 | |
| 				break;	/* pass to ^D handler */
 | |
| 			case '1':	/* Home key */
 | |
| 			case '7':
 | |
| 				ichar = CTL_CH('a');
 | |
| 				act = ESC_CONVERTED;
 | |
| 				break;	/* pass to ^A handler */
 | |
| 			case '4':	/* End key */
 | |
| 			case '8':
 | |
| 				ichar = CTL_CH('e');
 | |
| 				act = ESC_CONVERTED;
 | |
| 				break;	/* pass to ^E handler */
 | |
| 			}
 | |
| 			break;
 | |
| 		case '0':
 | |
| 			if (cch->esc_save[2] == '2')
 | |
| 				act = ESC_SAVE;
 | |
| 			break;
 | |
| 		}
 | |
| 		break;
 | |
| 	case 4:
 | |
| 		switch (ichar) {
 | |
| 		case '0':
 | |
| 		case '1':
 | |
| 			act = ESC_SAVE;
 | |
| 			break;		/* bracketed paste */
 | |
| 		}
 | |
| 		break;
 | |
| 	case 5:
 | |
| 		if (ichar == '~') {	/* bracketed paste */
 | |
| 			ichar = 0;
 | |
| 			act = ESC_CONVERTED;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	*actp = act;
 | |
| 
 | |
| 	return ichar;
 | |
| }
 | |
| 
 | |
| int cli_ch_process(struct cli_ch_state *cch, int ichar)
 | |
| {
 | |
| 	/*
 | |
| 	 * ichar=0x0 when error occurs in U-Boot getchar() or when the caller
 | |
| 	 * wants to check if there are more characters saved in the escape
 | |
| 	 * sequence
 | |
| 	 */
 | |
| 	if (!ichar) {
 | |
| 		if (cch->emitting) {
 | |
| 			if (cch->emit_upto < cch->esc_len)
 | |
| 				return cch->esc_save[cch->emit_upto++];
 | |
| 			cch->emit_upto = 0;
 | |
| 			cch->emitting = false;
 | |
| 			cch->esc_len = 0;
 | |
| 		}
 | |
| 		return 0;
 | |
| 	} else if (ichar == -ETIMEDOUT) {
 | |
| 		/*
 | |
| 		 * If we are in an escape sequence but nothing has followed the
 | |
| 		 * Escape character, then the user probably just pressed the
 | |
| 		 * Escape key. Return it and clear the sequence.
 | |
| 		 */
 | |
| 		if (cch->esc_len) {
 | |
| 			cch->esc_len = 0;
 | |
| 			return '\e';
 | |
| 		}
 | |
| 
 | |
| 		/* Otherwise there is nothing to return */
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	if (ichar == '\n' || ichar == '\r')
 | |
| 		return '\n';
 | |
| 
 | |
| 	/* handle standard linux xterm esc sequences for arrow key, etc. */
 | |
| 	if (cch->esc_len != 0) {
 | |
| 		enum cli_esc_state_t act;
 | |
| 
 | |
| 		ichar = cli_ch_esc(cch, ichar, &act);
 | |
| 
 | |
| 		switch (act) {
 | |
| 		case ESC_SAVE:
 | |
| 			/* save this character and return nothing */
 | |
| 			cch->esc_save[cch->esc_len++] = ichar;
 | |
| 			ichar = 0;
 | |
| 			break;
 | |
| 		case ESC_REJECT:
 | |
| 			/*
 | |
| 			 * invalid escape sequence, start returning the
 | |
| 			 * characters in it
 | |
| 			 */
 | |
| 			cch->esc_save[cch->esc_len++] = ichar;
 | |
| 			ichar = cch->esc_save[cch->emit_upto++];
 | |
| 			cch->emitting = true;
 | |
| 			return ichar;
 | |
| 		case ESC_CONVERTED:
 | |
| 			/* valid escape sequence, return the resulting char */
 | |
| 			cch->esc_len = 0;
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (ichar == '\e') {
 | |
| 		if (!cch->esc_len) {
 | |
| 			cch->esc_save[cch->esc_len] = ichar;
 | |
| 			cch->esc_len = 1;
 | |
| 		} else {
 | |
| 			puts("impossible condition #876\n");
 | |
| 			cch->esc_len = 0;
 | |
| 		}
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	return ichar;
 | |
| }
 |