xref: /aosp_15_r20/external/coreboot/payloads/libpayload/curses/tinycurses.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*
2  *
3  * Copyright (C) 2007 Uwe Hermann <[email protected]>
4  * Copyright (C) 2008 Ulf Jordan <[email protected]>
5  * Copyright (C) 2008-2009 coresystems GmbH
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 /*
32  * This is a tiny implementation of the (n)curses library intended to be
33  * used in embedded/firmware/BIOS code where no libc or operating system
34  * environment is available and code size is very important.
35  *
36  * Design goals:
37  *  - Small object code.
38  *  - Self-contained.
39  *    - Doesn't require a libc (no glibc/uclibc/dietlibc/klibc/newlib).
40  *    - Works without any other external libraries or header files.
41  *  - Works without an underlying operating system.
42  *    - Doesn't use files, signals, syscalls, ttys, library calls, etc.
43  *  - Doesn't do any dynamic memory allocation (no malloc() and friends).
44  *     - All data structures are statically allocated.
45  *  - Supports standard VGA console (80x25) and serial port console.
46  *     - This includes character output and keyboard input over serial.
47  *  - Supports beep() through a minimal PC speaker driver.
48  *
49  * Limitations:
50  *  - Only implements a small subset of the (n)curses functions.
51  *  - Only implements very few sanity checks (for smaller code).
52  *     - Thus: Don't do obviously stupid things in your code.
53  *  - Doesn't implement the 'form', 'panel', and 'menu' extensions.
54  *  - Only implements C bindings (no C++, Ada95, or others).
55  *  - Doesn't include wide character support.
56  */
57 
58 #include "local.h"
59 
60 #undef _XOPEN_SOURCE_EXTENDED
61 #define _XOPEN_SOURCE_EXTENDED 1
62 
63 #define MAX_WINDOWS 3
64 
65 /* Statically allocate all structures (no malloc())! */
66 static WINDOW window_list[MAX_WINDOWS];
67 static int window_count = 0;
68 
69 // struct ldat foo;
70 static struct ldat ldat_list[MAX_WINDOWS][SCREEN_Y];
71 static int ldat_count = 0;
72 
73 /* One item bigger than SCREEN_X to reserve space for a NUL byte. */
74 static NCURSES_CH_T linebuf_list[SCREEN_Y * MAX_WINDOWS][SCREEN_X + 1];
75 static int linebuf_count = 0;
76 
77 /* Globals */
78 int COLORS;		/* Currently unused? */
79 int COLOR_PAIRS = 255;
80 WINDOW *stdscr;
81 WINDOW *curscr;
82 WINDOW *newscr;
83 int LINES = 25;
84 int COLS = 80;
85 int TABSIZE;
86 int ESCDELAY;
87 // char ttytype[];
88 // cchar_t *_nc_wacs;
89 SCREEN *SP;
90 chtype acs_map[128];
91 
92 /* See terminfo(5). */
93 chtype fallback_acs_map[128] =
94 	{
95 	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
96 	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
97 	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
98 	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
99 	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
100 	' ',	' ',	' ',	'>',	'<',	'^',	'v',	' ',
101 	'#',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
102 	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
103 	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
104 	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
105 	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
106 	' ',	' ',	' ',	' ',	' ',	' ',	' ',	' ',
107 	'+',	':',	' ',	' ',	' ',	' ',	'\\',   '#',
108 	'#',	'#',	'+',	'+',	'+',	'+',	'+',	'~',
109 	'-',	'-',	'-',	'_',	'+',	'+',	'+',	'+',
110 	'|',	'<',	'>',	'*',	'!',	'f',	'o',	' ',
111 	};
112 
113 #if CONFIG(LP_SERIAL_CONSOLE)
114 #if CONFIG(LP_SERIAL_ACS_FALLBACK)
115 chtype serial_acs_map[128];
116 #else
117 /* See acsc of vt100. */
118 chtype serial_acs_map[128] =
119 	{
120 	0,	0,	0,	0,	0,	0,	0,	0,
121 	0,	0,	0,	0,	0,	0,	0,	0,
122 	0,	0,	0,	0,	0,	0,	0,	0,
123 	0,	0,	0,	0,	0,	0,	0,	0,
124 	0,	0,	0,	0,	0,	0,	0,	0,
125 	0,	0,	0,	0,	0,	0,	0,	0,
126 	0,	0,	0,	0,	0,	0,	0,	0,
127 	0,	0,	0,	0,	0,	0,	0,	0,
128 	0,	0,	0,	0,	0,	0,	0,	0,
129 	0,	0,	0,	0,	0,	0,	0,	0,
130 	0,	0,	0,	0,	0,	0,	0,	0,
131 	0,	0,	0,	0,	0,	0,	0,	0,
132 	'`',	'a',	0,	0,	0,	0,	'f',	'g',
133 	0,	0,	'j',	'k',	'l',	'm',	'n',	'o',
134 	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
135 	'x',	'y',	'z',	'{',	'|',	'}',	'~',	0,
136 	};
137 #endif
138 #endif
139 
140 #if CONFIG(LP_VIDEO_CONSOLE)
141 /* See acsc of linux. */
142 chtype console_acs_map[128] =
143 	{
144 	0,	0,	0,	0,	0,	0,	0,	0,
145 	0,	0,	0,	0,	0,	0,	0,	0,
146 	0,	0,	0,	0,	0,	0,	0,	0,
147 	0,	0,	0,	0,	0,	0,	0,	0,
148 	0,	0,	0,	0,	0,	0,	0,	0,
149 	0,	0,	0,	'\020', '\021', '\030', '\031',	0,
150 	'\333',	0,	0,	0,	0,	0,	0,	0,
151 	0,	0,	0,	0,	0,	0,	0,	0,
152 	0,	0,	0,	0,	0,	0,	0,	0,
153 	0,	0,	0,	0,	0,	0,	0,	0,
154 	0,	0,	0,	0,	0,	0,	0,	0,
155 	0,	0,	0,	0,	0,	0,	0,	0,
156 	'\004',	'\261',	0,	0,	0,	0,	'\370',	'\361',
157 	'\260',	'\316',	'\331',	'\277',	'\332',	'\300',	'\305',	'~',
158 	'\304',	'\304',	'\304',	'_',	'\303', '\264', '\301',	'\302',
159 	'\263',	'\363',	'\362',	'\343',	'\330',	'\234',	'\376',	0,
160 	};
161 #endif
162 
163 // FIXME: Ugly (and insecure!) hack!
164 char sprintf_tmp[1024];
165 
166 int curses_flags = (F_ENABLE_CONSOLE | F_ENABLE_SERIAL);
167 
168 /* Return bit mask for clearing color pair number if given ch has color */
169 #define COLOR_MASK(ch) (~(attr_t)((ch) & A_COLOR ? A_COLOR : 0))
170 
171 /* Compute a rendition of the given char correct for the current context. */
render_char(WINDOW * win,NCURSES_CH_T ch)172 static inline NCURSES_CH_T render_char(WINDOW *win, NCURSES_CH_T ch)
173 {
174 	/* TODO. */
175 	return ch;
176 }
177 
178 /* Make render_char() visible while still allowing us to inline it below. */
_nc_render(WINDOW * win,NCURSES_CH_T ch)179 NCURSES_CH_T _nc_render(WINDOW *win, NCURSES_CH_T ch)
180 {
181 	return render_char(win, ch);
182 }
183 
184 /*
185  * Implementations of most functions marked 'implemented' in include/curses.h:
186  */
187 
188 // int baudrate(void) {}
beep(void)189 int beep(void)
190 {
191 	/* TODO: Flash the screen if beeping fails? */
192 #if CONFIG(LP_SPEAKER)
193 	speaker_tone(1760, 500);	/* 1760 == note A6 */
194 #endif
195 	return OK;
196 }
197 // bool can_change_color(void) {}
cbreak(void)198 int cbreak(void) { /* TODO */ return 0; }
clearok(WINDOW * win,bool flag)199 /* D */ int clearok(WINDOW *win, bool flag) { win->_clear = flag; return OK; }
200 // int color_content(short color, short *r, short *g, short *b) {}
curs_set(int on)201 int curs_set(int on)
202 {
203 #if CONFIG(LP_SERIAL_CONSOLE)
204 	if (curses_flags & F_ENABLE_SERIAL) {
205 		serial_cursor_enable(on);
206 	}
207 #endif
208 #if CONFIG(LP_VIDEO_CONSOLE)
209 	if (curses_flags & F_ENABLE_CONSOLE) {
210 		video_console_cursor_enable(on);
211 	}
212 #endif
213 
214 	return OK;
215 }
216 // int def_prog_mode(void) {}
217 // int def_shell_mode(void) {}
218 // int delay_output(int) {}
219 // void delscreen(SCREEN *) {}
delwin(WINDOW * win)220 int delwin(WINDOW *win)
221 {
222 	/* TODO: Don't try to delete stdscr. */
223 	/* TODO: Don't delete parent windows before subwindows. */
224 
225 	// if (win->_flags & _SUBWIN)
226 	// 	touchwin(win->_parent);
227 	// else if (curscr != 0)
228 	// 	touchwin(curscr);
229 
230 	// return _nc_freewin(win);
231 	return OK;
232 }
derwin(WINDOW * orig,int num_lines,int num_columns,int begy,int begx)233 WINDOW *derwin(WINDOW *orig, int num_lines, int num_columns, int begy, int begx)
234 {
235 #if 0
236 	WINDOW *win = NULL;
237 	int i;
238 	int flags = _SUBWIN;
239 
240 	/* Make sure window fits inside the original one. */
241 	if (begy < 0 || begx < 0 || orig == 0 || num_lines < 0
242 	    || num_columns < 0)
243 		return NULL;
244 
245 	if (begy + num_lines > orig->_maxy + 1
246 	    || begx + num_columns > orig->_maxx + 1)
247 		return NULL;
248 
249 	if (num_lines == 0)
250 		num_lines = orig->_maxy + 1 - begy;
251 
252 	if (num_columns == 0)
253 		num_columns = orig->_maxx + 1 - begx;
254 
255 	if (orig->_flags & _ISPAD)
256 		flags |= _ISPAD;
257 
258 	// FIXME
259 	if ((win = _nc_makenew(num_lines, num_columns, orig->_begy + begy,
260 	                        orig->_begx + begx, flags)) == 0)
261 	     return NULL;
262 
263 	win->_pary = begy;
264 	win->_parx = begx;
265 	WINDOW_ATTRS(win) = WINDOW_ATTRS(orig);
266 	win->_nc_bkgd = orig->_nc_bkgd;
267 
268 	for (i = 0; i < num_lines; i++)
269 		win->_line[i].text = &orig->_line[begy++].text[begx];
270 
271 	win->_parent = orig;
272 
273 	return win;
274 #else
275 	return NULL;
276 #endif
277 }
doupdate(void)278 int doupdate(void) { /* TODO */ return(0); }
279 // WINDOW * dupwin (WINDOW *) {}
echo(void)280 /* D */ int echo(void) { SP->_echo = TRUE; return OK; }
endwin(void)281 int endwin(void)
282 {
283 	if (!SP)
284 		return ERR;
285 
286 	SP->_endwin = TRUE;
287 #ifdef NCURSES_MOUSE_VERSION
288 	SP->_mouse_wrap(SP);
289 #endif
290 	// _nc_screen_wrap();
291 	// _nc_mvcur_wrap();       /* wrap up cursor addressing */
292 	// return reset_shell_mode();
293 	return OK;	// FIXME
294 }
295 // char erasechar (void) {}
296 // void filter (void) {}
297 // int flash(void) {}
flushinp(void)298 int flushinp(void) { /* TODO */ return 0; }
299 // WINDOW *getwin (FILE *) {}
has_colors(void)300 bool has_colors (void) { return(TRUE); }
301 // bool has_ic (void) {}
302 // bool has_il (void) {}
303 // void idcok (WINDOW *, bool) {}
304 // int idlok (WINDOW *, bool) {}
immedok(WINDOW * win,bool flag)305 void immedok(WINDOW *win, bool flag) { win->_immed = flag; }
306 /** Note: Must _not_ be called twice! */
initscr(void)307 WINDOW *initscr(void)
308 {
309 	int i;
310 
311 	// newterm(name, stdout, stdin);
312 	// def_prog_mode();
313 
314 	for (i = 0; i < 128; i++)
315 	  acs_map[i] = (chtype) i | A_ALTCHARSET;
316 #if CONFIG(LP_SERIAL_CONSOLE)
317 	if (curses_flags & F_ENABLE_SERIAL) {
318 		serial_clear();
319 	}
320 #endif
321 #if CONFIG(LP_VIDEO_CONSOLE)
322 	if (curses_flags & F_ENABLE_CONSOLE) {
323 		/* Clear the screen and kill the cursor */
324 
325 		video_console_clear();
326 		video_console_cursor_enable(0);
327 	}
328 #endif
329 
330 	// Speaker init?
331 
332 	stdscr = newwin(SCREEN_Y, SCREEN_X, 0, 0);
333 	// TODO: curscr, newscr?
334 
335 	werase(stdscr);
336 
337 	return stdscr;
338 }
339 // int intrflush (WINDOW *,bool) {}
isendwin(void)340 /* D */ bool isendwin(void) { return ((SP == NULL) ? FALSE : SP->_endwin); }
341 // bool is_linetouched (WINDOW *,int) {}
342 // bool is_wintouched (WINDOW *) {}
343 // NCURSES_CONST char * keyname (int) {}
keypad(WINDOW * win,bool flag)344 int keypad (WINDOW *win, bool flag) { /* TODO */ return 0; }
345 // char killchar (void) {}
leaveok(WINDOW * win,bool flag)346 /* D */ int leaveok(WINDOW *win, bool flag) { win->_leaveok = flag; return OK; }
347 // char *longname (void) {}
348 // int meta (WINDOW *,bool) {}
349 // int mvcur (int,int,int,int) {}
350 // int mvderwin (WINDOW *, int, int) {}
mvprintw(int y,int x,const char * fmt,...)351 int mvprintw(int y, int x, const char *fmt, ...)
352 {
353 	va_list argp;
354 	int code;
355 
356 	if (move(y, x) == ERR)
357 		return ERR;
358 
359 	va_start(argp, fmt);
360 	code = vwprintw(stdscr, fmt, argp);
361 	va_end(argp);
362 
363 	return code;
364 }
365 // int mvscanw (int,int, NCURSES_CONST char *,...) {}
366 // int mvwin (WINDOW *,int,int) {}
mvwprintw(WINDOW * win,int y,int x,const char * fmt,...)367 int mvwprintw(WINDOW *win, int y, int x, const char *fmt, ...)
368 {
369 	va_list argp;
370 	int code;
371 
372 	if (wmove(win, y, x) == ERR)
373 		return ERR;
374 
375 	va_start(argp, fmt);
376 	code = vwprintw(win, fmt, argp);
377 	va_end(argp);
378 
379 	return code;
380 }
381 // int mvwscanw (WINDOW *,int,int, NCURSES_CONST char *,...) {}
382 // int napms (int) {}
383 // WINDOW *newpad (int,int) {}
384 // SCREEN *newterm (NCURSES_CONST char *,FILE *,FILE *) {}
newwin(int num_lines,int num_columns,int begy,int begx)385 WINDOW *newwin(int num_lines, int num_columns, int begy, int begx)
386 {
387 	WINDOW *win;
388 	int i;
389 
390 	/* Use next statically allocated window. */
391 	// TODO: Error handling. Yes. Please.
392 	// TODO: WINDOWLIST?
393 
394 	if (window_count >= MAX_WINDOWS)
395 		return NULL;
396 
397 	win = &window_list[window_count++];
398 
399 	// bool is_pad = (flags & _ISPAD);
400 
401 	// TODO: Checks.
402 
403 	win->_cury = 0;
404 	win->_curx = 0;
405 	win->_maxy = num_lines - 1;
406 	win->_maxx = num_columns - 1;
407 	win->_begy = begy;
408 	win->_begx = begx;
409 	// win->_yoffset = SP->_topstolen;
410 
411 	win->_line = ldat_list[ldat_count++];
412 
413 	/* FIXME: Is this right? Should the window attributes be normal? */
414 	win->_color = PAIR_NUMBER(0);
415 	win->_attrs = A_NORMAL;
416 
417 	for (i = 0; i < num_lines; i++)
418 		win->_line[i].text =
419 		     (NCURSES_CH_T *)&linebuf_list[linebuf_count++];
420 
421 	return win;
422 }
nl(void)423 /* D */ int nl(void) { SP->_nl = TRUE; return OK; }
noecho(void)424 /* D */ int noecho(void) { SP->_echo = FALSE; return OK; }
nonl(void)425 /* D */ int nonl(void) { SP->_nl = FALSE; return OK; }
426 // void noqiflush (void) {}
427 // int noraw (void) {}
notimeout(WINDOW * win,bool f)428 /* D */ int notimeout (WINDOW *win, bool f) { win->_notimeout = f; return OK; }
429 // int overlay (const WINDOW*,WINDOW *) {}
430 // int overwrite (const WINDOW*,WINDOW *) {}
431 // int pair_content (short,short*,short*) {}
432 // int pechochar (WINDOW *, const chtype) {}
433 // int pnoutrefresh (WINDOW*,int,int,int,int,int,int) {}
434 // int prefresh (WINDOW *,int,int,int,int,int,int) {}
printw(const char * fmt,...)435 int printw(const char *fmt, ...)
436 {
437 	va_list argp;
438 	int code;
439 
440 	va_start(argp, fmt);
441 	code = vwprintw(stdscr, fmt, argp);
442 	va_end(argp);
443 
444 	return code;
445 }
446 // int putwin (WINDOW *, FILE *) {}
447 // void qiflush (void) {}
448 // int raw (void) {}
449 // int resetty (void) {}
450 // int reset_prog_mode (void) {}
451 // int reset_shell_mode (void) {}
452 // int ripoffline (int, int (*)(WINDOW *, int)) {}
453 // int savetty (void) {}
454 // int scanw (NCURSES_CONST char *,...) {}
455 // int scr_dump (const char *) {}
456 // int scr_init (const char *) {}
scrollok(WINDOW * win,bool flag)457 /* D */ int scrollok(WINDOW *win, bool flag) { win->_scroll = flag; return OK; }
458 // int scr_restore (const char *) {}
459 // int scr_set (const char *) {}
460 // SCREEN *set_term (SCREEN *) {}
461 // int slk_attroff (const chtype) {}
462 // int slk_attron (const chtype) {}
463 // int slk_attrset (const chtype) {}
464 // attr_t slk_attr (void) {}
465 // int slk_attr_set (const attr_t,short,void*) {}
466 // int slk_clear (void) {}
467 // int slk_color (short) {}
468 // int slk_init (int) {}
slk_label(int n)469 /* D */ char *slk_label(int n)
470 {
471 	// TODO: Needed?
472 	// if (SP == NULL || SP->_slk == NULL || n < 1 || n > SP->_slk->labcnt)
473 	// 	return NULL;
474 	return SP->_slk->ent[n - 1].ent_text;
475 }
476 // int slk_noutrefresh (void) {}
477 // int slk_refresh (void) {}
478 // int slk_restore (void) {}
479 // int slk_set (int,const char *,int) {}
480 // int slk_touch (void) {}
481 
482 // WINDOW *subpad (WINDOW *, int, int, int, int) {}
subwin(WINDOW * w,int l,int c,int y,int x)483 WINDOW *subwin(WINDOW *w, int l, int c, int y, int x)
484 {
485 	return derwin(w, l, c, y - w->_begy, x - w->_begx);
486 }
487 // int syncok (WINDOW *, bool) {}
488 // chtype termattrs (void) {}
489 // char *termname (void) {}
490 // int typeahead (int) {}
ungetch(int ch)491 int ungetch(int ch) { /* TODO */ return ERR; }
492 // void use_env (bool) {}
493 // int vidattr (chtype) {}
494 // int vidputs (chtype, int (*)(int)) {}
vwprintw(WINDOW * win,const char * fmt,va_list argp)495 int vwprintw(WINDOW *win, const char *fmt, va_list argp)
496 {
497 	vsprintf((char *)&sprintf_tmp, fmt, argp);
498 
499 	/* TODO: Error handling? */
500 	return waddstr(win, (char *)&sprintf_tmp);
501 }
502 // int vwscanw (WINDOW *, NCURSES_CONST char *,va_list) {}
waddch(WINDOW * win,const chtype ch)503 int waddch(WINDOW *win, const chtype ch)
504 {
505 	int code = ERR;
506 	// NCURSES_CH_T wch;
507 	// SetChar2(wch, ch);
508 
509 	if (win->_line[win->_cury].firstchar == _NOCHANGE ||
510 			win->_line[win->_cury].firstchar > win->_curx)
511 		win->_line[win->_cury].firstchar = win->_curx;
512 
513 	win->_line[win->_cury].text[win->_curx].chars[0] =
514 		((ch) & (chtype)A_CHARTEXT);
515 
516 	win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win);
517 	win->_line[win->_cury].text[win->_curx].attr |=
518 		((ch) & (chtype)A_ATTRIBUTES);
519 
520 	if (win->_line[win->_cury].lastchar == _NOCHANGE ||
521 			win->_line[win->_cury].lastchar < win->_curx)
522 		win->_line[win->_cury].lastchar = win->_curx;
523 
524 	win->_curx++;	// FIXME
525 
526 	// if (win && (waddch_nosync(win, wch) != ERR)) {
527 	// 	_nc_synchook(win);
528 	// 	code = OK;
529 	// }
530 
531 	return code;
532 }
533 // int waddchnstr (WINDOW *,const chtype *,int) {}
waddnstr(WINDOW * win,const char * astr,int n)534 int waddnstr(WINDOW *win, const char *astr, int n)
535 {
536 	int code = OK;
537 	const char *str = astr;
538 
539 	if (!str)
540 		return ERR;
541 
542 	if (n < 0)
543 		n = strlen(astr);
544 
545 	if (win->_line[win->_cury].firstchar == _NOCHANGE ||
546 			win->_line[win->_cury].firstchar > win->_curx)
547 		win->_line[win->_cury].firstchar = win->_curx;
548 
549 	while ((n-- > 0) && (*str != '\0')) {
550 	// while (*str != '\0') {
551 		win->_line[win->_cury].text[win->_curx].chars[0] = *str++;
552 		win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win)
553 ;
554 		win->_curx++;	// FIXME
555 
556 		// NCURSES_CH_T ch;
557 		// SetChar(ch, UChar(*str++), A_NORMAL);
558 		// if (_nc_waddch_nosync(win, ch) == ERR) {
559 		// 	code = ERR;
560 		// 	break;
561 		// }
562 	}
563 
564 	if (win->_line[win->_cury].lastchar == _NOCHANGE ||
565 			win->_line[win->_cury].lastchar < win->_curx)
566 		win->_line[win->_cury].lastchar = win->_curx;
567 
568 	return code;
569 }
wattr_on(WINDOW * win,attr_t at,void * opts GCC_UNUSED)570 int wattr_on(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
571 {
572 	if (at & A_COLOR)
573 		win->_color = PAIR_NUMBER(at);
574 	// toggle_attr_on(WINDOW_ATTRS(win), at);
575 	return OK;
576 }
wattr_off(WINDOW * win,attr_t at,void * opts GCC_UNUSED)577 int wattr_off(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
578 {
579 	if (at & A_COLOR)
580 		win->_color = 0;
581 	// toggle_attr_off(WINDOW_ATTRS(win), at);
582 	return 0;
583 }
584 // int wbkgd (WINDOW *, chtype) {}
wbkgdset(WINDOW * win,chtype ch)585 void wbkgdset(WINDOW *win, chtype ch) { /* TODO */ }
586 
wborder(WINDOW * win,chtype ls,chtype rs,chtype ts,chtype bs,chtype tl,chtype tr,chtype bl,chtype br)587 int wborder(WINDOW *win, chtype ls, chtype rs, chtype ts, chtype bs,
588 		chtype tl, chtype tr, chtype bl, chtype br)
589 {
590 	int x, y;
591 
592 	if (ls == 0) ls = ACS_VLINE;
593 	if (rs == 0) rs = ACS_VLINE;
594 	if (ts == 0) ts = ACS_HLINE;
595 	if (bs == 0) bs = ACS_HLINE;
596 	if (tl == 0) tl = ACS_ULCORNER;
597 	if (tr == 0) tr = ACS_URCORNER;
598 	if (bl == 0) bl = ACS_LLCORNER;
599 	if (br == 0) br = ACS_LRCORNER;
600 
601 	for(y = 0; y <= win->_maxy; y++) {
602 
603 		if (y == 0) {
604 			 mvwaddch(win, y, 0, tl);
605 
606 			for(x = 1; x < win->_maxx; x++)
607 				mvwaddch(win, y, x, ts);
608 
609 			mvwaddch(win, y, win->_maxx, tr);
610 		}
611 		else if (y == win->_maxy) {
612 			mvwaddch(win, y, 0, bl);
613 
614 			for(x = 1; x < win->_maxx; x++)
615 				mvwaddch(win, y, x, bs);
616 
617 			mvwaddch(win, y, win->_maxx, br);
618 		}
619 		else {
620 			mvwaddch(win, y, 0, ls);
621 			mvwaddch(win, y, win->_maxx, rs);
622 		}
623 	}
624 
625 	return OK;
626 }
627 
628 // int wchgat (WINDOW *, int, attr_t, short, const void *) {}
wclear(WINDOW * win)629 /* D */ int wclear(WINDOW *win)
630 {
631 	if (werase(win) == ERR)
632 		return ERR;
633 	win->_clear = TRUE;
634 	return OK;
635 }
636 // int wclrtobot (WINDOW *) {}
wclrtoeol(WINDOW * win)637 int wclrtoeol(WINDOW *win) { /* TODO */ return ERR; }
wcolor_set(WINDOW * win,short color_pair_number,void * opts)638 int wcolor_set(WINDOW *win, short color_pair_number, void *opts)
639 {
640 	if (!opts && (color_pair_number >= 0)
641 	    && (color_pair_number < COLOR_PAIRS)) {
642 		SET_WINDOW_PAIR(win, color_pair_number);
643 		if_EXT_COLORS(win->_color = color_pair_number);
644 		return OK;
645 	}
646 	return ERR;
647 }
648 // void wcursyncup (WINDOW *) {}
649 // int wdelch (WINDOW *) {}
650 // int wechochar (WINDOW *, const chtype) {}
werase(WINDOW * win)651 int werase(WINDOW *win)
652 {
653 	int x, y;
654 	for (y = 0; y <= win->_maxy; y++) {
655 		for (x = 0; x <= win->_maxx; x++) {
656 			win->_line[y].text[x].chars[0] = ' ';
657 			win->_line[y].text[x].attr = WINDOW_ATTRS(win);
658 		}
659 		// Should we check instead?
660 		win->_line[y].firstchar = 0;
661 		win->_line[y].lastchar = win->_maxx;
662 	}
663 	return OK;
664 }
665 // int wgetnstr (WINDOW *,char *,int) {}
whline(WINDOW * win,chtype ch,int n)666 int whline(WINDOW *win, chtype ch, int n)
667 {
668 	NCURSES_SIZE_T start, end;
669 	struct ldat *line = &(win->_line[win->_cury]);
670 	NCURSES_CH_T wch;
671 
672 	start = win->_curx;
673 	end = start + n - 1;
674 	if (end > win->_maxx)
675 		end = win->_maxx;
676 
677 	CHANGED_RANGE(line, start, end);
678 
679 	//// TODO:
680 	//// if (ch == 0)
681 	////     SetChar2(wch, ACS_HLINE);
682 	//// else
683 	////     SetChar2(wch, ch);
684 	// Ugly hack:
685 	wch.chars[0] = ((ch) & (chtype)A_CHARTEXT);
686 	wch.attr = ((ch) & (chtype)A_ATTRIBUTES);
687 	wch = _nc_render(win, wch);
688 
689 	while (end >= start) {
690 		line->text[end] = wch;
691 		end--;
692 	}
693 
694 	//// _nc_synchook(win);
695 
696 	return OK;
697 }
winch(WINDOW * win)698 /* D */ chtype winch(WINDOW *win)
699 {
700 	//// TODO
701 	// return (CharOf(win->_line[win->_cury].text[win->_curx]) |
702 	//         AttrOf(win->_line[win->_cury].text[win->_curx]));
703 	return OK;	// FIXME
704 }
705 // int winchnstr (WINDOW *, chtype *, int) {}
706 // int winnstr (WINDOW *, char *, int) {}
707 // int winsch (WINDOW *, chtype) {}
708 // int winsdelln (WINDOW *,int) {}
709 // int winsnstr (WINDOW *, const char *,int) {}
wmove(WINDOW * win,int y,int x)710 /* D */ int wmove(WINDOW *win, int y, int x)
711 {
712 	if (!LEGALYX(win, y, x))
713 		return ERR;
714 	win->_curx = (NCURSES_SIZE_T) x;
715 	win->_cury = (NCURSES_SIZE_T) y;
716 	win->_flags &= ~_WRAPPED;
717 	win->_flags |= _HASMOVED;
718 	return OK;
719 }
720 
721 #define SWAP_RED_BLUE(c) \
722 	(((c) & 0x4400) >> 2) | ((c) & 0xAA00) | (((c) & 0x1100) << 2)
wnoutrefresh(WINDOW * win)723 int wnoutrefresh(WINDOW *win)
724 {
725 #if CONFIG(LP_SERIAL_CONSOLE)
726 	// FIXME.
727 	int serial_is_bold = 0;
728 	int serial_is_reverse = 0;
729 	int serial_is_altcharset = 0;
730 	int serial_cur_pair = 0;
731 
732 	int need_altcharset;
733 	short fg, bg;
734 #endif
735 	int x, y;
736 	chtype ch;
737 
738 #if CONFIG(LP_SERIAL_CONSOLE)
739 	serial_end_bold();
740 	serial_end_altcharset();
741 #endif
742 
743 	for (y = 0; y <= win->_maxy; y++) {
744 
745 		if (win->_line[y].firstchar == _NOCHANGE)
746 			continue;
747 
748 		/* Position the serial cursor */
749 
750 #if CONFIG(LP_SERIAL_CONSOLE)
751 		if (curses_flags & F_ENABLE_SERIAL)
752 			serial_set_cursor(win->_begy + y, win->_begx +
753 					win->_line[y].firstchar);
754 #endif
755 
756 		for (x = win->_line[y].firstchar; x <= win->_line[y].lastchar; x++) {
757 			attr_t attr = win->_line[y].text[x].attr;
758 
759 #if CONFIG(LP_SERIAL_CONSOLE)
760 			if (curses_flags & F_ENABLE_SERIAL) {
761 				ch = win->_line[y].text[x].chars[0];
762 
763 				if (attr & A_BOLD) {
764 					if (!serial_is_bold) {
765 						serial_start_bold();
766 						serial_is_bold = 1;
767 					}
768 				} else {
769 					if (serial_is_bold) {
770 						serial_end_bold();
771 						serial_is_bold = 0;
772 						/* work around serial.c
773 						 * shortcoming:
774 						 */
775 						serial_is_reverse = 0;
776 						serial_cur_pair = 0;
777 					}
778 				}
779 
780 				if (attr & A_REVERSE) {
781 					if (!serial_is_reverse) {
782 						serial_start_reverse();
783 						serial_is_reverse = 1;
784 					}
785 				} else {
786 					if (serial_is_reverse) {
787 						serial_end_reverse();
788 						serial_is_reverse = 0;
789 						/* work around serial.c
790 						 * shortcoming:
791 						 */
792 						serial_is_bold = 0;
793 						serial_cur_pair = 0;
794 					}
795 				}
796 
797 				need_altcharset = 0;
798 				if (attr & A_ALTCHARSET) {
799 					if (serial_acs_map[ch & 0x7f]) {
800 						ch = serial_acs_map[ch & 0x7f];
801 						need_altcharset = 1;
802 					} else
803 						ch = fallback_acs_map[ch & 0x7f];
804 				}
805 				if (need_altcharset && !serial_is_altcharset) {
806 					serial_start_altcharset();
807 					serial_is_altcharset = 1;
808 				}
809 				if (!need_altcharset && serial_is_altcharset) {
810 					serial_end_altcharset();
811 					serial_is_altcharset = 0;
812 				}
813 
814 				if (serial_cur_pair != PAIR_NUMBER(attr)) {
815 					pair_content(PAIR_NUMBER(attr),
816 						     &fg, &bg);
817 					serial_set_color(fg, bg);
818 					serial_cur_pair = PAIR_NUMBER(attr);
819 				}
820 
821 				serial_putchar(ch);
822 
823 			}
824 #endif
825 #if CONFIG(LP_VIDEO_CONSOLE)
826 			unsigned int c =
827 				((int)color_pairs[PAIR_NUMBER(attr)]) << 8;
828 
829 			c = SWAP_RED_BLUE(c);
830 
831 			if (curses_flags & F_ENABLE_CONSOLE) {
832 				ch = win->_line[y].text[x].chars[0];
833 
834 				/* Handle some of the attributes. */
835 				if (attr & A_BOLD)
836 					c |= 0x0800;
837 				if (attr & A_DIM)
838 					c &= ~0x800;
839 				if (attr & A_REVERSE) {
840 					unsigned char tmp = (c >> 8) & 0xf;
841 					c = (c >> 4) & 0xf00;
842 					c |= tmp << 12;
843 				}
844 				if (attr & A_ALTCHARSET) {
845 					if (console_acs_map[ch & 0x7f])
846 						ch = console_acs_map[ch & 0x7f];
847 					else
848 						ch = fallback_acs_map[ch & 0x7f];
849 				}
850 
851 				/*
852 				 * FIXME: Somewhere along the line, the
853 				 * character value is getting sign-extented.
854 				 * For now grab just the 8 bit character,
855 				 * but this will break wide characters!
856 				 */
857 				c |= (chtype) (ch & 0xff);
858 				video_console_putc(win->_begy + y, win->_begx + x, c);
859 			}
860 #endif
861 		}
862 		win->_line[y].firstchar = _NOCHANGE;
863 		win->_line[y].lastchar = _NOCHANGE;
864 	}
865 
866 #if CONFIG(LP_SERIAL_CONSOLE)
867 	if (curses_flags & F_ENABLE_SERIAL)
868 		serial_set_cursor(win->_begy + win->_cury, win->_begx + win->_curx);
869 #endif
870 
871 #if CONFIG(LP_VIDEO_CONSOLE)
872 	if (curses_flags & F_ENABLE_CONSOLE)
873 		video_console_set_cursor(win->_begx + win->_curx, win->_begy + win->_cury);
874 #endif
875 
876 	return OK;
877 }
wprintw(WINDOW * win,const char * fmt,...)878 int wprintw(WINDOW *win, const char *fmt, ...)
879 {
880 	va_list argp;
881 	int code;
882 
883 	va_start(argp, fmt);
884 	code = vwprintw(win, fmt, argp);
885 	va_end(argp);
886 
887 	return code;
888 }
889 
wredrawln(WINDOW * win,int beg_line,int num_lines)890 int wredrawln (WINDOW *win, int beg_line, int num_lines)
891 {
892 	int i;
893 
894 	for (i = beg_line; i < beg_line + num_lines; i++) {
895 		win->_line[i].firstchar = 0;
896 		win->_line[i].lastchar = win->_maxx;
897 	}
898 
899 	return OK;
900 }
901 
wrefresh(WINDOW * win)902 int wrefresh(WINDOW *win)
903 {
904 	// FIXME
905 	return wnoutrefresh(win);
906 
907 	// XXX
908 	int code;
909 
910 	if (win == curscr) {
911 		curscr->_clear = TRUE;
912 		// code = doupdate();
913 	} else if ((code = wnoutrefresh(win)) == OK) {
914 		if (win->_clear)
915 			newscr->_clear = TRUE;
916 		// code = doupdate();
917 		/*
918 		 * Reset the clearok() flag in case it was set for the special
919 		 * case in hardscroll.c (if we don't reset it here, we'll get 2
920 		 * refreshes because the flag is copied from stdscr to newscr).
921 		 * Resetting the flag shouldn't do any harm, anyway.
922 		 */
923 		win->_clear = FALSE;
924 	}
925 
926 	return code;
927 }
928 // int wscanw (WINDOW *, NCURSES_CONST char *,...) {}
wscrl(WINDOW * win,int n)929 int wscrl(WINDOW *win, int n)
930 {
931 	int x, y;
932 
933 	if (!win->_scroll)
934 		return ERR;
935 
936 	if (n == 0)
937 		return OK;
938 
939 	for (y = 0; y <= (win->_maxy - n); y++) {
940 		win->_line[y].firstchar = win->_line[y + n].firstchar;
941 		win->_line[y].lastchar = win->_line[y + n].lastchar;
942 		for (x = 0; x <= win->_maxx; x++) {
943 			if ((win->_line[y].text[x].chars[0] != win->_line[y + n].text[x].chars[0]) ||
944 					(win->_line[y].text[x].attr != win->_line[y + n].text[x].attr)) {
945 				if (win->_line[y].firstchar == _NOCHANGE)
946 					win->_line[y].firstchar = x;
947 
948 				win->_line[y].lastchar = x;
949 
950 				win->_line[y].text[x].chars[0] = win->_line[y + n].text[x].chars[0];
951 				win->_line[y].text[x].attr = win->_line[y + n].text[x].attr;
952 			}
953 		}
954 	}
955 
956 	for (y = (win->_maxy+1 - n); y <= win->_maxy; y++) {
957 		for (x = 0; x <= win->_maxx; x++) {
958 			if ((win->_line[y].text[x].chars[0] != ' ') ||
959 					(win->_line[y].text[x].attr != A_NORMAL)) {
960 				if (win->_line[y].firstchar == _NOCHANGE)
961 					win->_line[y].firstchar = x;
962 
963 				win->_line[y].lastchar = x;
964 
965 				win->_line[y].text[x].chars[0] = ' ';
966 				win->_line[y].text[x].attr = A_NORMAL;
967 			}
968 		}
969 	}
970 
971 	// _nc_scroll_window(win, n, win->_regtop, win->_regbottom, win->_nc_bkgd);
972 	// _nc_synchook(win);
973 
974 	return OK;
975 }
wsetscrreg(WINDOW * win,int top,int bottom)976 int wsetscrreg(WINDOW *win, int top, int bottom)
977 {
978 	if (top >= 0 && top <= win->_maxy && bottom >= 0 &&
979 	    bottom <= win->_maxy && bottom > top) {
980 		win->_regtop = (NCURSES_SIZE_T) top;
981 		win->_regbottom = (NCURSES_SIZE_T) bottom;
982 		return OK;
983 	}
984 	return ERR;
985 }
986 // void wsyncdown (WINDOW *) {}
987 // void wsyncup (WINDOW *) {}
wtimeout(WINDOW * win,int _delay)988 /* D */ void wtimeout(WINDOW *win, int _delay) { win->_delay = _delay; }
wtouchln(WINDOW * win,int y,int n,int changed)989 /* D */ int wtouchln(WINDOW *win, int y, int n, int changed)
990 {
991 	int i;
992 
993 	// if ((n < 0) || (y < 0) || (y > win->_maxy))
994 	//     return ERR;
995 
996 	for (i = y; i < y + n; i++) {
997 		if (i > win->_maxy)
998 			break;
999 		win->_line[i].firstchar = changed ? 0 : _NOCHANGE;
1000 		win->_line[i].lastchar = changed ? win->_maxx : _NOCHANGE;
1001 	}
1002 	return OK;
1003 }
1004 // int wvline (WINDOW *,chtype,int) {}
1005 // int tigetflag (NCURSES_CONST char *) {}
1006 // int tigetnum (NCURSES_CONST char *) {}
1007 // char *tigetstr (NCURSES_CONST char *) {}
1008 // int putp (const char *) {}
1009 // #if NCURSES_TPARM_VARARGS
1010 // char *tparm (NCURSES_CONST char *, ...) {}
1011 // #else
1012 // char *tparm (NCURSES_CONST char *, long,long,long,long,long,long,long,long,long) {}
1013 // char *tparm_varargs (NCURSES_CONST char *, ...) {}
1014 // #endif
1015