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