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