Cosmetics, coding style fixes (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' 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
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         //// if ((win = _nc_makenew(num_lines, num_columns, orig->_begy + begy,
171         ////                        orig->_begx + begx, flags)) == 0)
172         ////     return NULL;
173
174         win->_pary = begy;
175         win->_parx = begx;
176         WINDOW_ATTRS(win) = WINDOW_ATTRS(orig);
177         win->_nc_bkgd = orig->_nc_bkgd;
178
179         for (i = 0; i < num_lines; i++)
180                 win->_line[i].text = &orig->_line[begy++].text[begx];
181
182         win->_parent = orig;
183
184         return win;
185 }
186 int doupdate(void) { /* TODO */ return(*(int *)0); }
187 // WINDOW * dupwin (WINDOW *) {}
188 /* D */ int echo(void) { SP->_echo = TRUE; return OK; }
189 int endwin(void)
190 {
191         if (!SP)
192                 return ERR;
193
194         SP->_endwin = TRUE;
195         SP->_mouse_wrap(SP);
196         // _nc_screen_wrap();
197         // _nc_mvcur_wrap();       /* wrap up cursor addressing */
198         // return reset_shell_mode();
199         return OK;      // FIXME
200 }
201 // char erasechar (void) {}
202 // void filter (void) {}
203 // int flash(void) {}
204 // int flushinp (void) {}
205 // WINDOW *getwin (FILE *) {}
206
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
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 =
317                      (NCURSES_CH_T *)&linebuf_list[linebuf_count++];
318
319         return win;
320 }
321 /* D */ int nl(void) { SP->_nl = TRUE; return OK; }
322 int nocbreak(void) { /* TODO */ return(*(int *)0); }
323
324 /* D */ int noecho(void) { SP->_echo = FALSE; return OK; }
325 /* D */ int nonl(void) { SP->_nl = FALSE; return OK; }
326 // void noqiflush (void) {}
327 // int noraw (void) {}
328 // int notimeout (WINDOW *,bool) {}
329 // int overlay (const WINDOW*,WINDOW *) {}
330 // int overwrite (const WINDOW*,WINDOW *) {}
331 // int pair_content (short,short*,short*) {}
332 // int pechochar (WINDOW *, const chtype) {}
333 // int pnoutrefresh (WINDOW*,int,int,int,int,int,int) {}
334 // int prefresh (WINDOW *,int,int,int,int,int,int) {}
335 int printw(const char *fmt, ...)
336 {
337         va_list argp;
338         int code;
339
340         va_start(argp, fmt);
341         code = vwprintw(stdscr, fmt, argp);
342         va_end(argp);
343
344         return code;
345 }
346 // int putwin (WINDOW *, FILE *) {}
347 // void qiflush (void) {}
348 // int raw (void) {}
349 // int resetty (void) {}
350 // int reset_prog_mode (void) {}
351 // int reset_shell_mode (void) {}
352 // int ripoffline (int, int (*)(WINDOW *, int)) {}
353 // int savetty (void) {}
354 // int scanw (NCURSES_CONST char *,...) {}
355 // int scr_dump (const char *) {}
356 // int scr_init (const char *) {}
357 /* D */ int scrollok(WINDOW *win, bool flag) { win->_scroll = flag; return OK; }
358 // int scr_restore (const char *) {}
359 // int scr_set (const char *) {}
360 // SCREEN *set_term (SCREEN *) {}
361 // int slk_attroff (const chtype) {}
362 // int slk_attron (const chtype) {}
363 // int slk_attrset (const chtype) {}
364 // attr_t slk_attr (void) {}
365 // int slk_attr_set (const attr_t,short,void*) {}
366 // int slk_clear (void) {}
367 // int slk_color (short) {}
368 // int slk_init (int) {}
369 /* D */ char *slk_label(int n)
370 {
371         // TODO: Needed?
372         // if (SP == NULL || SP->_slk == NULL || n < 1 || n > SP->_slk->labcnt)
373         //      return NULL;
374         return SP->_slk->ent[n - 1].ent_text;
375 }
376 // int slk_noutrefresh (void) {}
377 // int slk_refresh (void) {}
378 // int slk_restore (void) {}
379 // int slk_set (int,const char *,int) {}
380 // int slk_touch (void) {}
381
382 // WINDOW *subpad (WINDOW *, int, int, int, int) {}
383 WINDOW *subwin(WINDOW *w, int l, int c, int y, int x)
384 {
385         return derwin(w, l, c, y - w->_begy, x - w->_begx);
386 }
387 // int syncok (WINDOW *, bool) {}
388 // chtype termattrs (void) {}
389 // char *termname (void) {}
390 // int typeahead (int) {}
391 int ungetch(int ch) { /* TODO */ return ERR; }
392 // void use_env (bool) {}
393 // int vidattr (chtype) {}
394 // int vidputs (chtype, int (*)(int)) {}
395 int vwprintw(WINDOW *win, const char *fmt, va_list argp)
396 {
397         vsprintf((char *)&sprintf_tmp, fmt, argp);
398
399         /* TODO: Error handling? */
400         return waddstr(win, (char *)&sprintf_tmp);
401 }
402 // int vwscanw (WINDOW *, NCURSES_CONST char *,va_list) {}
403 // int waddch (WINDOW *, const chtype) {}
404 int waddch(WINDOW *win, const chtype ch)
405 {
406         int code = ERR;
407         // NCURSES_CH_T wch;
408         // SetChar2(wch, ch);
409
410         win->_line[win->_cury].text[win->_curx].chars[0] = ch;
411
412         /* Use the window attributes - perhaps we also pull attributes from
413            the ch itself, I don't know */
414
415         win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win);
416         win->_curx++;   // FIXME
417
418         // if (win && (waddch_nosync(win, wch) != ERR)) {
419         //      _nc_synchook(win);
420         //      code = OK;
421         // }
422
423         return code;
424 }
425 // int waddchnstr (WINDOW *,const chtype *,int) {}
426 int waddnstr(WINDOW *win, const char *astr, int n)
427 {
428         int code = OK;
429         const char *str = astr;
430
431         if (!str)
432                 return ERR;
433
434         if (n < 0)
435                 n = strlen(astr);
436
437         while ((n-- > 0) && (*str != '\0')) {
438         // while (*str != '\0') {
439                 win->_line[win->_cury].text[win->_curx].chars[0] = *str++;
440                 win->_line[win->_cury].text[win->_curx].attr = WINDOW_ATTRS(win)
441 ;
442                 win->_curx++;   // FIXME
443
444                 // NCURSES_CH_T ch;
445                 // SetChar(ch, UChar(*str++), A_NORMAL);
446                 // if (_nc_waddch_nosync(win, ch) == ERR) {
447                 //      code = ERR;
448                 //      break;
449                 // }
450         }
451         return code;
452 }
453 int wattr_on(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
454 {
455         if (at & A_COLOR)
456                 win->_color = PAIR_NUMBER(at);
457         // toggle_attr_on(WINDOW_ATTRS(win), at);
458         return OK;
459 }
460 int wattr_off(WINDOW *win, attr_t at, void *opts GCC_UNUSED)
461 {
462         if (at & A_COLOR)
463                 win->_color = 0;
464         // toggle_attr_off(WINDOW_ATTRS(win), at);
465         return 0;
466 }
467 // int wbkgd (WINDOW *, chtype) {}
468 void wbkgdset(WINDOW *win, chtype ch) { /* TODO */ }
469 // int wborder (WINDOW *,chtype,chtype,chtype,chtype,chtype,chtype,chtype,chtype) {}
470 // int wchgat (WINDOW *, int, attr_t, short, const void *) {}
471 /* D */ int wclear(WINDOW *win)
472 {
473         if (werase(win) == ERR)
474                 return ERR;
475         win->_clear = TRUE;
476         return OK;
477 }
478 // int wclrtobot (WINDOW *) {}
479 int wclrtoeol(WINDOW *win) { /* TODO */ return(*(int *)0); }
480 int wcolor_set(WINDOW *win, short color_pair_number, void *opts)
481 {
482         if (!opts && (color_pair_number >= 0)
483             && (color_pair_number < COLOR_PAIRS)) {
484                 SET_WINDOW_PAIR(win, color_pair_number);
485                 if_EXT_COLORS(win->_color = color_pair_number);
486                 return OK;
487         }
488         return ERR;
489 }
490 // void wcursyncup (WINDOW *) {}
491 // int wdelch (WINDOW *) {}
492 // int wechochar (WINDOW *, const chtype) {}
493 int werase(WINDOW *win)
494 {
495         int x, y;
496         for (y = 0; y < win->_maxy; y++) {
497                 for (x = 0; x < win->_maxx; x++) {
498                         win->_line[y].text[x].chars[0] = ' ';
499                         win->_line[y].text[x].attr = WINDOW_ATTRS(win);
500                 }
501         }
502         return OK;
503 }
504
505 // int wgetnstr (WINDOW *,char *,int) {}
506 int whline(WINDOW *win, chtype ch, int n)
507 {
508         NCURSES_SIZE_T start, end;
509         struct ldat *line = &(win->_line[win->_cury]);
510         NCURSES_CH_T wch;
511
512         start = win->_curx;
513         end = start + n - 1;
514         if (end > win->_maxx)
515                 end = win->_maxx;
516
517         CHANGED_RANGE(line, start, end);
518
519         //// TODO:
520         //// if (ch == 0)
521         ////     SetChar2(wch, ACS_HLINE);
522         //// else
523         ////     SetChar2(wch, ch);
524         // Ugly hack:
525         wch.chars[0] = ((ch) & (chtype)A_CHARTEXT);
526         wch.attr = ((ch) & (chtype)A_ATTRIBUTES);
527         wch = _nc_render(win, wch);
528
529         while (end >= start) {
530                 line->text[end] = wch;
531                 end--;
532         }
533
534         //// _nc_synchook(win);
535
536         return OK;
537 }
538 /* D */ chtype winch(WINDOW *win)
539 {
540         //// TODO
541         // return (CharOf(win->_line[win->_cury].text[win->_curx]) |
542         //         AttrOf(win->_line[win->_cury].text[win->_curx]));
543         return OK;      // FIXME
544 }
545 // int winchnstr (WINDOW *, chtype *, int) {}
546 // int winnstr (WINDOW *, char *, int) {}
547 // int winsch (WINDOW *, chtype) {}
548 // int winsdelln (WINDOW *,int) {}
549 // int winsnstr (WINDOW *, const char *,int) {}
550 /* D */ int wmove(WINDOW *win, int y, int x)
551 {
552         if (!LEGALYX(win, y, x))
553                 return ERR;
554         win->_curx = (NCURSES_SIZE_T) x;
555         win->_cury = (NCURSES_SIZE_T) y;
556         win->_flags &= ~_WRAPPED;
557         win->_flags |= _HASMOVED;
558         return OK;
559 }
560
561
562 int wnoutrefresh(WINDOW *win)
563 {
564         // FIXME.
565         int x, y;
566
567         for (y = 0; y < win->_maxy; y++) {
568                 for (x = 0; x < win->_maxx; x++) {
569                         if (curses_flags & F_ENABLE_SERIAL)
570                                 serial_putchar(win->_line[y].text[x].chars[0]);
571
572                         if (curses_flags & F_ENABLE_CONSOLE) {
573                                 attr_t attr = win->_line[y].text[x].attr;
574                                 unsigned int c =
575                                   ((int)color_pairs[PAIR_NUMBER(attr)]) << 8;
576
577                                 /* Handle some of the attributes. */
578                                 if (attr & A_BOLD)
579                                         c |= 0x0800;
580                                 if (attr & A_DIM)
581                                         c &= ~0x800;
582                                 if (attr & A_REVERSE) {
583                                         unsigned char tmp = (c >> 8) & 0xf;
584                                         c = (c >> 4) & 0xf00;
585                                         c |= tmp << 12;
586                                 }
587
588                                 c |= win->_line[y].text[x].chars[0];
589                                 vga_putc(y, x, c);
590                         }
591                 }
592         }
593
594         return OK;
595 }
596
597 int wprintw(WINDOW *win, const char *fmt, ...)
598 {
599         va_list argp;
600         int code;
601
602         va_start(argp, fmt);
603         code = vwprintw(win, fmt, argp);
604         va_end(argp);
605
606         return code;
607 }
608 // int wredrawln (WINDOW *,int,int) {}
609 int wrefresh(WINDOW *win)
610 {
611         // FIXME
612         return wnoutrefresh(win);
613
614         // XXX
615         int code;
616
617         if (win == curscr) {
618                 curscr->_clear = TRUE;
619                 // code = doupdate();
620         } else if ((code = wnoutrefresh(win)) == OK) {
621                 if (win->_clear)
622                         newscr->_clear = TRUE;
623                 // code = doupdate();
624                 /*
625                  * Reset the clearok() flag in case it was set for the special
626                  * case in hardscroll.c (if we don't reset it here, we'll get 2
627                  * refreshes because the flag is copied from stdscr to newscr).
628                  * Resetting the flag shouldn't do any harm, anyway.
629                  */
630                 win->_clear = FALSE;
631         }
632
633         return code;
634 }
635 // int wscanw (WINDOW *, NCURSES_CONST char *,...) {}
636 int wscrl(WINDOW *win, int n)
637 {
638         if (!win->_scroll)
639                 return ERR;
640
641         if (n != 0) {
642                 // _nc_scroll_window(win, n, win->_regtop, win->_regbottom, win->_nc_bkgd);
643                 // _nc_synchook(win);
644         }
645         return OK;
646 }
647 int wsetscrreg(WINDOW *win, int top, int bottom)
648 {
649         if (top >= 0 && top <= win->_maxy && bottom >= 0 &&
650             bottom <= win->_maxy && bottom > top) {
651                 win->_regtop = (NCURSES_SIZE_T) top;
652                 win->_regbottom = (NCURSES_SIZE_T) bottom;
653                 return OK;
654         }
655         return ERR;
656 }
657 // void wsyncdown (WINDOW *) {}
658 // void wsyncup (WINDOW *) {}
659 // void wtimeout (WINDOW *,int) {}
660 /* D */ int wtouchln(WINDOW *win, int y, int n, int changed)
661 {
662         int i;
663
664         // if ((n < 0) || (y < 0) || (y > win->_maxy))
665         //     return ERR;
666
667         for (i = y; i < y + n; i++) {
668                 if (i > win->_maxy)
669                         break;
670                 win->_line[i].firstchar = changed ? 0 : _NOCHANGE;
671                 win->_line[i].lastchar = changed ? win->_maxx : _NOCHANGE;
672         }
673         return OK;
674 }
675 // int wvline (WINDOW *,chtype,int) {}
676 // int tigetflag (NCURSES_CONST char *) {}
677 // int tigetnum (NCURSES_CONST char *) {}
678 // char *tigetstr (NCURSES_CONST char *) {}
679 // int putp (const char *) {}
680 // #if NCURSES_TPARM_VARARGS
681 // char *tparm (NCURSES_CONST char *, ...) {}
682 // #else
683 // char *tparm (NCURSES_CONST char *, long,long,long,long,long,long,long,long,long) {}
684 // char *tparm_varargs (NCURSES_CONST char *, ...) {}
685 // #endif