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