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