Mostly cosmetical changes.
[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-2009 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 #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 }
278 int doupdate(void) { /* TODO */ return(0); }
279 // WINDOW * dupwin (WINDOW *) {}
280 /* D */ int echo(void) { SP->_echo = TRUE; return OK; }
281 int endwin(void)
282 {
283         if (!SP)
284                 return ERR;
285
286         SP->_endwin = TRUE;
287         SP->_mouse_wrap(SP);
288         // _nc_screen_wrap();
289         // _nc_mvcur_wrap();       /* wrap up cursor addressing */
290         // return reset_shell_mode();
291         return OK;      // FIXME
292 }
293 // char erasechar (void) {}
294 // void filter (void) {}
295 // int flash(void) {}
296 int flushinp(void) { /* TODO */ return 0; }
297 // WINDOW *getwin (FILE *) {}
298 bool has_colors (void) { return(TRUE); }
299 // bool has_ic (void) {}
300 // bool has_il (void) {}
301 // void idcok (WINDOW *, bool) {}
302 // int idlok (WINDOW *, bool) {}
303 void immedok(WINDOW *win, bool flag) { win->_immed = flag; }
304 /** Note: Must _not_ be called twice! */
305 WINDOW *initscr(void)
306 {
307         int i;
308
309         // newterm(name, stdout, stdin);
310         // def_prog_mode();
311
312         for (i = 0; i < 128; i++)
313           acs_map[i] = (chtype) i | A_ALTCHARSET;
314 #ifdef CONFIG_SERIAL_CONSOLE
315         if (curses_flags & F_ENABLE_SERIAL) {
316                 serial_clear();
317         }
318 #endif
319 #ifdef CONFIG_VIDEO_CONSOLE
320         if (curses_flags & F_ENABLE_CONSOLE) {
321                 /* Clear the screen and kill the cursor */
322
323                 video_console_clear();
324                 video_console_cursor_enable(0);
325         }
326 #endif
327
328         // Speaker init?
329
330         stdscr = newwin(SCREEN_Y, SCREEN_X, 0, 0);
331         // TODO: curscr, newscr?
332
333         werase(stdscr);
334
335         return stdscr;
336 }
337 // int intrflush (WINDOW *,bool) {}
338 /* D */ bool isendwin(void) { return ((SP == NULL) ? FALSE : SP->_endwin); }
339 // bool is_linetouched (WINDOW *,int) {}
340 // bool is_wintouched (WINDOW *) {}
341 // NCURSES_CONST char * keyname (int) {}
342 int keypad (WINDOW *win, bool flag) { /* TODO */ return 0; }
343 // char killchar (void) {}
344 /* D */ int leaveok(WINDOW *win, bool flag) { win->_leaveok = flag; return OK; }
345 // char *longname (void) {}
346 // int meta (WINDOW *,bool) {}
347 // int mvcur (int,int,int,int) {}
348 // int mvderwin (WINDOW *, int, int) {}
349 int mvprintw(int y, int x, const char *fmt, ...)
350 {
351         va_list argp;
352         int code;
353
354         if (move(y, x) == ERR)
355                 return ERR;
356
357         va_start(argp, fmt);
358         code = vwprintw(stdscr, fmt, argp);
359         va_end(argp);
360
361         return code;
362 }
363 // int mvscanw (int,int, NCURSES_CONST char *,...) {}
364 // int mvwin (WINDOW *,int,int) {}
365 int mvwprintw(WINDOW *win, int y, int x, const char *fmt, ...)
366 {
367         va_list argp;
368         int code;
369
370         if (wmove(win, y, x) == ERR)
371                 return ERR;
372
373         va_start(argp, fmt);
374         code = vwprintw(win, fmt, argp);
375         va_end(argp);
376
377         return code;
378 }
379 // int mvwscanw (WINDOW *,int,int, NCURSES_CONST char *,...) {}
380 // int napms (int) {}
381 // WINDOW *newpad (int,int) {}
382 // SCREEN *newterm (NCURSES_CONST char *,FILE *,FILE *) {}
383 WINDOW *newwin(int num_lines, int num_columns, int begy, int begx)
384 {
385         int i;
386
387         /* Use next statically allocated window. */
388         // TODO: Error handling.
389         // TODO: WINDOWLIST?
390         WINDOW *win = &window_list[window_count++];
391
392         // bool is_pad = (flags & _ISPAD);
393
394         // TODO: Checks.
395
396         win->_cury = 0;
397         win->_curx = 0;
398         win->_maxy = num_lines - 1;
399         win->_maxx = num_columns - 1;
400         win->_begy = begy;
401         win->_begx = begx;
402         // win->_yoffset = SP->_topstolen;
403
404         win->_line = ldat_list[ldat_count++];
405
406         /* FIXME: Is this right? Should the window attributes be normal? */
407         win->_color = PAIR_NUMBER(0);
408         win->_attrs = A_NORMAL;
409
410         for (i = 0; i < num_lines; i++)
411                 win->_line[i].text =
412                      (NCURSES_CH_T *)&linebuf_list[linebuf_count++];
413
414         return win;
415 }
416 /* D */ int nl(void) { SP->_nl = TRUE; return OK; }
417 /* D */ int noecho(void) { SP->_echo = FALSE; return OK; }
418 /* D */ int nonl(void) { SP->_nl = FALSE; return OK; }
419 // void noqiflush (void) {}
420 // int noraw (void) {}
421 /* D */ int notimeout (WINDOW *win, bool f) { win->_notimeout = f; return OK; }
422 // int overlay (const WINDOW*,WINDOW *) {}
423 // int overwrite (const WINDOW*,WINDOW *) {}
424 // int pair_content (short,short*,short*) {}
425 // int pechochar (WINDOW *, const chtype) {}
426 // int pnoutrefresh (WINDOW*,int,int,int,int,int,int) {}
427 // int prefresh (WINDOW *,int,int,int,int,int,int) {}
428 int printw(const char *fmt, ...)
429 {
430         va_list argp;
431         int code;
432
433         va_start(argp, fmt);
434         code = vwprintw(stdscr, fmt, argp);
435         va_end(argp);
436
437         return code;
438 }
439 // int putwin (WINDOW *, FILE *) {}
440 // void qiflush (void) {}
441 // int raw (void) {}
442 // int resetty (void) {}
443 // int reset_prog_mode (void) {}
444 // int reset_shell_mode (void) {}
445 // int ripoffline (int, int (*)(WINDOW *, int)) {}
446 // int savetty (void) {}
447 // int scanw (NCURSES_CONST char *,...) {}
448 // int scr_dump (const char *) {}
449 // int scr_init (const char *) {}
450 /* D */ int scrollok(WINDOW *win, bool flag) { win->_scroll = flag; return OK; }
451 // int scr_restore (const char *) {}
452 // int scr_set (const char *) {}
453 // SCREEN *set_term (SCREEN *) {}
454 // int slk_attroff (const chtype) {}
455 // int slk_attron (const chtype) {}
456 // int slk_attrset (const chtype) {}
457 // attr_t slk_attr (void) {}
458 // int slk_attr_set (const attr_t,short,void*) {}
459 // int slk_clear (void) {}
460 // int slk_color (short) {}
461 // int slk_init (int) {}
462 /* D */ char *slk_label(int n)
463 {
464         // TODO: Needed?
465         // if (SP == NULL || SP->_slk == NULL || n < 1 || n > SP->_slk->labcnt)
466         //      return NULL;
467         return SP->_slk->ent[n - 1].ent_text;
468 }
469 // int slk_noutrefresh (void) {}
470 // int slk_refresh (void) {}
471 // int slk_restore (void) {}
472 // int slk_set (int,const char *,int) {}
473 // int slk_touch (void) {}
474
475 // WINDOW *subpad (WINDOW *, int, int, int, int) {}
476 WINDOW *subwin(WINDOW *w, int l, int c, int y, int x)
477 {
478         return derwin(w, l, c, y - w->_begy, x - w->_begx);
479 }
480 // int syncok (WINDOW *, bool) {}
481 // chtype termattrs (void) {}
482 // char *termname (void) {}
483 // int typeahead (int) {}
484 int ungetch(int ch) { /* TODO */ return ERR; }
485 // void use_env (bool) {}
486 // int vidattr (chtype) {}
487 // int vidputs (chtype, int (*)(int)) {}
488 int vwprintw(WINDOW *win, const char *fmt, va_list argp)
489 {
490         vsprintf((char *)&sprintf_tmp, fmt, argp);
491
492         /* TODO: Error handling? */
493         return waddstr(win, (char *)&sprintf_tmp);
494 }
495 // int vwscanw (WINDOW *, NCURSES_CONST char *,va_list) {}
496 int waddch(WINDOW *win, const chtype ch)
497 {
498         int code = ERR;
499         // NCURSES_CH_T wch;
500         // SetChar2(wch, ch);
501
502         if (win->_line[win->_cury].firstchar == _NOCHANGE || 
503                         win->_line[win->_cury].firstchar > win->_curx)
504                 win->_line[win->_cury].firstchar = win->_curx;
505
506         win->_line[win->_cury].text[win->_curx].chars[0] =
507                 ((ch) & (chtype)A_CHARTEXT);
508
509         win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win);
510         win->_line[win->_cury].text[win->_curx].attr |=
511                 ((ch) & (chtype)A_ATTRIBUTES);
512
513         if (win->_line[win->_cury].lastchar == _NOCHANGE || 
514                         win->_line[win->_cury].lastchar < win->_curx)
515                 win->_line[win->_cury].lastchar = win->_curx;
516
517         win->_curx++;   // FIXME
518
519         // if (win && (waddch_nosync(win, wch) != ERR)) {
520         //      _nc_synchook(win);
521         //      code = OK;
522         // }
523
524         return code;
525 }
526 // int waddchnstr (WINDOW *,const chtype *,int) {}
527 int waddnstr(WINDOW *win, const char *astr, int n)
528 {
529         int code = OK;
530         const char *str = astr;
531
532         if (!str)
533                 return ERR;
534
535         if (n < 0)
536                 n = strlen(astr);
537
538         if (win->_line[win->_cury].firstchar == _NOCHANGE || 
539                         win->_line[win->_cury].firstchar > win->_curx)
540                 win->_line[win->_cury].firstchar = win->_curx;
541
542         while ((n-- > 0) && (*str != '\0')) {
543         // while (*str != '\0') {
544                 win->_line[win->_cury].text[win->_curx].chars[0] = *str++;
545                 win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win)
546 ;
547                 win->_curx++;   // FIXME
548
549                 // NCURSES_CH_T ch;
550                 // SetChar(ch, UChar(*str++), A_NORMAL);
551                 // if (_nc_waddch_nosync(win, ch) == ERR) {
552                 //      code = ERR;
553                 //      break;
554                 // }
555         }
556
557         if (win->_line[win->_cury].lastchar == _NOCHANGE || 
558                         win->_line[win->_cury].lastchar < win->_curx)
559                 win->_line[win->_cury].lastchar = win->_curx;
560
561         return code;
562 }
563 int wattr_on(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
564 {
565         if (at & A_COLOR)
566                 win->_color = PAIR_NUMBER(at);
567         // toggle_attr_on(WINDOW_ATTRS(win), at);
568         return OK;
569 }
570 int wattr_off(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
571 {
572         if (at & A_COLOR)
573                 win->_color = 0;
574         // toggle_attr_off(WINDOW_ATTRS(win), at);
575         return 0;
576 }
577 // int wbkgd (WINDOW *, chtype) {}
578 void wbkgdset(WINDOW *win, chtype ch) { /* TODO */ }
579
580 int wborder(WINDOW *win, chtype ls, chtype rs, chtype ts, chtype bs,
581                 chtype tl, chtype tr, chtype bl, chtype br)
582 {
583         int x, y;
584
585         for(y = 0; y <= win->_maxy; y++) {
586
587                 if (y == 0) {
588                          mvwaddch(win, y, 0, tl);
589
590                         for(x = 1; x < win->_maxx; x++)
591                                 mvwaddch(win, y, x, ts);
592
593                         mvwaddch(win, y, win->_maxx, tr);
594                 }
595                 else if (y == win->_maxy) {
596                         mvwaddch(win, y, 0, bl);
597
598                         for(x = 1; x < win->_maxx; x++)
599                                 mvwaddch(win, y, x, bs);
600
601                         mvwaddch(win, y, win->_maxx, br);
602                 }
603                 else {
604                         mvwaddch(win, y, 0, ls);
605                         mvwaddch(win, y, win->_maxx, rs);
606                 }
607         }
608
609         return OK;
610 }
611
612 // int wchgat (WINDOW *, int, attr_t, short, const void *) {}
613 /* D */ int wclear(WINDOW *win)
614 {
615         if (werase(win) == ERR)
616                 return ERR;
617         win->_clear = TRUE;
618         return OK;
619 }
620 // int wclrtobot (WINDOW *) {}
621 int wclrtoeol(WINDOW *win) { /* TODO */ return ERR; }
622 int wcolor_set(WINDOW *win, short color_pair_number, void *opts)
623 {
624         if (!opts && (color_pair_number >= 0)
625             && (color_pair_number < COLOR_PAIRS)) {
626                 SET_WINDOW_PAIR(win, color_pair_number);
627                 if_EXT_COLORS(win->_color = color_pair_number);
628                 return OK;
629         }
630         return ERR;
631 }
632 // void wcursyncup (WINDOW *) {}
633 // int wdelch (WINDOW *) {}
634 // int wechochar (WINDOW *, const chtype) {}
635 int werase(WINDOW *win)
636 {
637         int x, y;
638         for (y = 0; y <= win->_maxy; y++) {
639                 for (x = 0; x <= win->_maxx; x++) {
640                         win->_line[y].text[x].chars[0] = ' ';
641                         win->_line[y].text[x].attr = WINDOW_ATTRS(win);
642                 }
643                 // Should we check instead?
644                 win->_line[y].firstchar = 0;
645                 win->_line[y].lastchar = win->_maxx;
646         }
647         return OK;
648 }
649 // int wgetnstr (WINDOW *,char *,int) {}
650 int whline(WINDOW *win, chtype ch, int n)
651 {
652         NCURSES_SIZE_T start, end;
653         struct ldat *line = &(win->_line[win->_cury]);
654         NCURSES_CH_T wch;
655
656         start = win->_curx;
657         end = start + n - 1;
658         if (end > win->_maxx)
659                 end = win->_maxx;
660
661         CHANGED_RANGE(line, start, end);
662
663         //// TODO:
664         //// if (ch == 0)
665         ////     SetChar2(wch, ACS_HLINE);
666         //// else
667         ////     SetChar2(wch, ch);
668         // Ugly hack:
669         wch.chars[0] = ((ch) & (chtype)A_CHARTEXT);
670         wch.attr = ((ch) & (chtype)A_ATTRIBUTES);
671         wch = _nc_render(win, wch);
672
673         while (end >= start) {
674                 line->text[end] = wch;
675                 end--;
676         }
677
678         //// _nc_synchook(win);
679
680         return OK;
681 }
682 /* D */ chtype winch(WINDOW *win)
683 {
684         //// TODO
685         // return (CharOf(win->_line[win->_cury].text[win->_curx]) |
686         //         AttrOf(win->_line[win->_cury].text[win->_curx]));
687         return OK;      // FIXME
688 }
689 // int winchnstr (WINDOW *, chtype *, int) {}
690 // int winnstr (WINDOW *, char *, int) {}
691 // int winsch (WINDOW *, chtype) {}
692 // int winsdelln (WINDOW *,int) {}
693 // int winsnstr (WINDOW *, const char *,int) {}
694 /* D */ int wmove(WINDOW *win, int y, int x)
695 {
696         if (!LEGALYX(win, y, x))
697                 return ERR;
698         win->_curx = (NCURSES_SIZE_T) x;
699         win->_cury = (NCURSES_SIZE_T) y;
700         win->_flags &= ~_WRAPPED;
701         win->_flags |= _HASMOVED;
702         return OK;
703 }
704
705 #define SWAP_RED_BLUE(c) \
706         (((c) & 0x4400) >> 2) | ((c) & 0xAA00) | (((c) & 0x1100) << 2)
707 int wnoutrefresh(WINDOW *win)
708 {
709 #ifdef CONFIG_SERIAL_CONSOLE
710         // FIXME.
711         int serial_is_bold = 0;
712         int serial_is_reverse = 0;
713         int serial_is_altcharset = 0;
714         int serial_cur_pair = 0;
715
716         int need_altcharset;
717         short fg, bg;
718 #endif
719         int x, y;
720         chtype ch;
721
722 #ifdef CONFIG_SERIAL_CONSOLE
723         serial_end_bold();
724         serial_end_altcharset();
725 #endif
726
727         for (y = 0; y <= win->_maxy; y++) {
728
729                 if (win->_line[y].firstchar == _NOCHANGE)
730                         continue;
731
732                 /* Position the serial cursor */
733
734 #ifdef CONFIG_SERIAL_CONSOLE
735                 if (curses_flags & F_ENABLE_SERIAL)
736                         serial_set_cursor(win->_begy + y, win->_begx +
737                                         win->_line[y].firstchar);
738 #endif
739
740                 for (x = win->_line[y].firstchar; x <= win->_line[y].lastchar; x++) {
741                         attr_t attr = win->_line[y].text[x].attr;
742
743 #ifdef CONFIG_SERIAL_CONSOLE
744                         if (curses_flags & F_ENABLE_SERIAL) {
745                                 ch = win->_line[y].text[x].chars[0];
746
747                                 if (attr & A_BOLD) {
748                                         if (!serial_is_bold) {
749                                                 serial_start_bold();
750                                                 serial_is_bold = 1;
751                                         }
752                                 } else {
753                                         if (serial_is_bold) {
754                                                 serial_end_bold();
755                                                 serial_is_bold = 0;
756                                                 /* work around serial.c
757                                                  * shortcoming:
758                                                  */
759                                                 serial_is_reverse = 0;
760                                                 serial_cur_pair = 0;
761                                         }
762                                 }
763
764                                 if (attr & A_REVERSE) {
765                                         if (!serial_is_reverse) {
766                                                 serial_start_reverse();
767                                                 serial_is_reverse = 1;
768                                         }
769                                 } else {
770                                         if (serial_is_reverse) {
771                                                 serial_end_reverse();
772                                                 serial_is_reverse = 0;
773                                                 /* work around serial.c
774                                                  * shortcoming:
775                                                  */
776                                                 serial_is_bold = 0;
777                                                 serial_cur_pair = 0;
778                                         }
779                                 }
780
781                                 need_altcharset = 0;
782                                 if (attr & A_ALTCHARSET) {
783                                         if (serial_acs_map[ch & 0x7f]) {
784                                                 ch = serial_acs_map[ch & 0x7f];
785                                                 need_altcharset = 1;
786                                         } else
787                                                 ch = fallback_acs_map[ch & 0x7f];
788                                 }
789                                 if (need_altcharset && !serial_is_altcharset) {
790                                         serial_start_altcharset();
791                                         serial_is_altcharset = 1;
792                                 }
793                                 if (!need_altcharset && serial_is_altcharset) {
794                                         serial_end_altcharset();
795                                         serial_is_altcharset = 0;
796                                 }
797
798                                 if (serial_cur_pair != PAIR_NUMBER(attr)) {
799                                         pair_content(PAIR_NUMBER(attr),
800                                                      &fg, &bg);
801                                         serial_set_color(fg, bg);
802                                         serial_cur_pair = PAIR_NUMBER(attr);
803                                 }
804
805                                 serial_putchar(ch);
806
807                         }
808 #endif
809 #ifdef CONFIG_VIDEO_CONSOLE
810                         unsigned int c =
811                                 ((int)color_pairs[PAIR_NUMBER(attr)]) << 8;
812
813                         c = SWAP_RED_BLUE(c);
814
815                         if (curses_flags & F_ENABLE_CONSOLE) {
816                                 ch = win->_line[y].text[x].chars[0];
817
818                                 /* Handle some of the attributes. */
819                                 if (attr & A_BOLD)
820                                         c |= 0x0800;
821                                 if (attr & A_DIM)
822                                         c &= ~0x800;
823                                 if (attr & A_REVERSE) {
824                                         unsigned char tmp = (c >> 8) & 0xf;
825                                         c = (c >> 4) & 0xf00;
826                                         c |= tmp << 12;
827                                 }
828                                 if (attr & A_ALTCHARSET) {
829                                         if (console_acs_map[ch & 0x7f])
830                                                 ch = console_acs_map[ch & 0x7f];
831                                         else
832                                                 ch = fallback_acs_map[ch & 0x7f];
833                                 }
834
835                                 /*
836                                  * FIXME: Somewhere along the line, the
837                                  * character value is getting sign-extented.
838                                  * For now grab just the 8 bit character,
839                                  * but this will break wide characters!
840                                  */
841                                 c |= (chtype) (ch & 0xff);
842                                 video_console_putc(win->_begy + y, win->_begx + x, c);
843                         }
844 #endif
845                 }
846                 win->_line[y].firstchar = _NOCHANGE;
847                 win->_line[y].lastchar = _NOCHANGE;
848         }
849
850 #ifdef CONFIG_SERIAL_CONSOLE
851         if (curses_flags & F_ENABLE_SERIAL)
852                 serial_set_cursor(win->_begy + win->_cury, win->_begx + win->_curx);
853 #endif
854
855 #ifdef CONFIG_VIDEO_CONSOLE
856         if (curses_flags & F_ENABLE_CONSOLE)
857                 video_console_set_cursor(win->_begx + win->_curx, win->_begy + win->_cury);
858 #endif
859
860         return OK;
861 }
862 int wprintw(WINDOW *win, const char *fmt, ...)
863 {
864         va_list argp;
865         int code;
866
867         va_start(argp, fmt);
868         code = vwprintw(win, fmt, argp);
869         va_end(argp);
870
871         return code;
872 }
873
874 int wredrawln (WINDOW *win, int beg_line, int num_lines)
875 {
876         int i;
877
878         for (i = beg_line; i < beg_line + num_lines; i++) {
879                 win->_line[i].firstchar = 0;
880                 win->_line[i].lastchar = win->_maxx;
881         }
882
883         return OK;
884 }
885
886 int wrefresh(WINDOW *win)
887 {
888         // FIXME
889         return wnoutrefresh(win);
890
891         // XXX
892         int code;
893
894         if (win == curscr) {
895                 curscr->_clear = TRUE;
896                 // code = doupdate();
897         } else if ((code = wnoutrefresh(win)) == OK) {
898                 if (win->_clear)
899                         newscr->_clear = TRUE;
900                 // code = doupdate();
901                 /*
902                  * Reset the clearok() flag in case it was set for the special
903                  * case in hardscroll.c (if we don't reset it here, we'll get 2
904                  * refreshes because the flag is copied from stdscr to newscr).
905                  * Resetting the flag shouldn't do any harm, anyway.
906                  */
907                 win->_clear = FALSE;
908         }
909
910         return code;
911 }
912 // int wscanw (WINDOW *, NCURSES_CONST char *,...) {}
913 int wscrl(WINDOW *win, int n)
914 {
915         int x, y;
916
917         if (!win->_scroll)
918                 return ERR;
919
920         if (n == 0)
921                 return OK;
922
923         for (y = 0; y <= (win->_maxy - n); y++) {
924                 win->_line[y].firstchar = win->_line[y + n].firstchar;
925                 win->_line[y].lastchar = win->_line[y + n].lastchar;
926                 for (x = 0; x <= win->_maxx; x++) {
927                         if ((win->_line[y].text[x].chars[0] != win->_line[y + n].text[x].chars[0]) || 
928                                         (win->_line[y].text[x].attr != win->_line[y + n].text[x].attr)) {
929                                 if (win->_line[y].firstchar == _NOCHANGE)
930                                         win->_line[y].firstchar = x;
931
932                                 win->_line[y].lastchar = x;
933
934                                 win->_line[y].text[x].chars[0] = win->_line[y + n].text[x].chars[0];
935                                 win->_line[y].text[x].attr = win->_line[y + n].text[x].attr;
936                         }
937                 }
938         }
939
940         for (y = (win->_maxy+1 - n); y <= win->_maxy; y++) {
941                 for (x = 0; x <= win->_maxx; x++) {
942                         if ((win->_line[y].text[x].chars[0] != ' ') || 
943                                         (win->_line[y].text[x].attr != A_NORMAL)) {
944                                 if (win->_line[y].firstchar == _NOCHANGE)
945                                         win->_line[y].firstchar = x;
946
947                                 win->_line[y].lastchar = x;
948
949                                 win->_line[y].text[x].chars[0] = ' ';
950                                 win->_line[y].text[x].attr = A_NORMAL;
951                         }
952                 }
953         }
954
955         // _nc_scroll_window(win, n, win->_regtop, win->_regbottom, win->_nc_bkgd);
956         // _nc_synchook(win);
957
958         return OK;
959 }
960 int wsetscrreg(WINDOW *win, int top, int bottom)
961 {
962         if (top >= 0 && top <= win->_maxy && bottom >= 0 &&
963             bottom <= win->_maxy && bottom > top) {
964                 win->_regtop = (NCURSES_SIZE_T) top;
965                 win->_regbottom = (NCURSES_SIZE_T) bottom;
966                 return OK;
967         }
968         return ERR;
969 }
970 // void wsyncdown (WINDOW *) {}
971 // void wsyncup (WINDOW *) {}
972 /* D */ void wtimeout(WINDOW *win, int delay) { win->_delay = delay; }
973 /* D */ int wtouchln(WINDOW *win, int y, int n, int changed)
974 {
975         int i;
976
977         // if ((n < 0) || (y < 0) || (y > win->_maxy))
978         //     return ERR;
979
980         for (i = y; i < y + n; i++) {
981                 if (i > win->_maxy)
982                         break;
983                 win->_line[i].firstchar = changed ? 0 : _NOCHANGE;
984                 win->_line[i].lastchar = changed ? win->_maxx : _NOCHANGE;
985         }
986         return OK;
987 }
988 // int wvline (WINDOW *,chtype,int) {}
989 // int tigetflag (NCURSES_CONST char *) {}
990 // int tigetnum (NCURSES_CONST char *) {}
991 // char *tigetstr (NCURSES_CONST char *) {}
992 // int putp (const char *) {}
993 // #if NCURSES_TPARM_VARARGS
994 // char *tparm (NCURSES_CONST char *, ...) {}
995 // #else
996 // char *tparm (NCURSES_CONST char *, long,long,long,long,long,long,long,long,long) {}
997 // char *tparm_varargs (NCURSES_CONST char *, ...) {}
998 // #endif