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