1 #include <stdio.h>
2 #include <curses.h>
3 #include <ipxe/ansicol.h>
4 #include <ipxe/console.h>
5 
6 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
7 
8 static void ansiscr_reset(struct _curses_screen *scr) __nonnull;
9 static void ansiscr_movetoyx(struct _curses_screen *scr,
10                                unsigned int y, unsigned int x) __nonnull;
11 static void ansiscr_putc(struct _curses_screen *scr, chtype c) __nonnull;
12 
13 static unsigned int saved_usage;
14 
ansiscr_attrs(struct _curses_screen * scr,attr_t attrs)15 static void ansiscr_attrs ( struct _curses_screen *scr, attr_t attrs ) {
16 	int bold = ( attrs & A_BOLD );
17 	attr_t cpair = PAIR_NUMBER ( attrs );
18 
19 	if ( scr->attrs != attrs ) {
20 		scr->attrs = attrs;
21 		/* Reset attributes and set/clear bold as appropriate */
22 		printf ( "\033[0;%dm", ( bold ? 1 : 22 ) );
23 		/* Set foreground and background colours */
24 		ansicol_set_pair ( cpair );
25 	}
26 }
27 
ansiscr_reset(struct _curses_screen * scr)28 static void ansiscr_reset ( struct _curses_screen *scr ) {
29 	/* Reset terminal attributes and clear screen */
30 	scr->attrs = 0;
31 	scr->curs_x = 0;
32 	scr->curs_y = 0;
33 	printf ( "\0330m" );
34 	ansicol_set_pair ( CPAIR_DEFAULT );
35 	printf ( "\033[2J" );
36 }
37 
ansiscr_init(struct _curses_screen * scr)38 static void ansiscr_init ( struct _curses_screen *scr ) {
39 	saved_usage = console_set_usage ( CONSOLE_USAGE_TUI );
40 	ansiscr_reset ( scr );
41 }
42 
ansiscr_exit(struct _curses_screen * scr)43 static void ansiscr_exit ( struct _curses_screen *scr ) {
44 	ansiscr_reset ( scr );
45 	console_set_usage ( saved_usage );
46 }
47 
ansiscr_erase(struct _curses_screen * scr,attr_t attrs)48 static void ansiscr_erase ( struct _curses_screen *scr, attr_t attrs ) {
49 	ansiscr_attrs ( scr, attrs );
50 	printf ( "\033[2J" );
51 }
52 
ansiscr_movetoyx(struct _curses_screen * scr,unsigned int y,unsigned int x)53 static void ansiscr_movetoyx ( struct _curses_screen *scr,
54 			       unsigned int y, unsigned int x ) {
55 	if ( ( x != scr->curs_x ) || ( y != scr->curs_y ) ) {
56 		/* ANSI escape sequence to update cursor position */
57 		printf ( "\033[%d;%dH", ( y + 1 ), ( x + 1 ) );
58 		scr->curs_x = x;
59 		scr->curs_y = y;
60 	}
61 }
62 
ansiscr_putc(struct _curses_screen * scr,chtype c)63 static void ansiscr_putc ( struct _curses_screen *scr, chtype c ) {
64 	unsigned int character = ( c & A_CHARTEXT );
65 	attr_t attrs = ( c & ( A_ATTRIBUTES | A_COLOR ) );
66 
67 	/* Update attributes if changed */
68 	ansiscr_attrs ( scr, attrs );
69 
70 	/* Print the actual character */
71 	putchar ( character );
72 
73 	/* Update expected cursor position */
74 	if ( ++(scr->curs_x) == COLS ) {
75 		scr->curs_x = 0;
76 		++scr->curs_y;
77 	}
78 }
79 
ansiscr_getc(struct _curses_screen * scr __unused)80 static int ansiscr_getc ( struct _curses_screen *scr __unused ) {
81 	return getchar();
82 }
83 
ansiscr_peek(struct _curses_screen * scr __unused)84 static bool ansiscr_peek ( struct _curses_screen *scr __unused ) {
85 	return iskey();
86 }
87 
ansiscr_cursor(struct _curses_screen * scr __unused,int visibility)88 static void ansiscr_cursor ( struct _curses_screen *scr __unused,
89 			     int visibility ) {
90 	printf ( "\033[?25%c", ( visibility ? 'h' : 'l' ) );
91 }
92 
93 SCREEN _ansi_screen = {
94 	.init		= ansiscr_init,
95 	.exit		= ansiscr_exit,
96 	.erase		= ansiscr_erase,
97 	.movetoyx	= ansiscr_movetoyx,
98 	.putc		= ansiscr_putc,
99 	.getc		= ansiscr_getc,
100 	.peek		= ansiscr_peek,
101 	.cursor		= ansiscr_cursor,
102 };
103