e17a4649f57286c6d5eb654921dff685715b797d
[ncurses.git] / test / ncurses.c
1 /****************************************************************************
2  * Copyright (c) 1998-2011,2012 Free Software Foundation, Inc.              *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28 /****************************************************************************
29
30 NAME
31    ncurses.c --- ncurses library exerciser
32
33 SYNOPSIS
34    ncurses
35
36 DESCRIPTION
37    An interactive test module for the ncurses library.
38
39 AUTHOR
40    Author: Eric S. Raymond <esr@snark.thyrsus.com> 1993
41            Thomas E. Dickey (beginning revision 1.27 in 1996).
42
43 $Id: ncurses.c,v 1.372 2012/07/07 18:09:38 tom Exp $
44
45 ***************************************************************************/
46
47 #include <test.priv.h>
48
49 #ifdef __hpux
50 #undef mvwdelch                 /* HPUX 11.23 macro will not compile */
51 #endif
52
53 #if HAVE_GETTIMEOFDAY
54 #if HAVE_SYS_TIME_H && HAVE_SYS_TIME_SELECT
55 #include <sys/time.h>
56 #endif
57 #if HAVE_SYS_SELECT_H
58 #include <sys/select.h>
59 #endif
60 #endif
61
62 #if USE_LIBPANEL
63 #include <panel.h>
64 #endif
65
66 #if USE_LIBMENU
67 #include <menu.h>
68 #endif
69
70 #if USE_LIBFORM
71 #include <form.h>
72 #endif
73
74 #ifdef NCURSES_VERSION
75
76 #define NCURSES_CONST_PARAM const void
77
78 #ifdef TRACE
79 static unsigned save_trace = TRACE_ORDINARY | TRACE_ICALLS | TRACE_CALLS;
80 extern unsigned _nc_tracing;
81 #endif
82
83 #else
84
85 #define NCURSES_CONST_PARAM char
86
87 #define mmask_t chtype          /* not specified in XSI */
88
89 #ifndef ACS_S3
90 #ifdef CURSES_ACS_ARRAY
91 #define ACS_S3          (CURSES_ACS_ARRAY['p'])         /* scan line 3 */
92 #define ACS_S7          (CURSES_ACS_ARRAY['r'])         /* scan line 7 */
93 #define ACS_LEQUAL      (CURSES_ACS_ARRAY['y'])         /* less/equal */
94 #define ACS_GEQUAL      (CURSES_ACS_ARRAY['z'])         /* greater/equal */
95 #define ACS_PI          (CURSES_ACS_ARRAY['{'])         /* Pi */
96 #define ACS_NEQUAL      (CURSES_ACS_ARRAY['|'])         /* not equal */
97 #define ACS_STERLING    (CURSES_ACS_ARRAY['}'])         /* UK pound sign */
98 #else
99 #define ACS_S3          (A_ALTCHARSET + 'p')    /* scan line 3 */
100 #define ACS_S7          (A_ALTCHARSET + 'r')    /* scan line 7 */
101 #define ACS_LEQUAL      (A_ALTCHARSET + 'y')    /* less/equal */
102 #define ACS_GEQUAL      (A_ALTCHARSET + 'z')    /* greater/equal */
103 #define ACS_PI          (A_ALTCHARSET + '{')    /* Pi */
104 #define ACS_NEQUAL      (A_ALTCHARSET + '|')    /* not equal */
105 #define ACS_STERLING    (A_ALTCHARSET + '}')    /* UK pound sign */
106 #endif
107 #endif /* ACS_S3 */
108
109 #ifndef WACS_S3
110 #ifdef CURSES_WACS_ARRAY
111 #define WACS_S3         (&(CURSES_WACS_ARRAY['p']))     /* scan line 3 */
112 #define WACS_S7         (&(CURSES_WACS_ARRAY['r']))     /* scan line 7 */
113 #define WACS_LEQUAL     (&(CURSES_WACS_ARRAY['y']))     /* less/equal */
114 #define WACS_GEQUAL     (&(CURSES_WACS_ARRAY['z']))     /* greater/equal */
115 #define WACS_PI         (&(CURSES_WACS_ARRAY['{']))     /* Pi */
116 #define WACS_NEQUAL     (&(CURSES_WACS_ARRAY['|']))     /* not equal */
117 #define WACS_STERLING   (&(CURSES_WACS_ARRAY['}']))     /* UK pound sign */
118 #endif
119 #endif
120
121 #endif
122
123 #if HAVE_WCSRTOMBS
124 #define count_wchars(src, len, state)      wcsrtombs(0,   &src, len, state)
125 #define trans_wchars(dst, src, len, state) wcsrtombs(dst, &src, len, state)
126 #define reset_wchars(state) init_mb(state)
127 #elif HAVE_WCSTOMBS && HAVE_MBTOWC && HAVE_MBLEN
128 #define count_wchars(src, len, state)      wcstombs(0,   src, len)
129 #define trans_wchars(dst, src, len, state) wcstombs(dst, src, len)
130 #define reset_wchars(state) IGNORE_RC(mblen(NULL, 0)), IGNORE_RC(mbtowc(NULL, NULL, 0))
131 #define state_unused
132 #endif
133
134 #if HAVE_MBSRTOWCS
135 #define count_mbytes(src, len, state)      mbsrtowcs(0,   &src, len, state)
136 #define trans_mbytes(dst, src, len, state) mbsrtowcs(dst, &src, len, state)
137 #define reset_mbytes(state) init_mb(state)
138 #elif HAVE_MBSTOWCS && HAVE_MBTOWC && HAVE_MBLEN
139 #define count_mbytes(src, len, state)      mbstowcs(0,   src, len)
140 #define trans_mbytes(dst, src, len, state) mbstowcs(dst, src, len)
141 #define reset_mbytes(state) IGNORE_RC(mblen(NULL, 0)), IGNORE_RC(mbtowc(NULL, NULL, 0))
142 #define state_unused
143 #endif
144
145 #define ToggleAcs(temp,real) temp = ((temp == real) ? 0 : real)
146
147 #define P(string)       printw("%s\n", string)
148
149 #define BLANK           ' '     /* this is the background character */
150
151 #undef max_colors
152 static int max_colors;          /* the actual number of colors we'll use */
153 static int min_colors;          /* the minimum color code */
154 static bool use_colors;         /* true if we use colors */
155
156 #undef max_pairs
157 static int max_pairs;           /* ...and the number of color pairs */
158
159 typedef struct {
160     short red;
161     short green;
162     short blue;
163 } RGB_DATA;
164
165 static RGB_DATA *all_colors;
166
167 static void main_menu(bool);
168
169 /* The behavior of mvhline, mvvline for negative/zero length is unspecified,
170  * though we can rely on negative x/y values to stop the macro.
171  */
172 static void
173 do_h_line(int y, int x, chtype c, int to)
174 {
175     if ((to) > (x))
176         MvHLine(y, x, c, (to) - (x));
177 }
178
179 static void
180 do_v_line(int y, int x, chtype c, int to)
181 {
182     if ((to) > (y))
183         MvVLine(y, x, c, (to) - (y));
184 }
185
186 static void
187 Repaint(void)
188 {
189     touchwin(stdscr);
190     touchwin(curscr);
191     wrefresh(curscr);
192 }
193
194 static bool
195 isQuit(int c)
196 {
197     return ((c) == QUIT || (c) == ESCAPE);
198 }
199 #define case_QUIT       QUIT: case ESCAPE
200
201 /* Common function to allow ^T to toggle trace-mode in the middle of a test
202  * so that trace-files can be made smaller.
203  */
204 static int
205 wGetchar(WINDOW *win)
206 {
207     int c;
208 #ifdef TRACE
209     while ((c = wgetch(win)) == CTRL('T')) {
210         if (_nc_tracing) {
211             save_trace = _nc_tracing;
212             Trace(("TOGGLE-TRACING OFF"));
213             _nc_tracing = 0;
214         } else {
215             _nc_tracing = save_trace;
216         }
217         trace(_nc_tracing);
218         if (_nc_tracing)
219             Trace(("TOGGLE-TRACING ON"));
220     }
221 #else
222     c = wgetch(win);
223 #endif
224     return c;
225 }
226 #define Getchar() wGetchar(stdscr)
227
228 /* replaces wgetnstr(), since we want to be able to edit values */
229 static void
230 wGetstring(WINDOW *win, char *buffer, int limit)
231 {
232     int y0, x0, x, ch;
233     bool done = FALSE;
234
235     echo();
236     getyx(win, y0, x0);
237     (void) wattrset(win, A_REVERSE);
238
239     x = (int) strlen(buffer);
240     while (!done) {
241         if (x > (int) strlen(buffer))
242             x = (int) strlen(buffer);
243         wmove(win, y0, x0);
244         wprintw(win, "%-*s", limit, buffer);
245         wmove(win, y0, x0 + x);
246         switch (ch = wGetchar(win)) {
247         case '\n':
248         case KEY_ENTER:
249             done = TRUE;
250             break;
251         case CTRL('U'):
252             *buffer = '\0';
253             break;
254         case '\b':
255         case KEY_BACKSPACE:
256         case KEY_DC:
257             if (x > 0) {
258                 int j;
259                 for (j = --x; (buffer[j] = buffer[j + 1]) != '\0'; ++j) {
260                     ;
261                 }
262             } else {
263                 beep();
264             }
265             break;
266         case KEY_LEFT:
267             if (x > 0) {
268                 --x;
269             } else {
270                 flash();
271             }
272             break;
273         case KEY_RIGHT:
274             ++x;
275             break;
276         default:
277             if (!isprint(ch) || ch >= KEY_MIN) {
278                 beep();
279             } else if ((int) strlen(buffer) < limit) {
280                 int j;
281                 for (j = (int) strlen(buffer) + 1; j > x; --j) {
282                     buffer[j] = buffer[j - 1];
283                 }
284                 buffer[x++] = (char) ch;
285             } else {
286                 flash();
287             }
288         }
289     }
290
291     wattroff(win, A_REVERSE);
292     wmove(win, y0, x0);
293     noecho();
294 }
295
296 #if USE_WIDEC_SUPPORT
297 static wchar_t
298 fullwidth_of(int ch)
299 {
300     return (ch + 0xff10 - '0');
301 }
302
303 static void
304 make_fullwidth_text(wchar_t *target, const char *source)
305 {
306     int ch;
307     while ((ch = *source++) != 0) {
308         *target++ = fullwidth_of(ch);
309     }
310     *target = 0;
311 }
312
313 static void
314 make_narrow_text(wchar_t *target, const char *source)
315 {
316     int ch;
317     while ((ch = *source++) != 0) {
318         *target++ = ch;
319     }
320     *target = 0;
321 }
322
323 #if USE_LIBPANEL
324 static void
325 make_fullwidth_digit(cchar_t *target, int digit)
326 {
327     wchar_t source[2];
328
329     source[0] = fullwidth_of(digit + '0');
330     source[1] = 0;
331     setcchar(target, source, A_NORMAL, 0, 0);
332 }
333 #endif
334
335 static int
336 wGet_wchar(WINDOW *win, wint_t *result)
337 {
338     int c;
339 #ifdef TRACE
340     while ((c = wget_wch(win, result)) == CTRL('T')) {
341         if (_nc_tracing) {
342             save_trace = _nc_tracing;
343             Trace(("TOGGLE-TRACING OFF"));
344             _nc_tracing = 0;
345         } else {
346             _nc_tracing = save_trace;
347         }
348         trace(_nc_tracing);
349         if (_nc_tracing)
350             Trace(("TOGGLE-TRACING ON"));
351     }
352 #else
353     c = wget_wch(win, result);
354 #endif
355     return c;
356 }
357 #define Get_wchar(result) wGet_wchar(stdscr, result)
358
359 /* replaces wgetn_wstr(), since we want to be able to edit values */
360 static void
361 wGet_wstring(WINDOW *win, wchar_t *buffer, int limit)
362 {
363     int y0, x0, x;
364     wint_t ch;
365     bool done = FALSE;
366     bool fkey = FALSE;
367
368     echo();
369     getyx(win, y0, x0);
370     (void) wattrset(win, A_REVERSE);
371
372     x = (int) wcslen(buffer);
373     while (!done) {
374         if (x > (int) wcslen(buffer))
375             x = (int) wcslen(buffer);
376
377         /* clear the "window' */
378         wmove(win, y0, x0);
379         wprintw(win, "%*s", limit, " ");
380
381         /* write the existing buffer contents */
382         wmove(win, y0, x0);
383         waddnwstr(win, buffer, limit);
384
385         /* positions the cursor past character 'x' */
386         wmove(win, y0, x0);
387         waddnwstr(win, buffer, x);
388
389         switch (wGet_wchar(win, &ch)) {
390         case KEY_CODE_YES:
391             fkey = TRUE;
392             switch (ch) {
393             case KEY_ENTER:
394                 ch = '\n';
395                 fkey = FALSE;
396                 break;
397             case KEY_BACKSPACE:
398             case KEY_DC:
399                 ch = '\b';
400                 fkey = FALSE;
401                 break;
402             case KEY_LEFT:
403             case KEY_RIGHT:
404                 break;
405             default:
406                 ch = (wint_t) -1;
407                 break;
408             }
409             break;
410         case OK:
411             fkey = FALSE;
412             break;
413         default:
414             ch = (wint_t) -1;
415             fkey = TRUE;
416             break;
417         }
418
419         switch (ch) {
420         case '\n':
421             done = TRUE;
422             break;
423         case CTRL('U'):
424             *buffer = '\0';
425             break;
426         case '\b':
427             if (x > 0) {
428                 int j;
429                 for (j = --x; (buffer[j] = buffer[j + 1]) != '\0'; ++j) {
430                     ;
431                 }
432             } else {
433                 beep();
434             }
435             break;
436         case KEY_LEFT:
437             if (x > 0) {
438                 --x;
439             } else {
440                 beep();
441             }
442             break;
443         case KEY_RIGHT:
444             ++x;
445             break;
446         default:
447             if (fkey) {
448                 beep();
449             } else if ((int) wcslen(buffer) < limit) {
450                 int j;
451                 for (j = (int) wcslen(buffer) + 1; j > x; --j) {
452                     buffer[j] = buffer[j - 1];
453                 }
454                 buffer[x++] = (wchar_t) ch;
455             } else {
456                 beep();
457             }
458         }
459     }
460
461     wattroff(win, A_REVERSE);
462     wmove(win, y0, x0);
463     noecho();
464 }
465
466 #endif
467
468 static void
469 Pause(void)
470 {
471     move(LINES - 1, 0);
472     addstr("Press any key to continue... ");
473     (void) Getchar();
474 }
475
476 static void
477 Cannot(const char *what)
478 {
479     printw("\nThis %s terminal %s\n\n", getenv("TERM"), what);
480     Pause();
481 }
482
483 static void
484 ShellOut(bool message)
485 {
486     if (message)
487         addstr("Shelling out...");
488     def_prog_mode();
489     endwin();
490 #ifdef __MINGW32__
491     system("cmd.exe");
492 #else
493     IGNORE_RC(system("sh"));
494 #endif
495     if (message)
496         addstr("returned from shellout.\n");
497     refresh();
498 }
499
500 #ifdef NCURSES_MOUSE_VERSION
501 /*
502  * This function is the same as _tracemouse(), but we cannot count on that
503  * being available in the non-debug library.
504  */
505 static const char *
506 mouse_decode(MEVENT const *ep)
507 {
508     static char buf[80 + (5 * 10) + (32 * 15)];
509
510     (void) sprintf(buf, "id %2d at (%2d, %2d, %d) state %4lx = {",
511                    ep->id, ep->x, ep->y, ep->z, (unsigned long) ep->bstate);
512
513 #define SHOW(m, s) if ((ep->bstate & m)==m) {strcat(buf,s); strcat(buf, ", ");}
514
515     SHOW(BUTTON1_RELEASED, "release-1");
516     SHOW(BUTTON1_PRESSED, "press-1");
517     SHOW(BUTTON1_CLICKED, "click-1");
518     SHOW(BUTTON1_DOUBLE_CLICKED, "doubleclick-1");
519     SHOW(BUTTON1_TRIPLE_CLICKED, "tripleclick-1");
520 #if NCURSES_MOUSE_VERSION == 1
521     SHOW(BUTTON1_RESERVED_EVENT, "reserved-1");
522 #endif
523
524     SHOW(BUTTON2_RELEASED, "release-2");
525     SHOW(BUTTON2_PRESSED, "press-2");
526     SHOW(BUTTON2_CLICKED, "click-2");
527     SHOW(BUTTON2_DOUBLE_CLICKED, "doubleclick-2");
528     SHOW(BUTTON2_TRIPLE_CLICKED, "tripleclick-2");
529 #if NCURSES_MOUSE_VERSION == 1
530     SHOW(BUTTON2_RESERVED_EVENT, "reserved-2");
531 #endif
532
533     SHOW(BUTTON3_RELEASED, "release-3");
534     SHOW(BUTTON3_PRESSED, "press-3");
535     SHOW(BUTTON3_CLICKED, "click-3");
536     SHOW(BUTTON3_DOUBLE_CLICKED, "doubleclick-3");
537     SHOW(BUTTON3_TRIPLE_CLICKED, "tripleclick-3");
538 #if NCURSES_MOUSE_VERSION == 1
539     SHOW(BUTTON3_RESERVED_EVENT, "reserved-3");
540 #endif
541
542     SHOW(BUTTON4_RELEASED, "release-4");
543     SHOW(BUTTON4_PRESSED, "press-4");
544     SHOW(BUTTON4_CLICKED, "click-4");
545     SHOW(BUTTON4_DOUBLE_CLICKED, "doubleclick-4");
546     SHOW(BUTTON4_TRIPLE_CLICKED, "tripleclick-4");
547 #if NCURSES_MOUSE_VERSION == 1
548     SHOW(BUTTON4_RESERVED_EVENT, "reserved-4");
549 #endif
550
551 #if NCURSES_MOUSE_VERSION == 2
552     SHOW(BUTTON5_RELEASED, "release-5");
553     SHOW(BUTTON5_PRESSED, "press-5");
554     SHOW(BUTTON5_CLICKED, "click-5");
555     SHOW(BUTTON5_DOUBLE_CLICKED, "doubleclick-5");
556     SHOW(BUTTON5_TRIPLE_CLICKED, "tripleclick-5");
557 #endif
558
559     SHOW(BUTTON_CTRL, "ctrl");
560     SHOW(BUTTON_SHIFT, "shift");
561     SHOW(BUTTON_ALT, "alt");
562     SHOW(ALL_MOUSE_EVENTS, "all-events");
563     SHOW(REPORT_MOUSE_POSITION, "position");
564
565 #undef SHOW
566
567     if (buf[strlen(buf) - 1] == ' ')
568         buf[strlen(buf) - 2] = '\0';
569     (void) strcat(buf, "}");
570     return (buf);
571 }
572
573 static void
574 show_mouse(WINDOW *win)
575 {
576     int y, x;
577     MEVENT event;
578     bool outside;
579     bool show_loc;
580
581     getmouse(&event);
582     outside = !wenclose(win, event.y, event.x);
583
584     if (outside) {
585         (void) wstandout(win);
586         waddstr(win, "KEY_MOUSE");
587         (void) wstandend(win);
588     } else {
589         waddstr(win, "KEY_MOUSE");
590     }
591     wprintw(win, ", %s", mouse_decode(&event));
592
593     if (outside)
594         win = stdscr;
595
596     show_loc = wmouse_trafo(win, &event.y, &event.x, FALSE);
597
598     if (show_loc) {
599         getyx(win, y, x);
600         wmove(win, event.y, event.x);
601         waddch(win, '*');
602         wmove(win, y, x);
603     }
604
605     if (outside)
606         wnoutrefresh(win);
607 }
608 #endif /* NCURSES_MOUSE_VERSION */
609
610 /****************************************************************************
611  *
612  * Character input test
613  *
614  ****************************************************************************/
615
616 #define NUM_GETCH_FLAGS 256
617 typedef bool GetchFlags[NUM_GETCH_FLAGS];
618
619 static void
620 setup_getch(WINDOW *win, GetchFlags flags)
621 {
622     keypad(win, flags['k']);    /* should be redundant, but for testing */
623     meta(win, flags['m']);      /* force this to a known state */
624     if (flags['e'])
625         echo();
626     else
627         noecho();
628 }
629
630 static void
631 init_getch(WINDOW *win, GetchFlags flags)
632 {
633     memset(flags, FALSE, NUM_GETCH_FLAGS);
634     flags[UChar('k')] = (win == stdscr);
635     flags[UChar('m')] = TRUE;
636
637     setup_getch(win, flags);
638 }
639
640 static void
641 wgetch_help(WINDOW *win, GetchFlags flags)
642 {
643     static const char *help[] =
644     {
645         "e  -- toggle echo mode"
646         ,"g  -- triggers a getstr test"
647         ,"k  -- toggle keypad/literal mode"
648         ,"m  -- toggle meta (7-bit/8-bit) mode"
649         ,"^q -- quit"
650         ,"s  -- shell out\n"
651         ,"w  -- create a new window"
652 #ifdef SIGTSTP
653         ,"z  -- suspend this process"
654 #endif
655     };
656     int y, x;
657     unsigned chk = ((SIZEOF(help) + 1) / 2);
658     unsigned n;
659
660     getyx(win, y, x);
661     move(0, 0);
662     printw("Type any key to see its %s value.  Also:\n",
663            flags['k'] ? "keypad" : "literal");
664     for (n = 0; n < SIZEOF(help); ++n) {
665         int row = 1 + (int) (n % chk);
666         int col = (n >= chk) ? COLS / 2 : 0;
667         int flg = ((strstr(help[n], "toggle") != 0)
668                    && (flags[UChar(*help[n])] != FALSE));
669         if (flg)
670             (void) standout();
671         MvPrintw(row, col, "%s", help[n]);
672         if (col == 0)
673             clrtoeol();
674         if (flg)
675             (void) standend();
676     }
677     wrefresh(stdscr);
678     wmove(win, y, x);
679 }
680
681 static void
682 wgetch_wrap(WINDOW *win, int first_y)
683 {
684     int last_y = getmaxy(win) - 1;
685     int y = getcury(win) + 1;
686
687     if (y >= last_y)
688         y = first_y;
689     wmove(win, y, 0);
690     wclrtoeol(win);
691 }
692
693 #if defined(KEY_RESIZE) && HAVE_WRESIZE
694 typedef struct {
695     WINDOW *text;
696     WINDOW *frame;
697 } WINSTACK;
698
699 static WINSTACK *winstack = 0;
700 static unsigned len_winstack = 0;
701
702 static void
703 forget_boxes(void)
704 {
705     if (winstack != 0) {
706         free(winstack);
707     }
708     winstack = 0;
709     len_winstack = 0;
710 }
711
712 static void
713 remember_boxes(unsigned level, WINDOW *txt_win, WINDOW *box_win)
714 {
715     unsigned need = (level + 1) * 2;
716
717     assert(level < (unsigned) COLS);
718
719     if (winstack == 0) {
720         len_winstack = 20;
721         winstack = typeMalloc(WINSTACK, len_winstack);
722     } else if (need >= len_winstack) {
723         len_winstack = need;
724         winstack = typeRealloc(WINSTACK, len_winstack, winstack);
725     }
726     winstack[level].text = txt_win;
727     winstack[level].frame = box_win;
728 }
729
730 #if USE_SOFTKEYS && (defined(NCURSES_VERSION_PATCH) && NCURSES_VERSION_PATCH < 20071229) && NCURSES_EXT_FUNCS
731 static void
732 slk_repaint(void)
733 {
734     /* this chunk is now done in resize_term() */
735     slk_touch();
736     slk_clear();
737     slk_noutrefresh();
738 }
739
740 #else
741 #define slk_repaint()           /* nothing */
742 #endif
743
744 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
745 /*
746  * For wgetch_test(), we create pairs of windows - one for a box, one for text.
747  * Resize both and paint the box in the parent.
748  */
749 static void
750 resize_boxes(unsigned level, WINDOW *win)
751 {
752     unsigned n;
753     int base = 5;
754     int high = LINES - base;
755     int wide = COLS;
756
757     touchwin(stdscr);
758     wnoutrefresh(stdscr);
759
760     slk_repaint();
761
762     for (n = 0; n < level; ++n) {
763         wresize(winstack[n].frame, high, wide);
764         wresize(winstack[n].text, high - 2, wide - 2);
765         high -= 2;
766         wide -= 2;
767         werase(winstack[n].text);
768         box(winstack[n].frame, 0, 0);
769         wnoutrefresh(winstack[n].frame);
770         wprintw(winstack[n].text,
771                 "size %dx%d\n",
772                 getmaxy(winstack[n].text),
773                 getmaxx(winstack[n].text));
774         wnoutrefresh(winstack[n].text);
775         if (winstack[n].text == win)
776             break;
777     }
778     doupdate();
779 }
780 #endif /* resize_boxes */
781 #else
782 #define forget_boxes()          /* nothing */
783 #define remember_boxes(level,text,frame)        /* nothing */
784 #endif
785
786 /*
787  * Return-code is OK/ERR or a keyname.
788  */
789 static const char *
790 ok_keyname(int code)
791 {
792     return ((code == OK) ? "OK" : ((code == ERR) ? "ERR" : keyname(code)));
793 }
794
795 static void
796 wgetch_test(unsigned level, WINDOW *win, int delay)
797 {
798     char buf[BUFSIZ];
799     int first_y, first_x;
800     int c;
801     int incount = 0;
802     GetchFlags flags;
803     bool blocking = (delay < 0);
804
805     init_getch(win, flags);
806     wtimeout(win, delay);
807     getyx(win, first_y, first_x);
808
809     wgetch_help(win, flags);
810     wsetscrreg(win, first_y, getmaxy(win) - 1);
811     scrollok(win, TRUE);
812
813     for (;;) {
814         while ((c = wGetchar(win)) == ERR) {
815             incount++;
816             if (blocking) {
817                 (void) wprintw(win, "%05d: input error", incount);
818                 break;
819             } else {
820                 (void) wprintw(win, "%05d: input timed out", incount);
821             }
822             wgetch_wrap(win, first_y);
823         }
824         if (c == ERR && blocking) {
825             wprintw(win, "ERR");
826             wgetch_wrap(win, first_y);
827         } else if (isQuit(c)) {
828             break;
829         } else if (c == 'e') {
830             flags[UChar('e')] = !flags[UChar('e')];
831             setup_getch(win, flags);
832             wgetch_help(win, flags);
833         } else if (c == 'g') {
834             waddstr(win, "getstr test: ");
835             echo();
836             c = wgetnstr(win, buf, sizeof(buf) - 1);
837             noecho();
838             wprintw(win, "I saw %d characters:\n\t`%s' (%s).",
839                     (int) strlen(buf), buf,
840                     ok_keyname(c));
841             wclrtoeol(win);
842             wgetch_wrap(win, first_y);
843         } else if (c == 'k') {
844             flags[UChar('k')] = !flags[UChar('k')];
845             setup_getch(win, flags);
846             wgetch_help(win, flags);
847         } else if (c == 'm') {
848             flags[UChar('m')] = !flags[UChar('m')];
849             setup_getch(win, flags);
850             wgetch_help(win, flags);
851         } else if (c == 's') {
852             ShellOut(TRUE);
853         } else if (c == 'w') {
854             int high = getmaxy(win) - 1 - first_y + 1;
855             int wide = getmaxx(win) - first_x;
856             int old_y, old_x;
857             int new_y = first_y + getbegy(win);
858             int new_x = first_x + getbegx(win);
859
860             getyx(win, old_y, old_x);
861             if (high > 2 && wide > 2) {
862                 WINDOW *wb = newwin(high, wide, new_y, new_x);
863                 WINDOW *wi = newwin(high - 2, wide - 2, new_y + 1, new_x + 1);
864
865                 box(wb, 0, 0);
866                 wrefresh(wb);
867                 wmove(wi, 0, 0);
868                 remember_boxes(level, wi, wb);
869                 wgetch_test(level + 1, wi, delay);
870                 delwin(wi);
871                 delwin(wb);
872
873                 wgetch_help(win, flags);
874                 wmove(win, old_y, old_x);
875                 touchwin(win);
876                 wrefresh(win);
877                 doupdate();
878             }
879 #ifdef SIGTSTP
880         } else if (c == 'z') {
881             kill(getpid(), SIGTSTP);
882 #endif
883         } else {
884             wprintw(win, "Key pressed: %04o ", c);
885 #ifdef NCURSES_MOUSE_VERSION
886             if (c == KEY_MOUSE) {
887                 show_mouse(win);
888             } else
889 #endif /* NCURSES_MOUSE_VERSION */
890             if (c >= KEY_MIN) {
891 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
892                 if (c == KEY_RESIZE) {
893                     resize_boxes(level, win);
894                 }
895 #endif
896                 (void) waddstr(win, keyname(c));
897             } else if (c >= 0x80) {
898                 unsigned c2 = (unsigned) c;
899 #if !(defined(NCURSES_VERSION) || defined(_XOPEN_CURSES))
900                 /* at least Solaris SVR4 curses breaks unctrl(128), etc. */
901                 c2 &= 0x7f;
902 #endif
903                 if (isprint(c))
904                     (void) wprintw(win, "%c", UChar(c));
905                 else if (c2 != UChar(c))
906                     (void) wprintw(win, "M-%s", unctrl(c2));
907                 else
908                     (void) wprintw(win, "%s", unctrl(c2));
909                 waddstr(win, " (high-half character)");
910             } else {
911                 if (isprint(c))
912                     (void) wprintw(win, "%c (ASCII printable character)", c);
913                 else
914                     (void) wprintw(win, "%s (ASCII control character)",
915                                    unctrl(UChar(c)));
916             }
917             wgetch_wrap(win, first_y);
918         }
919     }
920
921     wtimeout(win, -1);
922
923     if (!level)
924         init_getch(win, flags);
925 }
926
927 static int
928 begin_getch_test(void)
929 {
930     char buf[BUFSIZ];
931     int delay;
932
933     refresh();
934
935 #ifdef NCURSES_MOUSE_VERSION
936     mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
937 #endif
938
939     (void) printw("Delay in 10ths of a second (<CR> for blocking input)? ");
940     echo();
941     getnstr(buf, sizeof(buf) - 1);
942     noecho();
943     nonl();
944
945     if (isdigit(UChar(buf[0]))) {
946         delay = atoi(buf) * 100;
947     } else {
948         delay = -1;
949     }
950     raw();
951     move(5, 0);
952     return delay;
953 }
954
955 static void
956 finish_getch_test(void)
957 {
958 #ifdef NCURSES_MOUSE_VERSION
959     mousemask(0, (mmask_t *) 0);
960 #endif
961     erase();
962     noraw();
963     nl();
964     endwin();
965 }
966
967 static void
968 getch_test(void)
969 {
970     int delay = begin_getch_test();
971
972     slk_restore();
973     wgetch_test(0, stdscr, delay);
974     forget_boxes();
975     finish_getch_test();
976     slk_clear();
977 }
978
979 #if USE_WIDEC_SUPPORT
980 /*
981  * For wget_wch_test(), we create pairs of windows - one for a box, one for text.
982  * Resize both and paint the box in the parent.
983  */
984 #if defined(KEY_RESIZE) && HAVE_WRESIZE
985 static void
986 resize_wide_boxes(unsigned level, WINDOW *win)
987 {
988     unsigned n;
989     int base = 5;
990     int high = LINES - base;
991     int wide = COLS;
992
993     touchwin(stdscr);
994     wnoutrefresh(stdscr);
995
996     slk_repaint();
997
998     for (n = 0; n < level; ++n) {
999         wresize(winstack[n].frame, high, wide);
1000         wresize(winstack[n].text, high - 2, wide - 2);
1001         high -= 2;
1002         wide -= 2;
1003         werase(winstack[n].text);
1004         box_set(winstack[n].frame, 0, 0);
1005         wnoutrefresh(winstack[n].frame);
1006         wprintw(winstack[n].text,
1007                 "size %dx%d\n",
1008                 getmaxy(winstack[n].text),
1009                 getmaxx(winstack[n].text));
1010         wnoutrefresh(winstack[n].text);
1011         if (winstack[n].text == win)
1012             break;
1013     }
1014     doupdate();
1015 }
1016 #endif /* KEY_RESIZE */
1017
1018 static char *
1019 wcstos(const wchar_t *src)
1020 {
1021     int need;
1022     char *result = 0;
1023     const wchar_t *tmp = src;
1024 #ifndef state_unused
1025     mbstate_t state;
1026 #endif
1027
1028     reset_wchars(state);
1029     if ((need = (int) count_wchars(tmp, 0, &state)) > 0) {
1030         unsigned have = (unsigned) need;
1031         if ((result = typeCalloc(char, have + 1)) != 0) {
1032             tmp = src;
1033             if (trans_wchars(result, tmp, have, &state) != have) {
1034                 free(result);
1035                 result = 0;
1036             }
1037         }
1038     }
1039     return result;
1040 }
1041
1042 static void
1043 wget_wch_test(unsigned level, WINDOW *win, int delay)
1044 {
1045     wchar_t wchar_buf[BUFSIZ];
1046     wint_t wint_buf[BUFSIZ];
1047     int first_y, first_x;
1048     wint_t c;
1049     int incount = 0;
1050     GetchFlags flags;
1051     bool blocking = (delay < 0);
1052     int code;
1053     char *temp;
1054
1055     init_getch(win, flags);
1056     wtimeout(win, delay);
1057     getyx(win, first_y, first_x);
1058
1059     wgetch_help(win, flags);
1060     wsetscrreg(win, first_y, getmaxy(win) - 1);
1061     scrollok(win, TRUE);
1062
1063     for (;;) {
1064         while ((code = wGet_wchar(win, &c)) == ERR) {
1065             incount++;
1066             if (blocking) {
1067                 (void) wprintw(win, "%05d: input error", incount);
1068                 break;
1069             } else {
1070                 (void) wprintw(win, "%05d: input timed out", incount);
1071             }
1072             wgetch_wrap(win, first_y);
1073         }
1074         if (code == ERR && blocking) {
1075             wprintw(win, "ERR");
1076             wgetch_wrap(win, first_y);
1077         } else if (isQuit((int) c)) {
1078             break;
1079         } else if (c == 'e') {
1080             flags[UChar('e')] = !flags[UChar('e')];
1081             setup_getch(win, flags);
1082             wgetch_help(win, flags);
1083         } else if (c == 'g') {
1084             waddstr(win, "getstr test: ");
1085             echo();
1086             code = wgetn_wstr(win, wint_buf, sizeof(wint_buf) - 1);
1087             noecho();
1088             if (code == ERR) {
1089                 wprintw(win, "wgetn_wstr returns an error.");
1090             } else {
1091                 int n;
1092                 for (n = 0; (wchar_buf[n] = (wchar_t) wint_buf[n]) != 0; ++n) {
1093                     ;
1094                 }
1095                 if ((temp = wcstos(wchar_buf)) != 0) {
1096                     wprintw(win, "I saw %d characters:\n\t`%s'.",
1097                             (int) wcslen(wchar_buf), temp);
1098                     free(temp);
1099                 } else {
1100                     wprintw(win, "I saw %d characters (cannot convert).",
1101                             (int) wcslen(wchar_buf));
1102                 }
1103             }
1104             wclrtoeol(win);
1105             wgetch_wrap(win, first_y);
1106         } else if (c == 'k') {
1107             flags[UChar('k')] = !flags[UChar('k')];
1108             setup_getch(win, flags);
1109             wgetch_help(win, flags);
1110         } else if (c == 'm') {
1111             flags[UChar('m')] = !flags[UChar('m')];
1112             setup_getch(win, flags);
1113             wgetch_help(win, flags);
1114         } else if (c == 's') {
1115             ShellOut(TRUE);
1116         } else if (c == 'w') {
1117             int high = getmaxy(win) - 1 - first_y + 1;
1118             int wide = getmaxx(win) - first_x;
1119             int old_y, old_x;
1120             int new_y = first_y + getbegy(win);
1121             int new_x = first_x + getbegx(win);
1122
1123             getyx(win, old_y, old_x);
1124             if (high > 2 && wide > 2) {
1125                 WINDOW *wb = newwin(high, wide, new_y, new_x);
1126                 WINDOW *wi = newwin(high - 2, wide - 2, new_y + 1, new_x + 1);
1127
1128                 box_set(wb, 0, 0);
1129                 wrefresh(wb);
1130                 wmove(wi, 0, 0);
1131                 remember_boxes(level, wi, wb);
1132                 wget_wch_test(level + 1, wi, delay);
1133                 delwin(wi);
1134                 delwin(wb);
1135
1136                 wgetch_help(win, flags);
1137                 wmove(win, old_y, old_x);
1138                 touchwin(win);
1139                 wrefresh(win);
1140             }
1141 #ifdef SIGTSTP
1142         } else if (c == 'z') {
1143             kill(getpid(), SIGTSTP);
1144 #endif
1145         } else {
1146             wprintw(win, "Key pressed: %04o ", (int) c);
1147 #ifdef NCURSES_MOUSE_VERSION
1148             if (c == KEY_MOUSE) {
1149                 show_mouse(win);
1150             } else
1151 #endif /* NCURSES_MOUSE_VERSION */
1152             if (code == KEY_CODE_YES) {
1153 #if defined(KEY_RESIZE) && HAVE_WRESIZE
1154                 if (c == KEY_RESIZE) {
1155                     resize_wide_boxes(level, win);
1156                 }
1157 #endif
1158                 (void) waddstr(win, keyname((wchar_t) c));
1159             } else {
1160                 (void) waddstr(win, key_name((wchar_t) c));
1161                 if (c < 256 && iscntrl(c)) {
1162                     (void) wprintw(win, " (control character)");
1163                 } else {
1164                     (void) wprintw(win, " = %#x (printable character)",
1165                                    (unsigned) c);
1166                 }
1167             }
1168             wgetch_wrap(win, first_y);
1169         }
1170     }
1171
1172     wtimeout(win, -1);
1173
1174     if (!level)
1175         init_getch(win, flags);
1176 }
1177
1178 static void
1179 get_wch_test(void)
1180 {
1181     int delay = begin_getch_test();
1182
1183     slk_restore();
1184     wget_wch_test(0, stdscr, delay);
1185     forget_boxes();
1186     finish_getch_test();
1187     slk_clear();
1188 }
1189 #endif
1190
1191 /****************************************************************************
1192  *
1193  * Character attributes test
1194  *
1195  ****************************************************************************/
1196
1197 #if HAVE_SETUPTERM || HAVE_TGETENT
1198 #define get_ncv() TIGETNUM("ncv","NC")
1199 #define get_xmc() TIGETNUM("xmc","sg")
1200 #else
1201 #define get_ncv() -1
1202 #define get_xmc() -1
1203 #endif
1204
1205 #if !HAVE_TERMATTRS
1206 static chtype
1207 my_termattrs(void)
1208 {
1209     static int first = TRUE;
1210     static chtype result = 0;
1211
1212     if (first) {
1213 #if !HAVE_TIGETSTR
1214         char buffer[4096];
1215         char parsed[4096];
1216         char *area_pointer = parsed;
1217
1218         tgetent(buffer, getenv("TERM"));
1219 #endif
1220
1221         if (TIGETSTR("smso", "so"))
1222             result |= A_STANDOUT;
1223         if (TIGETSTR("smul", "us"))
1224             result |= A_UNDERLINE;
1225         if (TIGETSTR("rev", "mr"))
1226             result |= A_REVERSE;
1227         if (TIGETSTR("blink", "mb"))
1228             result |= A_BLINK;
1229         if (TIGETSTR("dim", "mh"))
1230             result |= A_DIM;
1231         if (TIGETSTR("bold", "md"))
1232             result |= A_BOLD;
1233         if (TIGETSTR("smacs", "ac"))
1234             result |= A_ALTCHARSET;
1235
1236         first = FALSE;
1237     }
1238     return result;
1239 }
1240 #define termattrs() my_termattrs()
1241 #endif
1242
1243 #define MAX_ATTRSTRING 31
1244 #define LEN_ATTRSTRING 26
1245
1246 static char attr_test_string[MAX_ATTRSTRING + 1];
1247
1248 static void
1249 attr_legend(WINDOW *helpwin)
1250 {
1251     int row = 1;
1252     int col = 1;
1253
1254     MvWPrintw(helpwin, row++, col,
1255               "ESC to exit.");
1256     MvWPrintw(helpwin, row++, col,
1257               "^L repaints.");
1258     ++row;
1259     MvWPrintw(helpwin, row++, col,
1260               "Modify the test strings:");
1261     MvWPrintw(helpwin, row++, col,
1262               "  A digit sets gaps on each side of displayed attributes");
1263     MvWPrintw(helpwin, row++, col,
1264               "  </> shifts the text left/right. ");
1265     ++row;
1266     MvWPrintw(helpwin, row++, col,
1267               "Toggles:");
1268     if (use_colors) {
1269         MvWPrintw(helpwin, row++, col,
1270                   "  f/F/b/F toggle foreground/background background color");
1271         MvWPrintw(helpwin, row++, col,
1272                   "  t/T     toggle text/background color attribute");
1273     }
1274     MvWPrintw(helpwin, row++, col,
1275               "  a/A     toggle ACS (alternate character set) mapping");
1276     MvWPrintw(helpwin, row, col,
1277               "  v/V     toggle video attribute to combine with each line");
1278 }
1279
1280 static void
1281 show_color_attr(int fg, int bg, int tx)
1282 {
1283     if (use_colors) {
1284         printw("  Colors (fg %d, bg %d", fg, bg);
1285         if (tx >= 0)
1286             printw(", text %d", tx);
1287         printw("),");
1288     }
1289 }
1290
1291 static bool
1292 cycle_color_attr(int ch, short *fg, short *bg, short *tx)
1293 {
1294     bool error = FALSE;
1295
1296     if (use_colors) {
1297         switch (ch) {
1298         case 'f':
1299             *fg = (short) (*fg + 1);
1300             break;
1301         case 'F':
1302             *fg = (short) (*fg - 1);
1303             break;
1304         case 'b':
1305             *bg = (short) (*bg + 1);
1306             break;
1307         case 'B':
1308             *bg = (short) (*bg - 1);
1309             break;
1310         case 't':
1311             *tx = (short) (*tx + 1);
1312             break;
1313         case 'T':
1314             *tx = (short) (*tx - 1);
1315             break;
1316         default:
1317             beep();
1318             error = TRUE;
1319             break;
1320         }
1321         if (*fg >= COLORS)
1322             *fg = (short) min_colors;
1323         if (*fg < min_colors)
1324             *fg = (short) (COLORS - 1);
1325         if (*bg >= COLORS)
1326             *bg = (short) min_colors;
1327         if (*bg < min_colors)
1328             *bg = (short) (COLORS - 1);
1329         if (*tx >= COLORS)
1330             *tx = -1;
1331         if (*tx < -1)
1332             *tx = (short) (COLORS - 1);
1333     } else {
1334         beep();
1335         error = TRUE;
1336     }
1337     return error;
1338 }
1339
1340 static void
1341 adjust_attr_string(int adjust)
1342 {
1343     int first = ((int) UChar(attr_test_string[0])) + adjust;
1344     int last = first + LEN_ATTRSTRING;
1345
1346     if (first >= ' ' && last <= '~') {  /* 32..126 */
1347         int j, k;
1348         for (j = 0, k = first; j < MAX_ATTRSTRING && k <= last; ++j, ++k) {
1349             attr_test_string[j] = (char) k;
1350             if (((k + 1 - first) % 5) == 0) {
1351                 if (++j >= MAX_ATTRSTRING)
1352                     break;
1353                 attr_test_string[j] = ' ';
1354             }
1355         }
1356         while (j < MAX_ATTRSTRING)
1357             attr_test_string[j++] = ' ';
1358         attr_test_string[j] = '\0';
1359     } else {
1360         beep();
1361     }
1362 }
1363
1364 static void
1365 init_attr_string(void)
1366 {
1367     attr_test_string[0] = 'a';
1368     adjust_attr_string(0);
1369 }
1370
1371 static int
1372 show_attr(int row, int skip, bool arrow, chtype attr, const char *name)
1373 {
1374     int ncv = get_ncv();
1375     chtype test = attr & (chtype) (~A_ALTCHARSET);
1376
1377     if (arrow)
1378         MvPrintw(row, 5, "-->");
1379     MvPrintw(row, 8, "%s mode:", name);
1380     MvPrintw(row, 24, "|");
1381     if (skip)
1382         printw("%*s", skip, " ");
1383     /*
1384      * Just for testing, write text using the alternate character set one
1385      * character at a time (to pass its rendition directly), and use the
1386      * string operation for the other attributes.
1387      */
1388     if (attr & A_ALTCHARSET) {
1389         const char *s;
1390         chtype ch;
1391
1392         for (s = attr_test_string; *s != '\0'; ++s) {
1393             ch = UChar(*s);
1394             addch(ch | attr);
1395         }
1396     } else {
1397         (void) attrset(attr);
1398         addstr(attr_test_string);
1399         attroff(attr);
1400     }
1401     if (skip)
1402         printw("%*s", skip, " ");
1403     printw("|");
1404     if (test != A_NORMAL) {
1405         if (!(termattrs() & test)) {
1406             printw(" (N/A)");
1407         } else {
1408             if (ncv > 0 && stdscr && (getbkgd(stdscr) & A_COLOR)) {
1409                 static const chtype table[] =
1410                 {
1411                     A_STANDOUT,
1412                     A_UNDERLINE,
1413                     A_REVERSE,
1414                     A_BLINK,
1415                     A_DIM,
1416                     A_BOLD,
1417 #ifdef A_INVIS
1418                     A_INVIS,
1419 #endif
1420                     A_PROTECT,
1421                     A_ALTCHARSET
1422                 };
1423                 unsigned n;
1424                 bool found = FALSE;
1425                 for (n = 0; n < SIZEOF(table); n++) {
1426                     if ((table[n] & attr) != 0
1427                         && ((1 << n) & ncv) != 0) {
1428                         found = TRUE;
1429                         break;
1430                     }
1431                 }
1432                 if (found)
1433                     printw(" (NCV)");
1434             }
1435             if ((termattrs() & test) != test)
1436                 printw(" (Part)");
1437         }
1438     }
1439     return row + 2;
1440 }
1441 /* *INDENT-OFF* */
1442 static const struct {
1443     chtype                      attr;
1444     NCURSES_CONST char *        name;
1445 } attrs_to_test[] = {
1446     { A_STANDOUT,       "STANDOUT" },
1447     { A_REVERSE,        "REVERSE" },
1448     { A_BOLD,           "BOLD" },
1449     { A_UNDERLINE,      "UNDERLINE" },
1450     { A_DIM,            "DIM" },
1451     { A_BLINK,          "BLINK" },
1452     { A_PROTECT,        "PROTECT" },
1453 #ifdef A_INVIS
1454     { A_INVIS,          "INVISIBLE" },
1455 #endif
1456     { A_NORMAL,         "NORMAL" },
1457 };
1458 /* *INDENT-ON* */
1459
1460 static bool
1461 attr_getc(int *skip, short *fg, short *bg, short *tx, int *ac, unsigned *kc)
1462 {
1463     bool result = TRUE;
1464     bool error = FALSE;
1465     WINDOW *helpwin;
1466
1467     do {
1468         int ch = Getchar();
1469
1470         error = FALSE;
1471         if (ch < 256 && isdigit(ch)) {
1472             *skip = (ch - '0');
1473         } else {
1474             switch (ch) {
1475             case CTRL('L'):
1476                 Repaint();
1477                 break;
1478             case '?':
1479                 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
1480                     box(helpwin, 0, 0);
1481                     attr_legend(helpwin);
1482                     wGetchar(helpwin);
1483                     delwin(helpwin);
1484                 }
1485                 break;
1486             case 'a':
1487                 *ac = 0;
1488                 break;
1489             case 'A':
1490                 *ac = A_ALTCHARSET;
1491                 break;
1492             case 'v':
1493                 if (*kc == 0)
1494                     *kc = SIZEOF(attrs_to_test) - 1;
1495                 else
1496                     *kc -= 1;
1497                 break;
1498             case 'V':
1499                 *kc += 1;
1500                 if (*kc >= SIZEOF(attrs_to_test))
1501                     *kc = 0;
1502                 break;
1503             case '<':
1504                 adjust_attr_string(-1);
1505                 break;
1506             case '>':
1507                 adjust_attr_string(1);
1508                 break;
1509             case case_QUIT:
1510                 result = FALSE;
1511                 break;
1512             default:
1513                 error = cycle_color_attr(ch, fg, bg, tx);
1514                 break;
1515             }
1516         }
1517     } while (error);
1518     return result;
1519 }
1520
1521 static void
1522 attr_test(void)
1523 /* test text attributes */
1524 {
1525     int n;
1526     int skip = get_xmc();
1527     short fg = COLOR_BLACK;     /* color pair 0 is special */
1528     short bg = COLOR_BLACK;
1529     short tx = -1;
1530     int ac = 0;
1531     unsigned j, k;
1532
1533     if (skip < 0)
1534         skip = 0;
1535
1536     n = skip;                   /* make it easy */
1537     k = SIZEOF(attrs_to_test) - 1;
1538     init_attr_string();
1539
1540     do {
1541         int row = 2;
1542         chtype normal = A_NORMAL | BLANK;
1543         chtype extras = (chtype) ac;
1544
1545         if (use_colors) {
1546             short pair = (short) (fg != COLOR_BLACK || bg != COLOR_BLACK);
1547             if (pair != 0) {
1548                 pair = 1;
1549                 if (init_pair(pair, fg, bg) == ERR) {
1550                     beep();
1551                 } else {
1552                     normal |= (chtype) COLOR_PAIR(pair);
1553                 }
1554             }
1555             if (tx >= 0) {
1556                 pair = 2;
1557                 if (init_pair(pair, tx, bg) == ERR) {
1558                     beep();
1559                 } else {
1560                     extras |= (chtype) COLOR_PAIR(pair);
1561                 }
1562             }
1563         }
1564         bkgd(normal);
1565         bkgdset(normal);
1566         erase();
1567
1568         box(stdscr, 0, 0);
1569         MvAddStr(0, 20, "Character attribute test display");
1570
1571         for (j = 0; j < SIZEOF(attrs_to_test); ++j) {
1572             bool arrow = (j == k);
1573             row = show_attr(row, n, arrow,
1574                             extras |
1575                             attrs_to_test[j].attr |
1576                             attrs_to_test[k].attr,
1577                             attrs_to_test[j].name);
1578         }
1579
1580         MvPrintw(row, 8,
1581                  "This terminal does %shave the magic-cookie glitch",
1582                  get_xmc() > -1 ? "" : "not ");
1583         MvPrintw(row + 1, 8, "Enter '?' for help.");
1584         show_color_attr(fg, bg, tx);
1585         printw("  ACS (%d)", ac != 0);
1586
1587         refresh();
1588     } while (attr_getc(&n, &fg, &bg, &tx, &ac, &k));
1589
1590     bkgdset(A_NORMAL | BLANK);
1591     erase();
1592     endwin();
1593 }
1594
1595 #if USE_WIDEC_SUPPORT
1596 static wchar_t wide_attr_test_string[MAX_ATTRSTRING + 1];
1597
1598 static void
1599 wide_adjust_attr_string(int adjust)
1600 {
1601     int first = ((int) UChar(wide_attr_test_string[0])) + adjust;
1602     int last = first + LEN_ATTRSTRING;
1603
1604     if (first >= ' ' && last <= '~') {  /* 32..126 */
1605         int j, k;
1606         for (j = 0, k = first; j < MAX_ATTRSTRING && k <= last; ++j, ++k) {
1607             wide_attr_test_string[j] = k;
1608             if (((k + 1 - first) % 5) == 0) {
1609                 if (++j >= MAX_ATTRSTRING)
1610                     break;
1611                 wide_attr_test_string[j] = ' ';
1612             }
1613         }
1614         while (j < MAX_ATTRSTRING)
1615             wide_attr_test_string[j++] = ' ';
1616         wide_attr_test_string[j] = '\0';
1617     } else {
1618         beep();
1619     }
1620 }
1621
1622 static void
1623 wide_init_attr_string(void)
1624 {
1625     wide_attr_test_string[0] = 'a';
1626     wide_adjust_attr_string(0);
1627 }
1628
1629 static void
1630 set_wide_background(short pair)
1631 {
1632     cchar_t normal;
1633     wchar_t blank[2];
1634
1635     blank[0] = ' ';
1636     blank[1] = 0;
1637     setcchar(&normal, blank, A_NORMAL, pair, 0);
1638     bkgrnd(&normal);
1639     bkgrndset(&normal);
1640 }
1641
1642 static attr_t
1643 get_wide_background(void)
1644 {
1645     attr_t result = A_NORMAL;
1646     attr_t attr;
1647     cchar_t ch;
1648     short pair;
1649     wchar_t wch[10];
1650
1651     if (getbkgrnd(&ch) != ERR) {
1652         if (getcchar(&ch, wch, &attr, &pair, 0) != ERR) {
1653             result = attr;
1654         }
1655     }
1656     return result;
1657 }
1658
1659 static int
1660 wide_show_attr(int row, int skip, bool arrow, chtype attr, short pair, const char *name)
1661 {
1662     int ncv = get_ncv();
1663     chtype test = attr & ~WA_ALTCHARSET;
1664
1665     if (arrow)
1666         MvPrintw(row, 5, "-->");
1667     MvPrintw(row, 8, "%s mode:", name);
1668     MvPrintw(row, 24, "|");
1669     if (skip)
1670         printw("%*s", skip, " ");
1671
1672     /*
1673      * Just for testing, write text using the alternate character set one
1674      * character at a time (to pass its rendition directly), and use the
1675      * string operation for the other attributes.
1676      */
1677     if (attr & WA_ALTCHARSET) {
1678         const wchar_t *s;
1679         cchar_t ch;
1680
1681         for (s = wide_attr_test_string; *s != L'\0'; ++s) {
1682             wchar_t fill[2];
1683             fill[0] = *s;
1684             fill[1] = L'\0';
1685             setcchar(&ch, fill, attr, pair, 0);
1686             add_wch(&ch);
1687         }
1688     } else {
1689         attr_t old_attr = 0;
1690         short old_pair = 0;
1691
1692         (void) attr_get(&old_attr, &old_pair, 0);
1693         (void) attr_set(attr, pair, 0);
1694         addwstr(wide_attr_test_string);
1695         (void) attr_set(old_attr, old_pair, 0);
1696     }
1697     if (skip)
1698         printw("%*s", skip, " ");
1699     printw("|");
1700     if (test != A_NORMAL) {
1701         if (!(term_attrs() & test)) {
1702             printw(" (N/A)");
1703         } else {
1704             if (ncv > 0 && (get_wide_background() & A_COLOR)) {
1705                 static const attr_t table[] =
1706                 {
1707                     WA_STANDOUT,
1708                     WA_UNDERLINE,
1709                     WA_REVERSE,
1710                     WA_BLINK,
1711                     WA_DIM,
1712                     WA_BOLD,
1713                     WA_INVIS,
1714                     WA_PROTECT,
1715                     WA_ALTCHARSET
1716                 };
1717                 unsigned n;
1718                 bool found = FALSE;
1719                 for (n = 0; n < SIZEOF(table); n++) {
1720                     if ((table[n] & attr) != 0
1721                         && ((1 << n) & ncv) != 0) {
1722                         found = TRUE;
1723                         break;
1724                     }
1725                 }
1726                 if (found)
1727                     printw(" (NCV)");
1728             }
1729             if ((term_attrs() & test) != test)
1730                 printw(" (Part)");
1731         }
1732     }
1733     return row + 2;
1734 }
1735
1736 static bool
1737 wide_attr_getc(int *skip, short *fg, short *bg, short *tx, int *ac, unsigned *kc)
1738 {
1739     bool result = TRUE;
1740     bool error = FALSE;
1741     WINDOW *helpwin;
1742
1743     do {
1744         int ch = Getchar();
1745
1746         error = FALSE;
1747         if (ch < 256 && isdigit(ch)) {
1748             *skip = (ch - '0');
1749         } else {
1750             switch (ch) {
1751             case CTRL('L'):
1752                 Repaint();
1753                 break;
1754             case '?':
1755                 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
1756                     box_set(helpwin, 0, 0);
1757                     attr_legend(helpwin);
1758                     wGetchar(helpwin);
1759                     delwin(helpwin);
1760                 }
1761                 break;
1762             case 'a':
1763                 *ac = 0;
1764                 break;
1765             case 'A':
1766                 *ac = A_ALTCHARSET;
1767                 break;
1768             case 'v':
1769                 if (*kc == 0)
1770                     *kc = SIZEOF(attrs_to_test) - 1;
1771                 else
1772                     *kc -= 1;
1773                 break;
1774             case 'V':
1775                 *kc += 1;
1776                 if (*kc >= SIZEOF(attrs_to_test))
1777                     *kc = 0;
1778                 break;
1779             case '<':
1780                 wide_adjust_attr_string(-1);
1781                 break;
1782             case '>':
1783                 wide_adjust_attr_string(1);
1784                 break;
1785             case case_QUIT:
1786                 result = FALSE;
1787                 break;
1788             default:
1789                 error = cycle_color_attr(ch, fg, bg, tx);
1790                 break;
1791             }
1792         }
1793     } while (error);
1794     return result;
1795 }
1796
1797 static void
1798 wide_attr_test(void)
1799 /* test text attributes using wide-character calls */
1800 {
1801     int n;
1802     int skip = get_xmc();
1803     short fg = COLOR_BLACK;     /* color pair 0 is special */
1804     short bg = COLOR_BLACK;
1805     short tx = -1;
1806     int ac = 0;
1807     unsigned j, k;
1808
1809     if (skip < 0)
1810         skip = 0;
1811
1812     n = skip;                   /* make it easy */
1813     k = SIZEOF(attrs_to_test) - 1;
1814     wide_init_attr_string();
1815
1816     do {
1817         int row = 2;
1818         short pair = 0;
1819         short extras = 0;
1820
1821         if (use_colors) {
1822             pair = (short) (fg != COLOR_BLACK || bg != COLOR_BLACK);
1823             if (pair != 0) {
1824                 pair = 1;
1825                 if (init_pair(pair, fg, bg) == ERR) {
1826                     beep();
1827                 }
1828             }
1829             extras = pair;
1830             if (tx >= 0) {
1831                 extras = 2;
1832                 if (init_pair(extras, tx, bg) == ERR) {
1833                     beep();
1834                 }
1835             }
1836         }
1837         set_wide_background(pair);
1838         erase();
1839
1840         box_set(stdscr, 0, 0);
1841         MvAddStr(0, 20, "Character attribute test display");
1842
1843         for (j = 0; j < SIZEOF(attrs_to_test); ++j) {
1844             row = wide_show_attr(row, n, j == k,
1845                                  ((attr_t) ac |
1846                                   attrs_to_test[j].attr |
1847                                   attrs_to_test[k].attr),
1848                                  extras,
1849                                  attrs_to_test[j].name);
1850         }
1851
1852         MvPrintw(row, 8,
1853                  "This terminal does %shave the magic-cookie glitch",
1854                  get_xmc() > -1 ? "" : "not ");
1855         MvPrintw(row + 1, 8, "Enter '?' for help.");
1856         show_color_attr(fg, bg, tx);
1857         printw("  ACS (%d)", ac != 0);
1858
1859         refresh();
1860     } while (wide_attr_getc(&n, &fg, &bg, &tx, &ac, &k));
1861
1862     set_wide_background(0);
1863     erase();
1864     endwin();
1865 }
1866 #endif
1867
1868 /****************************************************************************
1869  *
1870  * Color support tests
1871  *
1872  ****************************************************************************/
1873
1874 static NCURSES_CONST char *the_color_names[] =
1875 {
1876     "black",
1877     "red",
1878     "green",
1879     "yellow",
1880     "blue",
1881     "magenta",
1882     "cyan",
1883     "white",
1884     "BLACK",
1885     "RED",
1886     "GREEN",
1887     "YELLOW",
1888     "BLUE",
1889     "MAGENTA",
1890     "CYAN",
1891     "WHITE"
1892 };
1893
1894 static void
1895 show_color_name(int y, int x, int color, bool wide)
1896 {
1897     if (move(y, x) != ERR) {
1898         char temp[80];
1899         int width = 8;
1900
1901         if (wide) {
1902             sprintf(temp, "%02d", color);
1903             width = 4;
1904         } else if (color >= 8) {
1905             sprintf(temp, "[%02d]", color);
1906         } else if (color < 0) {
1907             strcpy(temp, "default");
1908         } else {
1909             strcpy(temp, the_color_names[color]);
1910         }
1911         printw("%-*.*s", width, width, temp);
1912     }
1913 }
1914
1915 static void
1916 color_legend(WINDOW *helpwin, bool wide)
1917 {
1918     int row = 1;
1919     int col = 1;
1920
1921     MvWPrintw(helpwin, row++, col,
1922               "ESC to exit.");
1923     ++row;
1924     MvWPrintw(helpwin, row++, col,
1925               "Use up/down arrow to scroll through the display if it is");
1926     MvWPrintw(helpwin, row++, col,
1927               "longer than one screen. Control/N and Control/P can be used");
1928     MvWPrintw(helpwin, row++, col,
1929               "in place of up/down arrow.  Use pageup/pagedown to scroll a");
1930     MvWPrintw(helpwin, row++, col,
1931               "full screen; control/B and control/F can be used here.");
1932     ++row;
1933     MvWPrintw(helpwin, row++, col,
1934               "Toggles:");
1935     MvWPrintw(helpwin, row++, col,
1936               "  a/A     toggle altcharset off/on");
1937     MvWPrintw(helpwin, row++, col,
1938               "  b/B     toggle bold off/on");
1939     MvWPrintw(helpwin, row++, col,
1940               "  n/N     toggle text/number on/off");
1941     MvWPrintw(helpwin, row++, col,
1942               "  r/R     toggle reverse on/off");
1943     MvWPrintw(helpwin, row++, col,
1944               "  w/W     toggle width between 8/16 colors");
1945 #if USE_WIDEC_SUPPORT
1946     if (wide) {
1947         MvWPrintw(helpwin, row++, col,
1948                   "Wide characters:");
1949         MvWPrintw(helpwin, row, col,
1950                   "  x/X     toggle text between ASCII and wide-character");
1951     }
1952 #else
1953     (void) wide;
1954 #endif
1955 }
1956
1957 #define set_color_test(name, value) if (name != value) { name = value; base_row = 0; }
1958
1959 /* generate a color test pattern */
1960 static void
1961 color_test(void)
1962 {
1963     short i;
1964     int top = 0, width;
1965     int base_row = 0;
1966     int grid_top = top + 3;
1967     int page_size = (LINES - grid_top);
1968     int pairs_max = PAIR_NUMBER(A_COLOR) + 1;
1969     int row_limit;
1970     int per_row;
1971     char numbered[80];
1972     const char *hello;
1973     bool done = FALSE;
1974     bool opt_acsc = FALSE;
1975     bool opt_bold = FALSE;
1976     bool opt_revs = FALSE;
1977     bool opt_nums = FALSE;
1978     bool opt_wide = FALSE;
1979     WINDOW *helpwin;
1980
1981     if (COLORS * COLORS == COLOR_PAIRS) {
1982         int limit = (COLORS - min_colors) * (COLORS - min_colors);
1983         if (pairs_max > limit)
1984             pairs_max = limit;
1985     } else {
1986         if (pairs_max > COLOR_PAIRS)
1987             pairs_max = COLOR_PAIRS;
1988     }
1989
1990     while (!done) {
1991         int shown = 0;
1992
1993         /* this assumes an 80-column line */
1994         if (opt_wide) {
1995             width = 4;
1996             hello = "Test";
1997             per_row = (COLORS > 8) ? 16 : 8;
1998         } else {
1999             width = 8;
2000             hello = "Hello";
2001             per_row = 8;
2002         }
2003         per_row -= min_colors;
2004
2005         row_limit = (pairs_max + per_row - 1) / per_row;
2006
2007         move(0, 0);
2008         (void) printw("There are %d color pairs and %d colors%s\n",
2009                       pairs_max, COLORS,
2010                       min_colors ? " besides 'default'" : "");
2011
2012         clrtobot();
2013         MvPrintw(top + 1, 0,
2014                  "%dx%d matrix of foreground/background colors, bold *%s*\n",
2015                  row_limit,
2016                  per_row,
2017                  opt_bold ? "on" : "off");
2018
2019         /* show color names/numbers across the top */
2020         for (i = 0; i < per_row; i++)
2021             show_color_name(top + 2, (i + 1) * width, i + min_colors, opt_wide);
2022
2023         /* show a grid of colors, with color names/ numbers on the left */
2024         for (i = (short) (base_row * per_row); i < pairs_max; i++) {
2025             int row = grid_top + (i / per_row) - base_row;
2026             int col = (i % per_row + 1) * width;
2027             short pair = i;
2028
2029 #define InxToFG(i) (short) ((i % (COLORS - min_colors)) + min_colors)
2030 #define InxToBG(i) (short) ((i / (COLORS - min_colors)) + min_colors)
2031             if (row >= 0 && move(row, col) != ERR) {
2032                 short fg = InxToFG(i);
2033                 short bg = InxToBG(i);
2034
2035                 init_pair(pair, fg, bg);
2036                 attron((attr_t) COLOR_PAIR(pair));
2037                 if (opt_acsc)
2038                     attron((attr_t) A_ALTCHARSET);
2039                 if (opt_bold)
2040                     attron((attr_t) A_BOLD);
2041                 if (opt_revs)
2042                     attron((attr_t) A_REVERSE);
2043
2044                 if (opt_nums) {
2045                     sprintf(numbered, "{%02X}", i);
2046                     hello = numbered;
2047                 }
2048                 printw("%-*.*s", width, width, hello);
2049                 (void) attrset(A_NORMAL);
2050
2051                 if ((i % per_row) == 0 && InxToFG(i) == min_colors) {
2052                     show_color_name(row, 0, InxToBG(i), opt_wide);
2053                 }
2054                 ++shown;
2055             } else if (shown) {
2056                 break;
2057             }
2058         }
2059
2060         switch (wGetchar(stdscr)) {
2061         case 'a':
2062             opt_acsc = FALSE;
2063             break;
2064         case 'A':
2065             opt_acsc = TRUE;
2066             break;
2067         case 'b':
2068             opt_bold = FALSE;
2069             break;
2070         case 'B':
2071             opt_bold = TRUE;
2072             break;
2073         case 'n':
2074             opt_nums = FALSE;
2075             break;
2076         case 'N':
2077             opt_nums = TRUE;
2078             break;
2079         case 'r':
2080             opt_revs = FALSE;
2081             break;
2082         case 'R':
2083             opt_revs = TRUE;
2084             break;
2085         case case_QUIT:
2086             done = TRUE;
2087             continue;
2088         case 'w':
2089             set_color_test(opt_wide, FALSE);
2090             break;
2091         case 'W':
2092             set_color_test(opt_wide, TRUE);
2093             break;
2094         case CTRL('p'):
2095         case KEY_UP:
2096             if (base_row <= 0) {
2097                 beep();
2098             } else {
2099                 base_row -= 1;
2100             }
2101             break;
2102         case CTRL('n'):
2103         case KEY_DOWN:
2104             if (base_row + page_size >= row_limit) {
2105                 beep();
2106             } else {
2107                 base_row += 1;
2108             }
2109             break;
2110         case CTRL('b'):
2111         case KEY_PREVIOUS:
2112         case KEY_PPAGE:
2113             if (base_row <= 0) {
2114                 beep();
2115             } else {
2116                 base_row -= (page_size - 1);
2117                 if (base_row < 0)
2118                     base_row = 0;
2119             }
2120             break;
2121         case CTRL('f'):
2122         case KEY_NEXT:
2123         case KEY_NPAGE:
2124             if (base_row + page_size >= row_limit) {
2125                 beep();
2126             } else {
2127                 base_row += page_size - 1;
2128                 if (base_row + page_size >= row_limit) {
2129                     base_row = row_limit - page_size - 1;
2130                 }
2131             }
2132             break;
2133         case '?':
2134             if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
2135                 box(helpwin, 0, 0);
2136                 color_legend(helpwin, FALSE);
2137                 wGetchar(helpwin);
2138                 delwin(helpwin);
2139             }
2140             break;
2141         default:
2142             beep();
2143             continue;
2144         }
2145     }
2146
2147     erase();
2148     endwin();
2149 }
2150
2151 #if USE_WIDEC_SUPPORT
2152 /* generate a color test pattern */
2153 static void
2154 wide_color_test(void)
2155 {
2156     int i;
2157     int top = 0, width;
2158     int base_row = 0;
2159     int grid_top = top + 3;
2160     int page_size = (LINES - grid_top);
2161     int pairs_max = (unsigned short) (-1);
2162     int row_limit;
2163     int per_row;
2164     char numbered[80];
2165     const char *hello;
2166     bool done = FALSE;
2167     bool opt_acsc = FALSE;
2168     bool opt_bold = FALSE;
2169     bool opt_revs = FALSE;
2170     bool opt_wide = FALSE;
2171     bool opt_nums = FALSE;
2172     bool opt_xchr = FALSE;
2173     wchar_t buffer[10];
2174     WINDOW *helpwin;
2175
2176     if (COLORS * COLORS == COLOR_PAIRS) {
2177         int limit = (COLORS - min_colors) * (COLORS - min_colors);
2178         if (pairs_max > limit)
2179             pairs_max = limit;
2180     } else {
2181         if (pairs_max > COLOR_PAIRS)
2182             pairs_max = COLOR_PAIRS;
2183     }
2184
2185     while (!done) {
2186         int shown = 0;
2187
2188         /* this assumes an 80-column line */
2189         if (opt_wide) {
2190             width = 4;
2191             hello = "Test";
2192             per_row = (COLORS > 8) ? 16 : 8;
2193         } else {
2194             width = 8;
2195             hello = "Hello";
2196             per_row = 8;
2197         }
2198         per_row -= min_colors;
2199
2200         if (opt_xchr) {
2201             make_fullwidth_text(buffer, hello);
2202             width *= 2;
2203             per_row /= 2;
2204         } else {
2205             make_narrow_text(buffer, hello);
2206         }
2207
2208         row_limit = (pairs_max + per_row - 1) / per_row;
2209
2210         move(0, 0);
2211         (void) printw("There are %d color pairs and %d colors%s\n",
2212                       pairs_max, COLORS,
2213                       min_colors ? " besides 'default'" : "");
2214
2215         clrtobot();
2216         MvPrintw(top + 1, 0,
2217                  "%dx%d matrix of foreground/background colors, bold *%s*\n",
2218                  row_limit,
2219                  per_row,
2220                  opt_bold ? "on" : "off");
2221
2222         /* show color names/numbers across the top */
2223         for (i = 0; i < per_row; i++)
2224             show_color_name(top + 2, (i + 1) * width, i + min_colors, opt_wide);
2225
2226         /* show a grid of colors, with color names/ numbers on the left */
2227         for (i = (base_row * per_row); i < pairs_max; i++) {
2228             int row = grid_top + (i / per_row) - base_row;
2229             int col = (i % per_row + 1) * width;
2230             short pair = (short) i;
2231
2232             if (row >= 0 && move(row, col) != ERR) {
2233                 init_pair(pair, InxToFG(i), InxToBG(i));
2234                 color_set(pair, NULL);
2235                 if (opt_acsc)
2236                     attr_on((attr_t) A_ALTCHARSET, NULL);
2237                 if (opt_bold)
2238                     attr_on((attr_t) A_BOLD, NULL);
2239                 if (opt_revs)
2240                     attr_on((attr_t) A_REVERSE, NULL);
2241
2242                 if (opt_nums) {
2243                     sprintf(numbered, "{%02X}", i);
2244                     if (opt_xchr) {
2245                         make_fullwidth_text(buffer, numbered);
2246                     } else {
2247                         make_narrow_text(buffer, numbered);
2248                     }
2249                 }
2250                 addnwstr(buffer, width);
2251                 (void) attr_set(A_NORMAL, 0, NULL);
2252
2253                 if ((i % per_row) == 0 && InxToFG(i) == min_colors) {
2254                     show_color_name(row, 0, InxToBG(i), opt_wide);
2255                 }
2256                 ++shown;
2257             } else if (shown) {
2258                 break;
2259             }
2260         }
2261
2262         switch (wGetchar(stdscr)) {
2263         case 'a':
2264             opt_acsc = FALSE;
2265             break;
2266         case 'A':
2267             opt_acsc = TRUE;
2268             break;
2269         case 'b':
2270             opt_bold = FALSE;
2271             break;
2272         case 'B':
2273             opt_bold = TRUE;
2274             break;
2275         case 'n':
2276             opt_nums = FALSE;
2277             break;
2278         case 'N':
2279             opt_nums = TRUE;
2280             break;
2281         case 'r':
2282             opt_revs = FALSE;
2283             break;
2284         case 'R':
2285             opt_revs = TRUE;
2286             break;
2287         case case_QUIT:
2288             done = TRUE;
2289             continue;
2290         case 'w':
2291             set_color_test(opt_wide, FALSE);
2292             break;
2293         case 'W':
2294             set_color_test(opt_wide, TRUE);
2295             break;
2296         case 'x':
2297             opt_xchr = FALSE;
2298             break;
2299         case 'X':
2300             opt_xchr = TRUE;
2301             break;
2302         case CTRL('p'):
2303         case KEY_UP:
2304             if (base_row <= 0) {
2305                 beep();
2306             } else {
2307                 base_row -= 1;
2308             }
2309             break;
2310         case CTRL('n'):
2311         case KEY_DOWN:
2312             if (base_row + page_size >= row_limit) {
2313                 beep();
2314             } else {
2315                 base_row += 1;
2316             }
2317             break;
2318         case CTRL('b'):
2319         case KEY_PREVIOUS:
2320         case KEY_PPAGE:
2321             if (base_row <= 0) {
2322                 beep();
2323             } else {
2324                 base_row -= (page_size - 1);
2325                 if (base_row < 0)
2326                     base_row = 0;
2327             }
2328             break;
2329         case CTRL('f'):
2330         case KEY_NEXT:
2331         case KEY_NPAGE:
2332             if (base_row + page_size >= row_limit) {
2333                 beep();
2334             } else {
2335                 base_row += page_size - 1;
2336                 if (base_row + page_size >= row_limit) {
2337                     base_row = row_limit - page_size - 1;
2338                 }
2339             }
2340             break;
2341         case '?':
2342             if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
2343                 box(helpwin, 0, 0);
2344                 color_legend(helpwin, TRUE);
2345                 wGetchar(helpwin);
2346                 delwin(helpwin);
2347             }
2348             break;
2349         default:
2350             beep();
2351             continue;
2352         }
2353     }
2354
2355     erase();
2356     endwin();
2357 }
2358 #endif /* USE_WIDEC_SUPPORT */
2359
2360 static void
2361 change_color(short current, int field, int value, int usebase)
2362 {
2363     short red, green, blue;
2364
2365     color_content(current, &red, &green, &blue);
2366
2367     switch (field) {
2368     case 0:
2369         red = (short) (usebase ? (red + value) : value);
2370         break;
2371     case 1:
2372         green = (short) (usebase ? (green + value) : value);
2373         break;
2374     case 2:
2375         blue = (short) (usebase ? (blue + value) : value);
2376         break;
2377     }
2378
2379     if (init_color(current, red, green, blue) == ERR)
2380         beep();
2381 }
2382
2383 static void
2384 init_all_colors(void)
2385 {
2386     short c;
2387
2388     for (c = 0; c < COLORS; ++c)
2389         init_color(c,
2390                    all_colors[c].red,
2391                    all_colors[c].green,
2392                    all_colors[c].blue);
2393 }
2394
2395 #define scaled_rgb(n) ((255 * (n)) / 1000)
2396
2397 static void
2398 color_edit(void)
2399 /* display the color test pattern, without trying to edit colors */
2400 {
2401     int i;
2402     int current = 0;
2403     int this_c = 0, value = 0, field = 0;
2404     int last_c;
2405     int top_color = 0;
2406     int page_size = (LINES - 6);
2407
2408     init_all_colors();
2409     refresh();
2410
2411     for (i = 0; i < max_colors; i++)
2412         init_pair((short) i, (short) COLOR_WHITE, (short) i);
2413
2414     MvPrintw(LINES - 2, 0, "Number: %d", value);
2415
2416     do {
2417         short red, green, blue;
2418
2419         attron(A_BOLD);
2420         MvAddStr(0, 20, "Color RGB Value Editing");
2421         attroff(A_BOLD);
2422
2423         for (i = (short) top_color;
2424              (i - top_color < page_size)
2425              && (i < max_colors); i++) {
2426             char numeric[80];
2427
2428             sprintf(numeric, "[%d]", i);
2429             MvPrintw(2 + i - top_color, 0, "%c %-8s:",
2430                      (i == current ? '>' : ' '),
2431                      (i < (int) SIZEOF(the_color_names)
2432                       ? the_color_names[i] : numeric));
2433             (void) attrset((attr_t) COLOR_PAIR(i));
2434             addstr("        ");
2435             (void) attrset(A_NORMAL);
2436
2437             color_content((short) i, &red, &green, &blue);
2438             addstr("   R = ");
2439             if (current == i && field == 0)
2440                 attron(A_STANDOUT);
2441             printw("%04d", red);
2442             if (current == i && field == 0)
2443                 (void) attrset(A_NORMAL);
2444             addstr(", G = ");
2445             if (current == i && field == 1)
2446                 attron(A_STANDOUT);
2447             printw("%04d", green);
2448             if (current == i && field == 1)
2449                 (void) attrset(A_NORMAL);
2450             addstr(", B = ");
2451             if (current == i && field == 2)
2452                 attron(A_STANDOUT);
2453             printw("%04d", blue);
2454             if (current == i && field == 2)
2455                 (void) attrset(A_NORMAL);
2456             (void) attrset(A_NORMAL);
2457             printw(" ( %3d %3d %3d )",
2458                    scaled_rgb(red),
2459                    scaled_rgb(green),
2460                    scaled_rgb(blue));
2461         }
2462
2463         MvAddStr(LINES - 3, 0,
2464                  "Use up/down to select a color, left/right to change fields.");
2465         MvAddStr(LINES - 2, 0,
2466                  "Modify field by typing nnn=, nnn-, or nnn+.  ? for help.");
2467
2468         move(2 + current - top_color, 0);
2469
2470         last_c = this_c;
2471         this_c = Getchar();
2472         if (this_c < 256 && isdigit(this_c) && !isdigit(last_c))
2473             value = 0;
2474
2475         switch (this_c) {
2476         case CTRL('b'):
2477         case KEY_PPAGE:
2478             if (current > 0)
2479                 current -= (page_size - 1);
2480             else
2481                 beep();
2482             break;
2483
2484         case CTRL('f'):
2485         case KEY_NPAGE:
2486             if (current < (max_colors - 1))
2487                 current += (page_size - 1);
2488             else
2489                 beep();
2490             break;
2491
2492         case CTRL('p'):
2493         case KEY_UP:
2494             current = (current == 0 ? (max_colors - 1) : current - 1);
2495             break;
2496
2497         case CTRL('n'):
2498         case KEY_DOWN:
2499             current = (current == (max_colors - 1) ? 0 : current + 1);
2500             break;
2501
2502         case KEY_RIGHT:
2503             field = (field == 2 ? 0 : field + 1);
2504             break;
2505
2506         case KEY_LEFT:
2507             field = (field == 0 ? 2 : field - 1);
2508             break;
2509
2510         case '0':
2511         case '1':
2512         case '2':
2513         case '3':
2514         case '4':
2515         case '5':
2516         case '6':
2517         case '7':
2518         case '8':
2519         case '9':
2520             value = value * 10 + (this_c - '0');
2521             break;
2522
2523         case '+':
2524             change_color((short) current, field, value, 1);
2525             break;
2526
2527         case '-':
2528             change_color((short) current, field, -value, 1);
2529             break;
2530
2531         case '=':
2532             change_color((short) current, field, value, 0);
2533             break;
2534
2535         case '?':
2536             erase();
2537             P("                      RGB Value Editing Help");
2538             P("");
2539             P("You are in the RGB value editor.  Use the arrow keys to select one of");
2540             P("the fields in one of the RGB triples of the current colors; the one");
2541             P("currently selected will be reverse-video highlighted.");
2542             P("");
2543             P("To change a field, enter the digits of the new value; they are echoed");
2544             P("as entered.  Finish by typing `='.  The change will take effect instantly.");
2545             P("To increment or decrement a value, use the same procedure, but finish");
2546             P("with a `+' or `-'.");
2547             P("");
2548             P("Press 'm' to invoke the top-level menu with the current color settings.");
2549             P("To quit, do ESC");
2550
2551             Pause();
2552             erase();
2553             break;
2554
2555         case 'm':
2556             endwin();
2557             main_menu(FALSE);
2558             for (i = 0; i < max_colors; i++)
2559                 init_pair((short) i, (short) COLOR_WHITE, (short) i);
2560             refresh();
2561             break;
2562
2563         case case_QUIT:
2564             break;
2565
2566         default:
2567             beep();
2568             break;
2569         }
2570
2571         if (current < 0)
2572             current = 0;
2573         if (current >= max_colors)
2574             current = max_colors - 1;
2575         if (current < top_color)
2576             top_color = current;
2577         if (current - top_color >= page_size)
2578             top_color = current - (page_size - 1);
2579
2580         MvPrintw(LINES - 1, 0, "Number: %d", value);
2581         clrtoeol();
2582     } while
2583         (!isQuit(this_c));
2584
2585     erase();
2586
2587     /*
2588      * ncurses does not reset each color individually when calling endwin().
2589      */
2590     init_all_colors();
2591
2592     endwin();
2593 }
2594
2595 /****************************************************************************
2596  *
2597  * Alternate character-set stuff
2598  *
2599  ****************************************************************************/
2600 /* *INDENT-OFF* */
2601 static struct {
2602     chtype attr;
2603     const char *name;
2604 } attrs_to_cycle[] = {
2605     { A_NORMAL,         "normal" },
2606     { A_BOLD,           "bold" },
2607     { A_BLINK,          "blink" },
2608     { A_REVERSE,        "reverse" },
2609     { A_UNDERLINE,      "underline" },
2610 };
2611 /* *INDENT-ON* */
2612
2613 static bool
2614 cycle_attr(int ch, unsigned *at_code, chtype *attr)
2615 {
2616     bool result = TRUE;
2617
2618     switch (ch) {
2619     case 'v':
2620         if ((*at_code += 1) >= SIZEOF(attrs_to_cycle))
2621             *at_code = 0;
2622         break;
2623     case 'V':
2624         if (*at_code == 0)
2625             *at_code = SIZEOF(attrs_to_cycle) - 1;
2626         else
2627             *at_code -= 1;
2628         break;
2629     default:
2630         result = FALSE;
2631         break;
2632     }
2633     if (result)
2634         *attr = attrs_to_cycle[*at_code].attr;
2635     return result;
2636 }
2637
2638 static bool
2639 cycle_colors(int ch, int *fg, int *bg, short *pair)
2640 {
2641     bool result = FALSE;
2642
2643     if (use_colors) {
2644         result = TRUE;
2645         switch (ch) {
2646         case 'F':
2647             if ((*fg -= 1) < 0)
2648                 *fg = COLORS - 1;
2649             break;
2650         case 'f':
2651             if ((*fg += 1) >= COLORS)
2652                 *fg = 0;
2653             break;
2654         case 'B':
2655             if ((*bg -= 1) < 0)
2656                 *bg = COLORS - 1;
2657             break;
2658         case 'b':
2659             if ((*bg += 1) >= COLORS)
2660                 *bg = 0;
2661             break;
2662         default:
2663             result = FALSE;
2664             break;
2665         }
2666         if (result) {
2667             *pair = (short) (*fg != COLOR_BLACK || *bg != COLOR_BLACK);
2668             if (*pair != 0) {
2669                 *pair = 1;
2670                 if (init_pair(*pair, (short) *fg, (short) *bg) == ERR) {
2671                     result = FALSE;
2672                 }
2673             }
2674         }
2675     }
2676     return result;
2677 }
2678
2679 /****************************************************************************
2680  *
2681  * Soft-key label test
2682  *
2683  ****************************************************************************/
2684
2685 #if USE_SOFTKEYS
2686
2687 #define SLK_HELP 17
2688 #define SLK_WORK (SLK_HELP + 3)
2689
2690 static void
2691 slk_help(void)
2692 {
2693     static const char *table[] =
2694     {
2695         "Available commands are:"
2696         ,""
2697         ,"^L         -- repaint this message and activate soft keys"
2698         ,"a/d        -- activate/disable soft keys"
2699         ,"c          -- set centered format for labels"
2700         ,"l          -- set left-justified format for labels"
2701         ,"r          -- set right-justified format for labels"
2702         ,"[12345678] -- set label; labels are numbered 1 through 8"
2703         ,"e          -- erase stdscr (should not erase labels)"
2704         ,"s          -- test scrolling of shortened screen"
2705         ,"v/V        -- cycle through video attributes"
2706 #if HAVE_SLK_COLOR
2707         ,"F/f/B/b    -- cycle through foreground/background colors"
2708 #endif
2709         ,"ESC        -- return to main menu"
2710         ,""
2711         ,"Note: if activating the soft keys causes your terminal to scroll up"
2712         ,"one line, your terminal auto-scrolls when anything is written to the"
2713         ,"last screen position.  The ncurses code does not yet handle this"
2714         ,"gracefully."
2715     };
2716     unsigned j;
2717
2718     move(2, 0);
2719     for (j = 0; j < SIZEOF(table); ++j) {
2720         P(table[j]);
2721     }
2722     refresh();
2723 }
2724
2725 #if HAVE_SLK_COLOR
2726 static void
2727 call_slk_color(int fg, int bg)
2728 {
2729     init_pair(1, (short) bg, (short) fg);
2730     slk_color(1);
2731     MvPrintw(SLK_WORK, 0, "Colors %d/%d\n", fg, bg);
2732     clrtoeol();
2733     slk_touch();
2734     slk_noutrefresh();
2735     refresh();
2736 }
2737 #endif
2738
2739 static void
2740 slk_test(void)
2741 /* exercise the soft keys */
2742 {
2743     int c, fmt = 1;
2744     char buf[9];
2745     char *s;
2746     chtype attr = A_NORMAL;
2747     unsigned at_code = 0;
2748 #if HAVE_SLK_COLOR
2749     int fg = COLOR_BLACK;
2750     int bg = COLOR_WHITE;
2751     short pair = 0;
2752 #endif
2753
2754     c = CTRL('l');
2755 #if HAVE_SLK_COLOR
2756     if (use_colors) {
2757         call_slk_color(fg, bg);
2758     }
2759 #endif
2760
2761     do {
2762         move(0, 0);
2763         switch (c) {
2764         case CTRL('l'):
2765             erase();
2766             attron(A_BOLD);
2767             MvAddStr(0, 20, "Soft Key Exerciser");
2768             attroff(A_BOLD);
2769
2770             slk_help();
2771             /* fall through */
2772
2773         case 'a':
2774             slk_restore();
2775             break;
2776
2777         case 'e':
2778             wclear(stdscr);
2779             break;
2780
2781         case 's':
2782             MvPrintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: ");
2783             while ((c = Getchar()) != 'Q' && (c != ERR))
2784                 addch((chtype) c);
2785             break;
2786
2787         case 'd':
2788             slk_clear();
2789             break;
2790
2791         case 'l':
2792             fmt = 0;
2793             break;
2794
2795         case 'c':
2796             fmt = 1;
2797             break;
2798
2799         case 'r':
2800             fmt = 2;
2801             break;
2802
2803         case '1':
2804         case '2':
2805         case '3':
2806         case '4':
2807         case '5':
2808         case '6':
2809         case '7':
2810         case '8':
2811             MvAddStr(SLK_WORK, 0, "Please enter the label value: ");
2812             strcpy(buf, "");
2813             if ((s = slk_label(c - '0')) != 0) {
2814                 strncpy(buf, s, 8);
2815             }
2816             wGetstring(stdscr, buf, 8);
2817             slk_set((c - '0'), buf, fmt);
2818             slk_refresh();
2819             move(SLK_WORK, 0);
2820             clrtobot();
2821             break;
2822
2823         case case_QUIT:
2824             goto done;
2825
2826 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
2827         case KEY_RESIZE:
2828             wnoutrefresh(stdscr);
2829             break;
2830 #endif
2831
2832         default:
2833             if (cycle_attr(c, &at_code, &attr)) {
2834                 slk_attrset(attr);
2835                 slk_touch();
2836                 slk_noutrefresh();
2837                 break;
2838             }
2839 #if HAVE_SLK_COLOR
2840             if (cycle_colors(c, &fg, &bg, &pair)) {
2841                 if (use_colors) {
2842                     call_slk_color(fg, bg);
2843                 } else {
2844                     beep();
2845                 }
2846                 break;
2847             }
2848 #endif
2849             beep();
2850             break;
2851         }
2852     } while (!isQuit(c = Getchar()));
2853
2854   done:
2855     slk_clear();
2856     erase();
2857     endwin();
2858 }
2859
2860 #if USE_WIDEC_SUPPORT
2861 #define SLKLEN 8
2862 static void
2863 wide_slk_test(void)
2864 /* exercise the soft keys */
2865 {
2866     int c, fmt = 1;
2867     wchar_t buf[SLKLEN + 1];
2868     char *s;
2869     chtype attr = A_NORMAL;
2870     unsigned at_code = 0;
2871     int fg = COLOR_BLACK;
2872     int bg = COLOR_WHITE;
2873     short pair = 0;
2874
2875     c = CTRL('l');
2876     if (use_colors) {
2877         call_slk_color(fg, bg);
2878     }
2879     do {
2880         move(0, 0);
2881         switch (c) {
2882         case CTRL('l'):
2883             erase();
2884             attr_on(WA_BOLD, NULL);
2885             MvAddStr(0, 20, "Soft Key Exerciser");
2886             attr_off(WA_BOLD, NULL);
2887
2888             slk_help();
2889             /* fall through */
2890
2891         case 'a':
2892             slk_restore();
2893             break;
2894
2895         case 'e':
2896             wclear(stdscr);
2897             break;
2898
2899         case 's':
2900             MvPrintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: ");
2901             while ((c = Getchar()) != 'Q' && (c != ERR))
2902                 addch((chtype) c);
2903             break;
2904
2905         case 'd':
2906             slk_clear();
2907             break;
2908
2909         case 'l':
2910             fmt = 0;
2911             break;
2912
2913         case 'c':
2914             fmt = 1;
2915             break;
2916
2917         case 'r':
2918             fmt = 2;
2919             break;
2920
2921         case '1':
2922         case '2':
2923         case '3':
2924         case '4':
2925         case '5':
2926         case '6':
2927         case '7':
2928         case '8':
2929             MvAddStr(SLK_WORK, 0, "Please enter the label value: ");
2930             *buf = 0;
2931             if ((s = slk_label(c - '0')) != 0) {
2932                 char *temp = strdup(s);
2933                 size_t used = strlen(temp);
2934                 size_t want = SLKLEN;
2935                 size_t test;
2936 #ifndef state_unused
2937                 mbstate_t state;
2938 #endif
2939
2940                 buf[0] = L'\0';
2941                 while (want > 0 && used != 0) {
2942                     const char *base = s;
2943                     reset_mbytes(state);
2944                     test = count_mbytes(base, 0, &state);
2945                     if (test == (size_t) -1) {
2946                         temp[--used] = 0;
2947                     } else if (test > want) {
2948                         temp[--used] = 0;
2949                     } else {
2950                         reset_mbytes(state);
2951                         trans_mbytes(buf, base, want, &state);
2952                         break;
2953                     }
2954                 }
2955                 free(temp);
2956             }
2957             wGet_wstring(stdscr, buf, SLKLEN);
2958             slk_wset((c - '0'), buf, fmt);
2959             slk_refresh();
2960             move(SLK_WORK, 0);
2961             clrtobot();
2962             break;
2963
2964         case case_QUIT:
2965             goto done;
2966
2967         case 'F':
2968             if (use_colors) {
2969                 fg = (short) ((fg + 1) % COLORS);
2970                 call_slk_color(fg, bg);
2971             }
2972             break;
2973         case 'B':
2974             if (use_colors) {
2975                 bg = (short) ((bg + 1) % COLORS);
2976                 call_slk_color(fg, bg);
2977             }
2978             break;
2979 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
2980         case KEY_RESIZE:
2981             wnoutrefresh(stdscr);
2982             break;
2983 #endif
2984         default:
2985             if (cycle_attr(c, &at_code, &attr)) {
2986                 slk_attr_set(attr, (short) (fg || bg), NULL);
2987                 slk_touch();
2988                 slk_noutrefresh();
2989                 break;
2990             }
2991 #if HAVE_SLK_COLOR
2992             if (cycle_colors(c, &fg, &bg, &pair)) {
2993                 if (use_colors) {
2994                     call_slk_color(fg, bg);
2995                 } else {
2996                     beep();
2997                 }
2998                 break;
2999             }
3000 #endif
3001             beep();
3002             break;
3003         }
3004     } while (!isQuit(c = Getchar()));
3005
3006   done:
3007     slk_clear();
3008     erase();
3009     endwin();
3010 }
3011 #endif
3012 #endif /* SLK_INIT */
3013
3014 /* ISO 6429:  codes 0x80 to 0x9f may be control characters that cause the
3015  * terminal to perform functions.  The remaining codes can be graphic.
3016  */
3017 static void
3018 show_upper_chars(unsigned first, int repeat, attr_t attr, short pair)
3019 {
3020     bool C1 = (first == 128);
3021     unsigned code;
3022     unsigned last = first + 31;
3023     int reply;
3024
3025     erase();
3026     attron(A_BOLD);
3027     MvPrintw(0, 20, "Display of %s Character Codes %d to %d",
3028              C1 ? "C1" : "GR", first, last);
3029     attroff(A_BOLD);
3030     refresh();
3031
3032     for (code = first; code <= last; code++) {
3033         int count = repeat;
3034         int row = 2 + ((int) (code - first) % 16);
3035         int col = ((int) (code - first) / 16) * COLS / 2;
3036         char tmp[80];
3037         sprintf(tmp, "%3u (0x%x)", code, code);
3038         MvPrintw(row, col, "%*s: ", COLS / 4, tmp);
3039
3040         do {
3041             if (C1)
3042                 nodelay(stdscr, TRUE);
3043             echochar(colored_chtype(code, attr, pair));
3044             if (C1) {
3045                 /* (yes, this _is_ crude) */
3046                 while ((reply = Getchar()) != ERR) {
3047                     addch(UChar(reply));
3048                     napms(10);
3049                 }
3050                 nodelay(stdscr, FALSE);
3051             }
3052         } while (--count > 0);
3053     }
3054 }
3055
3056 #define PC_COLS 4
3057
3058 static void
3059 show_pc_chars(int repeat, attr_t attr, short pair)
3060 {
3061     unsigned code;
3062
3063     erase();
3064     attron(A_BOLD);
3065     MvPrintw(0, 20, "Display of PC Character Codes");
3066     attroff(A_BOLD);
3067     refresh();
3068
3069     for (code = 0; code < 16; ++code) {
3070         MvPrintw(2, (int) code * PC_COLS + 8, "%X", code);
3071     }
3072     for (code = 0; code < 256; code++) {
3073         int count = repeat;
3074         int row = 3 + (int) (code / 16) + (code >= 128);
3075         int col = 8 + (int) (code % 16) * PC_COLS;
3076         if ((code % 16) == 0)
3077             MvPrintw(row, 0, "0x%02x:", code);
3078         move(row, col);
3079         do {
3080             switch (code) {
3081             case '\n':
3082             case '\r':
3083             case '\b':
3084             case '\f':
3085             case '\033':
3086             case 0x9b:
3087                 /*
3088                  * Skip the ones that do not work.
3089                  */
3090                 break;
3091             default:
3092                 addch(colored_chtype(code, A_ALTCHARSET | attr, pair));
3093                 break;
3094             }
3095         } while (--count > 0);
3096     }
3097 }
3098
3099 static void
3100 show_box_chars(int repeat, attr_t attr, short pair)
3101 {
3102     (void) repeat;
3103
3104     attr |= (attr_t) COLOR_PAIR(pair);
3105
3106     erase();
3107     attron(A_BOLD);
3108     MvAddStr(0, 20, "Display of the ACS Line-Drawing Set");
3109     attroff(A_BOLD);
3110     refresh();
3111     /* *INDENT-OFF* */
3112     wborder(stdscr,
3113             colored_chtype(ACS_VLINE,    attr, pair),
3114             colored_chtype(ACS_VLINE,    attr, pair),
3115             colored_chtype(ACS_HLINE,    attr, pair),
3116             colored_chtype(ACS_HLINE,    attr, pair),
3117             colored_chtype(ACS_ULCORNER, attr, pair),
3118             colored_chtype(ACS_URCORNER, attr, pair),
3119             colored_chtype(ACS_LLCORNER, attr, pair),
3120             colored_chtype(ACS_LRCORNER, attr, pair));
3121     MvHLine(LINES / 2, 0,        colored_chtype(ACS_HLINE, attr, pair), COLS);
3122     MvVLine(0,         COLS / 2, colored_chtype(ACS_VLINE, attr, pair), LINES);
3123     MvAddCh(0,         COLS / 2, colored_chtype(ACS_TTEE,  attr, pair));
3124     MvAddCh(LINES / 2, COLS / 2, colored_chtype(ACS_PLUS,  attr, pair));
3125     MvAddCh(LINES - 1, COLS / 2, colored_chtype(ACS_BTEE,  attr, pair));
3126     MvAddCh(LINES / 2, 0,        colored_chtype(ACS_LTEE,  attr, pair));
3127     MvAddCh(LINES / 2, COLS - 1, colored_chtype(ACS_RTEE,  attr, pair));
3128     /* *INDENT-ON* */
3129
3130 }
3131
3132 static int
3133 show_1_acs(int n, int repeat, const char *name, chtype code)
3134 {
3135     const int height = 16;
3136     int row = 2 + (n % height);
3137     int col = (n / height) * COLS / 2;
3138
3139     MvPrintw(row, col, "%*s : ", COLS / 4, name);
3140     do {
3141         addch(code);
3142     } while (--repeat > 0);
3143     return n + 1;
3144 }
3145
3146 static void
3147 show_acs_chars(int repeat, attr_t attr, short pair)
3148 /* display the ACS character set */
3149 {
3150     int n;
3151
3152 #define BOTH(name) #name, colored_chtype(name, attr, (chtype) pair)
3153
3154     erase();
3155     attron(A_BOLD);
3156     MvAddStr(0, 20, "Display of the ACS Character Set");
3157     attroff(A_BOLD);
3158     refresh();
3159
3160     n = show_1_acs(0, repeat, BOTH(ACS_ULCORNER));
3161     n = show_1_acs(n, repeat, BOTH(ACS_URCORNER));
3162     n = show_1_acs(n, repeat, BOTH(ACS_LLCORNER));
3163     n = show_1_acs(n, repeat, BOTH(ACS_LRCORNER));
3164
3165     n = show_1_acs(n, repeat, BOTH(ACS_LTEE));
3166     n = show_1_acs(n, repeat, BOTH(ACS_RTEE));
3167     n = show_1_acs(n, repeat, BOTH(ACS_TTEE));
3168     n = show_1_acs(n, repeat, BOTH(ACS_BTEE));
3169
3170     n = show_1_acs(n, repeat, BOTH(ACS_HLINE));
3171     n = show_1_acs(n, repeat, BOTH(ACS_VLINE));
3172
3173     /*
3174      * HPUX's ACS definitions are broken here.  Just give up.
3175      */
3176 #if !(defined(__hpux) && !defined(NCURSES_VERSION))
3177     n = show_1_acs(n, repeat, BOTH(ACS_LARROW));
3178     n = show_1_acs(n, repeat, BOTH(ACS_RARROW));
3179     n = show_1_acs(n, repeat, BOTH(ACS_UARROW));
3180     n = show_1_acs(n, repeat, BOTH(ACS_DARROW));
3181
3182     n = show_1_acs(n, repeat, BOTH(ACS_BLOCK));
3183     n = show_1_acs(n, repeat, BOTH(ACS_BOARD));
3184     n = show_1_acs(n, repeat, BOTH(ACS_LANTERN));
3185     n = show_1_acs(n, repeat, BOTH(ACS_BULLET));
3186     n = show_1_acs(n, repeat, BOTH(ACS_CKBOARD));
3187     n = show_1_acs(n, repeat, BOTH(ACS_DEGREE));
3188     n = show_1_acs(n, repeat, BOTH(ACS_DIAMOND));
3189     n = show_1_acs(n, repeat, BOTH(ACS_PLMINUS));
3190     n = show_1_acs(n, repeat, BOTH(ACS_PLUS));
3191
3192     n = show_1_acs(n, repeat, BOTH(ACS_GEQUAL));
3193     n = show_1_acs(n, repeat, BOTH(ACS_NEQUAL));
3194     n = show_1_acs(n, repeat, BOTH(ACS_LEQUAL));
3195
3196     n = show_1_acs(n, repeat, BOTH(ACS_STERLING));
3197     n = show_1_acs(n, repeat, BOTH(ACS_PI));
3198     n = show_1_acs(n, repeat, BOTH(ACS_S1));
3199     n = show_1_acs(n, repeat, BOTH(ACS_S3));
3200     n = show_1_acs(n, repeat, BOTH(ACS_S7));
3201     (void) show_1_acs(n, repeat, BOTH(ACS_S9));
3202 #endif
3203 }
3204
3205 static void
3206 acs_display(void)
3207 {
3208     int c = 'a';
3209     char *term = getenv("TERM");
3210     const char *pch_kludge = ((term != 0 && strstr(term, "linux"))
3211                               ? "p=PC, "
3212                               : "");
3213     chtype attr = A_NORMAL;
3214     int digit = 0;
3215     int repeat = 1;
3216     int fg = COLOR_BLACK;
3217     int bg = COLOR_BLACK;
3218     unsigned at_code = 0;
3219     short pair = 0;
3220     void (*last_show_acs) (int, attr_t, short) = 0;
3221
3222     do {
3223         switch (c) {
3224         case CTRL('L'):
3225             Repaint();
3226             break;
3227         case 'a':
3228             ToggleAcs(last_show_acs, show_acs_chars);
3229             break;
3230         case 'p':
3231             if (*pch_kludge)
3232                 ToggleAcs(last_show_acs, show_pc_chars);
3233             else
3234                 beep();
3235             break;
3236         case 'x':
3237             ToggleAcs(last_show_acs, show_box_chars);
3238             break;
3239         case '0':
3240         case '1':
3241         case '2':
3242         case '3':
3243             digit = (c - '0');
3244             last_show_acs = 0;
3245             break;
3246         case '-':
3247             if (digit > 0) {
3248                 --digit;
3249                 last_show_acs = 0;
3250             } else {
3251                 beep();
3252             }
3253             break;
3254         case '+':
3255             if (digit < 3) {
3256                 ++digit;
3257                 last_show_acs = 0;
3258             } else {
3259                 beep();
3260             }
3261             break;
3262         case '>':
3263             if (repeat < (COLS / 4))
3264                 ++repeat;
3265             break;
3266         case '<':
3267             if (repeat > 1)
3268                 --repeat;
3269             break;
3270         default:
3271             if (cycle_attr(c, &at_code, &attr)
3272                 || cycle_colors(c, &fg, &bg, &pair)) {
3273                 break;
3274             } else {
3275                 beep();
3276             }
3277             break;
3278         }
3279         if (last_show_acs != 0)
3280             last_show_acs(repeat, attr, pair);
3281         else
3282             show_upper_chars((unsigned) (digit * 32 + 128), repeat, attr, pair);
3283
3284         MvPrintw(LINES - 3, 0,
3285                  "Note: ANSI terminals may not display C1 characters.");
3286         MvPrintw(LINES - 2, 0,
3287                  "Select: a=ACS, x=box, %s0=C1, 1-3,+/- non-ASCII, </> repeat, ESC=quit",
3288                  pch_kludge);
3289         if (use_colors) {
3290             MvPrintw(LINES - 1, 0,
3291                      "v/V, f/F, b/B cycle through video attributes (%s) and color %d/%d.",
3292                      attrs_to_cycle[at_code].name,
3293                      fg, bg);
3294         } else {
3295             MvPrintw(LINES - 1, 0,
3296                      "v/V cycles through video attributes (%s).",
3297                      attrs_to_cycle[at_code].name);
3298         }
3299         refresh();
3300     } while (!isQuit(c = Getchar()));
3301
3302     Pause();
3303     erase();
3304     endwin();
3305 }
3306
3307 #if USE_WIDEC_SUPPORT
3308 static cchar_t *
3309 merge_wide_attr(cchar_t *dst, const cchar_t *src, attr_t attr, short pair)
3310 {
3311     int count;
3312
3313     *dst = *src;
3314     do {
3315         TEST_CCHAR(src, count, {
3316             attr |= (test_attrs & A_ALTCHARSET);
3317             setcchar(dst, test_wch, attr, pair, NULL);
3318         }
3319         , {
3320             ;
3321         });
3322     } while (0);
3323     return dst;
3324 }
3325
3326 static void
3327 show_upper_widechars(int first, int repeat, int space, attr_t attr, short pair)
3328 {
3329     cchar_t temp;
3330     wchar_t code;
3331     int last = first + 31;
3332
3333     erase();
3334     attron(A_BOLD);
3335     MvPrintw(0, 20, "Display of Character Codes %d to %d", first, last);
3336     attroff(A_BOLD);
3337
3338     for (code = first; (int) code <= last; code++) {
3339         int row = 2 + ((code - first) % 16);
3340         int col = ((code - first) / 16) * COLS / 2;
3341         wchar_t codes[10];
3342         char tmp[80];
3343         int count = repeat;
3344         int y, x;
3345
3346         memset(&codes, 0, sizeof(codes));
3347         codes[0] = code;
3348         sprintf(tmp, "%3ld (0x%lx)", (long) code, (long) code);
3349         MvPrintw(row, col, "%*s: ", COLS / 4, tmp);
3350         setcchar(&temp, codes, attr, pair, 0);
3351         do {
3352             /*
3353              * Give non-spacing characters something to combine with.  If we
3354              * don't, they'll bunch up in a heap on the space after the ":".
3355              * Mark them with reverse-video to make them simpler to find on
3356              * the display.
3357              */
3358             if (wcwidth(code) == 0) {
3359                 addch((chtype) space |
3360                       (A_REVERSE ^ attr) |
3361                       (attr_t) COLOR_PAIR(pair));
3362             }
3363             /*
3364              * This could use add_wch(), but is done for comparison with the
3365              * normal 'f' test (and to make a test-case for echo_wchar()).
3366              * The screen will flicker because the erase() at the top of the
3367              * function is met by the builtin refresh() in echo_wchar().
3368              */
3369             echo_wchar(&temp);
3370             /*
3371              * The repeat-count may make text wrap - avoid that.
3372              */
3373             getyx(stdscr, y, x);
3374             (void) y;
3375             if (x >= col + (COLS / 2) - 2)
3376                 break;
3377         } while (--count > 0);
3378     }
3379 }
3380
3381 static int
3382 show_1_wacs(int n, int repeat, const char *name, const cchar_t *code)
3383 {
3384     const int height = 16;
3385     int row = 2 + (n % height);
3386     int col = (n / height) * COLS / 2;
3387
3388     MvPrintw(row, col, "%*s : ", COLS / 4, name);
3389     while (--repeat >= 0) {
3390         add_wch(code);
3391     }
3392     return n + 1;
3393 }
3394
3395 #define MERGE_ATTR(wch) merge_wide_attr(&temp, wch, attr, pair)
3396
3397 static void
3398 show_wacs_chars(int repeat, attr_t attr, short pair)
3399 /* display the wide-ACS character set */
3400 {
3401     cchar_t temp;
3402
3403     int n;
3404
3405 /*#define BOTH2(name) #name, &(name) */
3406 #define BOTH2(name) #name, MERGE_ATTR(name)
3407
3408     erase();
3409     attron(A_BOLD);
3410     MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3411     attroff(A_BOLD);
3412     refresh();
3413
3414     n = show_1_wacs(0, repeat, BOTH2(WACS_ULCORNER));
3415     n = show_1_wacs(n, repeat, BOTH2(WACS_URCORNER));
3416     n = show_1_wacs(n, repeat, BOTH2(WACS_LLCORNER));
3417     n = show_1_wacs(n, repeat, BOTH2(WACS_LRCORNER));
3418
3419     n = show_1_wacs(n, repeat, BOTH2(WACS_LTEE));
3420     n = show_1_wacs(n, repeat, BOTH2(WACS_RTEE));
3421     n = show_1_wacs(n, repeat, BOTH2(WACS_TTEE));
3422     n = show_1_wacs(n, repeat, BOTH2(WACS_BTEE));
3423
3424     n = show_1_wacs(n, repeat, BOTH2(WACS_HLINE));
3425     n = show_1_wacs(n, repeat, BOTH2(WACS_VLINE));
3426
3427     n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3428     n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3429     n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3430     n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3431
3432     n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3433     n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3434     n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3435     n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3436     n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3437     n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3438     n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3439     n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3440     n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3441
3442 #ifdef CURSES_WACS_ARRAY
3443     n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3444     n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3445     n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3446
3447     n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3448     n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3449     n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3450     n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3451     n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3452     (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3453 #endif
3454 }
3455
3456 #ifdef WACS_D_PLUS
3457 static void
3458 show_wacs_chars_double(int repeat, attr_t attr, short pair)
3459 /* display the wide-ACS character set */
3460 {
3461     cchar_t temp;
3462
3463     int n;
3464
3465 /*#define BOTH2(name) #name, &(name) */
3466 #define BOTH2(name) #name, MERGE_ATTR(name)
3467
3468     erase();
3469     attron(A_BOLD);
3470     MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3471     attroff(A_BOLD);
3472     refresh();
3473
3474     n = show_1_wacs(0, repeat, BOTH2(WACS_D_ULCORNER));
3475     n = show_1_wacs(n, repeat, BOTH2(WACS_D_URCORNER));
3476     n = show_1_wacs(n, repeat, BOTH2(WACS_D_LLCORNER));
3477     n = show_1_wacs(n, repeat, BOTH2(WACS_D_LRCORNER));
3478
3479     n = show_1_wacs(n, repeat, BOTH2(WACS_D_LTEE));
3480     n = show_1_wacs(n, repeat, BOTH2(WACS_D_RTEE));
3481     n = show_1_wacs(n, repeat, BOTH2(WACS_D_TTEE));
3482     n = show_1_wacs(n, repeat, BOTH2(WACS_D_BTEE));
3483
3484     n = show_1_wacs(n, repeat, BOTH2(WACS_D_HLINE));
3485     n = show_1_wacs(n, repeat, BOTH2(WACS_D_VLINE));
3486
3487     n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3488     n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3489     n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3490     n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3491
3492     n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3493     n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3494     n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3495     n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3496     n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3497     n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3498     n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3499     n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3500     n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3501
3502 #ifdef CURSES_WACS_ARRAY
3503     n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3504     n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3505     n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3506
3507     n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3508     n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3509     n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3510     n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3511     n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3512     (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3513 #endif
3514 }
3515 #endif
3516
3517 #ifdef WACS_T_PLUS
3518 static void
3519 show_wacs_chars_thick(int repeat, attr_t attr, short pair)
3520 /* display the wide-ACS character set */
3521 {
3522     cchar_t temp;
3523
3524     int n;
3525
3526 /*#define BOTH2(name) #name, &(name) */
3527 #define BOTH2(name) #name, MERGE_ATTR(name)
3528
3529     erase();
3530     attron(A_BOLD);
3531     MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3532     attroff(A_BOLD);
3533     refresh();
3534
3535     n = show_1_wacs(0, repeat, BOTH2(WACS_T_ULCORNER));
3536     n = show_1_wacs(n, repeat, BOTH2(WACS_T_URCORNER));
3537     n = show_1_wacs(n, repeat, BOTH2(WACS_T_LLCORNER));
3538     n = show_1_wacs(n, repeat, BOTH2(WACS_T_LRCORNER));
3539
3540     n = show_1_wacs(n, repeat, BOTH2(WACS_T_LTEE));
3541     n = show_1_wacs(n, repeat, BOTH2(WACS_T_RTEE));
3542     n = show_1_wacs(n, repeat, BOTH2(WACS_T_TTEE));
3543     n = show_1_wacs(n, repeat, BOTH2(WACS_T_BTEE));
3544
3545     n = show_1_wacs(n, repeat, BOTH2(WACS_T_HLINE));
3546     n = show_1_wacs(n, repeat, BOTH2(WACS_T_VLINE));
3547
3548     n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3549     n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3550     n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3551     n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3552
3553     n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3554     n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3555     n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3556     n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3557     n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3558     n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3559     n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3560     n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3561     n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3562
3563 #ifdef CURSES_WACS_ARRAY
3564     n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3565     n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3566     n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3567
3568     n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3569     n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3570     n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3571     n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3572     n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3573     (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3574 #endif
3575 }
3576 #endif
3577
3578 #undef MERGE_ATTR
3579
3580 #define MERGE_ATTR(n,wch) merge_wide_attr(&temp[n], wch, attr, pair)
3581
3582 static void
3583 show_wbox_chars(int repeat, attr_t attr, short pair)
3584 {
3585     cchar_t temp[8];
3586
3587     (void) repeat;
3588     erase();
3589     attron(A_BOLD);
3590     MvAddStr(0, 20, "Display of the Wide-ACS Line-Drawing Set");
3591     attroff(A_BOLD);
3592     refresh();
3593
3594     wborder_set(stdscr,
3595                 MERGE_ATTR(0, WACS_VLINE),
3596                 MERGE_ATTR(1, WACS_VLINE),
3597                 MERGE_ATTR(2, WACS_HLINE),
3598                 MERGE_ATTR(3, WACS_HLINE),
3599                 MERGE_ATTR(4, WACS_ULCORNER),
3600                 MERGE_ATTR(5, WACS_URCORNER),
3601                 MERGE_ATTR(6, WACS_LLCORNER),
3602                 MERGE_ATTR(7, WACS_LRCORNER));
3603     /* *INDENT-OFF* */
3604     (void) mvhline_set(LINES / 2, 0,        MERGE_ATTR(0, WACS_HLINE), COLS);
3605     (void) mvvline_set(0,         COLS / 2, MERGE_ATTR(0, WACS_VLINE), LINES);
3606     (void) mvadd_wch(0,           COLS / 2, MERGE_ATTR(0, WACS_TTEE));
3607     (void) mvadd_wch(LINES / 2,   COLS / 2, MERGE_ATTR(0, WACS_PLUS));
3608     (void) mvadd_wch(LINES - 1,   COLS / 2, MERGE_ATTR(0, WACS_BTEE));
3609     (void) mvadd_wch(LINES / 2,   0,        MERGE_ATTR(0, WACS_LTEE));
3610     (void) mvadd_wch(LINES / 2,   COLS - 1, MERGE_ATTR(0, WACS_RTEE));
3611     /* *INDENT-ON* */
3612
3613 }
3614
3615 #undef MERGE_ATTR
3616
3617 static int
3618 show_2_wacs(int n, const char *name, const char *code, attr_t attr, short pair)
3619 {
3620     const int height = 16;
3621     int row = 2 + (n % height);
3622     int col = (n / height) * COLS / 2;
3623     char temp[80];
3624
3625     MvPrintw(row, col, "%*s : ", COLS / 4, name);
3626     (void) attr_set(attr, pair, 0);
3627     addstr(strcpy(temp, code));
3628     (void) attr_set(A_NORMAL, 0, 0);
3629     return n + 1;
3630 }
3631
3632 #define SHOW_UTF8(n, name, code) show_2_wacs(n, name, code, attr, pair)
3633
3634 static void
3635 show_utf8_chars(int repeat, attr_t attr, short pair)
3636 {
3637     int n;
3638
3639     (void) repeat;
3640     erase();
3641     attron(A_BOLD);
3642     MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3643     attroff(A_BOLD);
3644     refresh();
3645     /* *INDENT-OFF* */
3646     n = SHOW_UTF8(0, "WACS_ULCORNER",   "\342\224\214");
3647     n = SHOW_UTF8(n, "WACS_URCORNER",   "\342\224\220");
3648     n = SHOW_UTF8(n, "WACS_LLCORNER",   "\342\224\224");
3649     n = SHOW_UTF8(n, "WACS_LRCORNER",   "\342\224\230");
3650
3651     n = SHOW_UTF8(n, "WACS_LTEE",       "\342\224\234");
3652     n = SHOW_UTF8(n, "WACS_RTEE",       "\342\224\244");
3653     n = SHOW_UTF8(n, "WACS_TTEE",       "\342\224\254");
3654     n = SHOW_UTF8(n, "WACS_BTEE",       "\342\224\264");
3655
3656     n = SHOW_UTF8(n, "WACS_HLINE",      "\342\224\200");
3657     n = SHOW_UTF8(n, "WACS_VLINE",      "\342\224\202");
3658
3659     n = SHOW_UTF8(n, "WACS_LARROW",     "\342\206\220");
3660     n = SHOW_UTF8(n, "WACS_RARROW",     "\342\206\222");
3661     n = SHOW_UTF8(n, "WACS_UARROW",     "\342\206\221");
3662     n = SHOW_UTF8(n, "WACS_DARROW",     "\342\206\223");
3663
3664     n = SHOW_UTF8(n, "WACS_BLOCK",      "\342\226\256");
3665     n = SHOW_UTF8(n, "WACS_BOARD",      "\342\226\222");
3666     n = SHOW_UTF8(n, "WACS_LANTERN",    "\342\230\203");
3667     n = SHOW_UTF8(n, "WACS_BULLET",     "\302\267");
3668     n = SHOW_UTF8(n, "WACS_CKBOARD",    "\342\226\222");
3669     n = SHOW_UTF8(n, "WACS_DEGREE",     "\302\260");
3670     n = SHOW_UTF8(n, "WACS_DIAMOND",    "\342\227\206");
3671     n = SHOW_UTF8(n, "WACS_PLMINUS",    "\302\261");
3672     n = SHOW_UTF8(n, "WACS_PLUS",       "\342\224\274");
3673     n = SHOW_UTF8(n, "WACS_GEQUAL",     "\342\211\245");
3674     n = SHOW_UTF8(n, "WACS_NEQUAL",     "\342\211\240");
3675     n = SHOW_UTF8(n, "WACS_LEQUAL",     "\342\211\244");
3676
3677     n = SHOW_UTF8(n, "WACS_STERLING",   "\302\243");
3678     n = SHOW_UTF8(n, "WACS_PI",         "\317\200");
3679     n = SHOW_UTF8(n, "WACS_S1",         "\342\216\272");
3680     n = SHOW_UTF8(n, "WACS_S3",         "\342\216\273");
3681     n = SHOW_UTF8(n, "WACS_S7",         "\342\216\274");
3682     (void) SHOW_UTF8(n, "WACS_S9",      "\342\216\275");
3683     /* *INDENT-ON* */
3684
3685 }
3686
3687 /* display the wide-ACS character set */
3688 static void
3689 wide_acs_display(void)
3690 {
3691     int c = 'a';
3692     int digit = 0;
3693     int repeat = 1;
3694     int space = ' ';
3695     chtype attr = A_NORMAL;
3696     int fg = COLOR_BLACK;
3697     int bg = COLOR_BLACK;
3698     unsigned at_code = 0;
3699     short pair = 0;
3700     void (*last_show_wacs) (int, attr_t, short) = 0;
3701
3702     do {
3703         switch (c) {
3704         case CTRL('L'):
3705             Repaint();
3706             break;
3707         case 'a':
3708             ToggleAcs(last_show_wacs, show_wacs_chars);
3709             break;
3710 #ifdef WACS_D_PLUS
3711         case 'd':
3712             ToggleAcs(last_show_wacs, show_wacs_chars_double);
3713             break;
3714 #endif
3715 #ifdef WACS_T_PLUS
3716         case 't':
3717             ToggleAcs(last_show_wacs, show_wacs_chars_thick);
3718             break;
3719 #endif
3720         case 'x':
3721             ToggleAcs(last_show_wacs, show_wbox_chars);
3722             break;
3723         case 'u':
3724             ToggleAcs(last_show_wacs, show_utf8_chars);
3725             break;
3726         default:
3727             if (c < 256 && isdigit(c)) {
3728                 digit = (c - '0');
3729                 last_show_wacs = 0;
3730             } else if (c == '+') {
3731                 ++digit;
3732                 last_show_wacs = 0;
3733             } else if (c == '-' && digit > 0) {
3734                 --digit;
3735                 last_show_wacs = 0;
3736             } else if (c == '>' && repeat < (COLS / 4)) {
3737                 ++repeat;
3738             } else if (c == '<' && repeat > 1) {
3739                 --repeat;
3740             } else if (c == '_') {
3741                 space = (space == ' ') ? '_' : ' ';
3742                 last_show_wacs = 0;
3743             } else if (cycle_attr(c, &at_code, &attr)
3744                        || cycle_colors(c, &fg, &bg, &pair)) {
3745                 if (last_show_wacs != 0)
3746                     break;
3747             } else {
3748                 beep();
3749                 break;
3750             }
3751             break;
3752         }
3753         if (last_show_wacs != 0)
3754             last_show_wacs(repeat, attr, pair);
3755         else
3756             show_upper_widechars(digit * 32 + 128, repeat, space, attr, pair);
3757
3758         MvPrintw(LINES - 3, 0,
3759                  "Select: a/d/t WACS, x box, u UTF-8, 0-9,+/- non-ASCII, </> repeat, ESC=quit");
3760         if (use_colors) {
3761             MvPrintw(LINES - 2, 0,
3762                      "v/V, f/F, b/B cycle through video attributes (%s) and color %d/%d.",
3763                      attrs_to_cycle[at_code].name,
3764                      fg, bg);
3765         } else {
3766             MvPrintw(LINES - 2, 0,
3767                      "v/V cycles through video attributes (%s).",
3768                      attrs_to_cycle[at_code].name);
3769         }
3770         refresh();
3771     } while (!isQuit(c = Getchar()));
3772
3773     Pause();
3774     erase();
3775     endwin();
3776 }
3777
3778 #endif
3779
3780 /*
3781  * Graphic-rendition test (adapted from vttest)
3782  */
3783 static void
3784 test_sgr_attributes(void)
3785 {
3786     int pass;
3787
3788     for (pass = 0; pass < 2; pass++) {
3789         chtype normal = ((pass == 0 ? A_NORMAL : A_REVERSE)) | BLANK;
3790
3791         /* Use non-default colors if possible to exercise bce a little */
3792         if (use_colors) {
3793             init_pair(1, COLOR_WHITE, COLOR_BLUE);
3794             normal |= COLOR_PAIR(1);
3795         }
3796         bkgdset(normal);
3797         erase();
3798         MvPrintw(1, 20, "Graphic rendition test pattern:");
3799
3800         MvPrintw(4, 1, "vanilla");
3801
3802 #define set_sgr(mask) bkgdset((normal^(mask)));
3803         set_sgr(A_BOLD);
3804         MvPrintw(4, 40, "bold");
3805
3806         set_sgr(A_UNDERLINE);
3807         MvPrintw(6, 6, "underline");
3808
3809         set_sgr(A_BOLD | A_UNDERLINE);
3810         MvPrintw(6, 45, "bold underline");
3811
3812         set_sgr(A_BLINK);
3813         MvPrintw(8, 1, "blink");
3814
3815         set_sgr(A_BLINK | A_BOLD);
3816         MvPrintw(8, 40, "bold blink");
3817
3818         set_sgr(A_UNDERLINE | A_BLINK);
3819         MvPrintw(10, 6, "underline blink");
3820
3821         set_sgr(A_BOLD | A_UNDERLINE | A_BLINK);
3822         MvPrintw(10, 45, "bold underline blink");
3823
3824         set_sgr(A_REVERSE);
3825         MvPrintw(12, 1, "negative");
3826
3827         set_sgr(A_BOLD | A_REVERSE);
3828         MvPrintw(12, 40, "bold negative");
3829
3830         set_sgr(A_UNDERLINE | A_REVERSE);
3831         MvPrintw(14, 6, "underline negative");
3832
3833         set_sgr(A_BOLD | A_UNDERLINE | A_REVERSE);
3834         MvPrintw(14, 45, "bold underline negative");
3835
3836         set_sgr(A_BLINK | A_REVERSE);
3837         MvPrintw(16, 1, "blink negative");
3838
3839         set_sgr(A_BOLD | A_BLINK | A_REVERSE);
3840         MvPrintw(16, 40, "bold blink negative");
3841
3842         set_sgr(A_UNDERLINE | A_BLINK | A_REVERSE);
3843         MvPrintw(18, 6, "underline blink negative");
3844
3845         set_sgr(A_BOLD | A_UNDERLINE | A_BLINK | A_REVERSE);
3846         MvPrintw(18, 45, "bold underline blink negative");
3847
3848         bkgdset(normal);
3849         MvPrintw(LINES - 2, 1, "%s background. ", pass == 0 ? "Dark" :
3850                  "Light");
3851         clrtoeol();
3852         Pause();
3853     }
3854
3855     bkgdset(A_NORMAL | BLANK);
3856     erase();
3857     endwin();
3858 }
3859
3860 /****************************************************************************
3861  *
3862  * Windows and scrolling tester.
3863  *
3864  ****************************************************************************/
3865
3866 #define BOTLINES        4       /* number of line stolen from screen bottom */
3867
3868 typedef struct {
3869     int y, x;
3870 } pair;
3871
3872 #define FRAME struct frame
3873 FRAME
3874 {
3875     FRAME *next, *last;
3876     bool do_scroll;
3877     bool do_keypad;
3878     WINDOW *wind;
3879 };
3880
3881 #if defined(NCURSES_VERSION)
3882 #if (NCURSES_VERSION_PATCH < 20070331) && NCURSES_EXT_FUNCS
3883 #define is_keypad(win)   (win)->_use_keypad
3884 #define is_scrollok(win) (win)->_scroll
3885 #elif !defined(is_keypad)
3886 #define is_keypad(win)   FALSE
3887 #define is_scrollok(win) FALSE
3888 #endif
3889 #else
3890 #define is_keypad(win)   FALSE
3891 #define is_scrollok(win) FALSE
3892 #endif
3893
3894 static WINDOW *
3895 frame_win(FRAME * curp)
3896 {
3897     return (curp != 0) ? curp->wind : stdscr;
3898 }
3899
3900 /* We need to know if these flags are actually set, so don't look in FRAME.
3901  * These names are known to work with SVr4 curses as well as ncurses.  The
3902  * _use_keypad name does not work with Solaris 8.
3903  */
3904 static bool
3905 HaveKeypad(FRAME * curp)
3906 {
3907     WINDOW *win = frame_win(curp);
3908     (void) win;
3909     return is_keypad(win);
3910 }
3911
3912 static bool
3913 HaveScroll(FRAME * curp)
3914 {
3915     WINDOW *win = frame_win(curp);
3916     (void) win;
3917     return is_scrollok(win);
3918 }
3919
3920 static void
3921 newwin_legend(FRAME * curp)
3922 {
3923     static const struct {
3924         const char *msg;
3925         int code;
3926     } legend[] = {
3927         {
3928             "^C = create window", 0
3929         },
3930         {
3931             "^N = next window", 0
3932         },
3933         {
3934             "^P = previous window", 0
3935         },
3936         {
3937             "^F = scroll forward", 0
3938         },
3939         {
3940             "^B = scroll backward", 0
3941         },
3942         {
3943             "^K = keypad(%s)", 1
3944         },
3945         {
3946             "^S = scrollok(%s)", 2
3947         },
3948         {
3949             "^W = save window to file", 0
3950         },
3951         {
3952             "^R = restore window", 0
3953         },
3954 #if HAVE_WRESIZE
3955         {
3956             "^X = resize", 0
3957         },
3958 #endif
3959         {
3960             "^Q%s = exit", 3
3961         }
3962     };
3963     size_t n;
3964     int x;
3965     bool do_keypad = HaveKeypad(curp);
3966     bool do_scroll = HaveScroll(curp);
3967     char buf[BUFSIZ];
3968
3969     move(LINES - 4, 0);
3970     for (n = 0; n < SIZEOF(legend); n++) {
3971         switch (legend[n].code) {
3972         default:
3973             strcpy(buf, legend[n].msg);
3974             break;
3975         case 1:
3976             sprintf(buf, legend[n].msg, do_keypad ? "yes" : "no");
3977             break;
3978         case 2:
3979             sprintf(buf, legend[n].msg, do_scroll ? "yes" : "no");
3980             break;
3981         case 3:
3982             sprintf(buf, legend[n].msg, do_keypad ? "/ESC" : "");
3983             break;
3984         }
3985         x = getcurx(stdscr);
3986         addstr((COLS < (x + 3 + (int) strlen(buf))) ? "\n" : (n ? ", " : ""));
3987         addstr(buf);
3988     }
3989     clrtoeol();
3990 }
3991
3992 static void
3993 transient(FRAME * curp, NCURSES_CONST char *msg)
3994 {
3995     newwin_legend(curp);
3996     if (msg) {
3997         MvAddStr(LINES - 1, 0, msg);
3998         refresh();
3999         napms(1000);
4000     }
4001
4002     move(LINES - 1, 0);
4003     printw("%s characters are echoed, window should %sscroll.",
4004            HaveKeypad(curp) ? "Non-arrow" : "All other",
4005            HaveScroll(curp) ? "" : "not ");
4006     clrtoeol();
4007 }
4008
4009 static void
4010 newwin_report(FRAME * curp)
4011 /* report on the cursor's current position, then restore it */
4012 {
4013     WINDOW *win = frame_win(curp);
4014     int y, x;
4015
4016     if (win != stdscr)
4017         transient(curp, (char *) 0);
4018     getyx(win, y, x);
4019     move(LINES - 1, COLS - 17);
4020     printw("Y = %2d X = %2d", y, x);
4021     if (win != stdscr)
4022         refresh();
4023     else
4024         wmove(win, y, x);
4025 }
4026
4027 static pair *
4028 selectcell(int uli, int ulj, int lri, int lrj)
4029 /* arrows keys move cursor, return location at current on non-arrow key */
4030 {
4031     static pair res;            /* result cell */
4032     int si = lri - uli + 1;     /* depth of the select area */
4033     int sj = lrj - ulj + 1;     /* width of the select area */
4034     int i = 0, j = 0;           /* offsets into the select area */
4035
4036     res.y = uli;
4037     res.x = ulj;
4038     for (;;) {
4039         move(uli + i, ulj + j);
4040         newwin_report((FRAME *) 0);
4041
4042         switch (Getchar()) {
4043         case KEY_UP:
4044             i += si - 1;
4045             break;
4046         case KEY_DOWN:
4047             i++;
4048             break;
4049         case KEY_LEFT:
4050             j += sj - 1;
4051             break;
4052         case KEY_RIGHT:
4053             j++;
4054             break;
4055         case case_QUIT:
4056             return ((pair *) 0);
4057 #ifdef NCURSES_MOUSE_VERSION
4058         case KEY_MOUSE:
4059             {
4060                 MEVENT event;
4061
4062                 getmouse(&event);
4063                 if (event.y > uli && event.x > ulj) {
4064                     i = event.y - uli;
4065                     j = event.x - ulj;
4066                 } else {
4067                     beep();
4068                     break;
4069                 }
4070             }
4071             /* FALLTHRU */
4072 #endif
4073         default:
4074             res.y = uli + i;
4075             res.x = ulj + j;
4076             return (&res);
4077         }
4078         i %= si;
4079         j %= sj;
4080     }
4081 }
4082
4083 static void
4084 outerbox(pair ul, pair lr, bool onoff)
4085 /* draw or erase a box *outside* the given pair of corners */
4086 {
4087     MvAddCh(ul.y - 1, lr.x - 1, onoff ? ACS_ULCORNER : ' ');
4088     MvAddCh(ul.y - 1, lr.x + 1, onoff ? ACS_URCORNER : ' ');
4089     MvAddCh(lr.y + 1, lr.x + 1, onoff ? ACS_LRCORNER : ' ');
4090     MvAddCh(lr.y + 1, ul.x - 1, onoff ? ACS_LLCORNER : ' ');
4091     move(ul.y - 1, ul.x);
4092     hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1);
4093     move(ul.y, ul.x - 1);
4094     vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1);
4095     move(lr.y + 1, ul.x);
4096     hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1);
4097     move(ul.y, lr.x + 1);
4098     vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1);
4099 }
4100
4101 static WINDOW *
4102 getwindow(void)
4103 /* Ask user for a window definition */
4104 {
4105     WINDOW *rwindow;
4106     pair ul, lr, *tmp;
4107
4108     move(0, 0);
4109     clrtoeol();
4110     addstr("Use arrows to move cursor, anything else to mark corner 1");
4111     refresh();
4112     if ((tmp = selectcell(2, 1, LINES - BOTLINES - 2, COLS - 2)) == (pair *) 0)
4113         return ((WINDOW *) 0);
4114     memcpy(&ul, tmp, sizeof(pair));
4115     MvAddCh(ul.y - 1, ul.x - 1, ACS_ULCORNER);
4116     move(0, 0);
4117     clrtoeol();
4118     addstr("Use arrows to move cursor, anything else to mark corner 2");
4119     refresh();
4120     if ((tmp = selectcell(ul.y, ul.x, LINES - BOTLINES - 2, COLS - 2)) ==
4121         (pair *) 0)
4122         return ((WINDOW *) 0);
4123     memcpy(&lr, tmp, sizeof(pair));
4124
4125     rwindow = subwin(stdscr, lr.y - ul.y + 1, lr.x - ul.x + 1, ul.y, ul.x);
4126
4127     outerbox(ul, lr, TRUE);
4128     refresh();
4129
4130     wrefresh(rwindow);
4131
4132     move(0, 0);
4133     clrtoeol();
4134     return (rwindow);
4135 }
4136
4137 static void
4138 newwin_move(FRAME * curp, int dy, int dx)
4139 {
4140     WINDOW *win = frame_win(curp);
4141     int cur_y, cur_x;
4142     int max_y, max_x;
4143
4144     getyx(win, cur_y, cur_x);
4145     getmaxyx(win, max_y, max_x);
4146     if ((cur_x += dx) < 0)
4147         cur_x = 0;
4148     else if (cur_x >= max_x)
4149         cur_x = max_x - 1;
4150     if ((cur_y += dy) < 0)
4151         cur_y = 0;
4152     else if (cur_y >= max_y)
4153         cur_y = max_y - 1;
4154     wmove(win, cur_y, cur_x);
4155 }
4156
4157 static FRAME *
4158 delete_framed(FRAME * fp, bool showit)
4159 {
4160     FRAME *np = 0;
4161
4162     if (fp != 0) {
4163         fp->last->next = fp->next;
4164         fp->next->last = fp->last;
4165
4166         if (showit) {
4167             werase(fp->wind);
4168             wrefresh(fp->wind);
4169         }
4170         delwin(fp->wind);
4171
4172         np = (fp == fp->next) ? 0 : fp->next;
4173         free(fp);
4174     }
4175     return np;
4176 }
4177
4178 static void
4179 acs_and_scroll(void)
4180 /* Demonstrate windows */
4181 {
4182     int c;
4183     FRAME *current = (FRAME *) 0, *neww;
4184     WINDOW *usescr;
4185 #if HAVE_PUTWIN && HAVE_GETWIN
4186     FILE *fp;
4187 #endif
4188
4189 #define DUMPFILE        "screendump"
4190
4191 #ifdef NCURSES_MOUSE_VERSION
4192     mousemask(BUTTON1_CLICKED, (mmask_t *) 0);
4193 #endif
4194     c = CTRL('C');
4195     raw();
4196     do {
4197         transient((FRAME *) 0, (char *) 0);
4198         switch (c) {
4199         case CTRL('C'):
4200             if ((neww = typeCalloc(FRAME, 1)) == 0) {
4201                 goto breakout;
4202             }
4203             if ((neww->wind = getwindow()) == (WINDOW *) 0) {
4204                 free(neww);
4205                 goto breakout;
4206             }
4207
4208             if (current == 0) { /* First element,  */
4209                 neww->next = neww;      /*   so point it at itself */
4210                 neww->last = neww;
4211             } else {
4212                 neww->next = current->next;
4213                 neww->last = current;
4214                 neww->last->next = neww;
4215                 neww->next->last = neww;
4216             }
4217             current = neww;
4218             /* SVr4 curses sets the keypad on all newly-created windows to
4219              * false.  Someone reported that PDCurses makes new windows inherit
4220              * this flag.  Remove the following 'keypad()' call to test this
4221              */
4222             keypad(current->wind, TRUE);
4223             current->do_keypad = HaveKeypad(current);
4224             current->do_scroll = HaveScroll(current);
4225             break;
4226
4227         case CTRL('N'): /* go to next window */
4228             if (current)
4229                 current = current->next;
4230             break;
4231
4232         case CTRL('P'): /* go to previous window */
4233             if (current)
4234                 current = current->last;
4235             break;
4236
4237         case CTRL('F'): /* scroll current window forward */
4238             if (current)
4239                 wscrl(frame_win(current), 1);
4240             break;
4241
4242         case CTRL('B'): /* scroll current window backwards */
4243             if (current)
4244                 wscrl(frame_win(current), -1);
4245             break;
4246
4247         case CTRL('K'): /* toggle keypad mode for current */
4248             if (current) {
4249                 current->do_keypad = !current->do_keypad;
4250                 keypad(current->wind, current->do_keypad);
4251             }
4252             break;
4253
4254         case CTRL('S'):
4255             if (current) {
4256                 current->do_scroll = !current->do_scroll;
4257                 scrollok(current->wind, current->do_scroll);
4258             }
4259             break;
4260
4261 #if HAVE_PUTWIN && HAVE_GETWIN
4262         case CTRL('W'): /* save and delete window */
4263             if ((current != 0) && (current == current->next)) {
4264                 transient(current, "Will not save/delete ONLY window");
4265                 break;
4266             } else if ((fp = fopen(DUMPFILE, "w")) == (FILE *) 0) {
4267                 transient(current, "Can't open screen dump file");
4268             } else {
4269                 (void) putwin(frame_win(current), fp);
4270                 (void) fclose(fp);
4271
4272                 current = delete_framed(current, TRUE);
4273             }
4274             break;
4275
4276         case CTRL('R'): /* restore window */
4277             if ((fp = fopen(DUMPFILE, "r")) == (FILE *) 0) {
4278                 transient(current, "Can't open screen dump file");
4279             } else {
4280                 if ((neww = typeCalloc(FRAME, 1)) != 0) {
4281
4282                     neww->next = current ? current->next : 0;
4283                     neww->last = current;
4284                     if (neww->last != 0)
4285                         neww->last->next = neww;
4286                     if (neww->next != 0)
4287                         neww->next->last = neww;
4288
4289                     neww->wind = getwin(fp);
4290
4291                     wrefresh(neww->wind);
4292                 }
4293                 (void) fclose(fp);
4294             }
4295             break;
4296 #endif
4297
4298 #if HAVE_WRESIZE
4299         case CTRL('X'): /* resize window */
4300             if (current) {
4301                 pair *tmp, ul, lr;
4302                 int i, mx, my;
4303
4304                 move(0, 0);
4305                 clrtoeol();
4306                 addstr("Use arrows to move cursor, anything else to mark new corner");
4307                 refresh();
4308
4309                 getbegyx(current->wind, ul.y, ul.x);
4310
4311                 tmp = selectcell(ul.y, ul.x, LINES - BOTLINES - 2, COLS - 2);
4312                 if (tmp == (pair *) 0) {
4313                     beep();
4314                     break;
4315                 }
4316
4317                 getmaxyx(current->wind, lr.y, lr.x);
4318                 lr.y += (ul.y - 1);
4319                 lr.x += (ul.x - 1);
4320                 outerbox(ul, lr, FALSE);
4321                 wnoutrefresh(stdscr);
4322
4323                 /* strictly cosmetic hack for the test */
4324                 getmaxyx(current->wind, my, mx);
4325                 if (my > tmp->y - ul.y) {
4326                     getyx(current->wind, lr.y, lr.x);
4327                     wmove(current->wind, tmp->y - ul.y + 1, 0);
4328                     wclrtobot(current->wind);
4329                     wmove(current->wind, lr.y, lr.x);
4330                 }
4331                 if (mx > tmp->x - ul.x)
4332                     for (i = 0; i < my; i++) {
4333                         wmove(current->wind, i, tmp->x - ul.x + 1);
4334                         wclrtoeol(current->wind);
4335                     }
4336                 wnoutrefresh(current->wind);
4337
4338                 memcpy(&lr, tmp, sizeof(pair));
4339                 (void) wresize(current->wind, lr.y - ul.y + 0, lr.x - ul.x + 0);
4340
4341                 getbegyx(current->wind, ul.y, ul.x);
4342                 getmaxyx(current->wind, lr.y, lr.x);
4343                 lr.y += (ul.y - 1);
4344                 lr.x += (ul.x - 1);
4345                 outerbox(ul, lr, TRUE);
4346                 wnoutrefresh(stdscr);
4347
4348                 wnoutrefresh(current->wind);
4349                 move(0, 0);
4350                 clrtoeol();
4351                 doupdate();
4352             }
4353             break;
4354 #endif /* HAVE_WRESIZE */
4355
4356         case KEY_F(10): /* undocumented --- use this to test area clears */
4357             selectcell(0, 0, LINES - 1, COLS - 1);
4358             clrtobot();
4359             refresh();
4360             break;
4361
4362         case KEY_UP:
4363             newwin_move(current, -1, 0);
4364             break;
4365         case KEY_DOWN:
4366             newwin_move(current, 1, 0);
4367             break;
4368         case KEY_LEFT:
4369             newwin_move(current, 0, -1);
4370             break;
4371         case KEY_RIGHT:
4372             newwin_move(current, 0, 1);
4373             break;
4374
4375         case KEY_BACKSPACE:
4376             /* FALLTHROUGH */
4377         case KEY_DC:
4378             {
4379                 int y, x;
4380                 getyx(frame_win(current), y, x);
4381                 if (--x < 0) {
4382                     if (--y < 0)
4383                         break;
4384                     x = getmaxx(frame_win(current)) - 1;
4385                 }
4386                 (void) mvwdelch(frame_win(current), y, x);
4387             }
4388             break;
4389
4390         case '\r':
4391             c = '\n';
4392             /* FALLTHROUGH */
4393
4394         default:
4395             if (current)
4396                 waddch(current->wind, (chtype) c);
4397             else
4398                 beep();
4399             break;
4400         }
4401         newwin_report(current);
4402         usescr = frame_win(current);
4403         wrefresh(usescr);
4404     } while
4405         (!isQuit(c = wGetchar(usescr))
4406          && (c != ERR));
4407
4408   breakout:
4409     while (current != 0)
4410         current = delete_framed(current, FALSE);
4411
4412     scrollok(stdscr, TRUE);     /* reset to driver's default */
4413 #ifdef NCURSES_MOUSE_VERSION
4414     mousemask(0, (mmask_t *) 0);
4415 #endif
4416     noraw();
4417     erase();
4418     endwin();
4419 }
4420
4421 /****************************************************************************
4422  *
4423  * Panels tester
4424  *
4425  ****************************************************************************/
4426
4427 #if USE_LIBPANEL
4428 static int nap_msec = 1;
4429
4430 static NCURSES_CONST char *mod[] =
4431 {
4432     "test ",
4433     "TEST ",
4434     "(**) ",
4435     "*()* ",
4436     "<--> ",
4437     "LAST "
4438 };
4439
4440 /*+-------------------------------------------------------------------------
4441         wait_a_while(msec)
4442 --------------------------------------------------------------------------*/
4443 static void
4444 wait_a_while(int msec GCC_UNUSED)
4445 {
4446 #if HAVE_NAPMS
4447     if (nap_msec == 1)
4448         wGetchar(stdscr);
4449     else
4450         napms(nap_msec);
4451 #else
4452     if (nap_msec == 1)
4453         wGetchar(stdscr);
4454     else if (msec > 1000)
4455         sleep((unsigned) msec / 1000);
4456     else
4457         sleep(1);
4458 #endif
4459 }                               /* end of wait_a_while */
4460
4461 /*+-------------------------------------------------------------------------
4462         saywhat(text)
4463 --------------------------------------------------------------------------*/
4464 static void
4465 saywhat(NCURSES_CONST char *text)
4466 {
4467     wmove(stdscr, LINES - 1, 0);
4468     wclrtoeol(stdscr);
4469     if (text != 0 && *text != '\0') {
4470         waddstr(stdscr, text);
4471         waddstr(stdscr, "; ");
4472     }
4473     waddstr(stdscr, "press any key to continue");
4474 }                               /* end of saywhat */
4475
4476 /*+-------------------------------------------------------------------------
4477         mkpanel(rows,cols,tly,tlx) - alloc a win and panel and associate them
4478 --------------------------------------------------------------------------*/
4479 static PANEL *
4480 mkpanel(short color, int rows, int cols, int tly, int tlx)
4481 {
4482     WINDOW *win;
4483     PANEL *pan = 0;
4484
4485     if ((win = newwin(rows, cols, tly, tlx)) != 0) {
4486         if ((pan = new_panel(win)) == 0) {
4487             delwin(win);
4488         } else if (use_colors) {
4489             short fg = (short) ((color == COLOR_BLUE) ? COLOR_WHITE : COLOR_BLACK);
4490             short bg = color;
4491
4492             init_pair(color, fg, bg);
4493             wbkgdset(win, (attr_t) (COLOR_PAIR(color) | ' '));
4494         } else {
4495             wbkgdset(win, A_BOLD | ' ');
4496         }
4497     }
4498     return pan;
4499 }                               /* end of mkpanel */
4500
4501 /*+-------------------------------------------------------------------------
4502         rmpanel(pan)
4503 --------------------------------------------------------------------------*/
4504 static void
4505 rmpanel(PANEL * pan)
4506 {
4507     WINDOW *win = panel_window(pan);
4508     del_panel(pan);
4509     delwin(win);
4510 }                               /* end of rmpanel */
4511
4512 /*+-------------------------------------------------------------------------
4513         pflush()
4514 --------------------------------------------------------------------------*/
4515 static void
4516 pflush(void)
4517 {
4518     update_panels();