ncurses 5.9 - patch 20110521
[ncurses.git] / test / ncurses.c
1 /****************************************************************************
2  * Copyright (c) 1998-2010,2011 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.368 2011/05/21 18:50:56 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 static void
787 wgetch_test(unsigned level, WINDOW *win, int delay)
788 {
789     char buf[BUFSIZ];
790     int first_y, first_x;
791     int c;
792     int incount = 0;
793     GetchFlags flags;
794     bool blocking = (delay < 0);
795
796     init_getch(win, flags);
797     wtimeout(win, delay);
798     getyx(win, first_y, first_x);
799
800     wgetch_help(win, flags);
801     wsetscrreg(win, first_y, getmaxy(win) - 1);
802     scrollok(win, TRUE);
803
804     for (;;) {
805         while ((c = wGetchar(win)) == ERR) {
806             incount++;
807             if (blocking) {
808                 (void) wprintw(win, "%05d: input error", incount);
809                 break;
810             } else {
811                 (void) wprintw(win, "%05d: input timed out", incount);
812             }
813             wgetch_wrap(win, first_y);
814         }
815         if (c == ERR && blocking) {
816             wprintw(win, "ERR");
817             wgetch_wrap(win, first_y);
818         } else if (isQuit(c)) {
819             break;
820         } else if (c == 'e') {
821             flags[UChar('e')] = !flags[UChar('e')];
822             setup_getch(win, flags);
823             wgetch_help(win, flags);
824         } else if (c == 'g') {
825             waddstr(win, "getstr test: ");
826             echo();
827             wgetnstr(win, buf, sizeof(buf) - 1);
828             noecho();
829             wprintw(win, "I saw %d characters:\n\t`%s'.", (int) strlen(buf), buf);
830             wclrtoeol(win);
831             wgetch_wrap(win, first_y);
832         } else if (c == 'k') {
833             flags[UChar('k')] = !flags[UChar('k')];
834             setup_getch(win, flags);
835             wgetch_help(win, flags);
836         } else if (c == 'm') {
837             flags[UChar('m')] = !flags[UChar('m')];
838             setup_getch(win, flags);
839             wgetch_help(win, flags);
840         } else if (c == 's') {
841             ShellOut(TRUE);
842         } else if (c == 'w') {
843             int high = getmaxy(win) - 1 - first_y + 1;
844             int wide = getmaxx(win) - first_x;
845             int old_y, old_x;
846             int new_y = first_y + getbegy(win);
847             int new_x = first_x + getbegx(win);
848
849             getyx(win, old_y, old_x);
850             if (high > 2 && wide > 2) {
851                 WINDOW *wb = newwin(high, wide, new_y, new_x);
852                 WINDOW *wi = newwin(high - 2, wide - 2, new_y + 1, new_x + 1);
853
854                 box(wb, 0, 0);
855                 wrefresh(wb);
856                 wmove(wi, 0, 0);
857                 remember_boxes(level, wi, wb);
858                 wgetch_test(level + 1, wi, delay);
859                 delwin(wi);
860                 delwin(wb);
861
862                 wgetch_help(win, flags);
863                 wmove(win, old_y, old_x);
864                 touchwin(win);
865                 wrefresh(win);
866                 doupdate();
867             }
868 #ifdef SIGTSTP
869         } else if (c == 'z') {
870             kill(getpid(), SIGTSTP);
871 #endif
872         } else {
873             wprintw(win, "Key pressed: %04o ", c);
874 #ifdef NCURSES_MOUSE_VERSION
875             if (c == KEY_MOUSE) {
876                 show_mouse(win);
877             } else
878 #endif /* NCURSES_MOUSE_VERSION */
879             if (c >= KEY_MIN) {
880 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
881                 if (c == KEY_RESIZE) {
882                     resize_boxes(level, win);
883                 }
884 #endif
885                 (void) waddstr(win, keyname(c));
886             } else if (c >= 0x80) {
887                 unsigned c2 = (unsigned) c;
888 #if !(defined(NCURSES_VERSION) || defined(_XOPEN_CURSES))
889                 /* at least Solaris SVR4 curses breaks unctrl(128), etc. */
890                 c2 &= 0x7f;
891 #endif
892                 if (isprint(c))
893                     (void) wprintw(win, "%c", UChar(c));
894                 else if (c2 != UChar(c))
895                     (void) wprintw(win, "M-%s", unctrl(c2));
896                 else
897                     (void) wprintw(win, "%s", unctrl(c2));
898                 waddstr(win, " (high-half character)");
899             } else {
900                 if (isprint(c))
901                     (void) wprintw(win, "%c (ASCII printable character)", c);
902                 else
903                     (void) wprintw(win, "%s (ASCII control character)",
904                                    unctrl(UChar(c)));
905             }
906             wgetch_wrap(win, first_y);
907         }
908     }
909
910     wtimeout(win, -1);
911
912     if (!level)
913         init_getch(win, flags);
914 }
915
916 static int
917 begin_getch_test(void)
918 {
919     char buf[BUFSIZ];
920     int delay;
921
922     refresh();
923
924 #ifdef NCURSES_MOUSE_VERSION
925     mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
926 #endif
927
928     (void) printw("Delay in 10ths of a second (<CR> for blocking input)? ");
929     echo();
930     getnstr(buf, sizeof(buf) - 1);
931     noecho();
932     nonl();
933
934     if (isdigit(UChar(buf[0]))) {
935         delay = atoi(buf) * 100;
936     } else {
937         delay = -1;
938     }
939     raw();
940     move(5, 0);
941     return delay;
942 }
943
944 static void
945 finish_getch_test(void)
946 {
947 #ifdef NCURSES_MOUSE_VERSION
948     mousemask(0, (mmask_t *) 0);
949 #endif
950     erase();
951     noraw();
952     nl();
953     endwin();
954 }
955
956 static void
957 getch_test(void)
958 {
959     int delay = begin_getch_test();
960
961     slk_restore();
962     wgetch_test(0, stdscr, delay);
963     forget_boxes();
964     finish_getch_test();
965     slk_clear();
966 }
967
968 #if USE_WIDEC_SUPPORT
969 /*
970  * For wget_wch_test(), we create pairs of windows - one for a box, one for text.
971  * Resize both and paint the box in the parent.
972  */
973 #if defined(KEY_RESIZE) && HAVE_WRESIZE
974 static void
975 resize_wide_boxes(unsigned level, WINDOW *win)
976 {
977     unsigned n;
978     int base = 5;
979     int high = LINES - base;
980     int wide = COLS;
981
982     touchwin(stdscr);
983     wnoutrefresh(stdscr);
984
985     slk_repaint();
986
987     for (n = 0; n < level; ++n) {
988         wresize(winstack[n].frame, high, wide);
989         wresize(winstack[n].text, high - 2, wide - 2);
990         high -= 2;
991         wide -= 2;
992         werase(winstack[n].text);
993         box_set(winstack[n].frame, 0, 0);
994         wnoutrefresh(winstack[n].frame);
995         wprintw(winstack[n].text,
996                 "size %dx%d\n",
997                 getmaxy(winstack[n].text),
998                 getmaxx(winstack[n].text));
999         wnoutrefresh(winstack[n].text);
1000         if (winstack[n].text == win)
1001             break;
1002     }
1003     doupdate();
1004 }
1005 #endif /* KEY_RESIZE */
1006
1007 static char *
1008 wcstos(const wchar_t *src)
1009 {
1010     int need;
1011     char *result = 0;
1012     const wchar_t *tmp = src;
1013 #ifndef state_unused
1014     mbstate_t state;
1015 #endif
1016
1017     reset_wchars(state);
1018     if ((need = (int) count_wchars(tmp, 0, &state)) > 0) {
1019         unsigned have = (unsigned) need;
1020         if ((result = typeCalloc(char, have + 1)) != 0) {
1021             tmp = src;
1022             if (trans_wchars(result, tmp, have, &state) != have) {
1023                 free(result);
1024                 result = 0;
1025             }
1026         }
1027     }
1028     return result;
1029 }
1030
1031 static void
1032 wget_wch_test(unsigned level, WINDOW *win, int delay)
1033 {
1034     wchar_t wchar_buf[BUFSIZ];
1035     wint_t wint_buf[BUFSIZ];
1036     int first_y, first_x;
1037     wint_t c;
1038     int incount = 0;
1039     GetchFlags flags;
1040     bool blocking = (delay < 0);
1041     int code;
1042     char *temp;
1043
1044     init_getch(win, flags);
1045     wtimeout(win, delay);
1046     getyx(win, first_y, first_x);
1047
1048     wgetch_help(win, flags);
1049     wsetscrreg(win, first_y, getmaxy(win) - 1);
1050     scrollok(win, TRUE);
1051
1052     for (;;) {
1053         while ((code = wGet_wchar(win, &c)) == ERR) {
1054             incount++;
1055             if (blocking) {
1056                 (void) wprintw(win, "%05d: input error", incount);
1057                 break;
1058             } else {
1059                 (void) wprintw(win, "%05d: input timed out", incount);
1060             }
1061             wgetch_wrap(win, first_y);
1062         }
1063         if (code == ERR && blocking) {
1064             wprintw(win, "ERR");
1065             wgetch_wrap(win, first_y);
1066         } else if (isQuit((int) c)) {
1067             break;
1068         } else if (c == 'e') {
1069             flags[UChar('e')] = !flags[UChar('e')];
1070             setup_getch(win, flags);
1071             wgetch_help(win, flags);
1072         } else if (c == 'g') {
1073             waddstr(win, "getstr test: ");
1074             echo();
1075             code = wgetn_wstr(win, wint_buf, sizeof(wint_buf) - 1);
1076             noecho();
1077             if (code == ERR) {
1078                 wprintw(win, "wgetn_wstr returns an error.");
1079             } else {
1080                 int n;
1081                 for (n = 0; (wchar_buf[n] = (wchar_t) wint_buf[n]) != 0; ++n) {
1082                     ;
1083                 }
1084                 if ((temp = wcstos(wchar_buf)) != 0) {
1085                     wprintw(win, "I saw %d characters:\n\t`%s'.",
1086                             (int) wcslen(wchar_buf), temp);
1087                     free(temp);
1088                 } else {
1089                     wprintw(win, "I saw %d characters (cannot convert).",
1090                             (int) wcslen(wchar_buf));
1091                 }
1092             }
1093             wclrtoeol(win);
1094             wgetch_wrap(win, first_y);
1095         } else if (c == 'k') {
1096             flags[UChar('k')] = !flags[UChar('k')];
1097             setup_getch(win, flags);
1098             wgetch_help(win, flags);
1099         } else if (c == 'm') {
1100             flags[UChar('m')] = !flags[UChar('m')];
1101             setup_getch(win, flags);
1102             wgetch_help(win, flags);
1103         } else if (c == 's') {
1104             ShellOut(TRUE);
1105         } else if (c == 'w') {
1106             int high = getmaxy(win) - 1 - first_y + 1;
1107             int wide = getmaxx(win) - first_x;
1108             int old_y, old_x;
1109             int new_y = first_y + getbegy(win);
1110             int new_x = first_x + getbegx(win);
1111
1112             getyx(win, old_y, old_x);
1113             if (high > 2 && wide > 2) {
1114                 WINDOW *wb = newwin(high, wide, new_y, new_x);
1115                 WINDOW *wi = newwin(high - 2, wide - 2, new_y + 1, new_x + 1);
1116
1117                 box_set(wb, 0, 0);
1118                 wrefresh(wb);
1119                 wmove(wi, 0, 0);
1120                 remember_boxes(level, wi, wb);
1121                 wget_wch_test(level + 1, wi, delay);
1122                 delwin(wi);
1123                 delwin(wb);
1124
1125                 wgetch_help(win, flags);
1126                 wmove(win, old_y, old_x);
1127                 touchwin(win);
1128                 wrefresh(win);
1129             }
1130 #ifdef SIGTSTP
1131         } else if (c == 'z') {
1132             kill(getpid(), SIGTSTP);
1133 #endif
1134         } else {
1135             wprintw(win, "Key pressed: %04o ", (int) c);
1136 #ifdef NCURSES_MOUSE_VERSION
1137             if (c == KEY_MOUSE) {
1138                 show_mouse(win);
1139             } else
1140 #endif /* NCURSES_MOUSE_VERSION */
1141             if (code == KEY_CODE_YES) {
1142 #if defined(KEY_RESIZE) && HAVE_WRESIZE
1143                 if (c == KEY_RESIZE) {
1144                     resize_wide_boxes(level, win);
1145                 }
1146 #endif
1147                 (void) waddstr(win, keyname((wchar_t) c));
1148             } else {
1149                 (void) waddstr(win, key_name((wchar_t) c));
1150                 if (c < 256 && iscntrl(c)) {
1151                     (void) wprintw(win, " (control character)");
1152                 } else {
1153                     (void) wprintw(win, " = %#x (printable character)",
1154                                    (unsigned) c);
1155                 }
1156             }
1157             wgetch_wrap(win, first_y);
1158         }
1159     }
1160
1161     wtimeout(win, -1);
1162
1163     if (!level)
1164         init_getch(win, flags);
1165 }
1166
1167 static void
1168 get_wch_test(void)
1169 {
1170     int delay = begin_getch_test();
1171
1172     slk_restore();
1173     wget_wch_test(0, stdscr, delay);
1174     forget_boxes();
1175     finish_getch_test();
1176     slk_clear();
1177 }
1178 #endif
1179
1180 /****************************************************************************
1181  *
1182  * Character attributes test
1183  *
1184  ****************************************************************************/
1185
1186 #if HAVE_SETUPTERM || HAVE_TGETENT
1187 #define get_ncv() TIGETNUM("ncv","NC")
1188 #define get_xmc() TIGETNUM("xmc","sg")
1189 #else
1190 #define get_ncv() -1
1191 #define get_xmc() -1
1192 #endif
1193
1194 #if !HAVE_TERMATTRS
1195 static chtype
1196 my_termattrs(void)
1197 {
1198     static int first = TRUE;
1199     static chtype result = 0;
1200
1201     if (first) {
1202 #if !HAVE_TIGETSTR
1203         char buffer[4096];
1204         char parsed[4096];
1205         char *area_pointer = parsed;
1206
1207         tgetent(buffer, getenv("TERM"));
1208 #endif
1209
1210         if (TIGETSTR("smso", "so"))
1211             result |= A_STANDOUT;
1212         if (TIGETSTR("smul", "us"))
1213             result |= A_UNDERLINE;
1214         if (TIGETSTR("rev", "mr"))
1215             result |= A_REVERSE;
1216         if (TIGETSTR("blink", "mb"))
1217             result |= A_BLINK;
1218         if (TIGETSTR("dim", "mh"))
1219             result |= A_DIM;
1220         if (TIGETSTR("bold", "md"))
1221             result |= A_BOLD;
1222         if (TIGETSTR("smacs", "ac"))
1223             result |= A_ALTCHARSET;
1224
1225         first = FALSE;
1226     }
1227     return result;
1228 }
1229 #define termattrs() my_termattrs()
1230 #endif
1231
1232 #define MAX_ATTRSTRING 31
1233 #define LEN_ATTRSTRING 26
1234
1235 static char attr_test_string[MAX_ATTRSTRING + 1];
1236
1237 static void
1238 attr_legend(WINDOW *helpwin)
1239 {
1240     int row = 1;
1241     int col = 1;
1242
1243     MvWPrintw(helpwin, row++, col,
1244               "ESC to exit.");
1245     MvWPrintw(helpwin, row++, col,
1246               "^L repaints.");
1247     ++row;
1248     MvWPrintw(helpwin, row++, col,
1249               "Modify the test strings:");
1250     MvWPrintw(helpwin, row++, col,
1251               "  A digit sets gaps on each side of displayed attributes");
1252     MvWPrintw(helpwin, row++, col,
1253               "  </> shifts the text left/right. ");
1254     ++row;
1255     MvWPrintw(helpwin, row++, col,
1256               "Toggles:");
1257     if (use_colors) {
1258         MvWPrintw(helpwin, row++, col,
1259                   "  f/F/b/F toggle foreground/background background color");
1260         MvWPrintw(helpwin, row++, col,
1261                   "  t/T     toggle text/background color attribute");
1262     }
1263     MvWPrintw(helpwin, row++, col,
1264               "  a/A     toggle ACS (alternate character set) mapping");
1265     MvWPrintw(helpwin, row, col,
1266               "  v/V     toggle video attribute to combine with each line");
1267 }
1268
1269 static void
1270 show_color_attr(int fg, int bg, int tx)
1271 {
1272     if (use_colors) {
1273         printw("  Colors (fg %d, bg %d", fg, bg);
1274         if (tx >= 0)
1275             printw(", text %d", tx);
1276         printw("),");
1277     }
1278 }
1279
1280 static bool
1281 cycle_color_attr(int ch, short *fg, short *bg, short *tx)
1282 {
1283     bool error = FALSE;
1284
1285     if (use_colors) {
1286         switch (ch) {
1287         case 'f':
1288             *fg = (short) (*fg + 1);
1289             break;
1290         case 'F':
1291             *fg = (short) (*fg - 1);
1292             break;
1293         case 'b':
1294             *bg = (short) (*bg + 1);
1295             break;
1296         case 'B':
1297             *bg = (short) (*bg - 1);
1298             break;
1299         case 't':
1300             *tx = (short) (*tx + 1);
1301             break;
1302         case 'T':
1303             *tx = (short) (*tx - 1);
1304             break;
1305         default:
1306             beep();
1307             error = TRUE;
1308             break;
1309         }
1310         if (*fg >= COLORS)
1311             *fg = (short) min_colors;
1312         if (*fg < min_colors)
1313             *fg = (short) (COLORS - 1);
1314         if (*bg >= COLORS)
1315             *bg = (short) min_colors;
1316         if (*bg < min_colors)
1317             *bg = (short) (COLORS - 1);
1318         if (*tx >= COLORS)
1319             *tx = -1;
1320         if (*tx < -1)
1321             *tx = (short) (COLORS - 1);
1322     } else {
1323         beep();
1324         error = TRUE;
1325     }
1326     return error;
1327 }
1328
1329 static void
1330 adjust_attr_string(int adjust)
1331 {
1332     int first = ((int) UChar(attr_test_string[0])) + adjust;
1333     int last = first + LEN_ATTRSTRING;
1334
1335     if (first >= ' ' && last <= '~') {  /* 32..126 */
1336         int j, k;
1337         for (j = 0, k = first; j < MAX_ATTRSTRING && k <= last; ++j, ++k) {
1338             attr_test_string[j] = (char) k;
1339             if (((k + 1 - first) % 5) == 0) {
1340                 if (++j >= MAX_ATTRSTRING)
1341                     break;
1342                 attr_test_string[j] = ' ';
1343             }
1344         }
1345         while (j < MAX_ATTRSTRING)
1346             attr_test_string[j++] = ' ';
1347         attr_test_string[j] = '\0';
1348     } else {
1349         beep();
1350     }
1351 }
1352
1353 static void
1354 init_attr_string(void)
1355 {
1356     attr_test_string[0] = 'a';
1357     adjust_attr_string(0);
1358 }
1359
1360 static int
1361 show_attr(int row, int skip, bool arrow, chtype attr, const char *name)
1362 {
1363     int ncv = get_ncv();
1364     chtype test = attr & (chtype) (~A_ALTCHARSET);
1365
1366     if (arrow)
1367         MvPrintw(row, 5, "-->");
1368     MvPrintw(row, 8, "%s mode:", name);
1369     MvPrintw(row, 24, "|");
1370     if (skip)
1371         printw("%*s", skip, " ");
1372     /*
1373      * Just for testing, write text using the alternate character set one
1374      * character at a time (to pass its rendition directly), and use the
1375      * string operation for the other attributes.
1376      */
1377     if (attr & A_ALTCHARSET) {
1378         const char *s;
1379         chtype ch;
1380
1381         for (s = attr_test_string; *s != '\0'; ++s) {
1382             ch = UChar(*s);
1383             addch(ch | attr);
1384         }
1385     } else {
1386         (void) attrset(attr);
1387         addstr(attr_test_string);
1388         attroff(attr);
1389     }
1390     if (skip)
1391         printw("%*s", skip, " ");
1392     printw("|");
1393     if (test != A_NORMAL) {
1394         if (!(termattrs() & test)) {
1395             printw(" (N/A)");
1396         } else {
1397             if (ncv > 0 && stdscr && (getbkgd(stdscr) & A_COLOR)) {
1398                 static const chtype table[] =
1399                 {
1400                     A_STANDOUT,
1401                     A_UNDERLINE,
1402                     A_REVERSE,
1403                     A_BLINK,
1404                     A_DIM,
1405                     A_BOLD,
1406 #ifdef A_INVIS
1407                     A_INVIS,
1408 #endif
1409                     A_PROTECT,
1410                     A_ALTCHARSET
1411                 };
1412                 unsigned n;
1413                 bool found = FALSE;
1414                 for (n = 0; n < SIZEOF(table); n++) {
1415                     if ((table[n] & attr) != 0
1416                         && ((1 << n) & ncv) != 0) {
1417                         found = TRUE;
1418                         break;
1419                     }
1420                 }
1421                 if (found)
1422                     printw(" (NCV)");
1423             }
1424             if ((termattrs() & test) != test)
1425                 printw(" (Part)");
1426         }
1427     }
1428     return row + 2;
1429 }
1430 /* *INDENT-OFF* */
1431 static const struct {
1432     chtype                      attr;
1433     NCURSES_CONST char *        name;
1434 } attrs_to_test[] = {
1435     { A_STANDOUT,       "STANDOUT" },
1436     { A_REVERSE,        "REVERSE" },
1437     { A_BOLD,           "BOLD" },
1438     { A_UNDERLINE,      "UNDERLINE" },
1439     { A_DIM,            "DIM" },
1440     { A_BLINK,          "BLINK" },
1441     { A_PROTECT,        "PROTECT" },
1442 #ifdef A_INVIS
1443     { A_INVIS,          "INVISIBLE" },
1444 #endif
1445     { A_NORMAL,         "NORMAL" },
1446 };
1447 /* *INDENT-ON* */
1448
1449 static bool
1450 attr_getc(int *skip, short *fg, short *bg, short *tx, int *ac, unsigned *kc)
1451 {
1452     bool result = TRUE;
1453     bool error = FALSE;
1454     WINDOW *helpwin;
1455
1456     do {
1457         int ch = Getchar();
1458
1459         error = FALSE;
1460         if (ch < 256 && isdigit(ch)) {
1461             *skip = (ch - '0');
1462         } else {
1463             switch (ch) {
1464             case CTRL('L'):
1465                 Repaint();
1466                 break;
1467             case '?':
1468                 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
1469                     box(helpwin, 0, 0);
1470                     attr_legend(helpwin);
1471                     wGetchar(helpwin);
1472                     delwin(helpwin);
1473                 }
1474                 break;
1475             case 'a':
1476                 *ac = 0;
1477                 break;
1478             case 'A':
1479                 *ac = A_ALTCHARSET;
1480                 break;
1481             case 'v':
1482                 if (*kc == 0)
1483                     *kc = SIZEOF(attrs_to_test) - 1;
1484                 else
1485                     *kc -= 1;
1486                 break;
1487             case 'V':
1488                 *kc += 1;
1489                 if (*kc >= SIZEOF(attrs_to_test))
1490                     *kc = 0;
1491                 break;
1492             case '<':
1493                 adjust_attr_string(-1);
1494                 break;
1495             case '>':
1496                 adjust_attr_string(1);
1497                 break;
1498             case case_QUIT:
1499                 result = FALSE;
1500                 break;
1501             default:
1502                 error = cycle_color_attr(ch, fg, bg, tx);
1503                 break;
1504             }
1505         }
1506     } while (error);
1507     return result;
1508 }
1509
1510 static void
1511 attr_test(void)
1512 /* test text attributes */
1513 {
1514     int n;
1515     int skip = get_xmc();
1516     short fg = COLOR_BLACK;     /* color pair 0 is special */
1517     short bg = COLOR_BLACK;
1518     short tx = -1;
1519     int ac = 0;
1520     unsigned j, k;
1521
1522     if (skip < 0)
1523         skip = 0;
1524
1525     n = skip;                   /* make it easy */
1526     k = SIZEOF(attrs_to_test) - 1;
1527     init_attr_string();
1528
1529     do {
1530         int row = 2;
1531         chtype normal = A_NORMAL | BLANK;
1532         chtype extras = (chtype) ac;
1533
1534         if (use_colors) {
1535             short pair = (short) (fg != COLOR_BLACK || bg != COLOR_BLACK);
1536             if (pair != 0) {
1537                 pair = 1;
1538                 if (init_pair(pair, fg, bg) == ERR) {
1539                     beep();
1540                 } else {
1541                     normal |= (chtype) COLOR_PAIR(pair);
1542                 }
1543             }
1544             if (tx >= 0) {
1545                 pair = 2;
1546                 if (init_pair(pair, tx, bg) == ERR) {
1547                     beep();
1548                 } else {
1549                     extras |= (chtype) COLOR_PAIR(pair);
1550                 }
1551             }
1552         }
1553         bkgd(normal);
1554         bkgdset(normal);
1555         erase();
1556
1557         box(stdscr, 0, 0);
1558         MvAddStr(0, 20, "Character attribute test display");
1559
1560         for (j = 0; j < SIZEOF(attrs_to_test); ++j) {
1561             bool arrow = (j == k);
1562             row = show_attr(row, n, arrow,
1563                             extras |
1564                             attrs_to_test[j].attr |
1565                             attrs_to_test[k].attr,
1566                             attrs_to_test[j].name);
1567         }
1568
1569         MvPrintw(row, 8,
1570                  "This terminal does %shave the magic-cookie glitch",
1571                  get_xmc() > -1 ? "" : "not ");
1572         MvPrintw(row + 1, 8, "Enter '?' for help.");
1573         show_color_attr(fg, bg, tx);
1574         printw("  ACS (%d)", ac != 0);
1575
1576         refresh();
1577     } while (attr_getc(&n, &fg, &bg, &tx, &ac, &k));
1578
1579     bkgdset(A_NORMAL | BLANK);
1580     erase();
1581     endwin();
1582 }
1583
1584 #if USE_WIDEC_SUPPORT
1585 static wchar_t wide_attr_test_string[MAX_ATTRSTRING + 1];
1586
1587 static void
1588 wide_adjust_attr_string(int adjust)
1589 {
1590     int first = ((int) UChar(wide_attr_test_string[0])) + adjust;
1591     int last = first + LEN_ATTRSTRING;
1592
1593     if (first >= ' ' && last <= '~') {  /* 32..126 */
1594         int j, k;
1595         for (j = 0, k = first; j < MAX_ATTRSTRING && k <= last; ++j, ++k) {
1596             wide_attr_test_string[j] = k;
1597             if (((k + 1 - first) % 5) == 0) {
1598                 if (++j >= MAX_ATTRSTRING)
1599                     break;
1600                 wide_attr_test_string[j] = ' ';
1601             }
1602         }
1603         while (j < MAX_ATTRSTRING)
1604             wide_attr_test_string[j++] = ' ';
1605         wide_attr_test_string[j] = '\0';
1606     } else {
1607         beep();
1608     }
1609 }
1610
1611 static void
1612 wide_init_attr_string(void)
1613 {
1614     wide_attr_test_string[0] = 'a';
1615     wide_adjust_attr_string(0);
1616 }
1617
1618 static void
1619 set_wide_background(short pair)
1620 {
1621     cchar_t normal;
1622     wchar_t blank[2];
1623
1624     blank[0] = ' ';
1625     blank[1] = 0;
1626     setcchar(&normal, blank, A_NORMAL, pair, 0);
1627     bkgrnd(&normal);
1628     bkgrndset(&normal);
1629 }
1630
1631 static attr_t
1632 get_wide_background(void)
1633 {
1634     attr_t result = A_NORMAL;
1635     attr_t attr;
1636     cchar_t ch;
1637     short pair;
1638     wchar_t wch[10];
1639
1640     if (getbkgrnd(&ch) != ERR) {
1641         if (getcchar(&ch, wch, &attr, &pair, 0) != ERR) {
1642             result = attr;
1643         }
1644     }
1645     return result;
1646 }
1647
1648 static int
1649 wide_show_attr(int row, int skip, bool arrow, chtype attr, short pair, const char *name)
1650 {
1651     int ncv = get_ncv();
1652     chtype test = attr & ~WA_ALTCHARSET;
1653
1654     if (arrow)
1655         MvPrintw(row, 5, "-->");
1656     MvPrintw(row, 8, "%s mode:", name);
1657     MvPrintw(row, 24, "|");
1658     if (skip)
1659         printw("%*s", skip, " ");
1660
1661     /*
1662      * Just for testing, write text using the alternate character set one
1663      * character at a time (to pass its rendition directly), and use the
1664      * string operation for the other attributes.
1665      */
1666     if (attr & WA_ALTCHARSET) {
1667         const wchar_t *s;
1668         cchar_t ch;
1669
1670         for (s = wide_attr_test_string; *s != L'\0'; ++s) {
1671             wchar_t fill[2];
1672             fill[0] = *s;
1673             fill[1] = L'\0';
1674             setcchar(&ch, fill, attr, pair, 0);
1675             add_wch(&ch);
1676         }
1677     } else {
1678         attr_t old_attr;
1679         short old_pair;
1680
1681         (void) attr_get(&old_attr, &old_pair, 0);
1682         (void) attr_set(attr, pair, 0);
1683         addwstr(wide_attr_test_string);
1684         (void) attr_set(old_attr, old_pair, 0);
1685     }
1686     if (skip)
1687         printw("%*s", skip, " ");
1688     printw("|");
1689     if (test != A_NORMAL) {
1690         if (!(term_attrs() & test)) {
1691             printw(" (N/A)");
1692         } else {
1693             if (ncv > 0 && (get_wide_background() & A_COLOR)) {
1694                 static const attr_t table[] =
1695                 {
1696                     WA_STANDOUT,
1697                     WA_UNDERLINE,
1698                     WA_REVERSE,
1699                     WA_BLINK,
1700                     WA_DIM,
1701                     WA_BOLD,
1702                     WA_INVIS,
1703                     WA_PROTECT,
1704                     WA_ALTCHARSET
1705                 };
1706                 unsigned n;
1707                 bool found = FALSE;
1708                 for (n = 0; n < SIZEOF(table); n++) {
1709                     if ((table[n] & attr) != 0
1710                         && ((1 << n) & ncv) != 0) {
1711                         found = TRUE;
1712                         break;
1713                     }
1714                 }
1715                 if (found)
1716                     printw(" (NCV)");
1717             }
1718             if ((term_attrs() & test) != test)
1719                 printw(" (Part)");
1720         }
1721     }
1722     return row + 2;
1723 }
1724
1725 static bool
1726 wide_attr_getc(int *skip, short *fg, short *bg, short *tx, int *ac, unsigned *kc)
1727 {
1728     bool result = TRUE;
1729     bool error = FALSE;
1730     WINDOW *helpwin;
1731
1732     do {
1733         int ch = Getchar();
1734
1735         error = FALSE;
1736         if (ch < 256 && isdigit(ch)) {
1737             *skip = (ch - '0');
1738         } else {
1739             switch (ch) {
1740             case CTRL('L'):
1741                 Repaint();
1742                 break;
1743             case '?':
1744                 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
1745                     box_set(helpwin, 0, 0);
1746                     attr_legend(helpwin);
1747                     wGetchar(helpwin);
1748                     delwin(helpwin);
1749                 }
1750                 break;
1751             case 'a':
1752                 *ac = 0;
1753                 break;
1754             case 'A':
1755                 *ac = A_ALTCHARSET;
1756                 break;
1757             case 'v':
1758                 if (*kc == 0)
1759                     *kc = SIZEOF(attrs_to_test) - 1;
1760                 else
1761                     *kc -= 1;
1762                 break;
1763             case 'V':
1764                 *kc += 1;
1765                 if (*kc >= SIZEOF(attrs_to_test))
1766                     *kc = 0;
1767                 break;
1768             case '<':
1769                 wide_adjust_attr_string(-1);
1770                 break;
1771             case '>':
1772                 wide_adjust_attr_string(1);
1773                 break;
1774             case case_QUIT:
1775                 result = FALSE;
1776                 break;
1777             default:
1778                 error = cycle_color_attr(ch, fg, bg, tx);
1779                 break;
1780             }
1781         }
1782     } while (error);
1783     return result;
1784 }
1785
1786 static void
1787 wide_attr_test(void)
1788 /* test text attributes using wide-character calls */
1789 {
1790     int n;
1791     int skip = get_xmc();
1792     short fg = COLOR_BLACK;     /* color pair 0 is special */
1793     short bg = COLOR_BLACK;
1794     short tx = -1;
1795     int ac = 0;
1796     unsigned j, k;
1797
1798     if (skip < 0)
1799         skip = 0;
1800
1801     n = skip;                   /* make it easy */
1802     k = SIZEOF(attrs_to_test) - 1;
1803     wide_init_attr_string();
1804
1805     do {
1806         int row = 2;
1807         short pair = 0;
1808         short extras = 0;
1809
1810         if (use_colors) {
1811             pair = (short) (fg != COLOR_BLACK || bg != COLOR_BLACK);
1812             if (pair != 0) {
1813                 pair = 1;
1814                 if (init_pair(pair, fg, bg) == ERR) {
1815                     beep();
1816                 }
1817             }
1818             extras = pair;
1819             if (tx >= 0) {
1820                 extras = 2;
1821                 if (init_pair(extras, tx, bg) == ERR) {
1822                     beep();
1823                 }
1824             }
1825         }
1826         set_wide_background(pair);
1827         erase();
1828
1829         box_set(stdscr, 0, 0);
1830         MvAddStr(0, 20, "Character attribute test display");
1831
1832         for (j = 0; j < SIZEOF(attrs_to_test); ++j) {
1833             row = wide_show_attr(row, n, j == k,
1834                                  ((attr_t) ac |
1835                                   attrs_to_test[j].attr |
1836                                   attrs_to_test[k].attr),
1837                                  extras,
1838                                  attrs_to_test[j].name);
1839         }
1840
1841         MvPrintw(row, 8,
1842                  "This terminal does %shave the magic-cookie glitch",
1843                  get_xmc() > -1 ? "" : "not ");
1844         MvPrintw(row + 1, 8, "Enter '?' for help.");
1845         show_color_attr(fg, bg, tx);
1846         printw("  ACS (%d)", ac != 0);
1847
1848         refresh();
1849     } while (wide_attr_getc(&n, &fg, &bg, &tx, &ac, &k));
1850
1851     set_wide_background(0);
1852     erase();
1853     endwin();
1854 }
1855 #endif
1856
1857 /****************************************************************************
1858  *
1859  * Color support tests
1860  *
1861  ****************************************************************************/
1862
1863 static NCURSES_CONST char *the_color_names[] =
1864 {
1865     "black",
1866     "red",
1867     "green",
1868     "yellow",
1869     "blue",
1870     "magenta",
1871     "cyan",
1872     "white",
1873     "BLACK",
1874     "RED",
1875     "GREEN",
1876     "YELLOW",
1877     "BLUE",
1878     "MAGENTA",
1879     "CYAN",
1880     "WHITE"
1881 };
1882
1883 static void
1884 show_color_name(int y, int x, int color, bool wide)
1885 {
1886     if (move(y, x) != ERR) {
1887         char temp[80];
1888         int width = 8;
1889
1890         if (wide) {
1891             sprintf(temp, "%02d", color);
1892             width = 4;
1893         } else if (color >= 8) {
1894             sprintf(temp, "[%02d]", color);
1895         } else if (color < 0) {
1896             strcpy(temp, "default");
1897         } else {
1898             strcpy(temp, the_color_names[color]);
1899         }
1900         printw("%-*.*s", width, width, temp);
1901     }
1902 }
1903
1904 static void
1905 color_legend(WINDOW *helpwin, bool wide)
1906 {
1907     int row = 1;
1908     int col = 1;
1909
1910     MvWPrintw(helpwin, row++, col,
1911               "ESC to exit.");
1912     ++row;
1913     MvWPrintw(helpwin, row++, col,
1914               "Use up/down arrow to scroll through the display if it is");
1915     MvWPrintw(helpwin, row++, col,
1916               "longer than one screen. Control/N and Control/P can be used");
1917     MvWPrintw(helpwin, row++, col,
1918               "in place of up/down arrow.  Use pageup/pagedown to scroll a");
1919     MvWPrintw(helpwin, row++, col,
1920               "full screen; control/B and control/F can be used here.");
1921     ++row;
1922     MvWPrintw(helpwin, row++, col,
1923               "Toggles:");
1924     MvWPrintw(helpwin, row++, col,
1925               "  a/A     toggle altcharset off/on");
1926     MvWPrintw(helpwin, row++, col,
1927               "  b/B     toggle bold off/on");
1928     MvWPrintw(helpwin, row++, col,
1929               "  n/N     toggle text/number on/off");
1930     MvWPrintw(helpwin, row++, col,
1931               "  r/R     toggle reverse on/off");
1932     MvWPrintw(helpwin, row++, col,
1933               "  w/W     toggle width between 8/16 colors");
1934 #if USE_WIDEC_SUPPORT
1935     if (wide) {
1936         MvWPrintw(helpwin, row++, col,
1937                   "Wide characters:");
1938         MvWPrintw(helpwin, row, col,
1939                   "  x/X     toggle text between ASCII and wide-character");
1940     }
1941 #else
1942     (void) wide;
1943 #endif
1944 }
1945
1946 #define set_color_test(name, value) if (name != value) { name = value; base_row = 0; }
1947
1948 /* generate a color test pattern */
1949 static void
1950 color_test(void)
1951 {
1952     short i;
1953     int top = 0, width;
1954     int base_row = 0;
1955     int grid_top = top + 3;
1956     int page_size = (LINES - grid_top);
1957     int pairs_max = PAIR_NUMBER(A_COLOR) + 1;
1958     int row_limit;
1959     int per_row;
1960     char numbered[80];
1961     const char *hello;
1962     bool done = FALSE;
1963     bool opt_acsc = FALSE;
1964     bool opt_bold = FALSE;
1965     bool opt_revs = FALSE;
1966     bool opt_nums = FALSE;
1967     bool opt_wide = FALSE;
1968     WINDOW *helpwin;
1969
1970     if (COLORS * COLORS == COLOR_PAIRS) {
1971         int limit = (COLORS - min_colors) * (COLORS - min_colors);
1972         if (pairs_max > limit)
1973             pairs_max = limit;
1974     } else {
1975         if (pairs_max > COLOR_PAIRS)
1976             pairs_max = COLOR_PAIRS;
1977     }
1978
1979     while (!done) {
1980         int shown = 0;
1981
1982         /* this assumes an 80-column line */
1983         if (opt_wide) {
1984             width = 4;
1985             hello = "Test";
1986             per_row = (COLORS > 8) ? 16 : 8;
1987         } else {
1988             width = 8;
1989             hello = "Hello";
1990             per_row = 8;
1991         }
1992         per_row -= min_colors;
1993
1994         row_limit = (pairs_max + per_row - 1) / per_row;
1995
1996         move(0, 0);
1997         (void) printw("There are %d color pairs and %d colors%s\n",
1998                       pairs_max, COLORS,
1999                       min_colors ? " besides 'default'" : "");
2000
2001         clrtobot();
2002         MvPrintw(top + 1, 0,
2003                  "%dx%d matrix of foreground/background colors, bold *%s*\n",
2004                  row_limit,
2005                  per_row,
2006                  opt_bold ? "on" : "off");
2007
2008         /* show color names/numbers across the top */
2009         for (i = 0; i < per_row; i++)
2010             show_color_name(top + 2, (i + 1) * width, i + min_colors, opt_wide);
2011
2012         /* show a grid of colors, with color names/ numbers on the left */
2013         for (i = (short) (base_row * per_row); i < pairs_max; i++) {
2014             int row = grid_top + (i / per_row) - base_row;
2015             int col = (i % per_row + 1) * width;
2016             short pair = i;
2017
2018 #define InxToFG(i) (short) ((i % (COLORS - min_colors)) + min_colors)
2019 #define InxToBG(i) (short) ((i / (COLORS - min_colors)) + min_colors)
2020             if (row >= 0 && move(row, col) != ERR) {
2021                 short fg = InxToFG(i);
2022                 short bg = InxToBG(i);
2023
2024                 init_pair(pair, fg, bg);
2025                 attron((attr_t) COLOR_PAIR(pair));
2026                 if (opt_acsc)
2027                     attron((attr_t) A_ALTCHARSET);
2028                 if (opt_bold)
2029                     attron((attr_t) A_BOLD);
2030                 if (opt_revs)
2031                     attron((attr_t) A_REVERSE);
2032
2033                 if (opt_nums) {
2034                     sprintf(numbered, "{%02X}", i);
2035                     hello = numbered;
2036                 }
2037                 printw("%-*.*s", width, width, hello);
2038                 (void) attrset(A_NORMAL);
2039
2040                 if ((i % per_row) == 0 && InxToFG(i) == min_colors) {
2041                     show_color_name(row, 0, InxToBG(i), opt_wide);
2042                 }
2043                 ++shown;
2044             } else if (shown) {
2045                 break;
2046             }
2047         }
2048
2049         switch (wGetchar(stdscr)) {
2050         case 'a':
2051             opt_acsc = FALSE;
2052             break;
2053         case 'A':
2054             opt_acsc = TRUE;
2055             break;
2056         case 'b':
2057             opt_bold = FALSE;
2058             break;
2059         case 'B':
2060             opt_bold = TRUE;
2061             break;
2062         case 'n':
2063             opt_nums = FALSE;
2064             break;
2065         case 'N':
2066             opt_nums = TRUE;
2067             break;
2068         case 'r':
2069             opt_revs = FALSE;
2070             break;
2071         case 'R':
2072             opt_revs = TRUE;
2073             break;
2074         case case_QUIT:
2075             done = TRUE;
2076             continue;
2077         case 'w':
2078             set_color_test(opt_wide, FALSE);
2079             break;
2080         case 'W':
2081             set_color_test(opt_wide, TRUE);
2082             break;
2083         case CTRL('p'):
2084         case KEY_UP:
2085             if (base_row <= 0) {
2086                 beep();
2087             } else {
2088                 base_row -= 1;
2089             }
2090             break;
2091         case CTRL('n'):
2092         case KEY_DOWN:
2093             if (base_row + page_size >= row_limit) {
2094                 beep();
2095             } else {
2096                 base_row += 1;
2097             }
2098             break;
2099         case CTRL('b'):
2100         case KEY_PREVIOUS:
2101         case KEY_PPAGE:
2102             if (base_row <= 0) {
2103                 beep();
2104             } else {
2105                 base_row -= (page_size - 1);
2106                 if (base_row < 0)
2107                     base_row = 0;
2108             }
2109             break;
2110         case CTRL('f'):
2111         case KEY_NEXT:
2112         case KEY_NPAGE:
2113             if (base_row + page_size >= row_limit) {
2114                 beep();
2115             } else {
2116                 base_row += page_size - 1;
2117                 if (base_row + page_size >= row_limit) {
2118                     base_row = row_limit - page_size - 1;
2119                 }
2120             }
2121             break;
2122         case '?':
2123             if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
2124                 box(helpwin, 0, 0);
2125                 color_legend(helpwin, FALSE);
2126                 wGetchar(helpwin);
2127                 delwin(helpwin);
2128             }
2129             break;
2130         default:
2131             beep();
2132             continue;
2133         }
2134     }
2135
2136     erase();
2137     endwin();
2138 }
2139
2140 #if USE_WIDEC_SUPPORT
2141 /* generate a color test pattern */
2142 static void
2143 wide_color_test(void)
2144 {
2145     int i;
2146     int top = 0, width;
2147     int base_row = 0;
2148     int grid_top = top + 3;
2149     int page_size = (LINES - grid_top);
2150     int pairs_max = (unsigned short) (-1);
2151     int row_limit;
2152     int per_row;
2153     char numbered[80];
2154     const char *hello;
2155     bool done = FALSE;
2156     bool opt_acsc = FALSE;
2157     bool opt_bold = FALSE;
2158     bool opt_revs = FALSE;
2159     bool opt_wide = FALSE;
2160     bool opt_nums = FALSE;
2161     bool opt_xchr = FALSE;
2162     wchar_t buffer[10];
2163     WINDOW *helpwin;
2164
2165     if (COLORS * COLORS == COLOR_PAIRS) {
2166         int limit = (COLORS - min_colors) * (COLORS - min_colors);
2167         if (pairs_max > limit)
2168             pairs_max = limit;
2169     } else {
2170         if (pairs_max > COLOR_PAIRS)
2171             pairs_max = COLOR_PAIRS;
2172     }
2173
2174     while (!done) {
2175         int shown = 0;
2176
2177         /* this assumes an 80-column line */
2178         if (opt_wide) {
2179             width = 4;
2180             hello = "Test";
2181             per_row = (COLORS > 8) ? 16 : 8;
2182         } else {
2183             width = 8;
2184             hello = "Hello";
2185             per_row = 8;
2186         }
2187         per_row -= min_colors;
2188
2189         if (opt_xchr) {
2190             make_fullwidth_text(buffer, hello);
2191             width *= 2;
2192             per_row /= 2;
2193         } else {
2194             make_narrow_text(buffer, hello);
2195         }
2196
2197         row_limit = (pairs_max + per_row - 1) / per_row;
2198
2199         move(0, 0);
2200         (void) printw("There are %d color pairs and %d colors%s\n",
2201                       pairs_max, COLORS,
2202                       min_colors ? " besides 'default'" : "");
2203
2204         clrtobot();
2205         MvPrintw(top + 1, 0,
2206                  "%dx%d matrix of foreground/background colors, bold *%s*\n",
2207                  row_limit,
2208                  per_row,
2209                  opt_bold ? "on" : "off");
2210
2211         /* show color names/numbers across the top */
2212         for (i = 0; i < per_row; i++)
2213             show_color_name(top + 2, (i + 1) * width, i + min_colors, opt_wide);
2214
2215         /* show a grid of colors, with color names/ numbers on the left */
2216         for (i = (base_row * per_row); i < pairs_max; i++) {
2217             int row = grid_top + (i / per_row) - base_row;
2218             int col = (i % per_row + 1) * width;
2219             short pair = (short) i;
2220
2221             if (row >= 0 && move(row, col) != ERR) {
2222                 init_pair(pair, InxToFG(i), InxToBG(i));
2223                 color_set(pair, NULL);
2224                 if (opt_acsc)
2225                     attr_on((attr_t) A_ALTCHARSET, NULL);
2226                 if (opt_bold)
2227                     attr_on((attr_t) A_BOLD, NULL);
2228                 if (opt_revs)
2229                     attr_on((attr_t) A_REVERSE, NULL);
2230
2231                 if (opt_nums) {
2232                     sprintf(numbered, "{%02X}", i);
2233                     if (opt_xchr) {
2234                         make_fullwidth_text(buffer, numbered);
2235                     } else {
2236                         make_narrow_text(buffer, numbered);
2237                     }
2238                 }
2239                 addnwstr(buffer, width);
2240                 (void) attr_set(A_NORMAL, 0, NULL);
2241
2242                 if ((i % per_row) == 0 && InxToFG(i) == min_colors) {
2243                     show_color_name(row, 0, InxToBG(i), opt_wide);
2244                 }
2245                 ++shown;
2246             } else if (shown) {
2247                 break;
2248             }
2249         }
2250
2251         switch (wGetchar(stdscr)) {
2252         case 'a':
2253             opt_acsc = FALSE;
2254             break;
2255         case 'A':
2256             opt_acsc = TRUE;
2257             break;
2258         case 'b':
2259             opt_bold = FALSE;
2260             break;
2261         case 'B':
2262             opt_bold = TRUE;
2263             break;
2264         case 'n':
2265             opt_nums = FALSE;
2266             break;
2267         case 'N':
2268             opt_nums = TRUE;
2269             break;
2270         case 'r':
2271             opt_revs = FALSE;
2272             break;
2273         case 'R':
2274             opt_revs = TRUE;
2275             break;
2276         case case_QUIT:
2277             done = TRUE;
2278             continue;
2279         case 'w':
2280             set_color_test(opt_wide, FALSE);
2281             break;
2282         case 'W':
2283             set_color_test(opt_wide, TRUE);
2284             break;
2285         case 'x':
2286             opt_xchr = FALSE;
2287             break;
2288         case 'X':
2289             opt_xchr = TRUE;
2290             break;
2291         case CTRL('p'):
2292         case KEY_UP:
2293             if (base_row <= 0) {
2294                 beep();
2295             } else {
2296                 base_row -= 1;
2297             }
2298             break;
2299         case CTRL('n'):
2300         case KEY_DOWN:
2301             if (base_row + page_size >= row_limit) {
2302                 beep();
2303             } else {
2304                 base_row += 1;
2305             }
2306             break;
2307         case CTRL('b'):
2308         case KEY_PREVIOUS:
2309         case KEY_PPAGE:
2310             if (base_row <= 0) {
2311                 beep();
2312             } else {
2313                 base_row -= (page_size - 1);
2314                 if (base_row < 0)
2315                     base_row = 0;
2316             }
2317             break;
2318         case CTRL('f'):
2319         case KEY_NEXT:
2320         case KEY_NPAGE:
2321             if (base_row + page_size >= row_limit) {
2322                 beep();
2323             } else {
2324                 base_row += page_size - 1;
2325                 if (base_row + page_size >= row_limit) {
2326                     base_row = row_limit - page_size - 1;
2327                 }
2328             }
2329             break;
2330         case '?':
2331             if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
2332                 box(helpwin, 0, 0);
2333                 color_legend(helpwin, TRUE);
2334                 wGetchar(helpwin);
2335                 delwin(helpwin);
2336             }
2337             break;
2338         default:
2339             beep();
2340             continue;
2341         }
2342     }
2343
2344     erase();
2345     endwin();
2346 }
2347 #endif /* USE_WIDEC_SUPPORT */
2348
2349 static void
2350 change_color(short current, int field, int value, int usebase)
2351 {
2352     short red, green, blue;
2353
2354     color_content(current, &red, &green, &blue);
2355
2356     switch (field) {
2357     case 0:
2358         red = (short) (usebase ? (red + value) : value);
2359         break;
2360     case 1:
2361         green = (short) (usebase ? (green + value) : value);
2362         break;
2363     case 2:
2364         blue = (short) (usebase ? (blue + value) : value);
2365         break;
2366     }
2367
2368     if (init_color(current, red, green, blue) == ERR)
2369         beep();
2370 }
2371
2372 static void
2373 init_all_colors(void)
2374 {
2375     short c;
2376
2377     for (c = 0; c < COLORS; ++c)
2378         init_color(c,
2379                    all_colors[c].red,
2380                    all_colors[c].green,
2381                    all_colors[c].blue);
2382 }
2383
2384 #define scaled_rgb(n) ((255 * (n)) / 1000)
2385
2386 static void
2387 color_edit(void)
2388 /* display the color test pattern, without trying to edit colors */
2389 {
2390     int i;
2391     int current = 0;
2392     int this_c = 0, value = 0, field = 0;
2393     int last_c;
2394     int top_color = 0;
2395     int page_size = (LINES - 6);
2396
2397     init_all_colors();
2398     refresh();
2399
2400     for (i = 0; i < max_colors; i++)
2401         init_pair((short) i, (short) COLOR_WHITE, (short) i);
2402
2403     MvPrintw(LINES - 2, 0, "Number: %d", value);
2404
2405     do {
2406         short red, green, blue;
2407
2408         attron(A_BOLD);
2409         MvAddStr(0, 20, "Color RGB Value Editing");
2410         attroff(A_BOLD);
2411
2412         for (i = (short) top_color;
2413              (i - top_color < page_size)
2414              && (i < max_colors); i++) {
2415             char numeric[80];
2416
2417             sprintf(numeric, "[%d]", i);
2418             MvPrintw(2 + i - top_color, 0, "%c %-8s:",
2419                      (i == current ? '>' : ' '),
2420                      (i < (int) SIZEOF(the_color_names)
2421                       ? the_color_names[i] : numeric));
2422             (void) attrset((attr_t) COLOR_PAIR(i));
2423             addstr("        ");
2424             (void) attrset(A_NORMAL);
2425
2426             color_content((short) i, &red, &green, &blue);
2427             addstr("   R = ");
2428             if (current == i && field == 0)
2429                 attron(A_STANDOUT);
2430             printw("%04d", red);
2431             if (current == i && field == 0)
2432                 (void) attrset(A_NORMAL);
2433             addstr(", G = ");
2434             if (current == i && field == 1)
2435                 attron(A_STANDOUT);
2436             printw("%04d", green);
2437             if (current == i && field == 1)
2438                 (void) attrset(A_NORMAL);
2439             addstr(", B = ");
2440             if (current == i && field == 2)
2441                 attron(A_STANDOUT);
2442             printw("%04d", blue);
2443             if (current == i && field == 2)
2444                 (void) attrset(A_NORMAL);
2445             (void) attrset(A_NORMAL);
2446             printw(" ( %3d %3d %3d )",
2447                    scaled_rgb(red),
2448                    scaled_rgb(green),
2449                    scaled_rgb(blue));
2450         }
2451
2452         MvAddStr(LINES - 3, 0,
2453                  "Use up/down to select a color, left/right to change fields.");
2454         MvAddStr(LINES - 2, 0,
2455                  "Modify field by typing nnn=, nnn-, or nnn+.  ? for help.");
2456
2457         move(2 + current - top_color, 0);
2458
2459         last_c = this_c;
2460         this_c = Getchar();
2461         if (this_c < 256 && isdigit(this_c) && !isdigit(last_c))
2462             value = 0;
2463
2464         switch (this_c) {
2465         case CTRL('b'):
2466         case KEY_PPAGE:
2467             if (current > 0)
2468                 current -= (page_size - 1);
2469             else
2470                 beep();
2471             break;
2472
2473         case CTRL('f'):
2474         case KEY_NPAGE:
2475             if (current < (max_colors - 1))
2476                 current += (page_size - 1);
2477             else
2478                 beep();
2479             break;
2480
2481         case CTRL('p'):
2482         case KEY_UP:
2483             current = (current == 0 ? (max_colors - 1) : current - 1);
2484             break;
2485
2486         case CTRL('n'):
2487         case KEY_DOWN:
2488             current = (current == (max_colors - 1) ? 0 : current + 1);
2489             break;
2490
2491         case KEY_RIGHT:
2492             field = (field == 2 ? 0 : field + 1);
2493             break;
2494
2495         case KEY_LEFT:
2496             field = (field == 0 ? 2 : field - 1);
2497             break;
2498
2499         case '0':
2500         case '1':
2501         case '2':
2502         case '3':
2503         case '4':
2504         case '5':
2505         case '6':
2506         case '7':
2507         case '8':
2508         case '9':
2509             value = value * 10 + (this_c - '0');
2510             break;
2511
2512         case '+':
2513             change_color((short) current, field, value, 1);
2514             break;
2515
2516         case '-':
2517             change_color((short) current, field, -value, 1);
2518             break;
2519
2520         case '=':
2521             change_color((short) current, field, value, 0);
2522             break;
2523
2524         case '?':
2525             erase();
2526             P("                      RGB Value Editing Help");
2527             P("");
2528             P("You are in the RGB value editor.  Use the arrow keys to select one of");
2529             P("the fields in one of the RGB triples of the current colors; the one");
2530             P("currently selected will be reverse-video highlighted.");
2531             P("");
2532             P("To change a field, enter the digits of the new value; they are echoed");
2533             P("as entered.  Finish by typing `='.  The change will take effect instantly.");
2534             P("To increment or decrement a value, use the same procedure, but finish");
2535             P("with a `+' or `-'.");
2536             P("");
2537             P("Press 'm' to invoke the top-level menu with the current color settings.");
2538             P("To quit, do ESC");
2539
2540             Pause();
2541             erase();
2542             break;
2543
2544         case 'm':
2545             endwin();
2546             main_menu(FALSE);
2547             for (i = 0; i < max_colors; i++)
2548                 init_pair((short) i, (short) COLOR_WHITE, (short) i);
2549             refresh();
2550             break;
2551
2552         case case_QUIT:
2553             break;
2554
2555         default:
2556             beep();
2557             break;
2558         }
2559
2560         if (current < 0)
2561             current = 0;
2562         if (current >= max_colors)
2563             current = max_colors - 1;
2564         if (current < top_color)
2565             top_color = current;
2566         if (current - top_color >= page_size)
2567             top_color = current - (page_size - 1);
2568
2569         MvPrintw(LINES - 1, 0, "Number: %d", value);
2570         clrtoeol();
2571     } while
2572         (!isQuit(this_c));
2573
2574     erase();
2575
2576     /*
2577      * ncurses does not reset each color individually when calling endwin().
2578      */
2579     init_all_colors();
2580
2581     endwin();
2582 }
2583
2584 /****************************************************************************
2585  *
2586  * Alternate character-set stuff
2587  *
2588  ****************************************************************************/
2589 /* *INDENT-OFF* */
2590 static struct {
2591     chtype attr;
2592     const char *name;
2593 } attrs_to_cycle[] = {
2594     { A_NORMAL,         "normal" },
2595     { A_BOLD,           "bold" },
2596     { A_BLINK,          "blink" },
2597     { A_REVERSE,        "reverse" },
2598     { A_UNDERLINE,      "underline" },
2599 };
2600 /* *INDENT-ON* */
2601
2602 static bool
2603 cycle_attr(int ch, unsigned *at_code, chtype *attr)
2604 {
2605     bool result = TRUE;
2606
2607     switch (ch) {
2608     case 'v':
2609         if ((*at_code += 1) >= SIZEOF(attrs_to_cycle))
2610             *at_code = 0;
2611         break;
2612     case 'V':
2613         if (*at_code == 0)
2614             *at_code = SIZEOF(attrs_to_cycle) - 1;
2615         else
2616             *at_code -= 1;
2617         break;
2618     default:
2619         result = FALSE;
2620         break;
2621     }
2622     if (result)
2623         *attr = attrs_to_cycle[*at_code].attr;
2624     return result;
2625 }
2626
2627 static bool
2628 cycle_colors(int ch, int *fg, int *bg, short *pair)
2629 {
2630     bool result = FALSE;
2631
2632     if (use_colors) {
2633         result = TRUE;
2634         switch (ch) {
2635         case 'F':
2636             if ((*fg -= 1) < 0)
2637                 *fg = COLORS - 1;
2638             break;
2639         case 'f':
2640             if ((*fg += 1) >= COLORS)
2641                 *fg = 0;
2642             break;
2643         case 'B':
2644             if ((*bg -= 1) < 0)
2645                 *bg = COLORS - 1;
2646             break;
2647         case 'b':
2648             if ((*bg += 1) >= COLORS)
2649                 *bg = 0;
2650             break;
2651         default:
2652             result = FALSE;
2653             break;
2654         }
2655         if (result) {
2656             *pair = (short) (*fg != COLOR_BLACK || *bg != COLOR_BLACK);
2657             if (*pair != 0) {
2658                 *pair = 1;
2659                 if (init_pair(*pair, (short) *fg, (short) *bg) == ERR) {
2660                     result = FALSE;
2661                 }
2662             }
2663         }
2664     }
2665     return result;
2666 }
2667
2668 /****************************************************************************
2669  *
2670  * Soft-key label test
2671  *
2672  ****************************************************************************/
2673
2674 #if USE_SOFTKEYS
2675
2676 #define SLK_HELP 17
2677 #define SLK_WORK (SLK_HELP + 3)
2678
2679 static void
2680 slk_help(void)
2681 {
2682     static const char *table[] =
2683     {
2684         "Available commands are:"
2685         ,""
2686         ,"^L         -- repaint this message and activate soft keys"
2687         ,"a/d        -- activate/disable soft keys"
2688         ,"c          -- set centered format for labels"
2689         ,"l          -- set left-justified format for labels"
2690         ,"r          -- set right-justified format for labels"
2691         ,"[12345678] -- set label; labels are numbered 1 through 8"
2692         ,"e          -- erase stdscr (should not erase labels)"
2693         ,"s          -- test scrolling of shortened screen"
2694         ,"v/V        -- cycle through video attributes"
2695 #if HAVE_SLK_COLOR
2696         ,"F/f/B/b    -- cycle through foreground/background colors"
2697 #endif
2698         ,"ESC        -- return to main menu"
2699         ,""
2700         ,"Note: if activating the soft keys causes your terminal to scroll up"
2701         ,"one line, your terminal auto-scrolls when anything is written to the"
2702         ,"last screen position.  The ncurses code does not yet handle this"
2703         ,"gracefully."
2704     };
2705     unsigned j;
2706
2707     move(2, 0);
2708     for (j = 0; j < SIZEOF(table); ++j) {
2709         P(table[j]);
2710     }
2711     refresh();
2712 }
2713
2714 #if HAVE_SLK_COLOR
2715 static void
2716 call_slk_color(int fg, int bg)
2717 {
2718     init_pair(1, (short) bg, (short) fg);
2719     slk_color(1);
2720     MvPrintw(SLK_WORK, 0, "Colors %d/%d\n", fg, bg);
2721     clrtoeol();
2722     slk_touch();
2723     slk_noutrefresh();
2724     refresh();
2725 }
2726 #endif
2727
2728 static void
2729 slk_test(void)
2730 /* exercise the soft keys */
2731 {
2732     int c, fmt = 1;
2733     char buf[9];
2734     char *s;
2735     chtype attr = A_NORMAL;
2736     unsigned at_code = 0;
2737 #if HAVE_SLK_COLOR
2738     int fg = COLOR_BLACK;
2739     int bg = COLOR_WHITE;
2740     short pair = 0;
2741 #endif
2742
2743     c = CTRL('l');
2744 #if HAVE_SLK_COLOR
2745     if (use_colors) {
2746         call_slk_color(fg, bg);
2747     }
2748 #endif
2749
2750     do {
2751         move(0, 0);
2752         switch (c) {
2753         case CTRL('l'):
2754             erase();
2755             attron(A_BOLD);
2756             MvAddStr(0, 20, "Soft Key Exerciser");
2757             attroff(A_BOLD);
2758
2759             slk_help();
2760             /* fall through */
2761
2762         case 'a':
2763             slk_restore();
2764             break;
2765
2766         case 'e':
2767             wclear(stdscr);
2768             break;
2769
2770         case 's':
2771             MvPrintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: ");
2772             while ((c = Getchar()) != 'Q' && (c != ERR))
2773                 addch((chtype) c);
2774             break;
2775
2776         case 'd':
2777             slk_clear();
2778             break;
2779
2780         case 'l':
2781             fmt = 0;
2782             break;
2783
2784         case 'c':
2785             fmt = 1;
2786             break;
2787
2788         case 'r':
2789             fmt = 2;
2790             break;
2791
2792         case '1':
2793         case '2':
2794         case '3':
2795         case '4':
2796         case '5':
2797         case '6':
2798         case '7':
2799         case '8':
2800             MvAddStr(SLK_WORK, 0, "Please enter the label value: ");
2801             strcpy(buf, "");
2802             if ((s = slk_label(c - '0')) != 0) {
2803                 strncpy(buf, s, 8);
2804             }
2805             wGetstring(stdscr, buf, 8);
2806             slk_set((c - '0'), buf, fmt);
2807             slk_refresh();
2808             move(SLK_WORK, 0);
2809             clrtobot();
2810             break;
2811
2812         case case_QUIT:
2813             goto done;
2814
2815 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
2816         case KEY_RESIZE:
2817             wnoutrefresh(stdscr);
2818             break;
2819 #endif
2820
2821         default:
2822             if (cycle_attr(c, &at_code, &attr)) {
2823                 slk_attrset(attr);
2824                 slk_touch();
2825                 slk_noutrefresh();
2826                 break;
2827             }
2828 #if HAVE_SLK_COLOR
2829             if (cycle_colors(c, &fg, &bg, &pair)) {
2830                 if (use_colors) {
2831                     call_slk_color(fg, bg);
2832                 } else {
2833                     beep();
2834                 }
2835                 break;
2836             }
2837 #endif
2838             beep();
2839             break;
2840         }
2841     } while (!isQuit(c = Getchar()));
2842
2843   done:
2844     slk_clear();
2845     erase();
2846     endwin();
2847 }
2848
2849 #if USE_WIDEC_SUPPORT
2850 #define SLKLEN 8
2851 static void
2852 wide_slk_test(void)
2853 /* exercise the soft keys */
2854 {
2855     int c, fmt = 1;
2856     wchar_t buf[SLKLEN + 1];
2857     char *s;
2858     chtype attr = A_NORMAL;
2859     unsigned at_code = 0;
2860     int fg = COLOR_BLACK;
2861     int bg = COLOR_WHITE;
2862     short pair = 0;
2863
2864     c = CTRL('l');
2865     if (use_colors) {
2866         call_slk_color(fg, bg);
2867     }
2868     do {
2869         move(0, 0);
2870         switch (c) {
2871         case CTRL('l'):
2872             erase();
2873             attr_on(WA_BOLD, NULL);
2874             MvAddStr(0, 20, "Soft Key Exerciser");
2875             attr_off(WA_BOLD, NULL);
2876
2877             slk_help();
2878             /* fall through */
2879
2880         case 'a':
2881             slk_restore();
2882             break;
2883
2884         case 'e':
2885             wclear(stdscr);
2886             break;
2887
2888         case 's':
2889             MvPrintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: ");
2890             while ((c = Getchar()) != 'Q' && (c != ERR))
2891                 addch((chtype) c);
2892             break;
2893
2894         case 'd':
2895             slk_clear();
2896             break;
2897
2898         case 'l':
2899             fmt = 0;
2900             break;
2901
2902         case 'c':
2903             fmt = 1;
2904             break;
2905
2906         case 'r':
2907             fmt = 2;
2908             break;
2909
2910         case '1':
2911         case '2':
2912         case '3':
2913         case '4':
2914         case '5':
2915         case '6':
2916         case '7':
2917         case '8':
2918             MvAddStr(SLK_WORK, 0, "Please enter the label value: ");
2919             *buf = 0;
2920             if ((s = slk_label(c - '0')) != 0) {
2921                 char *temp = strdup(s);
2922                 size_t used = strlen(temp);
2923                 size_t want = SLKLEN;
2924                 size_t test;
2925 #ifndef state_unused
2926                 mbstate_t state;
2927 #endif
2928
2929                 buf[0] = L'\0';
2930                 while (want > 0 && used != 0) {
2931                     const char *base = s;
2932                     reset_mbytes(state);
2933                     test = count_mbytes(base, 0, &state);
2934                     if (test == (size_t) -1) {
2935                         temp[--used] = 0;
2936                     } else if (test > want) {
2937                         temp[--used] = 0;
2938                     } else {
2939                         reset_mbytes(state);
2940                         trans_mbytes(buf, base, want, &state);
2941                         break;
2942                     }
2943                 }
2944                 free(temp);
2945             }
2946             wGet_wstring(stdscr, buf, SLKLEN);
2947             slk_wset((c - '0'), buf, fmt);
2948             slk_refresh();
2949             move(SLK_WORK, 0);
2950             clrtobot();
2951             break;
2952
2953         case case_QUIT:
2954             goto done;
2955
2956         case 'F':
2957             if (use_colors) {
2958                 fg = (short) ((fg + 1) % COLORS);
2959                 call_slk_color(fg, bg);
2960             }
2961             break;
2962         case 'B':
2963             if (use_colors) {
2964                 bg = (short) ((bg + 1) % COLORS);
2965                 call_slk_color(fg, bg);
2966             }
2967             break;
2968 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
2969         case KEY_RESIZE:
2970             wnoutrefresh(stdscr);
2971             break;
2972 #endif
2973         default:
2974             if (cycle_attr(c, &at_code, &attr)) {
2975                 slk_attr_set(attr, (fg || bg), NULL);
2976                 slk_touch();
2977                 slk_noutrefresh();
2978                 break;
2979             }
2980 #if HAVE_SLK_COLOR
2981             if (cycle_colors(c, &fg, &bg, &pair)) {
2982                 if (use_colors) {
2983                     call_slk_color(fg, bg);
2984                 } else {
2985                     beep();
2986                 }
2987                 break;
2988             }
2989 #endif
2990             beep();
2991             break;
2992         }
2993     } while (!isQuit(c = Getchar()));
2994
2995   done:
2996     slk_clear();
2997     erase();
2998     endwin();
2999 }
3000 #endif
3001 #endif /* SLK_INIT */
3002
3003 /* ISO 6429:  codes 0x80 to 0x9f may be control characters that cause the
3004  * terminal to perform functions.  The remaining codes can be graphic.
3005  */
3006 static void
3007 show_upper_chars(unsigned first, int repeat, attr_t attr, short pair)
3008 {
3009     bool C1 = (first == 128);
3010     unsigned code;
3011     unsigned last = first + 31;
3012     int reply;
3013
3014     erase();
3015     attron(A_BOLD);
3016     MvPrintw(0, 20, "Display of %s Character Codes %d to %d",
3017              C1 ? "C1" : "GR", first, last);
3018     attroff(A_BOLD);
3019     refresh();
3020
3021     for (code = first; code <= last; code++) {
3022         int count = repeat;
3023         int row = 2 + ((int) (code - first) % 16);
3024         int col = ((int) (code - first) / 16) * COLS / 2;
3025         char tmp[80];
3026         sprintf(tmp, "%3u (0x%x)", code, code);
3027         MvPrintw(row, col, "%*s: ", COLS / 4, tmp);
3028
3029         do {
3030             if (C1)
3031                 nodelay(stdscr, TRUE);
3032             echochar(colored_chtype(code, attr, pair));
3033             if (C1) {
3034                 /* (yes, this _is_ crude) */
3035                 while ((reply = Getchar()) != ERR) {
3036                     addch(UChar(reply));
3037                     napms(10);
3038                 }
3039                 nodelay(stdscr, FALSE);
3040             }
3041         } while (--count > 0);
3042     }
3043 }
3044
3045 #define PC_COLS 4
3046
3047 static void
3048 show_pc_chars(int repeat, attr_t attr, short pair)
3049 {
3050     unsigned code;
3051
3052     erase();
3053     attron(A_BOLD);
3054     MvPrintw(0, 20, "Display of PC Character Codes");
3055     attroff(A_BOLD);
3056     refresh();
3057
3058     for (code = 0; code < 16; ++code) {
3059         MvPrintw(2, (int) code * PC_COLS + 8, "%X", code);
3060     }
3061     for (code = 0; code < 256; code++) {
3062         int count = repeat;
3063         int row = 3 + (int) (code / 16) + (code >= 128);
3064         int col = 8 + (int) (code % 16) * PC_COLS;
3065         if ((code % 16) == 0)
3066             MvPrintw(row, 0, "0x%02x:", code);
3067         move(row, col);
3068         do {
3069             switch (code) {
3070             case '\n':
3071             case '\r':
3072             case '\b':
3073             case '\f':
3074             case '\033':
3075             case 0x9b:
3076                 /*
3077                  * Skip the ones that do not work.
3078                  */
3079                 break;
3080             default:
3081                 addch(colored_chtype(code, A_ALTCHARSET | attr, pair));
3082                 break;
3083             }
3084         } while (--count > 0);
3085     }
3086 }
3087
3088 static void
3089 show_box_chars(int repeat, attr_t attr, short pair)
3090 {
3091     (void) repeat;
3092
3093     attr |= (attr_t) COLOR_PAIR(pair);
3094
3095     erase();
3096     attron(A_BOLD);
3097     MvAddStr(0, 20, "Display of the ACS Line-Drawing Set");
3098     attroff(A_BOLD);
3099     refresh();
3100     /* *INDENT-OFF* */
3101     wborder(stdscr,
3102             colored_chtype(ACS_VLINE,    attr, pair),
3103             colored_chtype(ACS_VLINE,    attr, pair),
3104             colored_chtype(ACS_HLINE,    attr, pair),
3105             colored_chtype(ACS_HLINE,    attr, pair),
3106             colored_chtype(ACS_ULCORNER, attr, pair),
3107             colored_chtype(ACS_URCORNER, attr, pair),
3108             colored_chtype(ACS_LLCORNER, attr, pair),
3109             colored_chtype(ACS_LRCORNER, attr, pair));
3110     MvHLine(LINES / 2, 0,        colored_chtype(ACS_HLINE, attr, pair), COLS);
3111     MvVLine(0,         COLS / 2, colored_chtype(ACS_VLINE, attr, pair), LINES);
3112     MvAddCh(0,         COLS / 2, colored_chtype(ACS_TTEE,  attr, pair));
3113     MvAddCh(LINES / 2, COLS / 2, colored_chtype(ACS_PLUS,  attr, pair));
3114     MvAddCh(LINES - 1, COLS / 2, colored_chtype(ACS_BTEE,  attr, pair));
3115     MvAddCh(LINES / 2, 0,        colored_chtype(ACS_LTEE,  attr, pair));
3116     MvAddCh(LINES / 2, COLS - 1, colored_chtype(ACS_RTEE,  attr, pair));
3117     /* *INDENT-ON* */
3118
3119 }
3120
3121 static int
3122 show_1_acs(int n, int repeat, const char *name, chtype code)
3123 {
3124     const int height = 16;
3125     int row = 2 + (n % height);
3126     int col = (n / height) * COLS / 2;
3127
3128     MvPrintw(row, col, "%*s : ", COLS / 4, name);
3129     do {
3130         addch(code);
3131     } while (--repeat > 0);
3132     return n + 1;
3133 }
3134
3135 static void
3136 show_acs_chars(int repeat, attr_t attr, short pair)
3137 /* display the ACS character set */
3138 {
3139     int n;
3140
3141 #define BOTH(name) #name, colored_chtype(name, attr, (chtype) pair)
3142
3143     erase();
3144     attron(A_BOLD);
3145     MvAddStr(0, 20, "Display of the ACS Character Set");
3146     attroff(A_BOLD);
3147     refresh();
3148
3149     n = show_1_acs(0, repeat, BOTH(ACS_ULCORNER));
3150     n = show_1_acs(n, repeat, BOTH(ACS_URCORNER));
3151     n = show_1_acs(n, repeat, BOTH(ACS_LLCORNER));
3152     n = show_1_acs(n, repeat, BOTH(ACS_LRCORNER));
3153
3154     n = show_1_acs(n, repeat, BOTH(ACS_LTEE));
3155     n = show_1_acs(n, repeat, BOTH(ACS_RTEE));
3156     n = show_1_acs(n, repeat, BOTH(ACS_TTEE));
3157     n = show_1_acs(n, repeat, BOTH(ACS_BTEE));
3158
3159     n = show_1_acs(n, repeat, BOTH(ACS_HLINE));
3160     n = show_1_acs(n, repeat, BOTH(ACS_VLINE));
3161
3162     /*
3163      * HPUX's ACS definitions are broken here.  Just give up.
3164      */
3165 #if !(defined(__hpux) && !defined(NCURSES_VERSION))
3166     n = show_1_acs(n, repeat, BOTH(ACS_LARROW));
3167     n = show_1_acs(n, repeat, BOTH(ACS_RARROW));
3168     n = show_1_acs(n, repeat, BOTH(ACS_UARROW));
3169     n = show_1_acs(n, repeat, BOTH(ACS_DARROW));
3170
3171     n = show_1_acs(n, repeat, BOTH(ACS_BLOCK));
3172     n = show_1_acs(n, repeat, BOTH(ACS_BOARD));
3173     n = show_1_acs(n, repeat, BOTH(ACS_LANTERN));
3174     n = show_1_acs(n, repeat, BOTH(ACS_BULLET));
3175     n = show_1_acs(n, repeat, BOTH(ACS_CKBOARD));
3176     n = show_1_acs(n, repeat, BOTH(ACS_DEGREE));
3177     n = show_1_acs(n, repeat, BOTH(ACS_DIAMOND));
3178     n = show_1_acs(n, repeat, BOTH(ACS_PLMINUS));
3179     n = show_1_acs(n, repeat, BOTH(ACS_PLUS));
3180
3181     n = show_1_acs(n, repeat, BOTH(ACS_GEQUAL));
3182     n = show_1_acs(n, repeat, BOTH(ACS_NEQUAL));
3183     n = show_1_acs(n, repeat, BOTH(ACS_LEQUAL));
3184
3185     n = show_1_acs(n, repeat, BOTH(ACS_STERLING));
3186     n = show_1_acs(n, repeat, BOTH(ACS_PI));
3187     n = show_1_acs(n, repeat, BOTH(ACS_S1));
3188     n = show_1_acs(n, repeat, BOTH(ACS_S3));
3189     n = show_1_acs(n, repeat, BOTH(ACS_S7));
3190     (void) show_1_acs(n, repeat, BOTH(ACS_S9));
3191 #endif
3192 }
3193
3194 static void
3195 acs_display(void)
3196 {
3197     int c = 'a';
3198     char *term = getenv("TERM");
3199     const char *pch_kludge = ((term != 0 && strstr(term, "linux"))
3200                               ? "p=PC, "
3201                               : "");
3202     chtype attr = A_NORMAL;
3203     int digit = 0;
3204     int repeat = 1;
3205     int fg = COLOR_BLACK;
3206     int bg = COLOR_BLACK;
3207     unsigned at_code = 0;
3208     short pair = 0;
3209     void (*last_show_acs) (int, attr_t, short) = 0;
3210
3211     do {
3212         switch (c) {
3213         case CTRL('L'):
3214             Repaint();
3215             break;
3216         case 'a':
3217             ToggleAcs(last_show_acs, show_acs_chars);
3218             break;
3219         case 'p':
3220             if (*pch_kludge)
3221                 ToggleAcs(last_show_acs, show_pc_chars);
3222             else
3223                 beep();
3224             break;
3225         case 'x':
3226             ToggleAcs(last_show_acs, show_box_chars);
3227             break;
3228         case '0':
3229         case '1':
3230         case '2':
3231         case '3':
3232             digit = (c - '0');
3233             last_show_acs = 0;
3234             break;
3235         case '-':
3236             if (digit > 0) {
3237                 --digit;
3238                 last_show_acs = 0;
3239             } else {
3240                 beep();
3241             }
3242             break;
3243         case '+':
3244             if (digit < 3) {
3245                 ++digit;
3246                 last_show_acs = 0;
3247             } else {
3248                 beep();
3249             }
3250             break;
3251         case '>':
3252             if (repeat < (COLS / 4))
3253                 ++repeat;
3254             break;
3255         case '<':
3256             if (repeat > 1)
3257                 --repeat;
3258             break;
3259         default:
3260             if (cycle_attr(c, &at_code, &attr)
3261                 || cycle_colors(c, &fg, &bg, &pair)) {
3262                 break;
3263             } else {
3264                 beep();
3265             }
3266             break;
3267         }
3268         if (last_show_acs != 0)
3269             last_show_acs(repeat, attr, pair);
3270         else
3271             show_upper_chars((unsigned) (digit * 32 + 128), repeat, attr, pair);
3272
3273         MvPrintw(LINES - 3, 0,
3274                  "Note: ANSI terminals may not display C1 characters.");
3275         MvPrintw(LINES - 2, 0,
3276                  "Select: a=ACS, x=box, %s0=C1, 1-3,+/- non-ASCII, </> repeat, ESC=quit",
3277                  pch_kludge);
3278         if (use_colors) {
3279             MvPrintw(LINES - 1, 0,
3280                      "v/V, f/F, b/B cycle through video attributes (%s) and color %d/%d.",
3281                      attrs_to_cycle[at_code].name,
3282                      fg, bg);
3283         } else {
3284             MvPrintw(LINES - 1, 0,
3285                      "v/V cycles through video attributes (%s).",
3286                      attrs_to_cycle[at_code].name);
3287         }
3288         refresh();
3289     } while (!isQuit(c = Getchar()));
3290
3291     Pause();
3292     erase();
3293     endwin();
3294 }
3295
3296 #if USE_WIDEC_SUPPORT
3297 static cchar_t *
3298 merge_wide_attr(cchar_t *dst, const cchar_t *src, attr_t attr, short pair)
3299 {
3300     int count;
3301
3302     *dst = *src;
3303     do {
3304         TEST_CCHAR(src, count, {
3305             attr |= (test_attrs & A_ALTCHARSET);
3306             setcchar(dst, test_wch, attr, pair, NULL);
3307         }
3308         , {
3309             ;
3310         });
3311     } while (0);
3312     return dst;
3313 }
3314
3315 static void
3316 show_upper_widechars(int first, int repeat, int space, attr_t attr, short pair)
3317 {
3318     cchar_t temp;
3319     wchar_t code;
3320     int last = first + 31;
3321
3322     erase();
3323     attron(A_BOLD);
3324     MvPrintw(0, 20, "Display of Character Codes %d to %d", first, last);
3325     attroff(A_BOLD);
3326
3327     for (code = first; (int) code <= last; code++) {
3328         int row = 2 + ((code - first) % 16);
3329         int col = ((code - first) / 16) * COLS / 2;
3330         wchar_t codes[10];
3331         char tmp[80];
3332         int count = repeat;
3333         int y, x;
3334
3335         memset(&codes, 0, sizeof(codes));
3336         codes[0] = code;
3337         sprintf(tmp, "%3ld (0x%lx)", (long) code, (long) code);
3338         MvPrintw(row, col, "%*s: ", COLS / 4, tmp);
3339         setcchar(&temp, codes, attr, pair, 0);
3340         do {
3341             /*
3342              * Give non-spacing characters something to combine with.  If we
3343              * don't, they'll bunch up in a heap on the space after the ":".
3344              * Mark them with reverse-video to make them simpler to find on
3345              * the display.
3346              */
3347             if (wcwidth(code) == 0) {
3348                 addch((chtype) space |
3349                       (A_REVERSE ^ attr) |
3350                       (attr_t) COLOR_PAIR(pair));
3351             }
3352             /*
3353              * This could use add_wch(), but is done for comparison with the
3354              * normal 'f' test (and to make a test-case for echo_wchar()).
3355              * The screen will flicker because the erase() at the top of the
3356              * function is met by the builtin refresh() in echo_wchar().
3357              */
3358             echo_wchar(&temp);
3359             /*
3360              * The repeat-count may make text wrap - avoid that.
3361              */
3362             getyx(stdscr, y, x);
3363             if (x >= col + (COLS / 2) - 2)
3364                 break;
3365         } while (--count > 0);
3366     }
3367 }
3368
3369 static int
3370 show_1_wacs(int n, int repeat, const char *name, const cchar_t *code)
3371 {
3372     const int height = 16;
3373     int row = 2 + (n % height);
3374     int col = (n / height) * COLS / 2;
3375
3376     MvPrintw(row, col, "%*s : ", COLS / 4, name);
3377     while (--repeat >= 0) {
3378         add_wch(code);
3379     }
3380     return n + 1;
3381 }
3382
3383 #define MERGE_ATTR(wch) merge_wide_attr(&temp, wch, attr, pair)
3384
3385 static void
3386 show_wacs_chars(int repeat, attr_t attr, short pair)
3387 /* display the wide-ACS character set */
3388 {
3389     cchar_t temp;
3390
3391     int n;
3392
3393 /*#define BOTH2(name) #name, &(name) */
3394 #define BOTH2(name) #name, MERGE_ATTR(name)
3395
3396     erase();
3397     attron(A_BOLD);
3398     MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3399     attroff(A_BOLD);
3400     refresh();
3401
3402     n = show_1_wacs(0, repeat, BOTH2(WACS_ULCORNER));
3403     n = show_1_wacs(n, repeat, BOTH2(WACS_URCORNER));
3404     n = show_1_wacs(n, repeat, BOTH2(WACS_LLCORNER));
3405     n = show_1_wacs(n, repeat, BOTH2(WACS_LRCORNER));
3406
3407     n = show_1_wacs(n, repeat, BOTH2(WACS_LTEE));
3408     n = show_1_wacs(n, repeat, BOTH2(WACS_RTEE));
3409     n = show_1_wacs(n, repeat, BOTH2(WACS_TTEE));
3410     n = show_1_wacs(n, repeat, BOTH2(WACS_BTEE));
3411
3412     n = show_1_wacs(n, repeat, BOTH2(WACS_HLINE));
3413     n = show_1_wacs(n, repeat, BOTH2(WACS_VLINE));
3414
3415     n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3416     n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3417     n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3418     n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3419
3420     n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3421     n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3422     n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3423     n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3424     n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3425     n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3426     n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3427     n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3428     n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3429
3430 #ifdef CURSES_WACS_ARRAY
3431     n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3432     n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3433     n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3434
3435     n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3436     n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3437     n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3438     n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3439     n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3440     (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3441 #endif
3442 }
3443
3444 #ifdef WACS_D_PLUS
3445 static void
3446 show_wacs_chars_double(int repeat, attr_t attr, short pair)
3447 /* display the wide-ACS character set */
3448 {
3449     cchar_t temp;
3450
3451     int n;
3452
3453 /*#define BOTH2(name) #name, &(name) */
3454 #define BOTH2(name) #name, MERGE_ATTR(name)
3455
3456     erase();
3457     attron(A_BOLD);
3458     MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3459     attroff(A_BOLD);
3460     refresh();
3461
3462     n = show_1_wacs(0, repeat, BOTH2(WACS_D_ULCORNER));
3463     n = show_1_wacs(n, repeat, BOTH2(WACS_D_URCORNER));
3464     n = show_1_wacs(n, repeat, BOTH2(WACS_D_LLCORNER));
3465     n = show_1_wacs(n, repeat, BOTH2(WACS_D_LRCORNER));
3466
3467     n = show_1_wacs(n, repeat, BOTH2(WACS_D_LTEE));
3468     n = show_1_wacs(n, repeat, BOTH2(WACS_D_RTEE));
3469     n = show_1_wacs(n, repeat, BOTH2(WACS_D_TTEE));
3470     n = show_1_wacs(n, repeat, BOTH2(WACS_D_BTEE));
3471
3472     n = show_1_wacs(n, repeat, BOTH2(WACS_D_HLINE));
3473     n = show_1_wacs(n, repeat, BOTH2(WACS_D_VLINE));
3474
3475     n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3476     n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3477     n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3478     n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3479
3480     n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3481     n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3482     n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3483     n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3484     n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3485     n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3486     n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3487     n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3488     n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3489
3490 #ifdef CURSES_WACS_ARRAY
3491     n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3492     n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3493     n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3494
3495     n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3496     n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3497     n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3498     n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3499     n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3500     (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3501 #endif
3502 }
3503 #endif
3504
3505 #ifdef WACS_T_PLUS
3506 static void
3507 show_wacs_chars_thick(int repeat, attr_t attr, short pair)
3508 /* display the wide-ACS character set */
3509 {
3510     cchar_t temp;
3511
3512     int n;
3513
3514 /*#define BOTH2(name) #name, &(name) */
3515 #define BOTH2(name) #name, MERGE_ATTR(name)
3516
3517     erase();
3518     attron(A_BOLD);
3519     MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3520     attroff(A_BOLD);
3521     refresh();
3522
3523     n = show_1_wacs(0, repeat, BOTH2(WACS_T_ULCORNER));
3524     n = show_1_wacs(n, repeat, BOTH2(WACS_T_URCORNER));
3525     n = show_1_wacs(n, repeat, BOTH2(WACS_T_LLCORNER));
3526     n = show_1_wacs(n, repeat, BOTH2(WACS_T_LRCORNER));
3527
3528     n = show_1_wacs(n, repeat, BOTH2(WACS_T_LTEE));
3529     n = show_1_wacs(n, repeat, BOTH2(WACS_T_RTEE));
3530     n = show_1_wacs(n, repeat, BOTH2(WACS_T_TTEE));
3531     n = show_1_wacs(n, repeat, BOTH2(WACS_T_BTEE));
3532
3533     n = show_1_wacs(n, repeat, BOTH2(WACS_T_HLINE));
3534     n = show_1_wacs(n, repeat, BOTH2(WACS_T_VLINE));
3535
3536     n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3537     n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3538     n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3539     n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3540
3541     n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3542     n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3543     n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3544     n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3545     n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3546     n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3547     n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3548     n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3549     n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3550
3551 #ifdef CURSES_WACS_ARRAY
3552     n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3553     n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3554     n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3555
3556     n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3557     n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3558     n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3559     n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3560     n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3561     (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3562 #endif
3563 }
3564 #endif
3565
3566 #undef MERGE_ATTR
3567
3568 #define MERGE_ATTR(n,wch) merge_wide_attr(&temp[n], wch, attr, pair)
3569
3570 static void
3571 show_wbox_chars(int repeat, attr_t attr, short pair)
3572 {
3573     cchar_t temp[8];
3574
3575     (void) repeat;
3576     erase();
3577     attron(A_BOLD);
3578     MvAddStr(0, 20, "Display of the Wide-ACS Line-Drawing Set");
3579     attroff(A_BOLD);
3580     refresh();
3581
3582     wborder_set(stdscr,
3583                 MERGE_ATTR(0, WACS_VLINE),
3584                 MERGE_ATTR(1, WACS_VLINE),
3585                 MERGE_ATTR(2, WACS_HLINE),
3586                 MERGE_ATTR(3, WACS_HLINE),
3587                 MERGE_ATTR(4, WACS_ULCORNER),
3588                 MERGE_ATTR(5, WACS_URCORNER),
3589                 MERGE_ATTR(6, WACS_LLCORNER),
3590                 MERGE_ATTR(7, WACS_LRCORNER));
3591     /* *INDENT-OFF* */
3592     (void) mvhline_set(LINES / 2, 0,        MERGE_ATTR(0, WACS_HLINE), COLS);
3593     (void) mvvline_set(0,         COLS / 2, MERGE_ATTR(0, WACS_VLINE), LINES);
3594     (void) mvadd_wch(0,           COLS / 2, MERGE_ATTR(0, WACS_TTEE));
3595     (void) mvadd_wch(LINES / 2,   COLS / 2, MERGE_ATTR(0, WACS_PLUS));
3596     (void) mvadd_wch(LINES - 1,   COLS / 2, MERGE_ATTR(0, WACS_BTEE));
3597     (void) mvadd_wch(LINES / 2,   0,        MERGE_ATTR(0, WACS_LTEE));
3598     (void) mvadd_wch(LINES / 2,   COLS - 1, MERGE_ATTR(0, WACS_RTEE));
3599     /* *INDENT-ON* */
3600
3601 }
3602
3603 #undef MERGE_ATTR
3604
3605 static int
3606 show_2_wacs(int n, const char *name, const char *code, attr_t attr, short pair)
3607 {
3608     const int height = 16;
3609     int row = 2 + (n % height);
3610     int col = (n / height) * COLS / 2;
3611     char temp[80];
3612
3613     MvPrintw(row, col, "%*s : ", COLS / 4, name);
3614     (void) attr_set(attr, pair, 0);
3615     addstr(strcpy(temp, code));
3616     (void) attr_set(A_NORMAL, 0, 0);
3617     return n + 1;
3618 }
3619
3620 #define SHOW_UTF8(n, name, code) show_2_wacs(n, name, code, attr, pair)
3621
3622 static void
3623 show_utf8_chars(int repeat, attr_t attr, short pair)
3624 {
3625     int n;
3626
3627     (void) repeat;
3628     erase();
3629     attron(A_BOLD);
3630     MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3631     attroff(A_BOLD);
3632     refresh();
3633     /* *INDENT-OFF* */
3634     n = SHOW_UTF8(0, "WACS_ULCORNER",   "\342\224\214");
3635     n = SHOW_UTF8(n, "WACS_URCORNER",   "\342\224\220");
3636     n = SHOW_UTF8(n, "WACS_LLCORNER",   "\342\224\224");
3637     n = SHOW_UTF8(n, "WACS_LRCORNER",   "\342\224\230");
3638
3639     n = SHOW_UTF8(n, "WACS_LTEE",       "\342\224\234");
3640     n = SHOW_UTF8(n, "WACS_RTEE",       "\342\224\244");
3641     n = SHOW_UTF8(n, "WACS_TTEE",       "\342\224\254");
3642     n = SHOW_UTF8(n, "WACS_BTEE",       "\342\224\264");
3643
3644     n = SHOW_UTF8(n, "WACS_HLINE",      "\342\224\200");
3645     n = SHOW_UTF8(n, "WACS_VLINE",      "\342\224\202");
3646
3647     n = SHOW_UTF8(n, "WACS_LARROW",     "\342\206\220");
3648     n = SHOW_UTF8(n, "WACS_RARROW",     "\342\206\222");
3649     n = SHOW_UTF8(n, "WACS_UARROW",     "\342\206\221");
3650     n = SHOW_UTF8(n, "WACS_DARROW",     "\342\206\223");
3651
3652     n = SHOW_UTF8(n, "WACS_BLOCK",      "\342\226\256");
3653     n = SHOW_UTF8(n, "WACS_BOARD",      "\342\226\222");
3654     n = SHOW_UTF8(n, "WACS_LANTERN",    "\342\230\203");
3655     n = SHOW_UTF8(n, "WACS_BULLET",     "\302\267");
3656     n = SHOW_UTF8(n, "WACS_CKBOARD",    "\342\226\222");
3657     n = SHOW_UTF8(n, "WACS_DEGREE",     "\302\260");
3658     n = SHOW_UTF8(n, "WACS_DIAMOND",    "\342\227\206");
3659     n = SHOW_UTF8(n, "WACS_PLMINUS",    "\302\261");
3660     n = SHOW_UTF8(n, "WACS_PLUS",       "\342\224\274");
3661     n = SHOW_UTF8(n, "WACS_GEQUAL",     "\342\211\245");
3662     n = SHOW_UTF8(n, "WACS_NEQUAL",     "\342\211\240");
3663     n = SHOW_UTF8(n, "WACS_LEQUAL",     "\342\211\244");
3664
3665     n = SHOW_UTF8(n, "WACS_STERLING",   "\302\243");
3666     n = SHOW_UTF8(n, "WACS_PI",         "\317\200");
3667     n = SHOW_UTF8(n, "WACS_S1",         "\342\216\272");
3668     n = SHOW_UTF8(n, "WACS_S3",         "\342\216\273");
3669     n = SHOW_UTF8(n, "WACS_S7",         "\342\216\274");
3670     (void) SHOW_UTF8(n, "WACS_S9",      "\342\216\275");
3671     /* *INDENT-ON* */
3672
3673 }
3674
3675 /* display the wide-ACS character set */
3676 static void
3677 wide_acs_display(void)
3678 {
3679     int c = 'a';
3680     int digit = 0;
3681     int repeat = 1;
3682     int space = ' ';
3683     chtype attr = A_NORMAL;
3684     int fg = COLOR_BLACK;
3685     int bg = COLOR_BLACK;
3686     unsigned at_code = 0;
3687     short pair = 0;
3688     void (*last_show_wacs) (int, attr_t, short) = 0;
3689
3690     do {
3691         switch (c) {
3692         case CTRL('L'):
3693             Repaint();
3694             break;
3695         case 'a':
3696             ToggleAcs(last_show_wacs, show_wacs_chars);
3697             break;
3698 #ifdef WACS_D_PLUS
3699         case 'd':
3700             ToggleAcs(last_show_wacs, show_wacs_chars_double);
3701             break;
3702 #endif
3703 #ifdef WACS_T_PLUS
3704         case 't':
3705             ToggleAcs(last_show_wacs, show_wacs_chars_thick);
3706             break;
3707 #endif
3708         case 'x':
3709             ToggleAcs(last_show_wacs, show_wbox_chars);
3710             break;
3711         case 'u':
3712             ToggleAcs(last_show_wacs, show_utf8_chars);
3713             break;
3714         default:
3715             if (c < 256 && isdigit(c)) {
3716                 digit = (c - '0');
3717                 last_show_wacs = 0;
3718             } else if (c == '+') {
3719                 ++digit;
3720                 last_show_wacs = 0;
3721             } else if (c == '-' && digit > 0) {
3722                 --digit;
3723                 last_show_wacs = 0;
3724             } else if (c == '>' && repeat < (COLS / 4)) {
3725                 ++repeat;
3726             } else if (c == '<' && repeat > 1) {
3727                 --repeat;
3728             } else if (c == '_') {
3729                 space = (space == ' ') ? '_' : ' ';
3730                 last_show_wacs = 0;
3731             } else if (cycle_attr(c, &at_code, &attr)
3732                        || cycle_colors(c, &fg, &bg, &pair)) {
3733                 if (last_show_wacs != 0)
3734                     break;
3735             } else {
3736                 beep();
3737                 break;
3738             }
3739             break;
3740         }
3741         if (last_show_wacs != 0)
3742             last_show_wacs(repeat, attr, pair);
3743         else
3744             show_upper_widechars(digit * 32 + 128, repeat, space, attr, pair);
3745
3746         MvPrintw(LINES - 3, 0,
3747                  "Select: a/d/t WACS, x box, u UTF-8, 0-9,+/- non-ASCII, </> repeat, ESC=quit");
3748         if (use_colors) {
3749             MvPrintw(LINES - 2, 0,
3750                      "v/V, f/F, b/B cycle through video attributes (%s) and color %d/%d.",
3751                      attrs_to_cycle[at_code].name,
3752                      fg, bg);
3753         } else {
3754             MvPrintw(LINES - 2, 0,
3755                      "v/V cycles through video attributes (%s).",
3756                      attrs_to_cycle[at_code].name);
3757         }
3758         refresh();
3759     } while (!isQuit(c = Getchar()));
3760
3761     Pause();
3762     erase();
3763     endwin();
3764 }
3765
3766 #endif
3767
3768 /*
3769  * Graphic-rendition test (adapted from vttest)
3770  */
3771 static void
3772 test_sgr_attributes(void)
3773 {
3774     int pass;
3775
3776     for (pass = 0; pass < 2; pass++) {
3777         chtype normal = ((pass == 0 ? A_NORMAL : A_REVERSE)) | BLANK;
3778
3779         /* Use non-default colors if possible to exercise bce a little */
3780         if (use_colors) {
3781             init_pair(1, COLOR_WHITE, COLOR_BLUE);
3782             normal |= COLOR_PAIR(1);
3783         }
3784         bkgdset(normal);
3785         erase();
3786         MvPrintw(1, 20, "Graphic rendition test pattern:");