ncurses 5.9 - patch 20131012
[ncurses.git] / test / ncurses.c
1 /****************************************************************************
2  * Copyright (c) 1998-2012,2013 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.395 2013/10/12 22:09:33 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 #ifdef A_ITALIC
1433                     A_ITALIC,
1434 #endif
1435                     A_PROTECT,
1436                     A_ALTCHARSET
1437                 };
1438                 unsigned n;
1439                 bool found = FALSE;
1440                 for (n = 0; n < SIZEOF(table); n++) {
1441                     if ((table[n] & attr) != 0
1442                         && ((1 << n) & ncv) != 0) {
1443                         found = TRUE;
1444                         break;
1445                     }
1446                 }
1447                 if (found)
1448                     printw(" (NCV)");
1449             }
1450             if ((termattrs() & test) != test)
1451                 printw(" (Part)");
1452         }
1453     }
1454     return row + 2;
1455 }
1456
1457 typedef struct {
1458     attr_t attr;
1459     NCURSES_CONST char *name;
1460 } ATTR_TBL;
1461 /* *INDENT-OFF* */
1462 static const ATTR_TBL attrs_to_test[] = {
1463     { A_STANDOUT,       "STANDOUT" },
1464     { A_REVERSE,        "REVERSE" },
1465     { A_BOLD,           "BOLD" },
1466     { A_UNDERLINE,      "UNDERLINE" },
1467     { A_DIM,            "DIM" },
1468     { A_BLINK,          "BLINK" },
1469     { A_PROTECT,        "PROTECT" },
1470 #ifdef A_INVIS
1471     { A_INVIS,          "INVISIBLE" },
1472 #endif
1473 #ifdef A_ITALIC
1474     { A_ITALIC,         "ITALIC" },
1475 #endif
1476     { A_NORMAL,         "NORMAL" },
1477 };
1478 /* *INDENT-ON* */
1479
1480 static unsigned
1481 init_attr_list(ATTR_TBL * target, attr_t attrs)
1482 {
1483     unsigned result = 0;
1484     size_t n;
1485
1486     for (n = 0; n < SIZEOF(attrs_to_test); ++n) {
1487         attr_t test = attrs_to_test[n].attr;
1488         if (test == A_NORMAL || (test & attrs) != 0) {
1489             target[result++] = attrs_to_test[n];
1490         }
1491     }
1492     return result;
1493 }
1494
1495 static bool
1496 attr_getc(int *skip, short *fg, short *bg, short *tx, int *ac, unsigned *kc, unsigned limit)
1497 {
1498     bool result = TRUE;
1499     bool error = FALSE;
1500     WINDOW *helpwin;
1501
1502     do {
1503         int ch = Getchar();
1504
1505         error = FALSE;
1506         if (ch < 256 && isdigit(ch)) {
1507             *skip = (ch - '0');
1508         } else {
1509             switch (ch) {
1510             case CTRL('L'):
1511                 Repaint();
1512                 break;
1513             case '?':
1514                 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
1515                     box(helpwin, 0, 0);
1516                     attr_legend(helpwin);
1517                     wGetchar(helpwin);
1518                     delwin(helpwin);
1519                 }
1520                 break;
1521             case 'a':
1522                 *ac = 0;
1523                 break;
1524             case 'A':
1525                 *ac = A_ALTCHARSET;
1526                 break;
1527             case 'v':
1528                 if (*kc == 0)
1529                     *kc = limit - 1;
1530                 else
1531                     *kc -= 1;
1532                 break;
1533             case 'V':
1534                 *kc += 1;
1535                 if (*kc >= limit)
1536                     *kc = 0;
1537                 break;
1538             case '<':
1539                 adjust_attr_string(-1);
1540                 break;
1541             case '>':
1542                 adjust_attr_string(1);
1543                 break;
1544             case case_QUIT:
1545                 result = FALSE;
1546                 break;
1547             default:
1548                 error = cycle_color_attr(ch, fg, bg, tx);
1549                 break;
1550             }
1551         }
1552     } while (error);
1553     return result;
1554 }
1555
1556 static void
1557 attr_test(void)
1558 /* test text attributes */
1559 {
1560     int n;
1561     int skip = get_xmc();
1562     short fg = COLOR_BLACK;     /* color pair 0 is special */
1563     short bg = COLOR_BLACK;
1564     short tx = -1;
1565     int ac = 0;
1566     unsigned j, k;
1567     ATTR_TBL my_list[SIZEOF(attrs_to_test)];
1568     unsigned my_size = init_attr_list(my_list, termattrs());
1569
1570     if (my_size > 1) {
1571         if (skip < 0)
1572             skip = 0;
1573
1574         n = skip;               /* make it easy */
1575         k = my_size - 1;
1576         init_attr_string();
1577
1578         do {
1579             int row = 2;
1580             chtype normal = A_NORMAL | BLANK;
1581             chtype extras = (chtype) ac;
1582
1583             if (use_colors) {
1584                 short pair = (short) (fg != COLOR_BLACK || bg != COLOR_BLACK);
1585                 if (pair != 0) {
1586                     pair = 1;
1587                     if (init_pair(pair, fg, bg) == ERR) {
1588                         beep();
1589                     } else {
1590                         normal |= (chtype) COLOR_PAIR(pair);
1591                     }
1592                 }
1593                 if (tx >= 0) {
1594                     pair = 2;
1595                     if (init_pair(pair, tx, bg) == ERR) {
1596                         beep();
1597                     } else {
1598                         extras |= (chtype) COLOR_PAIR(pair);
1599                     }
1600                 }
1601             }
1602             bkgd(normal);
1603             bkgdset(normal);
1604             erase();
1605
1606             box(stdscr, 0, 0);
1607             MvAddStr(0, 20, "Character attribute test display");
1608
1609             for (j = 0; j < my_size; ++j) {
1610                 bool arrow = (j == k);
1611                 row = show_attr(row, n, arrow,
1612                                 extras |
1613                                 my_list[j].attr |
1614                                 my_list[k].attr,
1615                                 my_list[j].name);
1616             }
1617
1618             MvPrintw(row, 8,
1619                      "This terminal does %shave the magic-cookie glitch",
1620                      get_xmc() > -1 ? "" : "not ");
1621             MvPrintw(row + 1, 8, "Enter '?' for help.");
1622             show_color_attr(fg, bg, tx);
1623             printw("  ACS (%d)", ac != 0);
1624
1625             refresh();
1626         } while (attr_getc(&n, &fg, &bg, &tx, &ac, &k, my_size));
1627
1628         bkgdset(A_NORMAL | BLANK);
1629         erase();
1630         endwin();
1631     } else {
1632         Cannot("does not support video attributes.");
1633     }
1634 }
1635
1636 #if USE_WIDEC_SUPPORT
1637 static wchar_t wide_attr_test_string[MAX_ATTRSTRING + 1];
1638
1639 static void
1640 wide_adjust_attr_string(int adjust)
1641 {
1642     int first = ((int) UChar(wide_attr_test_string[0])) + adjust;
1643     int last = first + LEN_ATTRSTRING;
1644
1645     if (first >= ' ' && last <= '~') {  /* 32..126 */
1646         int j, k;
1647         for (j = 0, k = first; j < MAX_ATTRSTRING && k <= last; ++j, ++k) {
1648             wide_attr_test_string[j] = k;
1649             if (((k + 1 - first) % 5) == 0) {
1650                 if (++j >= MAX_ATTRSTRING)
1651                     break;
1652                 wide_attr_test_string[j] = ' ';
1653             }
1654         }
1655         while (j < MAX_ATTRSTRING)
1656             wide_attr_test_string[j++] = ' ';
1657         wide_attr_test_string[j] = '\0';
1658     } else {
1659         beep();
1660     }
1661 }
1662
1663 static void
1664 wide_init_attr_string(void)
1665 {
1666     wide_attr_test_string[0] = 'a';
1667     wide_adjust_attr_string(0);
1668 }
1669
1670 static void
1671 set_wide_background(short pair)
1672 {
1673     cchar_t normal;
1674     wchar_t blank[2];
1675
1676     blank[0] = ' ';
1677     blank[1] = 0;
1678     setcchar(&normal, blank, A_NORMAL, pair, 0);
1679     bkgrnd(&normal);
1680     bkgrndset(&normal);
1681 }
1682
1683 static attr_t
1684 get_wide_background(void)
1685 {
1686     attr_t result = A_NORMAL;
1687     attr_t attr;
1688     cchar_t ch;
1689     short pair;
1690     wchar_t wch[10];
1691
1692     memset(&ch, 0, sizeof(ch));
1693     if (getbkgrnd(&ch) != ERR) {
1694         if (getcchar(&ch, wch, &attr, &pair, 0) != ERR) {
1695             result = attr;
1696         }
1697     }
1698     return result;
1699 }
1700
1701 static int
1702 wide_show_attr(int row, int skip, bool arrow, chtype attr, short pair, const char *name)
1703 {
1704     int ncv = get_ncv();
1705     chtype test = attr & ~WA_ALTCHARSET;
1706
1707     if (arrow)
1708         MvPrintw(row, 5, "-->");
1709     MvPrintw(row, 8, "%s mode:", name);
1710     MvPrintw(row, 24, "|");
1711     if (skip)
1712         printw("%*s", skip, " ");
1713
1714     /*
1715      * Just for testing, write text using the alternate character set one
1716      * character at a time (to pass its rendition directly), and use the
1717      * string operation for the other attributes.
1718      */
1719     if (attr & WA_ALTCHARSET) {
1720         const wchar_t *s;
1721         cchar_t ch;
1722
1723         for (s = wide_attr_test_string; *s != L'\0'; ++s) {
1724             wchar_t fill[2];
1725             fill[0] = *s;
1726             fill[1] = L'\0';
1727             setcchar(&ch, fill, attr, pair, 0);
1728             add_wch(&ch);
1729         }
1730     } else {
1731         attr_t old_attr = 0;
1732         short old_pair = 0;
1733
1734         (void) (attr_get)(&old_attr, &old_pair, 0);
1735         (void) attr_set(attr, pair, 0);
1736         addwstr(wide_attr_test_string);
1737         (void) attr_set(old_attr, old_pair, 0);
1738     }
1739     if (skip)
1740         printw("%*s", skip, " ");
1741     printw("|");
1742     if (test != A_NORMAL) {
1743         if (!(term_attrs() & test)) {
1744             printw(" (N/A)");
1745         } else {
1746             if (ncv > 0 && (get_wide_background() & A_COLOR)) {
1747                 static const attr_t table[] =
1748                 {
1749                     WA_STANDOUT,
1750                     WA_UNDERLINE,
1751                     WA_REVERSE,
1752                     WA_BLINK,
1753                     WA_DIM,
1754                     WA_BOLD,
1755                     WA_INVIS,
1756                     WA_PROTECT,
1757                     WA_ALTCHARSET
1758                 };
1759                 unsigned n;
1760                 bool found = FALSE;
1761                 for (n = 0; n < SIZEOF(table); n++) {
1762                     if ((table[n] & attr) != 0
1763                         && ((1 << n) & ncv) != 0) {
1764                         found = TRUE;
1765                         break;
1766                     }
1767                 }
1768                 if (found)
1769                     printw(" (NCV)");
1770             }
1771             if ((term_attrs() & test) != test)
1772                 printw(" (Part)");
1773         }
1774     }
1775     return row + 2;
1776 }
1777
1778 static bool
1779 wide_attr_getc(int *skip,
1780                short *fg, short *bg,
1781                short *tx, int *ac,
1782                unsigned *kc, unsigned limit)
1783 {
1784     bool result = TRUE;
1785     bool error = FALSE;
1786     WINDOW *helpwin;
1787
1788     do {
1789         int ch = Getchar();
1790
1791         error = FALSE;
1792         if (ch < 256 && isdigit(ch)) {
1793             *skip = (ch - '0');
1794         } else {
1795             switch (ch) {
1796             case CTRL('L'):
1797                 Repaint();
1798                 break;
1799             case '?':
1800                 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
1801                     box_set(helpwin, 0, 0);
1802                     attr_legend(helpwin);
1803                     wGetchar(helpwin);
1804                     delwin(helpwin);
1805                 }
1806                 break;
1807             case 'a':
1808                 *ac = 0;
1809                 break;
1810             case 'A':
1811                 *ac = A_ALTCHARSET;
1812                 break;
1813             case 'v':
1814                 if (*kc == 0)
1815                     *kc = limit - 1;
1816                 else
1817                     *kc -= 1;
1818                 break;
1819             case 'V':
1820                 *kc += 1;
1821                 if (*kc >= limit)
1822                     *kc = 0;
1823                 break;
1824             case '<':
1825                 wide_adjust_attr_string(-1);
1826                 break;
1827             case '>':
1828                 wide_adjust_attr_string(1);
1829                 break;
1830             case case_QUIT:
1831                 result = FALSE;
1832                 break;
1833             default:
1834                 error = cycle_color_attr(ch, fg, bg, tx);
1835                 break;
1836             }
1837         }
1838     } while (error);
1839     return result;
1840 }
1841
1842 static void
1843 wide_attr_test(void)
1844 /* test text attributes using wide-character calls */
1845 {
1846     int n;
1847     int skip = get_xmc();
1848     short fg = COLOR_BLACK;     /* color pair 0 is special */
1849     short bg = COLOR_BLACK;
1850     short tx = -1;
1851     int ac = 0;
1852     unsigned j, k;
1853     ATTR_TBL my_list[SIZEOF(attrs_to_test)];
1854     unsigned my_size = init_attr_list(my_list, term_attrs());
1855
1856     if (my_size > 1) {
1857         if (skip < 0)
1858             skip = 0;
1859
1860         n = skip;               /* make it easy */
1861         k = my_size - 1;
1862         wide_init_attr_string();
1863
1864         do {
1865             int row = 2;
1866             short pair = 0;
1867             short extras = 0;
1868
1869             if (use_colors) {
1870                 pair = (short) (fg != COLOR_BLACK || bg != COLOR_BLACK);
1871                 if (pair != 0) {
1872                     pair = 1;
1873                     if (init_pair(pair, fg, bg) == ERR) {
1874                         beep();
1875                     }
1876                 }
1877                 extras = pair;
1878                 if (tx >= 0) {
1879                     extras = 2;
1880                     if (init_pair(extras, tx, bg) == ERR) {
1881                         beep();
1882                     }
1883                 }
1884             }
1885             set_wide_background(pair);
1886             erase();
1887
1888             box_set(stdscr, 0, 0);
1889             MvAddStr(0, 20, "Character attribute test display");
1890
1891             for (j = 0; j < my_size; ++j) {
1892                 row = wide_show_attr(row, n, j == k,
1893                                      ((attr_t) ac |
1894                                       my_list[j].attr |
1895                                       my_list[k].attr),
1896                                      extras,
1897                                      my_list[j].name);
1898             }
1899
1900             MvPrintw(row, 8,
1901                      "This terminal does %shave the magic-cookie glitch",
1902                      get_xmc() > -1 ? "" : "not ");
1903             MvPrintw(row + 1, 8, "Enter '?' for help.");
1904             show_color_attr(fg, bg, tx);
1905             printw("  ACS (%d)", ac != 0);
1906
1907             refresh();
1908         } while (wide_attr_getc(&n, &fg, &bg, &tx, &ac, &k, my_size));
1909
1910         set_wide_background(0);
1911         erase();
1912         endwin();
1913     } else {
1914         Cannot("does not support extended video attributes.");
1915     }
1916 }
1917 #endif
1918
1919 /****************************************************************************
1920  *
1921  * Color support tests
1922  *
1923  ****************************************************************************/
1924
1925 static NCURSES_CONST char *the_color_names[] =
1926 {
1927     "black",
1928     "red",
1929     "green",
1930     "yellow",
1931     "blue",
1932     "magenta",
1933     "cyan",
1934     "white",
1935     "BLACK",
1936     "RED",
1937     "GREEN",
1938     "YELLOW",
1939     "BLUE",
1940     "MAGENTA",
1941     "CYAN",
1942     "WHITE"
1943 };
1944
1945 static void
1946 show_color_name(int y, int x, int color, bool wide)
1947 {
1948     if (move(y, x) != ERR) {
1949         char temp[80];
1950         int width = 8;
1951
1952         if (wide) {
1953             sprintf(temp, "%02d", color);
1954             width = 4;
1955         } else if (color >= 8) {
1956             sprintf(temp, "[%02d]", color);
1957         } else if (color < 0) {
1958             strcpy(temp, "default");
1959         } else {
1960             sprintf(temp, "%.*s", 16, the_color_names[color]);
1961         }
1962         printw("%-*.*s", width, width, temp);
1963     }
1964 }
1965
1966 static void
1967 color_legend(WINDOW *helpwin, bool wide)
1968 {
1969     int row = 1;
1970     int col = 1;
1971
1972     MvWPrintw(helpwin, row++, col,
1973               "ESC to exit.");
1974     ++row;
1975     MvWPrintw(helpwin, row++, col,
1976               "Use up/down arrow to scroll through the display if it is");
1977     MvWPrintw(helpwin, row++, col,
1978               "longer than one screen. Control/N and Control/P can be used");
1979     MvWPrintw(helpwin, row++, col,
1980               "in place of up/down arrow.  Use pageup/pagedown to scroll a");
1981     MvWPrintw(helpwin, row++, col,
1982               "full screen; control/B and control/F can be used here.");
1983     ++row;
1984     MvWPrintw(helpwin, row++, col,
1985               "Toggles:");
1986     MvWPrintw(helpwin, row++, col,
1987               "  a/A     toggle altcharset off/on");
1988     MvWPrintw(helpwin, row++, col,
1989               "  b/B     toggle bold off/on");
1990     MvWPrintw(helpwin, row++, col,
1991               "  n/N     toggle text/number on/off");
1992     MvWPrintw(helpwin, row++, col,
1993               "  r/R     toggle reverse on/off");
1994     MvWPrintw(helpwin, row++, col,
1995               "  w/W     toggle width between 8/16 colors");
1996 #if USE_WIDEC_SUPPORT
1997     if (wide) {
1998         MvWPrintw(helpwin, row++, col,
1999                   "Wide characters:");
2000         MvWPrintw(helpwin, row, col,
2001                   "  x/X     toggle text between ASCII and wide-character");
2002     }
2003 #else
2004     (void) wide;
2005 #endif
2006 }
2007
2008 #define set_color_test(name, value) if (name != value) { name = value; base_row = 0; }
2009
2010 /* generate a color test pattern */
2011 static void
2012 color_test(void)
2013 {
2014     short i;
2015     int top = 0, width;
2016     int base_row = 0;
2017     int grid_top = top + 3;
2018     int page_size = (LINES - grid_top);
2019     int pairs_max = PAIR_NUMBER(A_COLOR) + 1;
2020     int row_limit;
2021     int per_row;
2022     char numbered[80];
2023     const char *hello;
2024     bool done = FALSE;
2025     bool opt_acsc = FALSE;
2026     bool opt_bold = FALSE;
2027     bool opt_revs = FALSE;
2028     bool opt_nums = FALSE;
2029     bool opt_wide = FALSE;
2030     WINDOW *helpwin;
2031
2032     if (COLORS * COLORS == COLOR_PAIRS) {
2033         int limit = (COLORS - min_colors) * (COLORS - min_colors);
2034         if (pairs_max > limit)
2035             pairs_max = limit;
2036     } else {
2037         if (pairs_max > COLOR_PAIRS)
2038             pairs_max = COLOR_PAIRS;
2039     }
2040
2041     while (!done) {
2042         int shown = 0;
2043
2044         /* this assumes an 80-column line */
2045         if (opt_wide) {
2046             width = 4;
2047             hello = "Test";
2048             per_row = (COLORS > 8) ? 16 : 8;
2049         } else {
2050             width = 8;
2051             hello = "Hello";
2052             per_row = 8;
2053         }
2054         per_row -= min_colors;
2055
2056         row_limit = (pairs_max + per_row - 1) / per_row;
2057
2058         move(0, 0);
2059         (void) printw("There are %d color pairs and %d colors%s\n",
2060                       pairs_max, COLORS,
2061                       min_colors ? " besides 'default'" : "");
2062
2063         clrtobot();
2064         MvPrintw(top + 1, 0,
2065                  "%dx%d matrix of foreground/background colors, bold *%s*\n",
2066                  row_limit,
2067                  per_row,
2068                  opt_bold ? "on" : "off");
2069
2070         /* show color names/numbers across the top */
2071         for (i = 0; i < per_row; i++)
2072             show_color_name(top + 2, (i + 1) * width, i + min_colors, opt_wide);
2073
2074         /* show a grid of colors, with color names/ numbers on the left */
2075         for (i = (short) (base_row * per_row); i < pairs_max; i++) {
2076             int row = grid_top + (i / per_row) - base_row;
2077             int col = (i % per_row + 1) * width;
2078             short pair = i;
2079
2080 #define InxToFG(i) (short) ((i % (COLORS - min_colors)) + min_colors)
2081 #define InxToBG(i) (short) ((i / (COLORS - min_colors)) + min_colors)
2082             if (row >= 0 && move(row, col) != ERR) {
2083                 short fg = InxToFG(i);
2084                 short bg = InxToBG(i);
2085
2086                 init_pair(pair, fg, bg);
2087                 attron((attr_t) COLOR_PAIR(pair));
2088                 if (opt_acsc)
2089                     attron((attr_t) A_ALTCHARSET);
2090                 if (opt_bold)
2091                     attron((attr_t) A_BOLD);
2092                 if (opt_revs)
2093                     attron((attr_t) A_REVERSE);
2094
2095                 if (opt_nums) {
2096                     sprintf(numbered, "{%02X}", i);
2097                     hello = numbered;
2098                 }
2099                 printw("%-*.*s", width, width, hello);
2100                 (void) attrset(A_NORMAL);
2101
2102                 if ((i % per_row) == 0 && InxToFG(i) == min_colors) {
2103                     show_color_name(row, 0, InxToBG(i), opt_wide);
2104                 }
2105                 ++shown;
2106             } else if (shown) {
2107                 break;
2108             }
2109         }
2110
2111         switch (wGetchar(stdscr)) {
2112         case 'a':
2113             opt_acsc = FALSE;
2114             break;
2115         case 'A':
2116             opt_acsc = TRUE;
2117             break;
2118         case 'b':
2119             opt_bold = FALSE;
2120             break;
2121         case 'B':
2122             opt_bold = TRUE;
2123             break;
2124         case 'n':
2125             opt_nums = FALSE;
2126             break;
2127         case 'N':
2128             opt_nums = TRUE;
2129             break;
2130         case 'r':
2131             opt_revs = FALSE;
2132             break;
2133         case 'R':
2134             opt_revs = TRUE;
2135             break;
2136         case case_QUIT:
2137             done = TRUE;
2138             continue;
2139         case 'w':
2140             set_color_test(opt_wide, FALSE);
2141             break;
2142         case 'W':
2143             set_color_test(opt_wide, TRUE);
2144             break;
2145         case CTRL('p'):
2146         case KEY_UP:
2147             if (base_row <= 0) {
2148                 beep();
2149             } else {
2150                 base_row -= 1;
2151             }
2152             break;
2153         case CTRL('n'):
2154         case KEY_DOWN:
2155             if (base_row + page_size >= row_limit) {
2156                 beep();
2157             } else {
2158                 base_row += 1;
2159             }
2160             break;
2161         case CTRL('b'):
2162         case KEY_PREVIOUS:
2163         case KEY_PPAGE:
2164             if (base_row <= 0) {
2165                 beep();
2166             } else {
2167                 base_row -= (page_size - 1);
2168                 if (base_row < 0)
2169                     base_row = 0;
2170             }
2171             break;
2172         case CTRL('f'):
2173         case KEY_NEXT:
2174         case KEY_NPAGE:
2175             if (base_row + page_size >= row_limit) {
2176                 beep();
2177             } else {
2178                 base_row += page_size - 1;
2179                 if (base_row + page_size >= row_limit) {
2180                     base_row = row_limit - page_size - 1;
2181                 }
2182             }
2183             break;
2184         case '?':
2185             if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
2186                 box(helpwin, 0, 0);
2187                 color_legend(helpwin, FALSE);
2188                 wGetchar(helpwin);
2189                 delwin(helpwin);
2190             }
2191             break;
2192         default:
2193             beep();
2194             continue;
2195         }
2196     }
2197
2198     erase();
2199     endwin();
2200 }
2201
2202 #if USE_WIDEC_SUPPORT
2203 /* generate a color test pattern */
2204 static void
2205 wide_color_test(void)
2206 {
2207     int i;
2208     int top = 0, width;
2209     int base_row = 0;
2210     int grid_top = top + 3;
2211     int page_size = (LINES - grid_top);
2212     int pairs_max = (unsigned short) (-1);
2213     int row_limit;
2214     int per_row;
2215     char numbered[80];
2216     const char *hello;
2217     bool done = FALSE;
2218     bool opt_acsc = FALSE;
2219     bool opt_bold = FALSE;
2220     bool opt_revs = FALSE;
2221     bool opt_wide = FALSE;
2222     bool opt_nums = FALSE;
2223     bool opt_xchr = FALSE;
2224     wchar_t buffer[80];
2225     WINDOW *helpwin;
2226
2227     if (COLORS * COLORS == COLOR_PAIRS) {
2228         int limit = (COLORS - min_colors) * (COLORS - min_colors);
2229         if (pairs_max > limit)
2230             pairs_max = limit;
2231     } else {
2232         if (pairs_max > COLOR_PAIRS)
2233             pairs_max = COLOR_PAIRS;
2234     }
2235
2236     while (!done) {
2237         int shown = 0;
2238
2239         /* this assumes an 80-column line */
2240         if (opt_wide) {
2241             width = 4;
2242             hello = "Test";
2243             per_row = (COLORS > 8) ? 16 : 8;
2244         } else {
2245             width = 8;
2246             hello = "Hello";
2247             per_row = 8;
2248         }
2249         per_row -= min_colors;
2250
2251         if (opt_xchr) {
2252             make_fullwidth_text(buffer, hello);
2253             width *= 2;
2254             per_row /= 2;
2255         } else {
2256             make_narrow_text(buffer, hello);
2257         }
2258
2259         row_limit = (pairs_max + per_row - 1) / per_row;
2260
2261         move(0, 0);
2262         (void) printw("There are %d color pairs and %d colors%s\n",
2263                       pairs_max, COLORS,
2264                       min_colors ? " besides 'default'" : "");
2265
2266         clrtobot();
2267         MvPrintw(top + 1, 0,
2268                  "%dx%d matrix of foreground/background colors, bold *%s*\n",
2269                  row_limit,
2270                  per_row,
2271                  opt_bold ? "on" : "off");
2272
2273         /* show color names/numbers across the top */
2274         for (i = 0; i < per_row; i++)
2275             show_color_name(top + 2, (i + 1) * width, i + min_colors, opt_wide);
2276
2277         /* show a grid of colors, with color names/ numbers on the left */
2278         for (i = (base_row * per_row); i < pairs_max; i++) {
2279             int row = grid_top + (i / per_row) - base_row;
2280             int col = (i % per_row + 1) * width;
2281             short pair = (short) i;
2282
2283             if (row >= 0 && move(row, col) != ERR) {
2284                 init_pair(pair, InxToFG(i), InxToBG(i));
2285                 (void) color_set(pair, NULL);
2286                 if (opt_acsc)
2287                     attr_on((attr_t) A_ALTCHARSET, NULL);
2288                 if (opt_bold)
2289                     attr_on((attr_t) A_BOLD, NULL);
2290                 if (opt_revs)
2291                     attr_on((attr_t) A_REVERSE, NULL);
2292
2293                 if (opt_nums) {
2294                     sprintf(numbered, "{%02X}", i);
2295                     if (opt_xchr) {
2296                         make_fullwidth_text(buffer, numbered);
2297                     } else {
2298                         make_narrow_text(buffer, numbered);
2299                     }
2300                 }
2301                 addnwstr(buffer, width);
2302                 (void) attr_set(A_NORMAL, 0, NULL);
2303
2304                 if ((i % per_row) == 0 && InxToFG(i) == min_colors) {
2305                     show_color_name(row, 0, InxToBG(i), opt_wide);
2306                 }
2307                 ++shown;
2308             } else if (shown) {
2309                 break;
2310             }
2311         }
2312
2313         switch (wGetchar(stdscr)) {
2314         case 'a':
2315             opt_acsc = FALSE;
2316             break;
2317         case 'A':
2318             opt_acsc = TRUE;
2319             break;
2320         case 'b':
2321             opt_bold = FALSE;
2322             break;
2323         case 'B':
2324             opt_bold = TRUE;
2325             break;
2326         case 'n':
2327             opt_nums = FALSE;
2328             break;
2329         case 'N':
2330             opt_nums = TRUE;
2331             break;
2332         case 'r':
2333             opt_revs = FALSE;
2334             break;
2335         case 'R':
2336             opt_revs = TRUE;
2337             break;
2338         case case_QUIT:
2339             done = TRUE;
2340             continue;
2341         case 'w':
2342             set_color_test(opt_wide, FALSE);
2343             break;
2344         case 'W':
2345             set_color_test(opt_wide, TRUE);
2346             break;
2347         case 'x':
2348             opt_xchr = FALSE;
2349             break;
2350         case 'X':
2351             opt_xchr = TRUE;
2352             break;
2353         case CTRL('p'):
2354         case KEY_UP:
2355             if (base_row <= 0) {
2356                 beep();
2357             } else {
2358                 base_row -= 1;
2359             }
2360             break;
2361         case CTRL('n'):
2362         case KEY_DOWN:
2363             if (base_row + page_size >= row_limit) {
2364                 beep();
2365             } else {
2366                 base_row += 1;
2367             }
2368             break;
2369         case CTRL('b'):
2370         case KEY_PREVIOUS:
2371         case KEY_PPAGE:
2372             if (base_row <= 0) {
2373                 beep();
2374             } else {
2375                 base_row -= (page_size - 1);
2376                 if (base_row < 0)
2377                     base_row = 0;
2378             }
2379             break;
2380         case CTRL('f'):
2381         case KEY_NEXT:
2382         case KEY_NPAGE:
2383             if (base_row + page_size >= row_limit) {
2384                 beep();
2385             } else {
2386                 base_row += page_size - 1;
2387                 if (base_row + page_size >= row_limit) {
2388                     base_row = row_limit - page_size - 1;
2389                 }
2390             }
2391             break;
2392         case '?':
2393             if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
2394                 box(helpwin, 0, 0);
2395                 color_legend(helpwin, TRUE);
2396                 wGetchar(helpwin);
2397                 delwin(helpwin);
2398             }
2399             break;
2400         default:
2401             beep();
2402             continue;
2403         }
2404     }
2405
2406     erase();
2407     endwin();
2408 }
2409 #endif /* USE_WIDEC_SUPPORT */
2410
2411 static void
2412 change_color(short current, int field, int value, int usebase)
2413 {
2414     short red, green, blue;
2415
2416     color_content(current, &red, &green, &blue);
2417
2418     switch (field) {
2419     case 0:
2420         red = (short) (usebase ? (red + value) : value);
2421         break;
2422     case 1:
2423         green = (short) (usebase ? (green + value) : value);
2424         break;
2425     case 2:
2426         blue = (short) (usebase ? (blue + value) : value);
2427         break;
2428     }
2429
2430     if (init_color(current, red, green, blue) == ERR)
2431         beep();
2432 }
2433
2434 static void
2435 init_all_colors(void)
2436 {
2437     short c;
2438
2439     for (c = 0; c < COLORS; ++c)
2440         init_color(c,
2441                    all_colors[c].red,
2442                    all_colors[c].green,
2443                    all_colors[c].blue);
2444 }
2445
2446 #define scaled_rgb(n) ((255 * (n)) / 1000)
2447
2448 static void
2449 color_edit(void)
2450 /* display the color test pattern, without trying to edit colors */
2451 {
2452     int i;
2453     int current = 0;
2454     int this_c = 0, value = 0, field = 0;
2455     int last_c;
2456     int top_color = 0;
2457     int page_size = (LINES - 6);
2458
2459     init_all_colors();
2460     refresh();
2461
2462     for (i = 0; i < max_colors; i++)
2463         init_pair((short) i, (short) COLOR_WHITE, (short) i);
2464
2465     MvPrintw(LINES - 2, 0, "Number: %d", value);
2466
2467     do {
2468         short red, green, blue;
2469
2470         attron(A_BOLD);
2471         MvAddStr(0, 20, "Color RGB Value Editing");
2472         attroff(A_BOLD);
2473
2474         for (i = (short) top_color;
2475              (i - top_color < page_size)
2476              && (i < max_colors); i++) {
2477             char numeric[80];
2478
2479             sprintf(numeric, "[%d]", i);
2480             MvPrintw(2 + i - top_color, 0, "%c %-8s:",
2481                      (i == current ? '>' : ' '),
2482                      (i < (int) SIZEOF(the_color_names)
2483                       ? the_color_names[i] : numeric));
2484             (void) attrset((attr_t) COLOR_PAIR(i));
2485             addstr("        ");
2486             (void) attrset(A_NORMAL);
2487
2488             color_content((short) i, &red, &green, &blue);
2489             addstr("   R = ");
2490             if (current == i && field == 0)
2491                 attron(A_STANDOUT);
2492             printw("%04d", red);
2493             if (current == i && field == 0)
2494                 (void) attrset(A_NORMAL);
2495             addstr(", G = ");
2496             if (current == i && field == 1)
2497                 attron(A_STANDOUT);
2498             printw("%04d", green);
2499             if (current == i && field == 1)
2500                 (void) attrset(A_NORMAL);
2501             addstr(", B = ");
2502             if (current == i && field == 2)
2503                 attron(A_STANDOUT);
2504             printw("%04d", blue);
2505             if (current == i && field == 2)
2506                 (void) attrset(A_NORMAL);
2507             (void) attrset(A_NORMAL);
2508             printw(" ( %3d %3d %3d )",
2509                    scaled_rgb(red),
2510                    scaled_rgb(green),
2511                    scaled_rgb(blue));
2512         }
2513
2514         MvAddStr(LINES - 3, 0,
2515                  "Use up/down to select a color, left/right to change fields.");
2516         MvAddStr(LINES - 2, 0,
2517                  "Modify field by typing nnn=, nnn-, or nnn+.  ? for help.");
2518
2519         move(2 + current - top_color, 0);
2520
2521         last_c = this_c;
2522         this_c = Getchar();
2523         if (this_c < 256 && isdigit(this_c) && !isdigit(last_c))
2524             value = 0;
2525
2526         switch (this_c) {
2527         case CTRL('b'):
2528         case KEY_PPAGE:
2529             if (current > 0)
2530                 current -= (page_size - 1);
2531             else
2532                 beep();
2533             break;
2534
2535         case CTRL('f'):
2536         case KEY_NPAGE:
2537             if (current < (max_colors - 1))
2538                 current += (page_size - 1);
2539             else
2540                 beep();
2541             break;
2542
2543         case CTRL('p'):
2544         case KEY_UP:
2545             current = (current == 0 ? (max_colors - 1) : current - 1);
2546             break;
2547
2548         case CTRL('n'):
2549         case KEY_DOWN:
2550             current = (current == (max_colors - 1) ? 0 : current + 1);
2551             break;
2552
2553         case KEY_RIGHT:
2554             field = (field == 2 ? 0 : field + 1);
2555             break;
2556
2557         case KEY_LEFT:
2558             field = (field == 0 ? 2 : field - 1);
2559             break;
2560
2561         case '0':
2562         case '1':
2563         case '2':
2564         case '3':
2565         case '4':
2566         case '5':
2567         case '6':
2568         case '7':
2569         case '8':
2570         case '9':
2571             value = value * 10 + (this_c - '0');
2572             break;
2573
2574         case '+':
2575             change_color((short) current, field, value, 1);
2576             break;
2577
2578         case '-':
2579             change_color((short) current, field, -value, 1);
2580             break;
2581
2582         case '=':
2583             change_color((short) current, field, value, 0);
2584             break;
2585
2586         case '?':
2587             erase();
2588             P("                      RGB Value Editing Help");
2589             P("");
2590             P("You are in the RGB value editor.  Use the arrow keys to select one of");
2591             P("the fields in one of the RGB triples of the current colors; the one");
2592             P("currently selected will be reverse-video highlighted.");
2593             P("");
2594             P("To change a field, enter the digits of the new value; they are echoed");
2595             P("as entered.  Finish by typing `='.  The change will take effect instantly.");
2596             P("To increment or decrement a value, use the same procedure, but finish");
2597             P("with a `+' or `-'.");
2598             P("");
2599             P("Press 'm' to invoke the top-level menu with the current color settings.");
2600             P("To quit, do ESC");
2601
2602             Pause();
2603             erase();
2604             break;
2605
2606         case 'm':
2607             endwin();
2608             main_menu(FALSE);
2609             for (i = 0; i < max_colors; i++)
2610                 init_pair((short) i, (short) COLOR_WHITE, (short) i);
2611             refresh();
2612             break;
2613
2614         case case_QUIT:
2615             break;
2616
2617         default:
2618             beep();
2619             break;
2620         }
2621
2622         if (current < 0)
2623             current = 0;
2624         if (current >= max_colors)
2625             current = max_colors - 1;
2626         if (current < top_color)
2627             top_color = current;
2628         if (current - top_color >= page_size)
2629             top_color = current - (page_size - 1);
2630
2631         MvPrintw(LINES - 1, 0, "Number: %d", value);
2632         clrtoeol();
2633     } while
2634         (!isQuit(this_c));
2635
2636     erase();
2637
2638     /*
2639      * ncurses does not reset each color individually when calling endwin().
2640      */
2641     init_all_colors();
2642
2643     endwin();
2644 }
2645
2646 /****************************************************************************
2647  *
2648  * Alternate character-set stuff
2649  *
2650  ****************************************************************************/
2651 static bool
2652 cycle_attr(int ch, unsigned *at_code, chtype *attr, ATTR_TBL * list, unsigned limit)
2653 {
2654     bool result = TRUE;
2655
2656     switch (ch) {
2657     case 'v':
2658         if ((*at_code += 1) >= limit)
2659             *at_code = 0;
2660         break;
2661     case 'V':
2662         if (*at_code == 0)
2663             *at_code = limit - 1;
2664         else
2665             *at_code -= 1;
2666         break;
2667     default:
2668         result = FALSE;
2669         break;
2670     }
2671     if (result)
2672         *attr = list[*at_code].attr;
2673     return result;
2674 }
2675
2676 static bool
2677 cycle_colors(int ch, int *fg, int *bg, short *pair)
2678 {
2679     bool result = FALSE;
2680
2681     if (use_colors) {
2682         result = TRUE;
2683         switch (ch) {
2684         case 'F':
2685             if ((*fg -= 1) < 0)
2686                 *fg = COLORS - 1;
2687             break;
2688         case 'f':
2689             if ((*fg += 1) >= COLORS)
2690                 *fg = 0;
2691             break;
2692         case 'B':
2693             if ((*bg -= 1) < 0)
2694                 *bg = COLORS - 1;
2695             break;
2696         case 'b':
2697             if ((*bg += 1) >= COLORS)
2698                 *bg = 0;
2699             break;
2700         default:
2701             result = FALSE;
2702             break;
2703         }
2704         if (result) {
2705             *pair = (short) (*fg != COLOR_BLACK || *bg != COLOR_BLACK);
2706             if (*pair != 0) {
2707                 *pair = 1;
2708                 if (init_pair(*pair, (short) *fg, (short) *bg) == ERR) {
2709                     result = FALSE;
2710                 }
2711             }
2712         }
2713     }
2714     return result;
2715 }
2716
2717 /****************************************************************************
2718  *
2719  * Soft-key label test
2720  *
2721  ****************************************************************************/
2722
2723 #if USE_SOFTKEYS
2724
2725 #define SLK_HELP 17
2726 #define SLK_WORK (SLK_HELP + 3)
2727
2728 static void
2729 slk_help(void)
2730 {
2731     static const char *table[] =
2732     {
2733         "Available commands are:"
2734         ,""
2735         ,"^L         -- repaint this message and activate soft keys"
2736         ,"a/d        -- activate/disable soft keys"
2737         ,"c          -- set centered format for labels"
2738         ,"l          -- set left-justified format for labels"
2739         ,"r          -- set right-justified format for labels"
2740         ,"[12345678] -- set label; labels are numbered 1 through 8"
2741         ,"e          -- erase stdscr (should not erase labels)"
2742         ,"s          -- test scrolling of shortened screen"
2743         ,"v/V        -- cycle through video attributes"
2744 #if HAVE_SLK_COLOR
2745         ,"F/f/B/b    -- cycle through foreground/background colors"
2746 #endif
2747         ,"ESC        -- return to main menu"
2748         ,""
2749         ,"Note: if activating the soft keys causes your terminal to scroll up"
2750         ,"one line, your terminal auto-scrolls when anything is written to the"
2751         ,"last screen position.  The ncurses code does not yet handle this"
2752         ,"gracefully."
2753     };
2754     unsigned j;
2755
2756     move(2, 0);
2757     for (j = 0; j < SIZEOF(table); ++j) {
2758         P(table[j]);
2759     }
2760     refresh();
2761 }
2762
2763 #if HAVE_SLK_COLOR
2764 static void
2765 call_slk_color(int fg, int bg)
2766 {
2767     init_pair(1, (short) bg, (short) fg);
2768     slk_color(1);
2769     MvPrintw(SLK_WORK, 0, "Colors %d/%d\n", fg, bg);
2770     clrtoeol();
2771     slk_touch();
2772     slk_noutrefresh();
2773     refresh();
2774 }
2775 #endif
2776
2777 static void
2778 slk_test(void)
2779 /* exercise the soft keys */
2780 {
2781     int c, fmt = 1;
2782     char buf[9];
2783     char *s;
2784     chtype attr = A_NORMAL;
2785     unsigned at_code = 0;
2786 #if HAVE_SLK_COLOR
2787     int fg = COLOR_BLACK;
2788     int bg = COLOR_WHITE;
2789     short pair = 0;
2790 #endif
2791     ATTR_TBL my_list[SIZEOF(attrs_to_test)];
2792     unsigned my_size = init_attr_list(my_list, termattrs());
2793
2794     c = CTRL('l');
2795 #if HAVE_SLK_COLOR
2796     if (use_colors) {
2797         call_slk_color(fg, bg);
2798     }
2799 #endif
2800
2801     do {
2802         move(0, 0);
2803         switch (c) {
2804         case CTRL('l'):
2805             erase();
2806             attron(A_BOLD);
2807             MvAddStr(0, 20, "Soft Key Exerciser");
2808             attroff(A_BOLD);
2809
2810             slk_help();
2811             /* fall through */
2812
2813         case 'a':
2814             slk_restore();
2815             break;
2816
2817         case 'e':
2818             wclear(stdscr);
2819             break;
2820
2821         case 's':
2822             MvPrintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: ");
2823             while ((c = Getchar()) != 'Q' && (c != ERR))
2824                 addch((chtype) c);
2825             break;
2826
2827         case 'd':
2828             slk_clear();
2829             break;
2830
2831         case 'l':
2832             fmt = 0;
2833             break;
2834
2835         case 'c':
2836             fmt = 1;
2837             break;
2838
2839         case 'r':
2840             fmt = 2;
2841             break;
2842
2843         case '1':
2844         case '2':
2845         case '3':
2846         case '4':
2847         case '5':
2848         case '6':
2849         case '7':
2850         case '8':
2851             MvAddStr(SLK_WORK, 0, "Please enter the label value: ");
2852             strcpy(buf, "");
2853             if ((s = slk_label(c - '0')) != 0) {
2854                 strncpy(buf, s, (size_t) 8);
2855             }
2856             wGetstring(stdscr, buf, 8);
2857             slk_set((c - '0'), buf, fmt);
2858             slk_refresh();
2859             move(SLK_WORK, 0);
2860             clrtobot();
2861             break;
2862
2863         case case_QUIT:
2864             goto done;
2865
2866 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
2867         case KEY_RESIZE:
2868             wnoutrefresh(stdscr);
2869             break;
2870 #endif
2871
2872         default:
2873             if (cycle_attr(c, &at_code, &attr, my_list, my_size)) {
2874                 slk_attrset(attr);
2875                 slk_touch();
2876                 slk_noutrefresh();
2877                 break;
2878             }
2879 #if HAVE_SLK_COLOR
2880             if (cycle_colors(c, &fg, &bg, &pair)) {
2881                 if (use_colors) {
2882                     call_slk_color(fg, bg);
2883                 } else {
2884                     beep();
2885                 }
2886                 break;
2887             }
2888 #endif
2889             beep();
2890             break;
2891         }
2892     } while (!isQuit(c = Getchar()));
2893
2894   done:
2895     slk_clear();
2896     erase();
2897     endwin();
2898 }
2899
2900 #if USE_WIDEC_SUPPORT
2901 #define SLKLEN 8
2902 static void
2903 wide_slk_test(void)
2904 /* exercise the soft keys */
2905 {
2906     int c, fmt = 1;
2907     wchar_t buf[SLKLEN + 1];
2908     char *s;
2909     chtype attr = A_NORMAL;
2910     unsigned at_code = 0;
2911     int fg = COLOR_BLACK;
2912     int bg = COLOR_WHITE;
2913     short pair = 0;
2914     ATTR_TBL my_list[SIZEOF(attrs_to_test)];
2915     unsigned my_size = init_attr_list(my_list, term_attrs());
2916
2917     c = CTRL('l');
2918     if (use_colors) {
2919         call_slk_color(fg, bg);
2920     }
2921     do {
2922         move(0, 0);
2923         switch (c) {
2924         case CTRL('l'):
2925             erase();
2926             attr_on(WA_BOLD, NULL);
2927             MvAddStr(0, 20, "Soft Key Exerciser");
2928             attr_off(WA_BOLD, NULL);
2929
2930             slk_help();
2931             /* fall through */
2932
2933         case 'a':
2934             slk_restore();
2935             break;
2936
2937         case 'e':
2938             wclear(stdscr);
2939             break;
2940
2941         case 's':
2942             MvPrintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: ");
2943             while ((c = Getchar()) != 'Q' && (c != ERR))
2944                 addch((chtype) c);
2945             break;
2946
2947         case 'd':
2948             slk_clear();
2949             break;
2950
2951         case 'l':
2952             fmt = 0;
2953             break;
2954
2955         case 'c':
2956             fmt = 1;
2957             break;
2958
2959         case 'r':
2960             fmt = 2;
2961             break;
2962
2963         case '1':
2964         case '2':
2965         case '3':
2966         case '4':
2967         case '5':
2968         case '6':
2969         case '7':
2970         case '8':
2971             MvAddStr(SLK_WORK, 0, "Please enter the label value: ");
2972             *buf = 0;
2973             if ((s = slk_label(c - '0')) != 0) {
2974                 char *temp = strdup(s);
2975                 size_t used = strlen(temp);
2976                 size_t want = SLKLEN;
2977                 size_t test;
2978 #ifndef state_unused
2979                 mbstate_t state;
2980 #endif
2981
2982                 buf[0] = L'\0';
2983                 while (want > 0 && used != 0) {
2984                     const char *base = s;
2985                     reset_mbytes(state);
2986                     test = count_mbytes(base, 0, &state);
2987                     if (test == (size_t) -1) {
2988                         temp[--used] = 0;
2989                     } else if (test > want) {
2990                         temp[--used] = 0;
2991                     } else {
2992                         reset_mbytes(state);
2993                         trans_mbytes(buf, base, want, &state);
2994                         break;
2995                     }
2996                 }
2997                 free(temp);
2998             }
2999             wGet_wstring(stdscr, buf, SLKLEN);
3000             slk_wset((c - '0'), buf, fmt);
3001             slk_refresh();
3002             move(SLK_WORK, 0);
3003             clrtobot();
3004             break;
3005
3006         case case_QUIT:
3007             goto done;
3008
3009         case 'F':
3010             if (use_colors) {
3011                 fg = (short) ((fg + 1) % COLORS);
3012                 call_slk_color(fg, bg);
3013             }
3014             break;
3015         case 'B':
3016             if (use_colors) {
3017                 bg = (short) ((bg + 1) % COLORS);
3018                 call_slk_color(fg, bg);
3019             }
3020             break;
3021 #if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
3022         case KEY_RESIZE:
3023             wnoutrefresh(stdscr);
3024             break;
3025 #endif
3026         default:
3027             if (cycle_attr(c, &at_code, &attr, my_list, my_size)) {
3028                 slk_attr_set(attr, (short) (fg || bg), NULL);
3029                 slk_touch();
3030                 slk_noutrefresh();
3031                 break;
3032             }
3033 #if HAVE_SLK_COLOR
3034             if (cycle_colors(c, &fg, &bg, &pair)) {
3035                 if (use_colors) {
3036                     call_slk_color(fg, bg);
3037                 } else {
3038                     beep();
3039                 }
3040                 break;
3041             }
3042 #endif
3043             beep();
3044             break;
3045         }
3046     } while (!isQuit(c = Getchar()));
3047
3048   done:
3049     slk_clear();
3050     erase();
3051     endwin();
3052 }
3053 #endif
3054 #endif /* SLK_INIT */
3055
3056 static void
3057 show_256_chars(int repeat, attr_t attr, short pair)
3058 {
3059     unsigned first = 0;
3060     unsigned last = 255;
3061     unsigned code;
3062     int count;
3063
3064     erase();
3065     attron(A_BOLD);
3066     MvPrintw(0, 20, "Display of Character Codes %#0x to %#0x",
3067              first, last);
3068     attroff(A_BOLD);
3069     refresh();
3070
3071     for (code = first; code <= last; ++code) {
3072         int row = (int) (2 + (code / 16));
3073         int col = (int) (5 * (code % 16));
3074         IGNORE_RC(mvaddch(row, col, colored_chtype(code, attr, pair)));
3075         for (count = 1; count < repeat; ++count) {
3076             addch(colored_chtype(code, attr, pair));
3077         }
3078     }
3079
3080 }
3081
3082 /*
3083  * Show a slice of 32 characters, allowing those to be repeated up to the
3084  * screen's width.
3085  *
3086  * ISO 6429:  codes 0x80 to 0x9f may be control characters that cause the
3087  * terminal to perform functions.  The remaining codes can be graphic.
3088  */
3089 static void
3090 show_upper_chars(int base, int pagesize, int repeat, attr_t attr, short pair)
3091 {
3092     unsigned code;
3093     unsigned first = (unsigned) base;
3094     unsigned last = first + (unsigned) pagesize - 2;
3095     bool C1 = (first == 128);
3096     int reply;
3097
3098     erase();
3099     attron(A_BOLD);
3100     MvPrintw(0, 20, "Display of %s Character Codes %d to %d",
3101              C1 ? "C1" : "GR", first, last);
3102     attroff(A_BOLD);
3103     refresh();
3104
3105     for (code = first; code <= last; code++) {
3106         int count = repeat;
3107         int row = 2 + ((int) (code - first) % (pagesize / 2));
3108         int col = ((int) (code - first) / (pagesize / 2)) * COLS / 2;
3109         char tmp[80];
3110         sprintf(tmp, "%3u (0x%x)", code, code);
3111         MvPrintw(row, col, "%*s: ", COLS / 4, tmp);
3112
3113         do {
3114             if (C1)
3115                 nodelay(stdscr, TRUE);
3116             echochar(colored_chtype(code, attr, pair));
3117             if (C1) {
3118                 /* (yes, this _is_ crude) */
3119                 while ((reply = Getchar()) != ERR) {
3120                     addch(UChar(reply));
3121                     napms(10);
3122                 }
3123                 nodelay(stdscr, FALSE);
3124             }
3125         } while (--count > 0);
3126     }
3127 }
3128
3129 #define PC_COLS 4
3130
3131 static void
3132 show_pc_chars(int repeat, attr_t attr, short pair)
3133 {
3134     unsigned code;
3135
3136     erase();
3137     attron(A_BOLD);
3138     MvPrintw(0, 20, "Display of PC Character Codes");
3139     attroff(A_BOLD);
3140     refresh();
3141
3142     for (code = 0; code < 16; ++code) {
3143         MvPrintw(2, (int) code * PC_COLS + 8, "%X", code);
3144     }
3145     for (code = 0; code < 256; code++) {
3146         int count = repeat;
3147         int row = 3 + (int) (code / 16) + (code >= 128);
3148         int col = 8 + (int) (code % 16) * PC_COLS;
3149         if ((code % 16) == 0)
3150             MvPrintw(row, 0, "0x%02x:", code);
3151         move(row, col);
3152         do {
3153             switch (code) {
3154             case '\n':
3155             case '\r':
3156             case '\b':
3157             case '\f':
3158             case '\033':
3159             case 0x9b:
3160                 /*
3161                  * Skip the ones that do not work.
3162                  */
3163                 break;
3164             default:
3165                 addch(colored_chtype(code, A_ALTCHARSET | attr, pair));
3166                 break;
3167             }
3168         } while (--count > 0);
3169     }
3170 }
3171
3172 static void
3173 show_box_chars(int repeat, attr_t attr, short pair)
3174 {
3175     (void) repeat;
3176
3177     attr |= (attr_t) COLOR_PAIR(pair);
3178
3179     erase();
3180     attron(A_BOLD);
3181     MvAddStr(0, 20, "Display of the ACS Line-Drawing Set");
3182     attroff(A_BOLD);
3183     refresh();
3184     /* *INDENT-OFF* */
3185     wborder(stdscr,
3186             colored_chtype(ACS_VLINE,    attr, pair),
3187             colored_chtype(ACS_VLINE,    attr, pair),
3188             colored_chtype(ACS_HLINE,    attr, pair),
3189             colored_chtype(ACS_HLINE,    attr, pair),
3190             colored_chtype(ACS_ULCORNER, attr, pair),
3191             colored_chtype(ACS_URCORNER, attr, pair),
3192             colored_chtype(ACS_LLCORNER, attr, pair),
3193             colored_chtype(ACS_LRCORNER, attr, pair));
3194     MvHLine(LINES / 2, 0,        colored_chtype(ACS_HLINE, attr, pair), COLS);
3195     MvVLine(0,         COLS / 2, colored_chtype(ACS_VLINE, attr, pair), LINES);
3196     MvAddCh(0,         COLS / 2, colored_chtype(ACS_TTEE,  attr, pair));
3197     MvAddCh(LINES / 2, COLS / 2, colored_chtype(ACS_PLUS,  attr, pair));
3198     MvAddCh(LINES - 1, COLS / 2, colored_chtype(ACS_BTEE,  attr, pair));
3199     MvAddCh(LINES / 2, 0,        colored_chtype(ACS_LTEE,  attr, pair));
3200     MvAddCh(LINES / 2, COLS - 1, colored_chtype(ACS_RTEE,  attr, pair));
3201     /* *INDENT-ON* */
3202
3203 }
3204
3205 static int
3206 show_1_acs(int n, int repeat, const char *name, chtype code)
3207 {
3208     const int height = 16;
3209     int row = 2 + (n % height);
3210     int col = (n / height) * COLS / 2;
3211
3212     MvPrintw(row, col, "%*s : ", COLS / 4, name);
3213     do {
3214         addch(code);
3215     } while (--repeat > 0);
3216     return n + 1;
3217 }
3218
3219 static void
3220 show_acs_chars(int repeat, attr_t attr, short pair)
3221 /* display the ACS character set */
3222 {
3223     int n;
3224
3225 #define BOTH(name) #name, colored_chtype(name, attr, (chtype) pair)
3226
3227     erase();
3228     attron(A_BOLD);
3229     MvAddStr(0, 20, "Display of the ACS Character Set");
3230     attroff(A_BOLD);
3231     refresh();
3232
3233     n = show_1_acs(0, repeat, BOTH(ACS_ULCORNER));
3234     n = show_1_acs(n, repeat, BOTH(ACS_URCORNER));
3235     n = show_1_acs(n, repeat, BOTH(ACS_LLCORNER));
3236     n = show_1_acs(n, repeat, BOTH(ACS_LRCORNER));
3237
3238     n = show_1_acs(n, repeat, BOTH(ACS_LTEE));
3239     n = show_1_acs(n, repeat, BOTH(ACS_RTEE));
3240     n = show_1_acs(n, repeat, BOTH(ACS_TTEE));
3241     n = show_1_acs(n, repeat, BOTH(ACS_BTEE));
3242
3243     n = show_1_acs(n, repeat, BOTH(ACS_HLINE));
3244     n = show_1_acs(n, repeat, BOTH(ACS_VLINE));
3245
3246     /*
3247      * HPUX's ACS definitions are broken here.  Just give up.
3248      */
3249 #if !(defined(__hpux) && !defined(NCURSES_VERSION))
3250     n = show_1_acs(n, repeat, BOTH(ACS_LARROW));
3251     n = show_1_acs(n, repeat, BOTH(ACS_RARROW));
3252     n = show_1_acs(n, repeat, BOTH(ACS_UARROW));
3253     n = show_1_acs(n, repeat, BOTH(ACS_DARROW));
3254
3255     n = show_1_acs(n, repeat, BOTH(ACS_BLOCK));
3256     n = show_1_acs(n, repeat, BOTH(ACS_BOARD));
3257     n = show_1_acs(n, repeat, BOTH(ACS_LANTERN));
3258     n = show_1_acs(n, repeat, BOTH(ACS_BULLET));
3259     n = show_1_acs(n, repeat, BOTH(ACS_CKBOARD));
3260     n = show_1_acs(n, repeat, BOTH(ACS_DEGREE));
3261     n = show_1_acs(n, repeat, BOTH(ACS_DIAMOND));
3262     n = show_1_acs(n, repeat, BOTH(ACS_PLMINUS));
3263     n = show_1_acs(n, repeat, BOTH(ACS_PLUS));
3264
3265     n = show_1_acs(n, repeat, BOTH(ACS_GEQUAL));
3266     n = show_1_acs(n, repeat, BOTH(ACS_NEQUAL));
3267     n = show_1_acs(n, repeat, BOTH(ACS_LEQUAL));
3268
3269     n = show_1_acs(n, repeat, BOTH(ACS_STERLING));
3270     n = show_1_acs(n, repeat, BOTH(ACS_PI));
3271     n = show_1_acs(n, repeat, BOTH(ACS_S1));
3272     n = show_1_acs(n, repeat, BOTH(ACS_S3));
3273     n = show_1_acs(n, repeat, BOTH(ACS_S7));
3274     (void) show_1_acs(n, repeat, BOTH(ACS_S9));
3275 #endif
3276 }
3277
3278 static void
3279 acs_display(void)
3280 {
3281     int c = 'a';
3282     int pagesize = 32;
3283     char *term = getenv("TERM");
3284     const char *pch_kludge = ((term != 0 && strstr(term, "linux"))
3285                               ? "p=PC, "
3286                               : "");
3287     chtype attr = A_NORMAL;
3288     int digit = 0;
3289     int repeat = 1;
3290     int fg = COLOR_BLACK;
3291     int bg = COLOR_BLACK;
3292     unsigned at_code = 0;
3293     short pair = 0;
3294     void (*last_show_acs) (int, attr_t, short) = 0;
3295     ATTR_TBL my_list[SIZEOF(attrs_to_test)];
3296     unsigned my_size = init_attr_list(my_list, termattrs());
3297
3298     do {
3299         switch (c) {
3300         case CTRL('L'):
3301             Repaint();
3302             break;
3303         case 'a':
3304             ToggleAcs(last_show_acs, show_acs_chars);
3305             break;
3306         case 'p':
3307             if (*pch_kludge)
3308                 ToggleAcs(last_show_acs, show_pc_chars);
3309             else
3310                 beep();
3311             break;
3312         case 'w':
3313             if (pagesize == 32) {
3314                 pagesize = 256;
3315             } else {
3316                 pagesize = 32;
3317             }
3318             break;
3319         case 'x':
3320             ToggleAcs(last_show_acs, show_box_chars);
3321             break;
3322         case '0':
3323         case '1':
3324         case '2':
3325         case '3':
3326             digit = (c - '0');
3327             last_show_acs = 0;
3328             break;
3329         case '-':
3330             if (digit > 0) {
3331                 --digit;
3332                 last_show_acs = 0;
3333             } else {
3334                 beep();
3335             }
3336             break;
3337         case '+':
3338             if (digit < 3) {
3339                 ++digit;
3340                 last_show_acs = 0;
3341             } else {
3342                 beep();
3343             }
3344             break;
3345         case '>':
3346             if (repeat < (COLS / 4))
3347                 ++repeat;
3348             break;
3349         case '<':
3350             if (repeat > 1)
3351                 --repeat;
3352             break;
3353         default:
3354             if (cycle_attr(c, &at_code, &attr, my_list, my_size)
3355                 || cycle_colors(c, &fg, &bg, &pair)) {
3356                 break;
3357             } else {
3358                 beep();
3359             }
3360             break;
3361         }
3362         if (pagesize != 32) {
3363             show_256_chars(repeat, attr, pair);
3364         } else if (last_show_acs != 0) {
3365             last_show_acs(repeat, attr, pair);
3366         } else {
3367             show_upper_chars(digit * pagesize + 128, pagesize, repeat, attr, pair);
3368         }
3369
3370         MvPrintw(LINES - 3, 0,
3371                  "Note: ANSI terminals may not display C1 characters.");
3372         MvPrintw(LINES - 2, 0,
3373                  "Select: a=ACS, w=all x=box, %s0=C1, 1-3,+/- non-ASCII, </> repeat, ESC=quit",
3374                  pch_kludge);
3375         if (use_colors) {
3376             MvPrintw(LINES - 1, 0,
3377                      "v/V, f/F, b/B cycle through video attributes (%s) and color %d/%d.",
3378                      my_list[at_code].name,
3379                      fg, bg);
3380         } else {
3381             MvPrintw(LINES - 1, 0,
3382                      "v/V cycles through video attributes (%s).",
3383                      my_list[at_code].name);
3384         }
3385         refresh();
3386     } while (!isQuit(c = Getchar()));
3387
3388     Pause();
3389     erase();
3390     endwin();
3391 }
3392
3393 #if USE_WIDEC_SUPPORT
3394 static cchar_t *
3395 merge_wide_attr(cchar_t *dst, const cchar_t *src, attr_t attr, short pair)
3396 {
3397     int count;
3398
3399     *dst = *src;
3400     do {
3401         TEST_CCHAR(src, count, {
3402             attr |= (test_attrs & A_ALTCHARSET);
3403             setcchar(dst, test_wch, attr, pair, NULL);
3404         }
3405         , {
3406             ;
3407         });
3408     } while (0);
3409     return dst;
3410 }
3411
3412 /*
3413  * Header/legend take up no more than 8 lines, leaving 16 lines on a 24-line
3414  * display.  If there are no repeats, we could normally display 16 lines of 64
3415  * characters (1024 total).  However, taking repeats and double-width cells
3416  * into account, use 256 characters for the page.
3417  */
3418 static void
3419 show_paged_widechars(int base,
3420                      int pagesize,
3421                      int repeat,
3422                      int space,
3423                      attr_t attr,
3424                      short pair)
3425 {
3426     int first = base * pagesize;
3427     int last = first + pagesize - 1;
3428     int per_line = 16;
3429     cchar_t temp;
3430     wchar_t code;
3431     wchar_t codes[10];
3432
3433     erase();
3434     attron(A_BOLD);
3435     MvPrintw(0, 20, "Display of Character Codes %#x to %#x", first, last);
3436     attroff(A_BOLD);
3437
3438     for (code = first; (int) code <= last; code++) {
3439         int row = (2 + ((int) code - first) / per_line);
3440         int col = 5 * ((int) code % per_line);
3441         int count;
3442
3443         memset(&codes, 0, sizeof(codes));
3444         codes[0] = code;
3445         setcchar(&temp, codes, attr, pair, 0);
3446         move(row, col);
3447         if (wcwidth(code) == 0 && code != 0) {
3448             addch((chtype) space |
3449                   (A_REVERSE ^ attr) |
3450                   (attr_t) COLOR_PAIR(pair));
3451         }
3452         add_wch(&temp);
3453         for (count = 1; count < repeat; ++count) {
3454             add_wch(&temp);
3455         }
3456     }
3457 }
3458
3459 static void
3460 show_upper_widechars(int first, int repeat, int space, attr_t attr, short pair)
3461 {
3462     cchar_t temp;
3463     wchar_t code;
3464     int last = first + 31;
3465
3466     erase();
3467     attron(A_BOLD);
3468     MvPrintw(0, 20, "Display of Character Codes %d to %d", first, last);
3469     attroff(A_BOLD);
3470
3471     for (code = first; (int) code <= last; code++) {
3472         int row = 2 + ((code - first) % 16);
3473         int col = ((code - first) / 16) * COLS / 2;
3474         wchar_t codes[10];
3475         char tmp[80];
3476         int count = repeat;
3477         int y, x;
3478
3479         sprintf(tmp, "%3ld (0x%lx)", (long) code, (long) code);
3480         MvPrintw(row, col, "%*s: ", COLS / 4, tmp);
3481
3482         memset(&codes, 0, sizeof(codes));
3483         codes[0] = code;
3484         setcchar(&temp, codes, attr, pair, 0);
3485
3486         do {
3487             /*
3488              * Give non-spacing characters something to combine with.  If we
3489              * don't, they'll bunch up in a heap on the space after the ":".
3490              * Mark them with reverse-video to make them simpler to find on
3491              * the display.
3492              */
3493             if (wcwidth(code) == 0) {
3494                 addch((chtype) space |
3495                       (A_REVERSE ^ attr) |
3496                       (attr_t) COLOR_PAIR(pair));
3497             }
3498             /*
3499              * This uses echo_wchar(), for comparison with the normal 'f'
3500              * test (and to make a test-case for echo_wchar()).  The screen
3501              * may flicker because the erase() at the top of the function
3502              * is met by the builtin refresh() in echo_wchar().
3503              */
3504             echo_wchar(&temp);
3505             /*
3506              * The repeat-count may make text wrap - avoid that.
3507              */
3508             getyx(stdscr, y, x);
3509             (void) y;
3510             if (x >= col + (COLS / 2) - 2)
3511                 break;
3512         } while (--count > 0);
3513     }
3514 }
3515
3516 static int
3517 show_1_wacs(int n, int repeat, const char *name, const cchar_t *code)
3518 {
3519     const int height = 16;
3520     int row = 2 + (n % height);
3521     int col = (n / height) * COLS / 2;
3522
3523     MvPrintw(row, col, "%*s : ", COLS / 4, name);
3524     while (--repeat >= 0) {
3525         add_wch(code);
3526     }
3527     return n + 1;
3528 }
3529
3530 #define MERGE_ATTR(wch) merge_wide_attr(&temp, wch, attr, pair)
3531
3532 static void
3533 show_wacs_chars(int repeat, attr_t attr, short pair)
3534 /* display the wide-ACS character set */
3535 {
3536     cchar_t temp;
3537
3538     int n;
3539
3540 /*#define BOTH2(name) #name, &(name) */
3541 #define BOTH2(name) #name, MERGE_ATTR(name)
3542
3543     erase();
3544     attron(A_BOLD);
3545     MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3546     attroff(A_BOLD);
3547     refresh();
3548
3549     n = show_1_wacs(0, repeat, BOTH2(WACS_ULCORNER));
3550     n = show_1_wacs(n, repeat, BOTH2(WACS_URCORNER));
3551     n = show_1_wacs(n, repeat, BOTH2(WACS_LLCORNER));
3552     n = show_1_wacs(n, repeat, BOTH2(WACS_LRCORNER));
3553
3554     n = show_1_wacs(n, repeat, BOTH2(WACS_LTEE));
3555     n = show_1_wacs(n, repeat, BOTH2(WACS_RTEE));
3556     n = show_1_wacs(n, repeat, BOTH2(WACS_TTEE));
3557     n = show_1_wacs(n, repeat, BOTH2(WACS_BTEE));
3558
3559     n = show_1_wacs(n, repeat, BOTH2(WACS_HLINE));
3560     n = show_1_wacs(n, repeat, BOTH2(WACS_VLINE));
3561
3562     n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3563     n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3564     n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3565     n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3566
3567     n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3568     n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3569     n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3570     n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3571     n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3572     n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3573     n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3574     n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3575     n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3576
3577 #ifdef CURSES_WACS_ARRAY
3578     n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3579     n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3580     n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3581
3582     n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3583     n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3584     n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3585     n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3586     n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3587     (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3588 #endif
3589 }
3590
3591 #ifdef WACS_D_PLUS
3592 static void
3593 show_wacs_chars_double(int repeat, attr_t attr, short pair)
3594 /* display the wide-ACS character set */
3595 {
3596     cchar_t temp;
3597
3598     int n;
3599
3600 /*#define BOTH2(name) #name, &(name) */
3601 #define BOTH2(name) #name, MERGE_ATTR(name)
3602
3603     erase();
3604     attron(A_BOLD);
3605     MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3606     attroff(A_BOLD);
3607     refresh();
3608
3609     n = show_1_wacs(0, repeat, BOTH2(WACS_D_ULCORNER));
3610     n = show_1_wacs(n, repeat, BOTH2(WACS_D_URCORNER));
3611     n = show_1_wacs(n, repeat, BOTH2(WACS_D_LLCORNER));
3612     n = show_1_wacs(n, repeat, BOTH2(WACS_D_LRCORNER));
3613
3614     n = show_1_wacs(n, repeat, BOTH2(WACS_D_LTEE));
3615     n = show_1_wacs(n, repeat, BOTH2(WACS_D_RTEE));
3616     n = show_1_wacs(n, repeat, BOTH2(WACS_D_TTEE));
3617     n = show_1_wacs(n, repeat, BOTH2(WACS_D_BTEE));
3618
3619     n = show_1_wacs(n, repeat, BOTH2(WACS_D_HLINE));
3620     n = show_1_wacs(n, repeat, BOTH2(WACS_D_VLINE));
3621
3622     n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3623     n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3624     n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3625     n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3626
3627     n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3628     n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3629     n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3630     n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3631     n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3632     n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3633     n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3634     n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3635     n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3636
3637 #ifdef CURSES_WACS_ARRAY
3638     n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3639     n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3640     n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3641
3642     n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3643     n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3644     n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3645     n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3646     n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3647     (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3648 #endif
3649 }
3650 #endif
3651
3652 #ifdef WACS_T_PLUS
3653 static void
3654 show_wacs_chars_thick(int repeat, attr_t attr, short pair)
3655 /* display the wide-ACS character set */
3656 {
3657     cchar_t temp;
3658
3659     int n;
3660
3661 /*#define BOTH2(name) #name, &(name) */
3662 #define BOTH2(name) #name, MERGE_ATTR(name)
3663
3664     erase();
3665     attron(A_BOLD);
3666     MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3667     attroff(A_BOLD);
3668     refresh();
3669
3670     n = show_1_wacs(0, repeat, BOTH2(WACS_T_ULCORNER));
3671     n = show_1_wacs(n, repeat, BOTH2(WACS_T_URCORNER));
3672     n = show_1_wacs(n, repeat, BOTH2(WACS_T_LLCORNER));
3673     n = show_1_wacs(n, repeat, BOTH2(WACS_T_LRCORNER));
3674
3675     n = show_1_wacs(n, repeat, BOTH2(WACS_T_LTEE));
3676     n = show_1_wacs(n, repeat, BOTH2(WACS_T_RTEE));
3677     n = show_1_wacs(n, repeat, BOTH2(WACS_T_TTEE));
3678     n = show_1_wacs(n, repeat, BOTH2(WACS_T_BTEE));
3679
3680     n = show_1_wacs(n, repeat, BOTH2(WACS_T_HLINE));
3681     n = show_1_wacs(n, repeat, BOTH2(WACS_T_VLINE));
3682
3683     n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3684     n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3685     n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3686     n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3687
3688     n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3689     n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3690     n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3691     n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3692     n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3693     n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3694     n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3695     n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3696     n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3697
3698 #ifdef CURSES_WACS_ARRAY
3699     n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3700     n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3701     n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3702
3703     n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3704     n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3705     n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3706     n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3707     n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3708     (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3709 #endif
3710 }
3711 #endif
3712
3713 #undef MERGE_ATTR
3714
3715 #define MERGE_ATTR(n,wch) merge_wide_attr(&temp[n], wch, attr, pair)
3716
3717 static void
3718 show_wbox_chars(int repeat, attr_t attr, short pair)
3719 {
3720     cchar_t temp[8];
3721
3722     (void) repeat;
3723     erase();
3724     attron(A_BOLD);
3725     MvAddStr(0, 20, "Display of the Wide-ACS Line-Drawing Set");
3726     attroff(A_BOLD);
3727     refresh();
3728
3729     wborder_set(stdscr,
3730                 MERGE_ATTR(0, WACS_VLINE),
3731                 MERGE_ATTR(1, WACS_VLINE),
3732                 MERGE_ATTR(2, WACS_HLINE),
3733                 MERGE_ATTR(3, WACS_HLINE),
3734                 MERGE_ATTR(4, WACS_ULCORNER),
3735                 MERGE_ATTR(5, WACS_URCORNER),
3736                 MERGE_ATTR(6, WACS_LLCORNER),
3737                 MERGE_ATTR(7, WACS_LRCORNER));
3738     /* *INDENT-OFF* */
3739     (void) mvhline_set(LINES / 2, 0,        MERGE_ATTR(0, WACS_HLINE), COLS);
3740     (void) mvvline_set(0,         COLS / 2, MERGE_ATTR(0, WACS_VLINE), LINES);
3741     (void) mvadd_wch(0,           COLS / 2, MERGE_ATTR(0, WACS_TTEE));
3742     (void) mvadd_wch(LINES / 2,   COLS / 2, MERGE_ATTR(0, WACS_PLUS));
3743     (void) mvadd_wch(LINES - 1,   COLS / 2, MERGE_ATTR(0, WACS_BTEE));
3744     (void) mvadd_wch(LINES / 2,   0,        MERGE_ATTR(0, WACS_LTEE));
3745     (void) mvadd_wch(LINES / 2,   COLS - 1, MERGE_ATTR(0, WACS_RTEE));
3746     /* *INDENT-ON* */
3747
3748 }
3749
3750 #undef MERGE_ATTR
3751
3752 static int
3753 show_2_wacs(int n, const char *name, const char *code, attr_t attr, short pair)
3754 {
3755     const int height = 16;
3756     int row = 2 + (n % height);
3757     int col = (n / height) * COLS / 2;
3758     char temp[80];
3759
3760     MvPrintw(row, col, "%*s : ", COLS / 4, name);
3761     (void) attr_set(attr, pair, 0);
3762     addstr(strncpy(temp, code, 20));
3763     (void) attr_set(A_NORMAL, 0, 0);
3764     return n + 1;
3765 }
3766
3767 #define SHOW_UTF8(n, name, code) show_2_wacs(n, name, code, attr, pair)
3768
3769 static void
3770 show_utf8_chars(int repeat, attr_t attr, short pair)
3771 {
3772     int n;
3773
3774     (void) repeat;
3775     erase();
3776     attron(A_BOLD);
3777     MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3778     attroff(A_BOLD);
3779     refresh();
3780     /* *INDENT-OFF* */
3781     n = SHOW_UTF8(0, "WACS_ULCORNER",   "\342\224\214");
3782     n = SHOW_UTF8(n, "WACS_URCORNER",   "\342\224\220");
3783     n = SHOW_UTF8(n, "WACS_LLCORNER",   "\342\224\224");
3784     n = SHOW_UTF8(n, "WACS_LRCORNER",   "\342\224\230");
3785
3786     n = SHOW_UTF8(n, "WACS_LTEE",       "\342\224\234");
3787     n = SHOW_UTF8(n, "WACS_RTEE",       "\342\224\244");
3788     n = SHOW_UTF8(n, "WACS_TTEE",       "\342\224\254");
3789     n = SHOW_UTF8(n, "WACS_BTEE",       "\342\224\264");
3790