Add support for curses color output over serial.
[coreboot.git] / payloads / libpayload / curses / tinycurses.c
1 /*
2  * This file is part of the libpayload project.
3  *
4  * Copyright (C) 2007 Uwe Hermann <uwe@hermann-uwe.de>
5  * Copyright (C) 2008 Ulf Jordan <jordan@chalmers.se>
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 = 1;
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 reverse place 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;
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 #ifdef CONFIG_SERIAL_ACS_FALLBACK
114 chtype serial_acs_map[128];
115 #else
116 /* See acsc of vt100. */
117 chtype serial_acs_map[128] =
118         {
119         0,      0,      0,      0,      0,      0,      0,      0,
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         '`',    'a',    0,      0,      0,      0,      'f',    'g',
132         0,      0,      'j',    'k',    'l',    'm',    'n',    'o',
133         'p',    'q',    'r',    's',    't',    'u',    'v',    'w',
134         'x',    'y',    'z',    '{',    '|',    '}',    '~',    0,
135         };
136 #endif
137
138 /* See acsc of linux. */
139 chtype console_acs_map[128] =
140         {
141         0,      0,      0,      0,      0,      0,      0,      0,
142         0,      0,      0,      0,      0,      0,      0,      0,
143         0,      0,      0,      0,      0,      0,      0,      0,
144         0,      0,      0,      0,      0,      0,      0,      0,
145         0,      0,      0,      0,      0,      0,      0,      0,
146         0,      0,      0,      '\020', '\021', '\030', '\031', 0,
147         '\333', 0,      0,      0,      0,      0,      0,      0,
148         0,      0,      0,      0,      0,      0,      0,      0,
149         0,      0,      0,      0,      0,      0,      0,      0,
150         0,      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         '\004', '\261', 0,      0,      0,      0,      '\370', '\361',
154         '\260', '\316', '\331', '\277', '\332', '\300', '\305', '~',
155         '\304', '\304', '\304', '_',    '\303', '\264', '\301', '\302',
156         '\263', '\363', '\362', '\343', '\330', '\234', '\376', 0,
157         };
158
159 // FIXME: Ugly (and insecure!) hack!
160 char sprintf_tmp[1024];
161
162
163 int curses_flags = (F_ENABLE_CONSOLE | F_ENABLE_SERIAL);
164
165 /* Return bit mask for clearing color pair number if given ch has color */
166 #define COLOR_MASK(ch) (~(attr_t)((ch) & A_COLOR ? A_COLOR : 0))
167
168 /* Compute a rendition of the given char correct for the current context. */
169 static inline NCURSES_CH_T render_char(WINDOW *win, NCURSES_CH_T ch)
170 {
171         /* TODO. */
172         return ch;
173 }
174
175 /* Make render_char() visible while still allowing us to inline it below. */
176 NCURSES_CH_T _nc_render(WINDOW *win, NCURSES_CH_T ch)
177 {
178         return render_char(win, ch);
179 }
180
181 /*
182  * Implementations of most functions marked 'implemented' in include/curses.h:
183  */
184
185 // int baudrate(void) {}
186 int beep(void)
187 {
188         /* TODO: Flash the screen if beeping fails? */
189         speaker_tone(1760, 500);        /* 1760 == note A6 */
190         return OK;
191 }
192 // bool can_change_color(void) {}
193 int cbreak(void) { /* TODO */ return 0; }
194 /* D */ int clearok(WINDOW *win, bool flag) { win->_clear = flag; return OK; }
195 // int color_content(short color, short *r, short *g, short *b) {}
196 // int curs_set(int) {}
197 // int def_prog_mode(void) {}
198 // int def_shell_mode(void) {}
199 // int delay_output(int) {}
200 // void delscreen(SCREEN *) {}
201 int delwin(WINDOW *win)
202 {
203         /* TODO: Don't try to delete stdscr. */
204         /* TODO: Don't delete parent windows before subwindows. */
205
206         // if (win->_flags & _SUBWIN)
207         //      touchwin(win->_parent);
208         // else if (curscr != 0)
209         //      touchwin(curscr);
210
211         // return _nc_freewin(win);
212         return OK;
213 }
214 WINDOW *derwin(WINDOW *orig, int num_lines, int num_columns, int begy, int begx)
215 {
216         WINDOW *win = NULL;
217         int i;
218         int flags = _SUBWIN;
219
220         /* Make sure window fits inside the original one. */
221         if (begy < 0 || begx < 0 || orig == 0 || num_lines < 0
222             || num_columns < 0)
223                 return NULL;
224
225         if (begy + num_lines > orig->_maxy + 1
226             || begx + num_columns > orig->_maxx + 1)
227                 return NULL;
228
229         if (num_lines == 0)
230                 num_lines = orig->_maxy + 1 - begy;
231
232         if (num_columns == 0)
233                 num_columns = orig->_maxx + 1 - begx;
234
235         if (orig->_flags & _ISPAD)
236                 flags |= _ISPAD;
237
238         // FIXME
239         //// if ((win = _nc_makenew(num_lines, num_columns, orig->_begy + begy,
240         ////                        orig->_begx + begx, flags)) == 0)
241         ////     return NULL;
242
243         win->_pary = begy;
244         win->_parx = begx;
245         WINDOW_ATTRS(win) = WINDOW_ATTRS(orig);
246         win->_nc_bkgd = orig->_nc_bkgd;
247
248         for (i = 0; i < num_lines; i++)
249                 win->_line[i].text = &orig->_line[begy++].text[begx];
250
251         win->_parent = orig;
252
253         return win;
254 }
255 int doupdate(void) { /* TODO */ return(*(int *)0); }
256 // WINDOW * dupwin (WINDOW *) {}
257 /* D */ int echo(void) { SP->_echo = TRUE; return OK; }
258 int endwin(void)
259 {
260         if (!SP)
261                 return ERR;
262
263         SP->_endwin = TRUE;
264         SP->_mouse_wrap(SP);
265         // _nc_screen_wrap();
266         // _nc_mvcur_wrap();       /* wrap up cursor addressing */
267         // return reset_shell_mode();
268         return OK;      // FIXME
269 }
270 // char erasechar (void) {}
271 // void filter (void) {}
272 // int flash(void) {}
273 int flushinp(void) { /* TODO */ return 0; }
274 // WINDOW *getwin (FILE *) {}
275 bool has_colors (void) { /* TODO */ return(*(bool *)0); }
276 // bool has_ic (void) {}
277 // bool has_il (void) {}
278 // void idcok (WINDOW *, bool) {}
279 // int idlok (WINDOW *, bool) {}
280 void immedok(WINDOW *win, bool flag) { win->_immed = flag; }
281 /** Note: Must _not_ be called twice! */
282 WINDOW *initscr(void)
283 {
284         int x, y, i;
285
286         // newterm(name, stdout, stdin);
287         // def_prog_mode();
288
289         for (i = 0; i < 128; i++)
290           acs_map[i] = (chtype) i | A_ALTCHARSET;
291
292         if (curses_flags & F_ENABLE_SERIAL) {
293                 serial_clear();
294         }
295
296         if (curses_flags & F_ENABLE_CONSOLE) {
297                 /* Clear the screen and kill the cursor */
298
299                 video_console_clear();
300                 video_console_cursor_enable(0);
301         }
302
303         // Speaker init?
304
305         stdscr = newwin(SCREEN_Y, SCREEN_X + 1, 0, 0);
306         // TODO: curscr, newscr?
307
308         for (y = 0; y < stdscr->_maxy; y++) {
309                 for (x = 0; x < stdscr->_maxx; x++) {
310                         stdscr->_line[y].text[x].chars[0] = ' ';
311                         stdscr->_line[y].text[x].attr = A_NORMAL;
312                 }
313         }
314
315         return stdscr;
316 }
317 // int intrflush (WINDOW *,bool) {}
318 /* D */ bool isendwin(void) { return ((SP == NULL) ? FALSE : SP->_endwin); }
319 // bool is_linetouched (WINDOW *,int) {}
320 // bool is_wintouched (WINDOW *) {}
321 // NCURSES_CONST char * keyname (int) {}
322 int keypad (WINDOW *win, bool flag) { /* TODO */ return 0; }
323 // char killchar (void) {}
324 /* D */ int leaveok(WINDOW *win, bool flag) { win->_leaveok = flag; return OK; }
325 // char *longname (void) {}
326 // int meta (WINDOW *,bool) {}
327 // int mvcur (int,int,int,int) {}
328 // int mvderwin (WINDOW *, int, int) {}
329 int mvprintw(int y, int x, const char *fmt, ...)
330 {
331         va_list argp;
332         int code;
333
334         if (move(y, x) == ERR)
335                 return ERR;
336
337         va_start(argp, fmt);
338         code = vwprintw(stdscr, fmt, argp);
339         va_end(argp);
340
341         return code;
342 }
343 // int mvscanw (int,int, NCURSES_CONST char *,...) {}
344 // int mvwin (WINDOW *,int,int) {}
345 int mvwprintw(WINDOW *win, int y, int x, const char *fmt, ...)
346 {
347         va_list argp;
348         int code;
349
350         if (wmove(win, y, x) == ERR)
351                 return ERR;
352
353         va_start(argp, fmt);
354         code = vwprintw(win, fmt, argp);
355         va_end(argp);
356
357         return code;
358 }
359 // int mvwscanw (WINDOW *,int,int, NCURSES_CONST char *,...) {}
360 // int napms (int) {}
361 // WINDOW *newpad (int,int) {}
362 // SCREEN *newterm (NCURSES_CONST char *,FILE *,FILE *) {}
363 WINDOW *newwin(int num_lines, int num_columns, int begy, int begx)
364 {
365         int i;
366
367         /* Use next statically allocated window. */
368         // TODO: Error handling.
369         // TODO: WINDOWLIST?
370         WINDOW *win = &window_list[window_count++];
371
372         // bool is_pad = (flags & _ISPAD);
373
374         // TODO: Checks.
375
376         win->_cury = 0;
377         win->_curx = 0;
378         win->_maxy = num_lines - 1;
379         win->_maxx = num_columns - 1;
380         win->_begy = begy;
381         win->_begx = begx;
382         // win->_yoffset = SP->_topstolen;
383
384         win->_line = ldat_list[ldat_count++];
385
386         /* FIXME: Is this right? Should the window attributes be normal? */
387         win->_color = PAIR_NUMBER(0);
388         win->_attrs = A_NORMAL;
389
390         for (i = 0; i < num_lines; i++)
391                 win->_line[i].text =
392                      (NCURSES_CH_T *)&linebuf_list[linebuf_count++];
393
394         return win;
395 }
396 /* D */ int nl(void) { SP->_nl = TRUE; return OK; }
397 /* D */ int noecho(void) { SP->_echo = FALSE; return OK; }
398 /* D */ int nonl(void) { SP->_nl = FALSE; return OK; }
399 // void noqiflush (void) {}
400 // int noraw (void) {}
401 /* D */ int notimeout (WINDOW *win, bool f) { win->_notimeout = f; return OK; }
402 // int overlay (const WINDOW*,WINDOW *) {}
403 // int overwrite (const WINDOW*,WINDOW *) {}
404 // int pair_content (short,short*,short*) {}
405 // int pechochar (WINDOW *, const chtype) {}
406 // int pnoutrefresh (WINDOW*,int,int,int,int,int,int) {}
407 // int prefresh (WINDOW *,int,int,int,int,int,int) {}
408 int printw(const char *fmt, ...)
409 {
410         va_list argp;
411         int code;
412
413         va_start(argp, fmt);
414         code = vwprintw(stdscr, fmt, argp);
415         va_end(argp);
416
417         return code;
418 }
419 // int putwin (WINDOW *, FILE *) {}
420 // void qiflush (void) {}
421 // int raw (void) {}
422 // int resetty (void) {}
423 // int reset_prog_mode (void) {}
424 // int reset_shell_mode (void) {}
425 // int ripoffline (int, int (*)(WINDOW *, int)) {}
426 // int savetty (void) {}
427 // int scanw (NCURSES_CONST char *,...) {}
428 // int scr_dump (const char *) {}
429 // int scr_init (const char *) {}
430 /* D */ int scrollok(WINDOW *win, bool flag) { win->_scroll = flag; return OK; }
431 // int scr_restore (const char *) {}
432 // int scr_set (const char *) {}
433 // SCREEN *set_term (SCREEN *) {}
434 // int slk_attroff (const chtype) {}
435 // int slk_attron (const chtype) {}
436 // int slk_attrset (const chtype) {}
437 // attr_t slk_attr (void) {}
438 // int slk_attr_set (const attr_t,short,void*) {}
439 // int slk_clear (void) {}
440 // int slk_color (short) {}
441 // int slk_init (int) {}
442 /* D */ char *slk_label(int n)
443 {
444         // TODO: Needed?
445         // if (SP == NULL || SP->_slk == NULL || n < 1 || n > SP->_slk->labcnt)
446         //      return NULL;
447         return SP->_slk->ent[n - 1].ent_text;
448 }
449 // int slk_noutrefresh (void) {}
450 // int slk_refresh (void) {}
451 // int slk_restore (void) {}
452 // int slk_set (int,const char *,int) {}
453 // int slk_touch (void) {}
454
455 // WINDOW *subpad (WINDOW *, int, int, int, int) {}
456 WINDOW *subwin(WINDOW *w, int l, int c, int y, int x)
457 {
458         return derwin(w, l, c, y - w->_begy, x - w->_begx);
459 }
460 // int syncok (WINDOW *, bool) {}
461 // chtype termattrs (void) {}
462 // char *termname (void) {}
463 // int typeahead (int) {}
464 int ungetch(int ch) { /* TODO */ return ERR; }
465 // void use_env (bool) {}
466 // int vidattr (chtype) {}
467 // int vidputs (chtype, int (*)(int)) {}
468 int vwprintw(WINDOW *win, const char *fmt, va_list argp)
469 {
470         vsprintf((char *)&sprintf_tmp, fmt, argp);
471
472         /* TODO: Error handling? */
473         return waddstr(win, (char *)&sprintf_tmp);
474 }
475 // int vwscanw (WINDOW *, NCURSES_CONST char *,va_list) {}
476 // int waddch (WINDOW *, const chtype) {}
477 int waddch(WINDOW *win, const chtype ch)
478 {
479         int code = ERR;
480         // NCURSES_CH_T wch;
481         // SetChar2(wch, ch);
482
483         win->_line[win->_cury].text[win->_curx].chars[0] =
484                 ((ch) & (chtype)A_CHARTEXT);
485
486         win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win);
487         win->_line[win->_cury].text[win->_curx].attr |=
488                 ((ch) & (chtype)A_ATTRIBUTES);
489         win->_curx++;   // FIXME
490
491         // if (win && (waddch_nosync(win, wch) != ERR)) {
492         //      _nc_synchook(win);
493         //      code = OK;
494         // }
495
496         return code;
497 }
498 // int waddchnstr (WINDOW *,const chtype *,int) {}
499 int waddnstr(WINDOW *win, const char *astr, int n)
500 {
501         int code = OK;
502         const char *str = astr;
503
504         if (!str)
505                 return ERR;
506
507         if (n < 0)
508                 n = strlen(astr);
509
510         while ((n-- > 0) && (*str != '\0')) {
511         // while (*str != '\0') {
512                 win->_line[win->_cury].text[win->_curx].chars[0] = *str++;
513                 win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win)
514 ;
515                 win->_curx++;   // FIXME
516
517                 // NCURSES_CH_T ch;
518                 // SetChar(ch, UChar(*str++), A_NORMAL);
519                 // if (_nc_waddch_nosync(win, ch) == ERR) {
520                 //      code = ERR;
521                 //      break;
522                 // }
523         }
524         return code;
525 }
526 int wattr_on(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
527 {
528         if (at & A_COLOR)
529                 win->_color = PAIR_NUMBER(at);
530         // toggle_attr_on(WINDOW_ATTRS(win), at);
531         return OK;
532 }
533 int wattr_off(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
534 {
535         if (at & A_COLOR)
536                 win->_color = 0;
537         // toggle_attr_off(WINDOW_ATTRS(win), at);
538         return 0;
539 }
540 // int wbkgd (WINDOW *, chtype) {}
541 void wbkgdset(WINDOW *win, chtype ch) { /* TODO */ }
542
543 int wborder(WINDOW *win, chtype ls, chtype rs, chtype ts, chtype bs,
544                 chtype tl, chtype tr, chtype bl, chtype br)
545 {
546         int x, y;
547
548         for(y = 0; y <= win->_maxy; y++) {
549
550                 if (y == 0) {
551                          mvwaddch(win, y, 0, tl);
552
553                         for(x = 1; x < win->_maxx; x++)
554                                 mvwaddch(win, y, x, ts);
555
556                         mvwaddch(win, y, win->_maxx, tr);
557                 }
558                 else if (y == win->_maxy) {
559                         mvwaddch(win, y, 0, bl);
560
561                         for(x = 1; x < win->_maxx; x++)
562                                 mvwaddch(win, y, x, bs);
563
564                         mvwaddch(win, y, win->_maxx, br);
565                 }
566                 else {
567                         mvwaddch(win, y, 0, ls);
568                         mvwaddch(win, y, win->_maxx, rs);
569                 }
570         }
571
572         return OK;
573 }
574
575 // int wchgat (WINDOW *, int, attr_t, short, const void *) {}
576 /* D */ int wclear(WINDOW *win)
577 {
578         if (werase(win) == ERR)
579                 return ERR;
580         win->_clear = TRUE;
581         return OK;
582 }
583 // int wclrtobot (WINDOW *) {}
584 int wclrtoeol(WINDOW *win) { /* TODO */ return(*(int *)0); }
585 int wcolor_set(WINDOW *win, short color_pair_number, void *opts)
586 {
587         if (!opts && (color_pair_number >= 0)
588             && (color_pair_number < COLOR_PAIRS)) {
589                 SET_WINDOW_PAIR(win, color_pair_number);
590                 if_EXT_COLORS(win->_color = color_pair_number);
591                 return OK;
592         }
593         return ERR;
594 }
595 // void wcursyncup (WINDOW *) {}
596 // int wdelch (WINDOW *) {}
597 // int wechochar (WINDOW *, const chtype) {}
598 int werase(WINDOW *win)
599 {
600         int x, y;
601         for (y = 0; y <= win->_maxy; y++) {
602                 for (x = 0; x <= win->_maxx; x++) {
603                         win->_line[y].text[x].chars[0] = ' ';
604                         win->_line[y].text[x].attr = WINDOW_ATTRS(win);
605                 }
606         }
607         return OK;
608 }
609 // int wgetnstr (WINDOW *,char *,int) {}
610 int whline(WINDOW *win, chtype ch, int n)
611 {
612         NCURSES_SIZE_T start, end;
613         struct ldat *line = &(win->_line[win->_cury]);
614         NCURSES_CH_T wch;
615
616         start = win->_curx;
617         end = start + n - 1;
618         if (end > win->_maxx)
619                 end = win->_maxx;
620
621         CHANGED_RANGE(line, start, end);
622
623         //// TODO:
624         //// if (ch == 0)
625         ////     SetChar2(wch, ACS_HLINE);
626         //// else
627         ////     SetChar2(wch, ch);
628         // Ugly hack:
629         wch.chars[0] = ((ch) & (chtype)A_CHARTEXT);
630         wch.attr = ((ch) & (chtype)A_ATTRIBUTES);
631         wch = _nc_render(win, wch);
632
633         while (end >= start) {
634                 line->text[end] = wch;
635                 end--;
636         }
637
638         //// _nc_synchook(win);
639
640         return OK;
641 }
642 /* D */ chtype winch(WINDOW *win)
643 {
644         //// TODO
645         // return (CharOf(win->_line[win->_cury].text[win->_curx]) |
646         //         AttrOf(win->_line[win->_cury].text[win->_curx]));
647         return OK;      // FIXME
648 }
649 // int winchnstr (WINDOW *, chtype *, int) {}
650 // int winnstr (WINDOW *, char *, int) {}
651 // int winsch (WINDOW *, chtype) {}
652 // int winsdelln (WINDOW *,int) {}
653 // int winsnstr (WINDOW *, const char *,int) {}
654 /* D */ int wmove(WINDOW *win, int y, int x)
655 {
656         if (!LEGALYX(win, y, x))
657                 return ERR;
658         win->_curx = (NCURSES_SIZE_T) x;
659         win->_cury = (NCURSES_SIZE_T) y;
660         win->_flags &= ~_WRAPPED;
661         win->_flags |= _HASMOVED;
662         return OK;
663 }
664
665 #define SWAP_RED_BLUE(c) \
666         (((c) & 0x4400) >> 2) | ((c) & 0xAA00) | (((c) & 0x1100) << 2)
667 int wnoutrefresh(WINDOW *win)
668 {
669         // FIXME.
670         int serial_is_bold = 0;
671         int serial_is_altcharset = 0;
672         int serial_cur_pair = 0;
673
674         int x, y;
675         chtype ch;
676         int need_altcharset;
677         short fg, bg;
678
679         serial_end_bold();
680         serial_end_altcharset();
681
682         for (y = 0; y <= win->_maxy; y++) {
683
684                 /* Position the serial cursor */
685
686                 if (curses_flags & F_ENABLE_SERIAL)
687                         serial_set_cursor(win->_begy + y, win->_begx);
688
689                 for (x = 0; x <= win->_maxx; x++) {
690                         attr_t attr = win->_line[y].text[x].attr;
691
692                         unsigned int c =
693                                 ((int)color_pairs[PAIR_NUMBER(attr)]) << 8;
694
695                         if (curses_flags & F_ENABLE_SERIAL) {
696                                 ch = win->_line[y].text[x].chars[0];
697
698                                 if (attr & A_BOLD) {
699                                         if (!serial_is_bold) {
700                                                 serial_start_bold();
701                                                 serial_is_bold = 1;
702                                         }
703                                 }
704                                 else {
705                                         if (serial_is_bold) {
706                                                 serial_end_bold();
707                                                 serial_is_bold = 0;
708                                                 serial_cur_pair = 0;
709                                         }
710                                 }
711
712                                 need_altcharset = 0;
713                                 if (attr & A_ALTCHARSET) {
714                                         if (serial_acs_map[ch & 0x7f]) {
715                                                 ch = serial_acs_map[ch & 0x7f];
716                                                 need_altcharset = 1;
717                                         } else
718                                                 ch = fallback_acs_map[ch & 0x7f];
719                                 }
720                                 if (need_altcharset && !serial_is_altcharset) {
721                                         serial_start_altcharset();
722                                         serial_is_altcharset = 1;
723                                 }
724                                 if (!need_altcharset && serial_is_altcharset) {
725                                         serial_end_altcharset();
726                                         serial_is_altcharset = 0;
727                                 }
728
729                                 if (serial_cur_pair != PAIR_NUMBER(attr)) {
730                                         pair_content(PAIR_NUMBER(attr),
731                                                      &fg, &bg);
732                                         serial_set_color(fg, bg);
733                                         serial_cur_pair = PAIR_NUMBER(attr);
734                                 }
735
736                                 serial_putchar(ch);
737                         }
738
739                         c = SWAP_RED_BLUE(c);
740
741                         if (curses_flags & F_ENABLE_CONSOLE) {
742                                 ch = win->_line[y].text[x].chars[0];
743
744                                 /* Handle some of the attributes. */
745                                 if (attr & A_BOLD)
746                                         c |= 0x0800;
747                                 if (attr & A_DIM)
748                                         c &= ~0x800;
749                                 if (attr & A_REVERSE) {
750                                         unsigned char tmp = (c >> 8) & 0xf;
751                                         c = (c >> 4) & 0xf00;
752                                         c |= tmp << 12;
753                                 }
754                                 if (attr & A_ALTCHARSET) {
755                                         if (console_acs_map[ch & 0x7f])
756                                                 ch = console_acs_map[ch & 0x7f];
757                                         else
758                                                 ch = fallback_acs_map[ch & 0x7f];
759                                 }
760
761                                 /*
762                                  * FIXME: Somewhere along the line, the
763                                  * character value is getting sign-extented.
764                                  * For now grab just the 8 bit character,
765                                  * but this will break wide characters!
766                                  */
767                                 c |= (chtype) (ch & 0xff);
768                                 video_console_putc(win->_begy + y, win->_begx + x, c);
769                         }
770                 }
771         }
772
773         return OK;
774 }
775 int wprintw(WINDOW *win, const char *fmt, ...)
776 {
777         va_list argp;
778         int code;
779
780         va_start(argp, fmt);
781         code = vwprintw(win, fmt, argp);
782         va_end(argp);
783
784         return code;
785 }
786 // int wredrawln (WINDOW *,int,int) {}
787 int wrefresh(WINDOW *win)
788 {
789         // FIXME
790         return wnoutrefresh(win);
791
792         // XXX
793         int code;
794
795         if (win == curscr) {
796                 curscr->_clear = TRUE;
797                 // code = doupdate();
798         } else if ((code = wnoutrefresh(win)) == OK) {
799                 if (win->_clear)
800                         newscr->_clear = TRUE;
801                 // code = doupdate();
802                 /*
803                  * Reset the clearok() flag in case it was set for the special
804                  * case in hardscroll.c (if we don't reset it here, we'll get 2
805                  * refreshes because the flag is copied from stdscr to newscr).
806                  * Resetting the flag shouldn't do any harm, anyway.
807                  */
808                 win->_clear = FALSE;
809         }
810
811         return code;
812 }
813 // int wscanw (WINDOW *, NCURSES_CONST char *,...) {}
814 int wscrl(WINDOW *win, int n)
815 {
816         if (!win->_scroll)
817                 return ERR;
818
819         if (n != 0) {
820                 // _nc_scroll_window(win, n, win->_regtop, win->_regbottom, win->_nc_bkgd);
821                 // _nc_synchook(win);
822         }
823         return OK;
824 }
825 int wsetscrreg(WINDOW *win, int top, int bottom)
826 {
827         if (top >= 0 && top <= win->_maxy && bottom >= 0 &&
828             bottom <= win->_maxy && bottom > top) {
829                 win->_regtop = (NCURSES_SIZE_T) top;
830                 win->_regbottom = (NCURSES_SIZE_T) bottom;
831                 return OK;
832         }
833         return ERR;
834 }
835 // void wsyncdown (WINDOW *) {}
836 // void wsyncup (WINDOW *) {}
837 /* D */ void wtimeout(WINDOW *win, int delay) { win->_delay = delay; }
838 /* D */ int wtouchln(WINDOW *win, int y, int n, int changed)
839 {
840         int i;
841
842         // if ((n < 0) || (y < 0) || (y > win->_maxy))
843         //     return ERR;
844
845         for (i = y; i < y + n; i++) {
846                 if (i > win->_maxy)
847                         break;
848                 win->_line[i].firstchar = changed ? 0 : _NOCHANGE;
849                 win->_line[i].lastchar = changed ? win->_maxx : _NOCHANGE;
850         }
851         return OK;
852 }
853 // int wvline (WINDOW *,chtype,int) {}
854 // int tigetflag (NCURSES_CONST char *) {}
855 // int tigetnum (NCURSES_CONST char *) {}
856 // char *tigetstr (NCURSES_CONST char *) {}
857 // int putp (const char *) {}
858 // #if NCURSES_TPARM_VARARGS
859 // char *tparm (NCURSES_CONST char *, ...) {}
860 // #else
861 // char *tparm (NCURSES_CONST char *, long,long,long,long,long,long,long,long,long) {}
862 // char *tparm_varargs (NCURSES_CONST char *, ...) {}
863 // #endif