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