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