diff mbox

[U-Boot,v2,06/11] cfb_console: Add support for some ANSI terminal escape codes

Message ID 1335634011-9104-7-git-send-email-pali.rohar@gmail.com
State Superseded
Delegated to: Anatolij Gustschin
Headers show

Commit Message

Pali Rohár April 28, 2012, 5:26 p.m. UTC
* This patch add support for move cursor and reverse colors
   via ANSI espace codes in cfb_console driver
 * ANSI escape codes can be enabled/disabled via CONFIG_CFB_CONSOLE_ANSI

Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
---
Changes since v1:
   - Added support ANSI code show/hide cursor
   - Added info to README

Changes since original version:
   - Fixed commit message

 README                      |    3 +
 drivers/video/cfb_console.c |  234 ++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 234 insertions(+), 3 deletions(-)

Comments

Marek Vasut April 28, 2012, 10:19 p.m. UTC | #1
Dear Pali Rohár,

>  * This patch add support for move cursor and reverse colors
>    via ANSI espace codes in cfb_console driver
>  * ANSI escape codes can be enabled/disabled via CONFIG_CFB_CONSOLE_ANSI
> 
> Signed-off-by: Pali Rohár <pali.rohar@gmail.com>
> ---
> Changes since v1:
>    - Added support ANSI code show/hide cursor
>    - Added info to README
> 
> Changes since original version:
>    - Fixed commit message
> 
>  README                      |    3 +
>  drivers/video/cfb_console.c |  234
> ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 234
> insertions(+), 3 deletions(-)
> 
> diff --git a/README b/README
> index 60ad9c2..4a610f7 100644
> --- a/README
> +++ b/README
> @@ -613,6 +613,9 @@ The following options need to be configured:
>  						additional board info beside
>  						the logo
> 
> +		When CONFIG_CFB_CONSOLE_ANSI is defined, console will have
> +		ANSI terminal support. Needed for CONFIG_CMDLINE_EDITING.
> +
>  		When CONFIG_CFB_CONSOLE is defined, video console is
>  		default i/o. Serial console can be forced with
>  		environment 'console=serial'.
> diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
> index 43eb994..c9f9765 100644
> --- a/drivers/video/cfb_console.c
> +++ b/drivers/video/cfb_console.c
> @@ -377,6 +377,11 @@ static int console_row;		/* cursor row */
> 
>  static u32 eorx, fgx, bgx;	/* color pats */
> 
> +static char ansi_buf[10] = { 0, };
> +static int ansi_buf_size;
> +static int ansi_colors_need_revert;
> +static int ansi_cursor_hidden;
> +
>  static const int video_font_draw_table8[] = {
>  	0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
>  	0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
> @@ -602,6 +607,14 @@ static void video_putchar(int xx, int yy, unsigned
> char c) video_drawchars(xx, yy + video_logo_height, &c, 1);
>  }
> 
> +static void console_swap_colors(void)
> +{
> +	eorx = fgx;
> +	fgx = bgx;
> +	bgx = eorx;
> +	eorx = fgx ^ bgx;
> +}
> +
>  #if defined(CONFIG_CONSOLE_CURSOR) || defined(CONFIG_VIDEO_SW_CURSOR)
>  static void video_set_cursor(void)
>  {
> @@ -843,11 +856,12 @@ static void console_cr(void)
>  	console_col = 0;
>  }
> 
> -void video_putc(const char c)
> +static void parse_putc(const char c)
>  {
>  	static int nl = 1;
> 
> -	CURSOR_OFF;
> +	if (!ansi_cursor_hidden)
> +		CURSOR_OFF;
> 
>  	switch (c) {
>  	case 13:		/* back to first column */
> @@ -883,7 +897,221 @@ void video_putc(const char c)
>  			nl = 0;
>  		}
>  	}
> -	CURSOR_SET;
> +
> +	if (!ansi_cursor_hidden)
> +		CURSOR_SET;
> +}
> +
> +void video_putc(const char c)
> +{
> +#ifdef CONFIG_CFB_CONSOLE_ANSI
> +	int i;
> +
> +	if (c == 27) {
> +		for (i = 0; i < ansi_buf_size; ++i)
> +			parse_putc(ansi_buf[i]);
> +		ansi_buf[0] = 27;
> +		ansi_buf_size = 1;
> +		return;
> +	}
> +
> +	if (ansi_buf_size > 0) {
> +		/*
> +		0 - ESC
> +		1 - [
> +		2 - num1
> +		3 - ..
> +		4 - ;
> +		5 - num2
> +		6 - ..
> +		7 - cchar

wrong comment ... did you even run these patches through checkpatch? Run them 
and resubmit please, I'm ending my review here.

> +		*/
> +		int next = 0;
> +
> +		int flush = 0;
> +		int fail = 0;
> +
> +		int num1 = 0;
> +		int num2 = 0;
> +		int cchar = 0;
> +
> +		ansi_buf[ansi_buf_size++] = c;
> +
> +		if (ansi_buf_size >= sizeof(ansi_buf))
> +			fail = 1;
> +
> +		for (i = 0; i < ansi_buf_size; ++i) {
> +			if (fail)
> +				break;
> +
> +			switch (next) {
> +			case 0:
> +				if (ansi_buf[i] == 27)
> +					next = 1;
> +				else
> +					fail = 1;
> +				break;
> +
> +			case 1:
> +				if (ansi_buf[i] == '[')
> +					next = 2;
> +				else
> +					fail = 1;
> +				break;
> +
> +			case 2:
> +				if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
> +					num1 = ansi_buf[i]-'0';
> +					next = 3;
> +				} else if (ansi_buf[i] != '?') {
> +					--i;
> +					num1 = 1;
> +					next = 4;
> +				}
> +				break;
> +
> +			case 3:
> +				if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
> +					num1 *= 10;
> +					num1 += ansi_buf[i]-'0';
> +				} else {
> +					--i;
> +					next = 4;
> +				}
> +				break;
> +
> +			case 4:
> +				if (ansi_buf[i] != ';') {
> +					--i;
> +					next = 7;
> +				} else
> +					next = 5;
> +				break;
> +
> +			case 5:
> +				if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
> +					num2 = ansi_buf[i]-'0';
> +					next = 6;
> +				} else
> +					fail = 1;
> +				break;
> +
> +			case 6:
> +				if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
> +					num2 *= 10;
> +					num2 += ansi_buf[i]-'0';
> +				} else {
> +					--i;
> +					next = 7;
> +				}
> +				break;
> +
> +			case 7:
> +				if ((ansi_buf[i] >= 'A' && ansi_buf[i] <= 'H')
> +					|| ansi_buf[i] == 'J'
> +					|| ansi_buf[i] == 'K'
> +					|| ansi_buf[i] == 'h'
> +					|| ansi_buf[i] == 'l'
> +					|| ansi_buf[i] == 'm') {
> +					cchar = ansi_buf[i];
> +					flush = 1;
> +				} else
> +					fail = 1;
> +				break;
> +			}
> +		}
> +
> +		if (fail) {
> +			for (i = 0; i < ansi_buf_size; ++i)
> +				parse_putc(ansi_buf[i]);
> +			ansi_buf_size = 0;
> +			return;
> +		}
> +
> +		if (flush) {
> +			if (!ansi_cursor_hidden)
> +				CURSOR_OFF;
> +			ansi_buf_size = 0;
> +			switch (cchar) {
> +			case 'A':
> +				/* move cursor num1 rows up */
> +				console_cursor_up(num1);
> +				break;
> +			case 'B':
> +				/* move cursor num1 rows down */
> +				console_cursor_down(num1);
> +				break;
> +			case 'C':
> +				/* move cursor num1 columns forward */
> +				console_cursor_right(num1);
> +				break;
> +			case 'D':
> +				/* move cursor num1 columns back */
> +				console_cursor_left(num1);
> +				break;
> +			case 'E':
> +				/* move cursor num1 rows up at begin of row */
> +				console_previewsline(num1);
> +				break;
> +			case 'F':
> +				/* move cursor num1 rows down at begin of row */
> +				console_newline(num1);
> +				break;
> +			case 'G':
> +				/* move cursor to column num1 */
> +				console_cursor_set_position(-1, num1-1);
> +				break;
> +			case 'H':
> +				/* move cursor to row num1, column num2 */
> +				console_cursor_set_position(num1-1, num2-1);
> +				break;
> +			case 'J':
> +				/* clear console and move cursor to 0, 0 */
> +				console_clear();
> +				console_cursor_set_position(0, 0);
> +				break;
> +			case 'K':
> +				/* clear line */
> +				if (num1 == 0)
> +					console_clear_line(console_row,
> +							console_col,
> +							CONSOLE_COLS-1);
> +				else if (num1 == 1)
> +					console_clear_line(console_row,
> +							0, console_col);
> +				else
> +					console_clear_line(console_row,
> +							0, CONSOLE_COLS-1);
> +				break;
> +			case 'h':
> +				ansi_cursor_hidden = 0;
> +				break;
> +			case 'l':
> +				ansi_cursor_hidden = 1;
> +				break;
> +			case 'm':
> +				if (num1 == 0) { /* reset swapped colors */
> +					if (ansi_colors_need_revert) {
> +						console_swap_colors();
> +						ansi_colors_need_revert = 0;
> +					}
> +				} else if (num1 == 7) { /* once swap colors */
> +					if (!ansi_colors_need_revert) {
> +						console_swap_colors();
> +						ansi_colors_need_revert = 1;
> +					}
> +				}
> +				break;
> +			}
> +			if (!ansi_cursor_hidden)
> +				CURSOR_SET;
> +		}
> +	} else {
> +		parse_putc(c);
> +	}
> +#else
> +	parse_putc(c);
> +#endif
>  }
> 
>  void video_puts(const char *s)
Pali Rohár April 29, 2012, 7:29 a.m. UTC | #2
On Sunday 29 April 2012 00:19:03 Marek Vasut wrote:
> > +
> > +	if (ansi_buf_size > 0) {
> > +		/*
> > +		0 - ESC
> > +		1 - [
> > +		2 - num1
> > +		3 - ..
> > +		4 - ;
> > +		5 - num2
> > +		6 - ..
> > +		7 - cchar
> 
> wrong comment ... did you even run these patches through
> checkpatch? Run them and resubmit please, I'm ending my review
> here.
> 

Yes, I all patches except first is OK for checkpatch. It show no 
errors and no warnings.
Wolfgang Denk April 29, 2012, 12:42 p.m. UTC | #3
Dear Pali =?ISO-8859-1?Q?Roh=E1r?=,

In message <3284404.3VX1zBQJtc@pali> you wrote:
> 
> > > +	if (ansi_buf_size > 0) {
> > > +		/*
> > > +		0 - ESC
> > > +		1 - [
> > > +		2 - num1
> > > +		3 - ..
> > > +		4 - ;
> > > +		5 - num2
> > > +		6 - ..
> > > +		7 - cchar
> > 
> > wrong comment ... did you even run these patches through
> > checkpatch? Run them and resubmit please, I'm ending my review
> > here.
>
> Yes, I all patches except first is OK for checkpatch. It show no 
> errors and no warnings.

Nevertheless, this violates the CodingStyle (see entry for multiline
comments); please fix globally.

Best regards,

Wolfgang Denk
diff mbox

Patch

diff --git a/README b/README
index 60ad9c2..4a610f7 100644
--- a/README
+++ b/README
@@ -613,6 +613,9 @@  The following options need to be configured:
 						additional board info beside
 						the logo
 
+		When CONFIG_CFB_CONSOLE_ANSI is defined, console will have
+		ANSI terminal support. Needed for CONFIG_CMDLINE_EDITING.
+
 		When CONFIG_CFB_CONSOLE is defined, video console is
 		default i/o. Serial console can be forced with
 		environment 'console=serial'.
diff --git a/drivers/video/cfb_console.c b/drivers/video/cfb_console.c
index 43eb994..c9f9765 100644
--- a/drivers/video/cfb_console.c
+++ b/drivers/video/cfb_console.c
@@ -377,6 +377,11 @@  static int console_row;		/* cursor row */
 
 static u32 eorx, fgx, bgx;	/* color pats */
 
+static char ansi_buf[10] = { 0, };
+static int ansi_buf_size;
+static int ansi_colors_need_revert;
+static int ansi_cursor_hidden;
+
 static const int video_font_draw_table8[] = {
 	0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
 	0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
@@ -602,6 +607,14 @@  static void video_putchar(int xx, int yy, unsigned char c)
 	video_drawchars(xx, yy + video_logo_height, &c, 1);
 }
 
+static void console_swap_colors(void)
+{
+	eorx = fgx;
+	fgx = bgx;
+	bgx = eorx;
+	eorx = fgx ^ bgx;
+}
+
 #if defined(CONFIG_CONSOLE_CURSOR) || defined(CONFIG_VIDEO_SW_CURSOR)
 static void video_set_cursor(void)
 {
@@ -843,11 +856,12 @@  static void console_cr(void)
 	console_col = 0;
 }
 
-void video_putc(const char c)
+static void parse_putc(const char c)
 {
 	static int nl = 1;
 
-	CURSOR_OFF;
+	if (!ansi_cursor_hidden)
+		CURSOR_OFF;
 
 	switch (c) {
 	case 13:		/* back to first column */
@@ -883,7 +897,221 @@  void video_putc(const char c)
 			nl = 0;
 		}
 	}
-	CURSOR_SET;
+
+	if (!ansi_cursor_hidden)
+		CURSOR_SET;
+}
+
+void video_putc(const char c)
+{
+#ifdef CONFIG_CFB_CONSOLE_ANSI
+	int i;
+
+	if (c == 27) {
+		for (i = 0; i < ansi_buf_size; ++i)
+			parse_putc(ansi_buf[i]);
+		ansi_buf[0] = 27;
+		ansi_buf_size = 1;
+		return;
+	}
+
+	if (ansi_buf_size > 0) {
+		/*
+		0 - ESC
+		1 - [
+		2 - num1
+		3 - ..
+		4 - ;
+		5 - num2
+		6 - ..
+		7 - cchar
+		*/
+		int next = 0;
+
+		int flush = 0;
+		int fail = 0;
+
+		int num1 = 0;
+		int num2 = 0;
+		int cchar = 0;
+
+		ansi_buf[ansi_buf_size++] = c;
+
+		if (ansi_buf_size >= sizeof(ansi_buf))
+			fail = 1;
+
+		for (i = 0; i < ansi_buf_size; ++i) {
+			if (fail)
+				break;
+
+			switch (next) {
+			case 0:
+				if (ansi_buf[i] == 27)
+					next = 1;
+				else
+					fail = 1;
+				break;
+
+			case 1:
+				if (ansi_buf[i] == '[')
+					next = 2;
+				else
+					fail = 1;
+				break;
+
+			case 2:
+				if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
+					num1 = ansi_buf[i]-'0';
+					next = 3;
+				} else if (ansi_buf[i] != '?') {
+					--i;
+					num1 = 1;
+					next = 4;
+				}
+				break;
+
+			case 3:
+				if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
+					num1 *= 10;
+					num1 += ansi_buf[i]-'0';
+				} else {
+					--i;
+					next = 4;
+				}
+				break;
+
+			case 4:
+				if (ansi_buf[i] != ';') {
+					--i;
+					next = 7;
+				} else
+					next = 5;
+				break;
+
+			case 5:
+				if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
+					num2 = ansi_buf[i]-'0';
+					next = 6;
+				} else
+					fail = 1;
+				break;
+
+			case 6:
+				if (ansi_buf[i] >= '0' && ansi_buf[i] <= '9') {
+					num2 *= 10;
+					num2 += ansi_buf[i]-'0';
+				} else {
+					--i;
+					next = 7;
+				}
+				break;
+
+			case 7:
+				if ((ansi_buf[i] >= 'A' && ansi_buf[i] <= 'H')
+					|| ansi_buf[i] == 'J'
+					|| ansi_buf[i] == 'K'
+					|| ansi_buf[i] == 'h'
+					|| ansi_buf[i] == 'l'
+					|| ansi_buf[i] == 'm') {
+					cchar = ansi_buf[i];
+					flush = 1;
+				} else
+					fail = 1;
+				break;
+			}
+		}
+
+		if (fail) {
+			for (i = 0; i < ansi_buf_size; ++i)
+				parse_putc(ansi_buf[i]);
+			ansi_buf_size = 0;
+			return;
+		}
+
+		if (flush) {
+			if (!ansi_cursor_hidden)
+				CURSOR_OFF;
+			ansi_buf_size = 0;
+			switch (cchar) {
+			case 'A':
+				/* move cursor num1 rows up */
+				console_cursor_up(num1);
+				break;
+			case 'B':
+				/* move cursor num1 rows down */
+				console_cursor_down(num1);
+				break;
+			case 'C':
+				/* move cursor num1 columns forward */
+				console_cursor_right(num1);
+				break;
+			case 'D':
+				/* move cursor num1 columns back */
+				console_cursor_left(num1);
+				break;
+			case 'E':
+				/* move cursor num1 rows up at begin of row */
+				console_previewsline(num1);
+				break;
+			case 'F':
+				/* move cursor num1 rows down at begin of row */
+				console_newline(num1);
+				break;
+			case 'G':
+				/* move cursor to column num1 */
+				console_cursor_set_position(-1, num1-1);
+				break;
+			case 'H':
+				/* move cursor to row num1, column num2 */
+				console_cursor_set_position(num1-1, num2-1);
+				break;
+			case 'J':
+				/* clear console and move cursor to 0, 0 */
+				console_clear();
+				console_cursor_set_position(0, 0);
+				break;
+			case 'K':
+				/* clear line */
+				if (num1 == 0)
+					console_clear_line(console_row,
+							console_col,
+							CONSOLE_COLS-1);
+				else if (num1 == 1)
+					console_clear_line(console_row,
+							0, console_col);
+				else
+					console_clear_line(console_row,
+							0, CONSOLE_COLS-1);
+				break;
+			case 'h':
+				ansi_cursor_hidden = 0;
+				break;
+			case 'l':
+				ansi_cursor_hidden = 1;
+				break;
+			case 'm':
+				if (num1 == 0) { /* reset swapped colors */
+					if (ansi_colors_need_revert) {
+						console_swap_colors();
+						ansi_colors_need_revert = 0;
+					}
+				} else if (num1 == 7) { /* once swap colors */
+					if (!ansi_colors_need_revert) {
+						console_swap_colors();
+						ansi_colors_need_revert = 1;
+					}
+				}
+				break;
+			}
+			if (!ansi_cursor_hidden)
+				CURSOR_SET;
+		}
+	} else {
+		parse_putc(c);
+	}
+#else
+	parse_putc(c);
+#endif
 }
 
 void video_puts(const char *s)