Small curses fixes/additions for libpayload (trivial).
[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[3];
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_CONSOLE) {
222                 /* Clear the screen and kill the cursor. */
223                 vga_clear();
224                 vga_cursor_enable(0);
225         }
226
227         // Speaker init?
228
229         stdscr = newwin(SCREEN_Y, SCREEN_X + 1, 0, 0);
230         // TODO: curscr, newscr?
231
232         for (y = 0; y < stdscr->_maxy; y++) {
233                 for (x = 0; x < stdscr->_maxx; x++) {
234                         stdscr->_line[y].text[x].chars[0] = ' ';
235                         stdscr->_line[y].text[x].attr = A_NORMAL;
236                 }
237         }
238
239         return stdscr;
240 }
241 // int intrflush (WINDOW *,bool) {}
242 /* D */ bool isendwin(void) { return ((SP == NULL) ? FALSE : SP->_endwin); }
243 // bool is_linetouched (WINDOW *,int) {}
244 // bool is_wintouched (WINDOW *) {}
245 // NCURSES_CONST char * keyname (int) {}
246 int keypad (WINDOW *win, bool flag) { /* TODO */ return 0; }
247 // char killchar (void) {}
248 /* D */ int leaveok(WINDOW *win, bool flag) { win->_leaveok = flag; return OK; }
249 // char *longname (void) {}
250 // int meta (WINDOW *,bool) {}
251 // int mvcur (int,int,int,int) {}
252 // int mvderwin (WINDOW *, int, int) {}
253 int mvprintw(int y, int x, const char *fmt, ...)
254 {
255         va_list argp;
256         int code;
257
258         if (move(y, x) == ERR)
259                 return ERR;
260
261         va_start(argp, fmt);
262         code = vwprintw(stdscr, fmt, argp);
263         va_end(argp);
264
265         return code;
266 }
267 // int mvscanw (int,int, NCURSES_CONST char *,...) {}
268 // int mvwin (WINDOW *,int,int) {}
269 int mvwprintw(WINDOW *win, int y, int x, const char *fmt, ...)
270 {
271         va_list argp;
272         int code;
273
274         if (wmove(win, y, x) == ERR)
275                 return ERR;
276
277         va_start(argp, fmt);
278         code = vwprintw(win, fmt, argp);
279         va_end(argp);
280
281         return code;
282 }
283 // int mvwscanw (WINDOW *,int,int, NCURSES_CONST char *,...) {}
284 // int napms (int) {}
285 // WINDOW *newpad (int,int) {}
286 // SCREEN *newterm (NCURSES_CONST char *,FILE *,FILE *) {}
287 WINDOW *newwin(int num_lines, int num_columns, int begy, int begx)
288 {
289         int i;
290
291         /* Use next statically allocated window. */
292         // TODO: Error handling.
293         // TODO: WINDOWLIST?
294         WINDOW *win = &window_list[window_count++];
295
296         // bool is_pad = (flags & _ISPAD);
297
298         // TODO: Checks.
299
300         win->_cury = 0;
301         win->_curx = 0;
302         win->_maxy = num_lines - 1;
303         win->_maxx = num_columns - 1;
304         win->_begy = begy;
305         win->_begx = begx;
306         // win->_yoffset = SP->_topstolen;
307
308         win->_line = &ldat_list[ldat_count++];
309
310         /* FIXME: Is this right? Should the window attributes be normal? */
311         win->_color = PAIR_NUMBER(0);
312         win->_attrs = A_NORMAL;
313
314         for (i = 0; i < num_lines; i++)
315                 win->_line[i].text =
316                      (NCURSES_CH_T *)&linebuf_list[linebuf_count++];
317
318         return win;
319 }
320 /* D */ int nl(void) { SP->_nl = TRUE; return OK; }
321 /* D */ int noecho(void) { SP->_echo = FALSE; return OK; }
322 /* D */ int nonl(void) { SP->_nl = FALSE; return OK; }
323 // void noqiflush (void) {}
324 // int noraw (void) {}
325 /* D */ int notimeout (WINDOW *win, bool f) { win->_notimeout = f; return OK; }
326 // int overlay (const WINDOW*,WINDOW *) {}
327 // int overwrite (const WINDOW*,WINDOW *) {}
328 // int pair_content (short,short*,short*) {}
329 // int pechochar (WINDOW *, const chtype) {}
330 // int pnoutrefresh (WINDOW*,int,int,int,int,int,int) {}
331 // int prefresh (WINDOW *,int,int,int,int,int,int) {}
332 int printw(const char *fmt, ...)
333 {
334         va_list argp;
335         int code;
336
337         va_start(argp, fmt);
338         code = vwprintw(stdscr, fmt, argp);
339         va_end(argp);
340
341         return code;
342 }
343 // int putwin (WINDOW *, FILE *) {}
344 // void qiflush (void) {}
345 // int raw (void) {}
346 // int resetty (void) {}
347 // int reset_prog_mode (void) {}
348 // int reset_shell_mode (void) {}
349 // int ripoffline (int, int (*)(WINDOW *, int)) {}
350 // int savetty (void) {}
351 // int scanw (NCURSES_CONST char *,...) {}
352 // int scr_dump (const char *) {}
353 // int scr_init (const char *) {}
354 /* D */ int scrollok(WINDOW *win, bool flag) { win->_scroll = flag; return OK; }
355 // int scr_restore (const char *) {}
356 // int scr_set (const char *) {}
357 // SCREEN *set_term (SCREEN *) {}
358 // int slk_attroff (const chtype) {}
359 // int slk_attron (const chtype) {}
360 // int slk_attrset (const chtype) {}
361 // attr_t slk_attr (void) {}
362 // int slk_attr_set (const attr_t,short,void*) {}
363 // int slk_clear (void) {}
364 // int slk_color (short) {}
365 // int slk_init (int) {}
366 /* D */ char *slk_label(int n)
367 {
368         // TODO: Needed?
369         // if (SP == NULL || SP->_slk == NULL || n < 1 || n > SP->_slk->labcnt)
370         //      return NULL;
371         return SP->_slk->ent[n - 1].ent_text;
372 }
373 // int slk_noutrefresh (void) {}
374 // int slk_refresh (void) {}
375 // int slk_restore (void) {}
376 // int slk_set (int,const char *,int) {}
377 // int slk_touch (void) {}
378
379 // WINDOW *subpad (WINDOW *, int, int, int, int) {}
380 WINDOW *subwin(WINDOW *w, int l, int c, int y, int x)
381 {
382         return derwin(w, l, c, y - w->_begy, x - w->_begx);
383 }
384 // int syncok (WINDOW *, bool) {}
385 // chtype termattrs (void) {}
386 // char *termname (void) {}
387 // int typeahead (int) {}
388 int ungetch(int ch) { /* TODO */ return ERR; }
389 // void use_env (bool) {}
390 // int vidattr (chtype) {}
391 // int vidputs (chtype, int (*)(int)) {}
392 int vwprintw(WINDOW *win, const char *fmt, va_list argp)
393 {
394         vsprintf((char *)&sprintf_tmp, fmt, argp);
395
396         /* TODO: Error handling? */
397         return waddstr(win, (char *)&sprintf_tmp);
398 }
399 // int vwscanw (WINDOW *, NCURSES_CONST char *,va_list) {}
400 // int waddch (WINDOW *, const chtype) {}
401 int waddch(WINDOW *win, const chtype ch)
402 {
403         int code = ERR;
404         // NCURSES_CH_T wch;
405         // SetChar2(wch, ch);
406
407         win->_line[win->_cury].text[win->_curx].chars[0] = ch;
408
409         /* Use the window attributes - perhaps we also pull attributes from
410            the ch itself, I don't know */
411
412         win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win);
413         win->_curx++;   // FIXME
414
415         // if (win && (waddch_nosync(win, wch) != ERR)) {
416         //      _nc_synchook(win);
417         //      code = OK;
418         // }
419
420         return code;
421 }
422 // int waddchnstr (WINDOW *,const chtype *,int) {}
423 int waddnstr(WINDOW *win, const char *astr, int n)
424 {
425         int code = OK;
426         const char *str = astr;
427
428         if (!str)
429                 return ERR;
430
431         if (n < 0)
432                 n = strlen(astr);
433
434         while ((n-- > 0) && (*str != '\0')) {
435         // while (*str != '\0') {
436                 win->_line[win->_cury].text[win->_curx].chars[0] = *str++;
437                 win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win)
438 ;
439                 win->_curx++;   // FIXME
440
441                 // NCURSES_CH_T ch;
442                 // SetChar(ch, UChar(*str++), A_NORMAL);
443                 // if (_nc_waddch_nosync(win, ch) == ERR) {
444                 //      code = ERR;
445                 //      break;
446                 // }
447         }
448         return code;
449 }
450 int wattr_on(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
451 {
452         if (at & A_COLOR)
453                 win->_color = PAIR_NUMBER(at);
454         // toggle_attr_on(WINDOW_ATTRS(win), at);
455         return OK;
456 }
457 int wattr_off(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
458 {
459         if (at & A_COLOR)
460                 win->_color = 0;
461         // toggle_attr_off(WINDOW_ATTRS(win), at);
462         return 0;
463 }
464 // int wbkgd (WINDOW *, chtype) {}
465 void wbkgdset(WINDOW *win, chtype ch) { /* TODO */ }
466 // int wborder (WINDOW *,chtype,chtype,chtype,chtype,chtype,chtype,chtype,chtype) {}
467 // int wchgat (WINDOW *, int, attr_t, short, const void *) {}
468 /* D */ int wclear(WINDOW *win)
469 {
470         if (werase(win) == ERR)
471                 return ERR;
472         win->_clear = TRUE;
473         return OK;
474 }
475 // int wclrtobot (WINDOW *) {}
476 int wclrtoeol(WINDOW *win) { /* TODO */ return(*(int *)0); }
477 int wcolor_set(WINDOW *win, short color_pair_number, void *opts)
478 {
479         if (!opts && (color_pair_number >= 0)
480             && (color_pair_number < COLOR_PAIRS)) {
481                 SET_WINDOW_PAIR(win, color_pair_number);
482                 if_EXT_COLORS(win->_color = color_pair_number);
483                 return OK;
484         }
485         return ERR;
486 }
487 // void wcursyncup (WINDOW *) {}
488 // int wdelch (WINDOW *) {}
489 // int wechochar (WINDOW *, const chtype) {}
490 int werase(WINDOW *win)
491 {
492         int x, y;
493         for (y = 0; y < win->_maxy; y++) {
494                 for (x = 0; x < win->_maxx; x++) {
495                         win->_line[y].text[x].chars[0] = ' ';
496                         win->_line[y].text[x].attr = WINDOW_ATTRS(win);
497                 }
498         }
499         return OK;
500 }
501 // int wgetnstr (WINDOW *,char *,int) {}
502 int whline(WINDOW *win, chtype ch, int n)
503 {
504         NCURSES_SIZE_T start, end;
505         struct ldat *line = &(win->_line[win->_cury]);
506         NCURSES_CH_T wch;
507
508         start = win->_curx;
509         end = start + n - 1;
510         if (end > win->_maxx)
511                 end = win->_maxx;
512
513         CHANGED_RANGE(line, start, end);
514
515         //// TODO:
516         //// if (ch == 0)
517         ////     SetChar2(wch, ACS_HLINE);
518         //// else
519         ////     SetChar2(wch, ch);
520         // Ugly hack:
521         wch.chars[0] = ((ch) & (chtype)A_CHARTEXT);
522         wch.attr = ((ch) & (chtype)A_ATTRIBUTES);
523         wch = _nc_render(win, wch);
524
525         while (end >= start) {
526                 line->text[end] = wch;
527                 end--;
528         }
529
530         //// _nc_synchook(win);
531
532         return OK;
533 }
534 /* D */ chtype winch(WINDOW *win)
535 {
536         //// TODO
537         // return (CharOf(win->_line[win->_cury].text[win->_curx]) |
538         //         AttrOf(win->_line[win->_cury].text[win->_curx]));
539         return OK;      // FIXME
540 }
541 // int winchnstr (WINDOW *, chtype *, int) {}
542 // int winnstr (WINDOW *, char *, int) {}
543 // int winsch (WINDOW *, chtype) {}
544 // int winsdelln (WINDOW *,int) {}
545 // int winsnstr (WINDOW *, const char *,int) {}
546 /* D */ int wmove(WINDOW *win, int y, int x)
547 {
548         if (!LEGALYX(win, y, x))
549                 return ERR;
550         win->_curx = (NCURSES_SIZE_T) x;
551         win->_cury = (NCURSES_SIZE_T) y;
552         win->_flags &= ~_WRAPPED;
553         win->_flags |= _HASMOVED;
554         return OK;
555 }
556 int wnoutrefresh(WINDOW *win)
557 {
558         // FIXME.
559         int x, y;
560
561         for (y = 0; y < win->_maxy; y++) {
562                 for (x = 0; x < win->_maxx; x++) {
563                         if (curses_flags & F_ENABLE_SERIAL)
564                                 serial_putchar(win->_line[y].text[x].chars[0]);
565
566                         if (curses_flags & F_ENABLE_CONSOLE) {
567                                 attr_t attr = win->_line[y].text[x].attr;
568                                 unsigned int c =
569                                   ((int)color_pairs[PAIR_NUMBER(attr)]) << 8;
570
571                                 /* Handle some of the attributes. */
572                                 if (attr & A_BOLD)
573                                         c |= 0x0800;
574                                 if (attr & A_DIM)
575                                         c &= ~0x800;
576                                 if (attr & A_REVERSE) {
577                                         unsigned char tmp = (c >> 8) & 0xf;
578                                         c = (c >> 4) & 0xf00;
579                                         c |= tmp << 12;
580                                 }
581
582                                 /*
583                                  * FIXME: Somewhere along the line, the
584                                  * character value is getting sign-extented.
585                                  * For now grab just the 8 bit character,
586                                  * but this will break wide characters!
587                                  */
588                                 c |= (chtype) (win->_line[y].text[x].chars[0] & 0xff);
589                                 vga_putc(y, x, c);
590                         }
591                 }
592         }
593
594         return OK;
595 }
596 int wprintw(WINDOW *win, const char *fmt, ...)
597 {
598         va_list argp;
599         int code;
600
601         va_start(argp, fmt);
602         code = vwprintw(win, fmt, argp);
603         va_end(argp);
604
605         return code;
606 }
607 // int wredrawln (WINDOW *,int,int) {}
608 int wrefresh(WINDOW *win)
609 {
610         // FIXME
611         return wnoutrefresh(win);
612
613         // XXX
614         int code;
615
616         if (win == curscr) {
617                 curscr->_clear = TRUE;
618                 // code = doupdate();
619         } else if ((code = wnoutrefresh(win)) == OK) {
620                 if (win->_clear)
621                         newscr->_clear = TRUE;
622                 // code = doupdate();
623                 /*
624                  * Reset the clearok() flag in case it was set for the special
625                  * case in hardscroll.c (if we don't reset it here, we'll get 2
626                  * refreshes because the flag is copied from stdscr to newscr).
627                  * Resetting the flag shouldn't do any harm, anyway.
628                  */
629                 win->_clear = FALSE;
630         }
631
632         return code;
633 }
634 // int wscanw (WINDOW *, NCURSES_CONST char *,...) {}
635 int wscrl(WINDOW *win, int n)
636 {
637         if (!win->_scroll)
638                 return ERR;
639
640         if (n != 0) {
641                 // _nc_scroll_window(win, n, win->_regtop, win->_regbottom, win->_nc_bkgd);
642                 // _nc_synchook(win);
643         }
644         return OK;
645 }
646 int wsetscrreg(WINDOW *win, int top, int bottom)
647 {
648         if (top >= 0 && top <= win->_maxy && bottom >= 0 &&
649             bottom <= win->_maxy && bottom > top) {
650                 win->_regtop = (NCURSES_SIZE_T) top;
651                 win->_regbottom = (NCURSES_SIZE_T) bottom;
652                 return OK;
653         }
654         return ERR;
655 }
656 // void wsyncdown (WINDOW *) {}
657 // void wsyncup (WINDOW *) {}
658 /* D */ void wtimeout(WINDOW *win, int delay) { win->_delay = delay; }
659 /* D */ int wtouchln(WINDOW *win, int y, int n, int changed)
660 {
661         int i;
662
663         // if ((n < 0) || (y < 0) || (y > win->_maxy))
664         //     return ERR;
665
666         for (i = y; i < y + n; i++) {
667                 if (i > win->_maxy)
668                         break;
669                 win->_line[i].firstchar = changed ? 0 : _NOCHANGE;
670                 win->_line[i].lastchar = changed ? win->_maxx : _NOCHANGE;
671         }
672         return OK;
673 }
674 // int wvline (WINDOW *,chtype,int) {}
675 // int tigetflag (NCURSES_CONST char *) {}
676 // int tigetnum (NCURSES_CONST char *) {}
677 // char *tigetstr (NCURSES_CONST char *) {}
678 // int putp (const char *) {}
679 // #if NCURSES_TPARM_VARARGS
680 // char *tparm (NCURSES_CONST char *, ...) {}
681 // #else
682 // char *tparm (NCURSES_CONST char *, long,long,long,long,long,long,long,long,long) {}
683 // char *tparm_varargs (NCURSES_CONST char *, ...) {}
684 // #endif