blob: 59a88c457402cc0a4ab43325e750246a0634ee56 [file] [log] [blame]
Steve Kondikae271bc2015-11-15 02:50:53 +01001/****************************************************************************
2 * Copyright (c) 1998-2014,2015 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
30NAME
31 ncurses.c --- ncurses library exerciser
32
33SYNOPSIS
34 ncurses
35
36DESCRIPTION
37 An interactive test module for the ncurses library.
38
39AUTHOR
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.420 2015/05/23 23:41:25 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
79static unsigned save_trace = TRACE_ORDINARY | TRACE_ICALLS | TRACE_CALLS;
80extern 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
152static int max_colors; /* the actual number of colors we'll use */
153static int min_colors; /* the minimum color code */
154static bool use_colors; /* true if we use colors */
155
156#undef max_pairs
157static int max_pairs; /* ...and the number of color pairs */
158
159typedef struct {
160 NCURSES_COLOR_T red;
161 NCURSES_COLOR_T green;
162 NCURSES_COLOR_T blue;
163} RGB_DATA;
164
165static RGB_DATA *all_colors;
166
167static void main_menu(bool);
168
169static void
170failed(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 */
180static void
181do_h_line(int y, int x, chtype c, int to)
182{
183 if ((to) > (x))
184 MvHLine(y, x, c, (to) - (x));
185}
186
187static void
188do_v_line(int y, int x, chtype c, int to)
189{
190 if ((to) > (y))
191 MvVLine(y, x, c, (to) - (y));
192}
193
194static void
195Repaint(void)
196{
197 touchwin(stdscr);
198 touchwin(curscr);
199 wrefresh(curscr);
200}
201
202static bool
203isQuit(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 */
212static int
213wGetchar(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 */
237static void
238wGetstring(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
305static wchar_t
306fullwidth_digit(int ch)
307{
308 return (wchar_t) (ch + 0xff10 - '0');
309}
310
311static void
312make_fullwidth_text(wchar_t *target, const char *source)
313{
314 int ch;
315 while ((ch = *source++) != 0) {
316 *target++ = fullwidth_digit(ch);
317 }
318 *target = 0;
319}
320
321static void
322make_narrow_text(wchar_t *target, const char *source)
323{
324 int ch;
325 while ((ch = *source++) != 0) {
326 *target++ = (wchar_t) ch;
327 }
328 *target = 0;
329}
330
331#if USE_LIBPANEL
332static void
333make_fullwidth_digit(cchar_t *target, int digit)
334{
335 wchar_t source[2];
336
337 source[0] = fullwidth_digit(digit + '0');
338 source[1] = 0;
339 setcchar(target, source, A_NORMAL, 0, 0);
340}
341#endif
342
343static int
344wGet_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 */
368static void
369wGet_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
476static void
477Pause(void)
478{
479 move(LINES - 1, 0);
480 addstr("Press any key to continue... ");
481 (void) Getchar();
482}
483
484static void
485Cannot(const char *what)
486{
487 printw("\nThis %s terminal %s\n\n", getenv("TERM"), what);
488 Pause();
489}
490
491static void
492ShellOut(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 */
513static const char *
514mouse_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
581static void
582show_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
625typedef bool GetchFlags[NUM_GETCH_FLAGS];
626
627static void
628setup_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
638static void
639init_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
648static void
649wgetch_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
689static void
690wgetch_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
702typedef struct {
703 WINDOW *text;
704 WINDOW *frame;
705} WINSTACK;
706
707static WINSTACK *winstack = 0;
708static unsigned len_winstack = 0;
709
710static void
711forget_boxes(void)
712{
713 if (winstack != 0) {
714 free(winstack);
715 }
716 winstack = 0;
717 len_winstack = 0;
718}
719
720static void
721remember_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
741static void
742slk_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 */
759static void
760resize_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 */
799static const char *
800ok_keyname(int code)
801{
802 return ((code == OK) ? "OK" : ((code == ERR) ? "ERR" : keyname(code)));
803}
804
805static void
806wgetch_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
937static int
938begin_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 | REPORT_MOUSE_POSITION, (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
965static void
966finish_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
977static void
978getch_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
995static void
996resize_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
1028static char *
1029wcstos(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
1054static void
1055wget_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
1190static void
1191get_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
1218static chtype
1219my_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 ATTRSTRING_1ST 32 /* ' ' */
1256#define ATTRSTRING_END 126 /* '~' */
1257
1258#define COL_ATTRSTRING 25
1259#define MARGIN_4_ATTRS (COL_ATTRSTRING + 8)
1260#define LEN_ATTRSTRING (COLS - MARGIN_4_ATTRS)
1261#define MAX_ATTRSTRING (ATTRSTRING_END + 1 - ATTRSTRING_1ST)
1262
1263static char attr_test_string[MAX_ATTRSTRING + 1];
1264
1265static void
1266attr_legend(WINDOW *helpwin)
1267{
1268 int row = 1;
1269 int col = 1;
1270
1271 MvWPrintw(helpwin, row++, col,
1272 "ESC to exit.");
1273 MvWPrintw(helpwin, row++, col,
1274 "^L repaints.");
1275 ++row;
1276 MvWPrintw(helpwin, row++, col,
1277 "Modify the test strings:");
1278 MvWPrintw(helpwin, row++, col,
1279 " A digit sets gaps on each side of displayed attributes");
1280 MvWPrintw(helpwin, row++, col,
1281 " </> shifts the text left/right. ");
1282 ++row;
1283 MvWPrintw(helpwin, row++, col,
1284 "Toggles:");
1285 if (use_colors) {
1286 MvWPrintw(helpwin, row++, col,
1287 " f/F/b/F toggle foreground/background background color");
1288 MvWPrintw(helpwin, row++, col,
1289 " t/T toggle text/background color attribute");
1290 }
1291 MvWPrintw(helpwin, row++, col,
1292 " a/A toggle ACS (alternate character set) mapping");
1293 MvWPrintw(helpwin, row, col,
1294 " v/V toggle video attribute to combine with each line");
1295#if USE_WIDEC_SUPPORT
1296 MvWPrintw(helpwin, row, col,
1297 " w/W toggle normal/wide (double-width) test-characters");
1298#endif
1299}
1300
1301static void
1302show_color_attr(int fg, int bg, int tx)
1303{
1304 if (use_colors) {
1305 printw(" Colors (fg %d, bg %d", fg, bg);
1306 if (tx >= 0)
1307 printw(", text %d", tx);
1308 printw("),");
1309 }
1310}
1311
1312static bool
1313cycle_color_attr(int ch, NCURSES_COLOR_T *fg, NCURSES_COLOR_T *bg, NCURSES_COLOR_T *tx)
1314{
1315 bool error = FALSE;
1316
1317 if (use_colors) {
1318 switch (ch) {
1319 case 'f':
1320 *fg = (NCURSES_COLOR_T) (*fg + 1);
1321 break;
1322 case 'F':
1323 *fg = (NCURSES_COLOR_T) (*fg - 1);
1324 break;
1325 case 'b':
1326 *bg = (NCURSES_COLOR_T) (*bg + 1);
1327 break;
1328 case 'B':
1329 *bg = (NCURSES_COLOR_T) (*bg - 1);
1330 break;
1331 case 't':
1332 *tx = (NCURSES_COLOR_T) (*tx + 1);
1333 break;
1334 case 'T':
1335 *tx = (NCURSES_COLOR_T) (*tx - 1);
1336 break;
1337 default:
1338 beep();
1339 error = TRUE;
1340 break;
1341 }
1342 if (*fg >= COLORS)
1343 *fg = (NCURSES_COLOR_T) min_colors;
1344 if (*fg < min_colors)
1345 *fg = (NCURSES_COLOR_T) (COLORS - 1);
1346 if (*bg >= COLORS)
1347 *bg = (NCURSES_COLOR_T) min_colors;
1348 if (*bg < min_colors)
1349 *bg = (NCURSES_COLOR_T) (COLORS - 1);
1350 if (*tx >= COLORS)
1351 *tx = -1;
1352 if (*tx < -1)
1353 *tx = (NCURSES_COLOR_T) (COLORS - 1);
1354 } else {
1355 beep();
1356 error = TRUE;
1357 }
1358 return error;
1359}
1360
1361static void
1362adjust_attr_string(int adjust)
1363{
1364 char save = attr_test_string[0];
1365 int first = ((int) UChar(save)) + adjust;
1366 int j, k;
1367
1368 if (first >= ATTRSTRING_1ST) {
1369 for (j = 0, k = first; j < MAX_ATTRSTRING; ++j, ++k) {
1370 if (k > ATTRSTRING_END)
1371 break;
1372 attr_test_string[j] = (char) k;
1373 if (((k + 1 - first) % 5) == 0) {
1374 if (++j >= MAX_ATTRSTRING)
1375 break;
1376 attr_test_string[j] = ' ';
1377 }
1378 }
1379 if ((LEN_ATTRSTRING - j) > 5) {
1380 attr_test_string[0] = save;
1381 adjust_attr_string(adjust - 1);
1382 } else {
1383 while (j < MAX_ATTRSTRING)
1384 attr_test_string[j++] = ' ';
1385 attr_test_string[j] = '\0';
1386 }
1387 }
1388}
1389
1390/*
1391 * Prefer the right-end of the string for starting, since that maps to the
1392 * VT100 line-drawing.
1393 */
1394static int
1395default_attr_string(void)
1396{
1397 int result = (ATTRSTRING_END - LEN_ATTRSTRING);
1398 result += (LEN_ATTRSTRING / 5);
1399 if (result < ATTRSTRING_1ST)
1400 result = ATTRSTRING_1ST;
1401 return result;
1402}
1403
1404static void
1405init_attr_string(void)
1406{
1407 attr_test_string[0] = (char) default_attr_string();
1408 adjust_attr_string(0);
1409}
1410
1411static int
1412show_attr(WINDOW *win, int row, int skip, bool arrow, chtype attr, const char *name)
1413{
1414 int ncv = get_ncv();
1415 chtype test = attr & (chtype) (~A_ALTCHARSET);
1416
1417 if (arrow)
1418 MvPrintw(row, 5, "-->");
1419 MvPrintw(row, 8, "%s mode:", name);
1420 MvPrintw(row, COL_ATTRSTRING - 1, "|");
1421 if (skip)
1422 printw("%*s", skip, " ");
1423 /*
1424 * Just for testing, write text using the alternate character set one
1425 * character at a time (to pass its rendition directly), and use the
1426 * string operation for the other attributes.
1427 */
1428 wmove(win, 0, 0);
1429 werase(win);
1430 if (attr & A_ALTCHARSET) {
1431 const char *s;
1432 chtype ch;
1433
1434 for (s = attr_test_string; *s != '\0'; ++s) {
1435 ch = UChar(*s);
1436 (void) waddch(win, ch | attr);
1437 }
1438 } else {
1439 (void) wattrset(win, AttrArg(attr, 0));
1440 (void) waddstr(win, attr_test_string);
1441 (void) wattroff(win, (int) attr);
1442 }
1443 if (skip)
1444 printw("%*s", skip, " ");
1445 MvPrintw(row, COL_ATTRSTRING + LEN_ATTRSTRING, "|");
1446 if (test != A_NORMAL) {
1447 if (!(termattrs() & test)) {
1448 printw(" (N/A)");
1449 } else {
1450 if (ncv > 0 && stdscr && (getbkgd(stdscr) & A_COLOR)) {
1451 static const chtype table[] =
1452 {
1453 A_STANDOUT,
1454 A_UNDERLINE,
1455 A_REVERSE,
1456 A_BLINK,
1457 A_DIM,
1458 A_BOLD,
1459#ifdef A_INVIS
1460 A_INVIS,
1461#endif
1462#ifdef A_ITALIC
1463 A_ITALIC,
1464#endif
1465 A_PROTECT,
1466 A_ALTCHARSET
1467 };
1468 unsigned n;
1469 bool found = FALSE;
1470 for (n = 0; n < SIZEOF(table); n++) {
1471 if ((table[n] & attr) != 0
1472 && ((1 << n) & ncv) != 0) {
1473 found = TRUE;
1474 break;
1475 }
1476 }
1477 if (found)
1478 printw(" (NCV)");
1479 }
1480 if ((termattrs() & test) != test)
1481 printw(" (Part)");
1482 }
1483 }
1484 return row + 2;
1485}
1486
1487typedef struct {
1488 attr_t attr;
1489 NCURSES_CONST char *name;
1490} ATTR_TBL;
1491/* *INDENT-OFF* */
1492static const ATTR_TBL attrs_to_test[] = {
1493 { A_STANDOUT, "STANDOUT" },
1494 { A_REVERSE, "REVERSE" },
1495 { A_BOLD, "BOLD" },
1496 { A_UNDERLINE, "UNDERLINE" },
1497 { A_DIM, "DIM" },
1498 { A_BLINK, "BLINK" },
1499 { A_PROTECT, "PROTECT" },
1500#ifdef A_INVIS
1501 { A_INVIS, "INVISIBLE" },
1502#endif
1503#ifdef A_ITALIC
1504 { A_ITALIC, "ITALIC" },
1505#endif
1506 { A_NORMAL, "NORMAL" },
1507};
1508/* *INDENT-ON* */
1509
1510static unsigned
1511init_attr_list(ATTR_TBL * target, attr_t attrs)
1512{
1513 unsigned result = 0;
1514 size_t n;
1515
1516 for (n = 0; n < SIZEOF(attrs_to_test); ++n) {
1517 attr_t test = attrs_to_test[n].attr;
1518 if (test == A_NORMAL || (test & attrs) != 0) {
1519 target[result++] = attrs_to_test[n];
1520 }
1521 }
1522 return result;
1523}
1524
1525static bool
1526attr_getc(int *skip,
1527 NCURSES_COLOR_T *fg,
1528 NCURSES_COLOR_T *bg,
1529 NCURSES_COLOR_T *tx,
1530 int *ac,
1531 unsigned *kc,
1532 unsigned limit)
1533{
1534 bool result = TRUE;
1535 bool error = FALSE;
1536 WINDOW *helpwin;
1537
1538 do {
1539 int ch = Getchar();
1540
1541 error = FALSE;
1542 if (ch < 256 && isdigit(ch)) {
1543 *skip = (ch - '0');
1544 } else {
1545 switch (ch) {
1546 case CTRL('L'):
1547 Repaint();
1548 break;
1549 case '?':
1550 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
1551 box(helpwin, 0, 0);
1552 attr_legend(helpwin);
1553 wGetchar(helpwin);
1554 delwin(helpwin);
1555 }
1556 break;
1557 case 'a':
1558 *ac = 0;
1559 break;
1560 case 'A':
1561 *ac = A_ALTCHARSET;
1562 break;
1563 case 'v':
1564 if (*kc == 0)
1565 *kc = limit - 1;
1566 else
1567 *kc -= 1;
1568 break;
1569 case 'V':
1570 *kc += 1;
1571 if (*kc >= limit)
1572 *kc = 0;
1573 break;
1574 case '<':
1575 adjust_attr_string(-1);
1576 break;
1577 case '>':
1578 adjust_attr_string(1);
1579 break;
1580 case case_QUIT:
1581 result = FALSE;
1582 break;
1583 default:
1584 error = cycle_color_attr(ch, fg, bg, tx);
1585 break;
1586 }
1587 }
1588 } while (error);
1589 return result;
1590}
1591
1592static void
1593attr_test(void)
1594/* test text attributes */
1595{
1596 int n;
1597 int skip = get_xmc();
1598 NCURSES_COLOR_T fg = COLOR_BLACK; /* color pair 0 is special */
1599 NCURSES_COLOR_T bg = COLOR_BLACK;
1600 NCURSES_COLOR_T tx = -1;
1601 int ac = 0;
1602 unsigned j, k;
1603 WINDOW *my_wins[SIZEOF(attrs_to_test)];
1604 ATTR_TBL my_list[SIZEOF(attrs_to_test)];
1605 unsigned my_size = init_attr_list(my_list, termattrs());
1606
1607 if (my_size > 1) {
1608 for (j = 0; j < my_size; ++j) {
1609 my_wins[j] = subwin(stdscr,
1610 1, LEN_ATTRSTRING,
1611 2 + (int) (2 * j), COL_ATTRSTRING);
1612 scrollok(my_wins[j], FALSE);
1613 }
1614
1615 if (skip < 0)
1616 skip = 0;
1617
1618 n = skip; /* make it easy */
1619 k = my_size - 1;
1620 init_attr_string();
1621
1622 do {
1623 int row = 2;
1624 chtype normal = A_NORMAL | BLANK;
1625 chtype extras = (chtype) ac;
1626
1627 if (use_colors) {
1628 NCURSES_PAIRS_T pair = 0;
1629 if ((fg != COLOR_BLACK) || (bg != COLOR_BLACK)) {
1630 pair = 1;
1631 if (init_pair(pair, fg, bg) == ERR) {
1632 beep();
1633 } else {
1634 normal |= (chtype) COLOR_PAIR(pair);
1635 }
1636 }
1637 if (tx >= 0) {
1638 pair = 2;
1639 if (init_pair(pair, tx, bg) == ERR) {
1640 beep();
1641 } else {
1642 extras |= (chtype) COLOR_PAIR(pair);
1643 normal &= ~A_COLOR;
1644 }
1645 }
1646 }
1647 bkgd(normal);
1648 bkgdset(normal);
1649 erase();
1650
1651 box(stdscr, 0, 0);
1652 MvAddStr(0, 20, "Character attribute test display");
1653
1654 for (j = 0; j < my_size; ++j) {
1655 bool arrow = (j == k);
1656 row = show_attr(my_wins[j], row, n, arrow,
1657 normal |
1658 extras |
1659 my_list[j].attr |
1660 my_list[k].attr,
1661 my_list[j].name);
1662 }
1663
1664 MvPrintw(row, 8,
1665 "This terminal does %shave the magic-cookie glitch",
1666 get_xmc() > -1 ? "" : "not ");
1667 MvPrintw(row + 1, 8, "Enter '?' for help.");
1668 show_color_attr(fg, bg, tx);
1669 printw(" ACS (%d)", ac != 0);
1670
1671 refresh();
1672 } while (attr_getc(&n, &fg, &bg, &tx, &ac, &k, my_size));
1673
1674 bkgdset(A_NORMAL | BLANK);
1675 erase();
1676 endwin();
1677 } else {
1678 Cannot("does not support video attributes.");
1679 }
1680}
1681
1682#if USE_WIDEC_SUPPORT
1683static bool use_fullwidth;
1684static wchar_t wide_attr_test_string[MAX_ATTRSTRING + 1];
1685
1686#define FULL_LO 0xff00
1687#define FULL_HI 0xff5e
1688#define HALF_LO 0x20
1689
1690#define isFullWidth(ch) ((int)(ch) >= FULL_LO && (int)(ch) <= FULL_HI)
1691#define ToNormalWidth(ch) (wchar_t) (((int)(ch) - FULL_LO) + HALF_LO)
1692#define ToFullWidth(ch) (wchar_t) (((int)(ch) - HALF_LO) + FULL_LO)
1693
1694/*
1695 * Returns an ASCII code in [32..126]
1696 */
1697static wchar_t
1698normal_wchar(int ch)
1699{
1700 wchar_t result = (wchar_t) ch;
1701 if (isFullWidth(ch))
1702 result = ToNormalWidth(ch);
1703 return result;
1704}
1705
1706/*
1707 * Returns either an ASCII code in in [32..126] or full-width in
1708 * [0xff00..0xff5e], according to use_fullwidth setting.
1709 */
1710static wchar_t
1711target_wchar(int ch)
1712{
1713 wchar_t result = (wchar_t) ch;
1714 if (use_fullwidth) {
1715 if (!isFullWidth(ch))
1716 result = ToFullWidth(ch);
1717 } else {
1718 if (isFullWidth(ch))
1719 result = ToNormalWidth(ch);
1720 }
1721 return result;
1722}
1723
1724static void
1725wide_adjust_attr_string(int adjust)
1726{
1727 wchar_t save = wide_attr_test_string[0];
1728 int first = ((int) normal_wchar(save)) + adjust;
1729 int j, k;
1730
1731 if (first >= ATTRSTRING_1ST) {
1732 for (j = 0, k = first; j < MAX_ATTRSTRING; ++j, ++k) {
1733 if (k > ATTRSTRING_END)
1734 break;
1735 wide_attr_test_string[j] = target_wchar(k);
1736 if (((k + 1 - first) % 5) == 0) {
1737 if (++j >= MAX_ATTRSTRING)
1738 break;
1739 wide_attr_test_string[j] = ' ';
1740 }
1741 }
1742 if ((LEN_ATTRSTRING - j) > 5) {
1743 wide_attr_test_string[0] = save;
1744 wide_adjust_attr_string(adjust - 1);
1745 } else {
1746 while (j < MAX_ATTRSTRING)
1747 wide_attr_test_string[j++] = ' ';
1748 wide_attr_test_string[j] = '\0';
1749 }
1750 }
1751}
1752
1753static void
1754wide_init_attr_string(void)
1755{
1756 use_fullwidth = FALSE;
1757 wide_attr_test_string[0] = (wchar_t) default_attr_string();
1758 wide_adjust_attr_string(0);
1759}
1760
1761static void
1762set_wide_background(NCURSES_PAIRS_T pair)
1763{
1764 cchar_t normal;
1765 wchar_t blank[2];
1766
1767 blank[0] = ' ';
1768 blank[1] = 0;
1769 setcchar(&normal, blank, A_NORMAL, pair, 0);
1770 bkgrnd(&normal);
1771 bkgrndset(&normal);
1772}
1773
1774static attr_t
1775get_wide_background(void)
1776{
1777 attr_t result = A_NORMAL;
1778 attr_t attr;
1779 cchar_t ch;
1780 NCURSES_PAIRS_T pair;
1781 wchar_t wch[10];
1782
1783 memset(&ch, 0, sizeof(ch));
1784 if (getbkgrnd(&ch) != ERR) {
1785 if (getcchar(&ch, wch, &attr, &pair, 0) != ERR) {
1786 result = attr;
1787 }
1788 }
1789 return result;
1790}
1791
1792static int
1793wide_show_attr(WINDOW *win,
1794 int row,
1795 int skip,
1796 bool arrow,
1797 chtype attr,
1798 NCURSES_PAIRS_T pair,
1799 const char *name)
1800{
1801 int ncv = get_ncv();
1802 chtype test = attr & ~WA_ALTCHARSET;
1803
1804 if (arrow)
1805 MvPrintw(row, 5, "-->");
1806 MvPrintw(row, 8, "%s mode:", name);
1807 MvPrintw(row, COL_ATTRSTRING - 1, "|");
1808 if (skip)
1809 printw("%*s", skip, " ");
1810
1811 /*
1812 * Just for testing, write text using the alternate character set one
1813 * character at a time (to pass its rendition directly), and use the
1814 * string operation for the other attributes.
1815 */
1816 wmove(win, 0, 0);
1817 werase(win);
1818 if (attr & WA_ALTCHARSET) {
1819 const wchar_t *s;
1820 cchar_t ch;
1821
1822 for (s = wide_attr_test_string; *s != L'\0'; ++s) {
1823 wchar_t fill[2];
1824 fill[0] = *s;
1825 fill[1] = L'\0';
1826 setcchar(&ch, fill, attr, pair, 0);
1827 (void) wadd_wch(win, &ch);
1828 }
1829 } else {
1830 attr_t old_attr = 0;
1831 NCURSES_PAIRS_T old_pair = 0;
1832
1833 (void) (wattr_get) (win, &old_attr, &old_pair, 0);
1834 (void) wattr_set(win, attr, pair, 0);
1835 (void) waddwstr(win, wide_attr_test_string);
1836 (void) wattr_set(win, old_attr, old_pair, 0);
1837 }
1838 if (skip)
1839 printw("%*s", skip, " ");
1840 MvPrintw(row, COL_ATTRSTRING + LEN_ATTRSTRING, "|");
1841 if (test != A_NORMAL) {
1842 if (!(term_attrs() & test)) {
1843 printw(" (N/A)");
1844 } else {
1845 if (ncv > 0 && (get_wide_background() & A_COLOR)) {
1846 static const attr_t table[] =
1847 {
1848 WA_STANDOUT,
1849 WA_UNDERLINE,
1850 WA_REVERSE,
1851 WA_BLINK,
1852 WA_DIM,
1853 WA_BOLD,
1854 WA_INVIS,
1855 WA_PROTECT,
1856 WA_ALTCHARSET
1857 };
1858 unsigned n;
1859 bool found = FALSE;
1860 for (n = 0; n < SIZEOF(table); n++) {
1861 if ((table[n] & attr) != 0
1862 && ((1 << n) & ncv) != 0) {
1863 found = TRUE;
1864 break;
1865 }
1866 }
1867 if (found)
1868 printw(" (NCV)");
1869 }
1870 if ((term_attrs() & test) != test)
1871 printw(" (Part)");
1872 }
1873 }
1874 return row + 2;
1875}
1876
1877static bool
1878wide_attr_getc(int *skip,
1879 NCURSES_COLOR_T *fg, NCURSES_COLOR_T *bg,
1880 NCURSES_COLOR_T *tx, int *ac,
1881 unsigned *kc, unsigned limit)
1882{
1883 bool result = TRUE;
1884 bool error = FALSE;
1885 WINDOW *helpwin;
1886
1887 do {
1888 int ch = Getchar();
1889
1890 error = FALSE;
1891 if (ch < 256 && isdigit(ch)) {
1892 *skip = (ch - '0');
1893 } else {
1894 switch (ch) {
1895 case CTRL('L'):
1896 Repaint();
1897 break;
1898 case '?':
1899 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
1900 box_set(helpwin, 0, 0);
1901 attr_legend(helpwin);
1902 wGetchar(helpwin);
1903 delwin(helpwin);
1904 }
1905 break;
1906 case 'a':
1907 *ac = 0;
1908 break;
1909 case 'A':
1910 *ac = A_ALTCHARSET;
1911 break;
1912 case 'v':
1913 if (*kc == 0)
1914 *kc = limit - 1;
1915 else
1916 *kc -= 1;
1917 break;
1918 case 'V':
1919 *kc += 1;
1920 if (*kc >= limit)
1921 *kc = 0;
1922 break;
1923 case 'w':
1924 use_fullwidth = FALSE;
1925 wide_adjust_attr_string(0);
1926 break;
1927 case 'W':
1928 use_fullwidth = TRUE;
1929 wide_adjust_attr_string(0);
1930 break;
1931 case '<':
1932 wide_adjust_attr_string(-1);
1933 break;
1934 case '>':
1935 wide_adjust_attr_string(1);
1936 break;
1937 case case_QUIT:
1938 result = FALSE;
1939 break;
1940 default:
1941 error = cycle_color_attr(ch, fg, bg, tx);
1942 break;
1943 }
1944 }
1945 } while (error);
1946 return result;
1947}
1948
1949static void
1950wide_attr_test(void)
1951/* test text attributes using wide-character calls */
1952{
1953 int n;
1954 int skip = get_xmc();
1955 NCURSES_COLOR_T fg = COLOR_BLACK; /* color pair 0 is special */
1956 NCURSES_COLOR_T bg = COLOR_BLACK;
1957 NCURSES_COLOR_T tx = -1;
1958 int ac = 0;
1959 unsigned j, k;
1960 ATTR_TBL my_list[SIZEOF(attrs_to_test)];
1961 WINDOW *my_wins[SIZEOF(attrs_to_test)];
1962 unsigned my_size = init_attr_list(my_list, term_attrs());
1963
1964 if (my_size > 1) {
1965 for (j = 0; j < my_size; ++j) {
1966 my_wins[j] = subwin(stdscr,
1967 1, LEN_ATTRSTRING,
1968 2 + (int) (2 * j), COL_ATTRSTRING);
1969 scrollok(my_wins[j], FALSE);
1970 }
1971
1972 if (skip < 0)
1973 skip = 0;
1974
1975 n = skip; /* make it easy */
1976 k = my_size - 1;
1977 wide_init_attr_string();
1978
1979 do {
1980 int row = 2;
1981 NCURSES_PAIRS_T pair = 0;
1982 NCURSES_PAIRS_T extras = 0;
1983
1984 if (use_colors) {
1985 pair = (NCURSES_PAIRS_T) (fg != COLOR_BLACK || bg != COLOR_BLACK);
1986 if (pair != 0) {
1987 pair = 1;
1988 if (init_pair(pair, fg, bg) == ERR) {
1989 beep();
1990 }
1991 }
1992 extras = pair;
1993 if (tx >= 0) {
1994 extras = 2;
1995 if (init_pair(extras, tx, bg) == ERR) {
1996 beep();
1997 }
1998 }
1999 }
2000 set_wide_background(pair);
2001 erase();
2002
2003 box_set(stdscr, 0, 0);
2004 MvAddStr(0, 20, "Character attribute test display");
2005
2006 for (j = 0; j < my_size; ++j) {
2007 row = wide_show_attr(my_wins[j], row, n, (j == k),
2008 ((attr_t) ac |
2009 my_list[j].attr |
2010 my_list[k].attr),
2011 extras,
2012 my_list[j].name);
2013 }
2014
2015 MvPrintw(row, 8,
2016 "This terminal does %shave the magic-cookie glitch",
2017 get_xmc() > -1 ? "" : "not ");
2018 MvPrintw(row + 1, 8, "Enter '?' for help.");
2019 show_color_attr(fg, bg, tx);
2020 printw(" ACS (%d)", ac != 0);
2021
2022 refresh();
2023 } while (wide_attr_getc(&n, &fg, &bg, &tx, &ac, &k, my_size));
2024
2025 set_wide_background(0);
2026 erase();
2027 endwin();
2028 } else {
2029 Cannot("does not support extended video attributes.");
2030 }
2031}
2032#endif
2033
2034/****************************************************************************
2035 *
2036 * Color support tests
2037 *
2038 ****************************************************************************/
2039
2040static NCURSES_CONST char *the_color_names[] =
2041{
2042 "black",
2043 "red",
2044 "green",
2045 "yellow",
2046 "blue",
2047 "magenta",
2048 "cyan",
2049 "white",
2050 "BLACK",
2051 "RED",
2052 "GREEN",
2053 "YELLOW",
2054 "BLUE",
2055 "MAGENTA",
2056 "CYAN",
2057 "WHITE"
2058};
2059
2060static void
2061show_color_name(int y, int x, int color, bool wide)
2062{
2063 if (move(y, x) != ERR) {
2064 char temp[80];
2065 int width = 8;
2066
2067 if (wide) {
2068 sprintf(temp, "%02d", color);
2069 width = 4;
2070 } else if (color >= 8) {
2071 sprintf(temp, "[%02d]", color);
2072 } else if (color < 0) {
2073 strcpy(temp, "default");
2074 } else {
2075 sprintf(temp, "%.*s", 16, the_color_names[color]);
2076 }
2077 printw("%-*.*s", width, width, temp);
2078 }
2079}
2080
2081static void
2082color_legend(WINDOW *helpwin, bool wide)
2083{
2084 int row = 1;
2085 int col = 1;
2086
2087 MvWPrintw(helpwin, row++, col,
2088 "ESC to exit.");
2089 ++row;
2090 MvWPrintw(helpwin, row++, col,
2091 "Use up/down arrow to scroll through the display if it is");
2092 MvWPrintw(helpwin, row++, col,
2093 "longer than one screen. Control/N and Control/P can be used");
2094 MvWPrintw(helpwin, row++, col,
2095 "in place of up/down arrow. Use pageup/pagedown to scroll a");
2096 MvWPrintw(helpwin, row++, col,
2097 "full screen; control/B and control/F can be used here.");
2098 ++row;
2099 MvWPrintw(helpwin, row++, col,
2100 "Toggles:");
2101 MvWPrintw(helpwin, row++, col,
2102 " a/A toggle altcharset off/on");
2103 MvWPrintw(helpwin, row++, col,
2104 " b/B toggle bold off/on");
2105 if (has_colors()) {
2106 MvWPrintw(helpwin, row++, col,
2107 " c/C cycle used-colors through 8,16,...,COLORS");
2108 }
2109 MvWPrintw(helpwin, row++, col,
2110 " n/N toggle text/number on/off");
2111 MvWPrintw(helpwin, row++, col,
2112 " r/R toggle reverse on/off");
2113 MvWPrintw(helpwin, row++, col,
2114 " w/W toggle width between 8/16 colors");
2115#if USE_WIDEC_SUPPORT
2116 if (wide) {
2117 MvWPrintw(helpwin, row++, col,
2118 "Wide characters:");
2119 MvWPrintw(helpwin, row, col,
2120 " x/X toggle text between ASCII and wide-character");
2121 }
2122#else
2123 (void) wide;
2124#endif
2125}
2126
2127#define set_color_test(name, value) if (name != value) { name = value; base_row = 0; }
2128
2129static int
2130color_cycle(int current, int step)
2131{
2132 int result = current;
2133 if (step < 0) {
2134 if (current <= 8) {
2135 result = COLORS;
2136 } else {
2137 result = 8;
2138 if ((result * 2) > COLORS) {
2139 result = COLORS;
2140 } else {
2141 while ((result * 2) < current) {
2142 result *= 2;
2143 }
2144 }
2145 }
2146 } else {
2147 if (current >= COLORS) {
2148 result = 8;
2149 } else {
2150 result *= 2;
2151 }
2152 if (result > COLORS)
2153 result = COLORS;
2154 }
2155 return result;
2156}
2157
2158/* generate a color test pattern */
2159static void
2160color_test(void)
2161{
2162 NCURSES_PAIRS_T i;
2163 int top = 0, width;
2164 int base_row = 0;
2165 int grid_top = top + 3;
2166 int page_size = (LINES - grid_top);
2167 int pairs_max;
2168 int colors_max = COLORS;
2169 int row_limit;
2170 int per_row;
2171 char numbered[80];
2172 const char *hello;
2173 bool done = FALSE;
2174 bool opt_acsc = FALSE;
2175 bool opt_bold = FALSE;
2176 bool opt_revs = FALSE;
2177 bool opt_nums = FALSE;
2178 bool opt_wide = FALSE;
2179 WINDOW *helpwin;
2180
2181 while (!done) {
2182 int shown = 0;
2183
2184 pairs_max = PAIR_NUMBER(A_COLOR) + 1;
2185 if (colors_max * colors_max <= COLOR_PAIRS) {
2186 int limit = (colors_max - min_colors) * (colors_max - min_colors);
2187 if (pairs_max > limit)
2188 pairs_max = limit;
2189 } else {
2190 if (pairs_max > COLOR_PAIRS)
2191 pairs_max = COLOR_PAIRS;
2192 }
2193
2194 /* this assumes an 80-column line */
2195 if (opt_wide) {
2196 width = 4;
2197 hello = "Test";
2198 per_row = (colors_max > 8) ? 16 : 8;
2199 } else {
2200 width = 8;
2201 hello = "Hello";
2202 per_row = 8;
2203 }
2204 per_row -= min_colors;
2205
2206 row_limit = (pairs_max + per_row - 1) / per_row;
2207
2208 move(0, 0);
2209 (void) printw("There are %d color pairs and %d colors",
2210 pairs_max, COLORS);
2211 if (colors_max != COLORS)
2212 (void) printw(" (using %d colors)", colors_max);
2213 if (min_colors)
2214 (void) addstr(" besides 'default'");
2215
2216 clrtobot();
2217 MvPrintw(top + 1, 0,
2218 "%dx%d matrix of foreground/background colors, bold *%s*\n",
2219 row_limit,
2220 per_row,
2221 opt_bold ? "on" : "off");
2222
2223 /* show color names/numbers across the top */
2224 for (i = 0; i < per_row; i++)
2225 show_color_name(top + 2, (i + 1) * width, i + min_colors, opt_wide);
2226
2227 /* show a grid of colors, with color names/ numbers on the left */
2228 for (i = (NCURSES_PAIRS_T) (base_row * per_row); i < pairs_max; i++) {
2229 int row = grid_top + (i / per_row) - base_row;
2230 int col = (i % per_row + 1) * width;
2231 NCURSES_PAIRS_T pair = i;
2232
2233#define InxToFG(i) (NCURSES_COLOR_T) ((i % (colors_max - min_colors)) + min_colors)
2234#define InxToBG(i) (NCURSES_COLOR_T) ((i / (colors_max - min_colors)) + min_colors)
2235 if (row >= 0 && move(row, col) != ERR) {
2236 NCURSES_COLOR_T fg = InxToFG(i);
2237 NCURSES_COLOR_T bg = InxToBG(i);
2238
2239 init_pair(pair, fg, bg);
2240 attron(COLOR_PAIR(pair));
2241 if (opt_acsc)
2242 attron(A_ALTCHARSET);
2243 if (opt_bold)
2244 attron(A_BOLD);
2245 if (opt_revs)
2246 attron(A_REVERSE);
2247
2248 if (opt_nums) {
2249 sprintf(numbered, "{%02X}", (int) i);
2250 hello = numbered;
2251 }
2252 printw("%-*.*s", width, width, hello);
2253 (void) attrset(A_NORMAL);
2254
2255 if ((i % per_row) == 0 && InxToFG(i) == min_colors) {
2256 show_color_name(row, 0, InxToBG(i), opt_wide);
2257 }
2258 ++shown;
2259 } else if (shown) {
2260 break;
2261 }
2262 }
2263
2264 switch (wGetchar(stdscr)) {
2265 case 'a':
2266 opt_acsc = FALSE;
2267 break;
2268 case 'A':
2269 opt_acsc = TRUE;
2270 break;
2271 case 'b':
2272 opt_bold = FALSE;
2273 break;
2274 case 'B':
2275 opt_bold = TRUE;
2276 break;
2277 case 'c':
2278 colors_max = color_cycle(colors_max, -1);
2279 break;
2280 case 'C':
2281 colors_max = color_cycle(colors_max, 1);
2282 break;
2283 case 'n':
2284 opt_nums = FALSE;
2285 break;
2286 case 'N':
2287 opt_nums = TRUE;
2288 break;
2289 case 'r':
2290 opt_revs = FALSE;
2291 break;
2292 case 'R':
2293 opt_revs = TRUE;
2294 break;
2295 case case_QUIT:
2296 done = TRUE;
2297 continue;
2298 case 'w':
2299 set_color_test(opt_wide, FALSE);
2300 break;
2301 case 'W':
2302 set_color_test(opt_wide, TRUE);
2303 break;
2304 case CTRL('p'):
2305 case KEY_UP:
2306 if (base_row <= 0) {
2307 beep();
2308 } else {
2309 base_row -= 1;
2310 }
2311 break;
2312 case CTRL('n'):
2313 case KEY_DOWN:
2314 if (base_row + page_size >= row_limit) {
2315 beep();
2316 } else {
2317 base_row += 1;
2318 }
2319 break;
2320 case CTRL('b'):
2321 case KEY_PREVIOUS:
2322 case KEY_PPAGE:
2323 if (base_row <= 0) {
2324 beep();
2325 } else {
2326 base_row -= (page_size - 1);
2327 if (base_row < 0)
2328 base_row = 0;
2329 }
2330 break;
2331 case CTRL('f'):
2332 case KEY_NEXT:
2333 case KEY_NPAGE:
2334 if (base_row + page_size >= row_limit) {
2335 beep();
2336 } else {
2337 base_row += page_size - 1;
2338 if (base_row + page_size >= row_limit) {
2339 base_row = row_limit - page_size - 1;
2340 }
2341 }
2342 break;
2343 case '?':
2344 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
2345 box(helpwin, 0, 0);
2346 color_legend(helpwin, FALSE);
2347 wGetchar(helpwin);
2348 delwin(helpwin);
2349 }
2350 break;
2351 default:
2352 beep();
2353 continue;
2354 }
2355 }
2356
2357 erase();
2358 endwin();
2359}
2360
2361#if USE_WIDEC_SUPPORT
2362/* generate a color test pattern */
2363static void
2364wide_color_test(void)
2365{
2366 int i;
2367 int top = 0, width;
2368 int base_row = 0;
2369 int grid_top = top + 3;
2370 int page_size = (LINES - grid_top);
2371 int pairs_max = (unsigned short) (-1);
2372 int colors_max = COLORS;
2373 int row_limit;
2374 int per_row;
2375 char numbered[80];
2376 const char *hello;
2377 bool done = FALSE;
2378 bool opt_acsc = FALSE;
2379 bool opt_bold = FALSE;
2380 bool opt_revs = FALSE;
2381 bool opt_wide = FALSE;
2382 bool opt_nums = FALSE;
2383 bool opt_xchr = FALSE;
2384 wchar_t buffer[80];
2385 WINDOW *helpwin;
2386
2387 while (!done) {
2388 int shown = 0;
2389
2390 pairs_max = (unsigned short) (-1);
2391 if (colors_max * colors_max <= COLOR_PAIRS) {
2392 int limit = (colors_max - min_colors) * (colors_max - min_colors);
2393 if (pairs_max > limit)
2394 pairs_max = limit;
2395 } else {
2396 if (pairs_max > COLOR_PAIRS)
2397 pairs_max = COLOR_PAIRS;
2398 }
2399
2400 /* this assumes an 80-column line */
2401 if (opt_wide) {
2402 width = 4;
2403 hello = "Test";
2404 per_row = (colors_max > 8) ? 16 : 8;
2405 } else {
2406 width = 8;
2407 hello = "Hello";
2408 per_row = 8;
2409 }
2410 per_row -= min_colors;
2411
2412 if (opt_xchr) {
2413 make_fullwidth_text(buffer, hello);
2414 width *= 2;
2415 per_row /= 2;
2416 } else {
2417 make_narrow_text(buffer, hello);
2418 }
2419
2420 row_limit = (pairs_max + per_row - 1) / per_row;
2421
2422 move(0, 0);
2423 (void) printw("There are %d color pairs and %d colors",
2424 pairs_max, COLORS);
2425 if (colors_max != COLORS)
2426 (void) printw(" (using %d colors)", colors_max);
2427 if (min_colors)
2428 (void) addstr(" besides 'default'");
2429
2430 clrtobot();
2431 MvPrintw(top + 1, 0,
2432 "%dx%d matrix of foreground/background colors, bold *%s*\n",
2433 row_limit,
2434 per_row,
2435 opt_bold ? "on" : "off");
2436
2437 /* show color names/numbers across the top */
2438 for (i = 0; i < per_row; i++)
2439 show_color_name(top + 2, (i + 1) * width, i + min_colors, opt_wide);
2440
2441 /* show a grid of colors, with color names/ numbers on the left */
2442 for (i = (base_row * per_row); i < pairs_max; i++) {
2443 int row = grid_top + (i / per_row) - base_row;
2444 int col = (i % per_row + 1) * width;
2445 NCURSES_PAIRS_T pair = (NCURSES_PAIRS_T) i;
2446
2447 if (row >= 0 && move(row, col) != ERR) {
2448 init_pair(pair, InxToFG(i), InxToBG(i));
2449 (void) color_set(pair, NULL);
2450 if (opt_acsc)
2451 attr_on(A_ALTCHARSET, NULL);
2452 if (opt_bold)
2453 attr_on(A_BOLD, NULL);
2454 if (opt_revs)
2455 attr_on(A_REVERSE, NULL);
2456
2457 if (opt_nums) {
2458 sprintf(numbered, "{%02X}", i);
2459 if (opt_xchr) {
2460 make_fullwidth_text(buffer, numbered);
2461 } else {
2462 make_narrow_text(buffer, numbered);
2463 }
2464 }
2465 addnwstr(buffer, width);
2466 (void) attr_set(A_NORMAL, 0, NULL);
2467
2468 if ((i % per_row) == 0 && InxToFG(i) == min_colors) {
2469 show_color_name(row, 0, InxToBG(i), opt_wide);
2470 }
2471 ++shown;
2472 } else if (shown) {
2473 break;
2474 }
2475 }
2476
2477 switch (wGetchar(stdscr)) {
2478 case 'a':
2479 opt_acsc = FALSE;
2480 break;
2481 case 'A':
2482 opt_acsc = TRUE;
2483 break;
2484 case 'b':
2485 opt_bold = FALSE;
2486 break;
2487 case 'B':
2488 opt_bold = TRUE;
2489 break;
2490 case 'c':
2491 colors_max = color_cycle(colors_max, -1);
2492 break;
2493 case 'C':
2494 colors_max = color_cycle(colors_max, 1);
2495 break;
2496 case 'n':
2497 opt_nums = FALSE;
2498 break;
2499 case 'N':
2500 opt_nums = TRUE;
2501 break;
2502 case 'r':
2503 opt_revs = FALSE;
2504 break;
2505 case 'R':
2506 opt_revs = TRUE;
2507 break;
2508 case case_QUIT:
2509 done = TRUE;
2510 continue;
2511 case 'w':
2512 set_color_test(opt_wide, FALSE);
2513 break;
2514 case 'W':
2515 set_color_test(opt_wide, TRUE);
2516 break;
2517 case 'x':
2518 opt_xchr = FALSE;
2519 break;
2520 case 'X':
2521 opt_xchr = TRUE;
2522 break;
2523 case CTRL('p'):
2524 case KEY_UP:
2525 if (base_row <= 0) {
2526 beep();
2527 } else {
2528 base_row -= 1;
2529 }
2530 break;
2531 case CTRL('n'):
2532 case KEY_DOWN:
2533 if (base_row + page_size >= row_limit) {
2534 beep();
2535 } else {
2536 base_row += 1;
2537 }
2538 break;
2539 case CTRL('b'):
2540 case KEY_PREVIOUS:
2541 case KEY_PPAGE:
2542 if (base_row <= 0) {
2543 beep();
2544 } else {
2545 base_row -= (page_size - 1);
2546 if (base_row < 0)
2547 base_row = 0;
2548 }
2549 break;
2550 case CTRL('f'):
2551 case KEY_NEXT:
2552 case KEY_NPAGE:
2553 if (base_row + page_size >= row_limit) {
2554 beep();
2555 } else {
2556 base_row += page_size - 1;
2557 if (base_row + page_size >= row_limit) {
2558 base_row = row_limit - page_size - 1;
2559 }
2560 }
2561 break;
2562 case '?':
2563 if ((helpwin = newwin(LINES - 1, COLS - 2, 0, 0)) != 0) {
2564 box(helpwin, 0, 0);
2565 color_legend(helpwin, TRUE);
2566 wGetchar(helpwin);
2567 delwin(helpwin);
2568 }
2569 break;
2570 default:
2571 beep();
2572 continue;
2573 }
2574 }
2575
2576 erase();
2577 endwin();
2578}
2579#endif /* USE_WIDEC_SUPPORT */
2580
2581static void
2582change_color(NCURSES_PAIRS_T current, int field, int value, int usebase)
2583{
2584 NCURSES_COLOR_T red, green, blue;
2585
2586 color_content(current, &red, &green, &blue);
2587
2588 switch (field) {
2589 case 0:
2590 red = (NCURSES_COLOR_T) (usebase ? (red + value) : value);
2591 break;
2592 case 1:
2593 green = (NCURSES_COLOR_T) (usebase ? (green + value) : value);
2594 break;
2595 case 2:
2596 blue = (NCURSES_COLOR_T) (usebase ? (blue + value) : value);
2597 break;
2598 }
2599
2600 if (init_color(current, red, green, blue) == ERR)
2601 beep();
2602}
2603
2604static void
2605init_all_colors(void)
2606{
2607 NCURSES_PAIRS_T c;
2608
2609 for (c = 0; c < COLORS; ++c)
2610 init_color(c,
2611 all_colors[c].red,
2612 all_colors[c].green,
2613 all_colors[c].blue);
2614}
2615
2616#define scaled_rgb(n) ((255 * (n)) / 1000)
2617
2618static void
2619color_edit(void)
2620/* display the color test pattern, without trying to edit colors */
2621{
2622 int i;
2623 int current = 0;
2624 int this_c = 0, value = 0, field = 0;
2625 int last_c;
2626 int top_color = 0;
2627 int page_size = (LINES - 6);
2628
2629 init_all_colors();
2630 refresh();
2631
2632 for (i = 0; i < max_colors; i++)
2633 init_pair((NCURSES_PAIRS_T) i,
2634 (NCURSES_COLOR_T) COLOR_WHITE,
2635 (NCURSES_COLOR_T) i);
2636
2637 MvPrintw(LINES - 2, 0, "Number: %d", value);
2638
2639 do {
2640 NCURSES_COLOR_T red, green, blue;
2641
2642 attron(A_BOLD);
2643 MvAddStr(0, 20, "Color RGB Value Editing");
2644 attroff(A_BOLD);
2645
2646 for (i = (NCURSES_COLOR_T) top_color;
2647 (i - top_color < page_size)
2648 && (i < max_colors); i++) {
2649 char numeric[80];
2650
2651 sprintf(numeric, "[%d]", i);
2652 MvPrintw(2 + i - top_color, 0, "%c %-8s:",
2653 (i == current ? '>' : ' '),
2654 (i < (int) SIZEOF(the_color_names)
2655 ? the_color_names[i] : numeric));
2656 (void) attrset(AttrArg(COLOR_PAIR(i), 0));
2657 addstr(" ");
2658 (void) attrset(A_NORMAL);
2659
2660 color_content((NCURSES_PAIRS_T) i, &red, &green, &blue);
2661 addstr(" R = ");
2662 if (current == i && field == 0)
2663 attron(A_STANDOUT);
2664 printw("%04d", (int) red);
2665 if (current == i && field == 0)
2666 (void) attrset(A_NORMAL);
2667 addstr(", G = ");
2668 if (current == i && field == 1)
2669 attron(A_STANDOUT);
2670 printw("%04d", (int) green);
2671 if (current == i && field == 1)
2672 (void) attrset(A_NORMAL);
2673 addstr(", B = ");
2674 if (current == i && field == 2)
2675 attron(A_STANDOUT);
2676 printw("%04d", (int) blue);
2677 if (current == i && field == 2)
2678 (void) attrset(A_NORMAL);
2679 (void) attrset(A_NORMAL);
2680 printw(" ( %3d %3d %3d )",
2681 (int) scaled_rgb(red),
2682 (int) scaled_rgb(green),
2683 (int) scaled_rgb(blue));
2684 }
2685
2686 MvAddStr(LINES - 3, 0,
2687 "Use up/down to select a color, left/right to change fields.");
2688 MvAddStr(LINES - 2, 0,
2689 "Modify field by typing nnn=, nnn-, or nnn+. ? for help.");
2690
2691 move(2 + current - top_color, 0);
2692
2693 last_c = this_c;
2694 this_c = Getchar();
2695 if (this_c < 256 && isdigit(this_c) && !isdigit(last_c))
2696 value = 0;
2697
2698 switch (this_c) {
2699 case CTRL('b'):
2700 case KEY_PPAGE:
2701 if (current > 0)
2702 current -= (page_size - 1);
2703 else
2704 beep();
2705 break;
2706
2707 case CTRL('f'):
2708 case KEY_NPAGE:
2709 if (current < (max_colors - 1))
2710 current += (page_size - 1);
2711 else
2712 beep();
2713 break;
2714
2715 case CTRL('p'):
2716 case KEY_UP:
2717 current = (current == 0 ? (max_colors - 1) : current - 1);
2718 break;
2719
2720 case CTRL('n'):
2721 case KEY_DOWN:
2722 current = (current == (max_colors - 1) ? 0 : current + 1);
2723 break;
2724
2725 case KEY_RIGHT:
2726 field = (field == 2 ? 0 : field + 1);
2727 break;
2728
2729 case KEY_LEFT:
2730 field = (field == 0 ? 2 : field - 1);
2731 break;
2732
2733 case '0':
2734 case '1':
2735 case '2':
2736 case '3':
2737 case '4':
2738 case '5':
2739 case '6':
2740 case '7':
2741 case '8':
2742 case '9':
2743 value = value * 10 + (this_c - '0');
2744 break;
2745
2746 case '+':
2747 change_color((NCURSES_PAIRS_T) current, field, value, 1);
2748 break;
2749
2750 case '-':
2751 change_color((NCURSES_PAIRS_T) current, field, -value, 1);
2752 break;
2753
2754 case '=':
2755 change_color((NCURSES_PAIRS_T) current, field, value, 0);
2756 break;
2757
2758 case '?':
2759 erase();
2760 P(" RGB Value Editing Help");
2761 P("");
2762 P("You are in the RGB value editor. Use the arrow keys to select one of");
2763 P("the fields in one of the RGB triples of the current colors; the one");
2764 P("currently selected will be reverse-video highlighted.");
2765 P("");
2766 P("To change a field, enter the digits of the new value; they are echoed");
2767 P("as entered. Finish by typing `='. The change will take effect instantly.");
2768 P("To increment or decrement a value, use the same procedure, but finish");
2769 P("with a `+' or `-'.");
2770 P("");
2771 P("Press 'm' to invoke the top-level menu with the current color settings.");
2772 P("To quit, do ESC");
2773
2774 Pause();
2775 erase();
2776 break;
2777
2778 case 'm':
2779 endwin();
2780 main_menu(FALSE);
2781 for (i = 0; i < max_colors; i++)
2782 init_pair((NCURSES_PAIRS_T) i,
2783 (NCURSES_COLOR_T) COLOR_WHITE,
2784 (NCURSES_COLOR_T) i);
2785 refresh();
2786 break;
2787
2788 case case_QUIT:
2789 break;
2790
2791 default:
2792 beep();
2793 break;
2794 }
2795
2796 if (current < 0)
2797 current = 0;
2798 if (current >= max_colors)
2799 current = max_colors - 1;
2800 if (current < top_color)
2801 top_color = current;
2802 if (current - top_color >= page_size)
2803 top_color = current - (page_size - 1);
2804
2805 MvPrintw(LINES - 1, 0, "Number: %d", value);
2806 clrtoeol();
2807 } while
2808 (!isQuit(this_c));
2809
2810 erase();
2811
2812 /*
2813 * ncurses does not reset each color individually when calling endwin().
2814 */
2815 init_all_colors();
2816
2817 endwin();
2818}
2819
2820/****************************************************************************
2821 *
2822 * Alternate character-set stuff
2823 *
2824 ****************************************************************************/
2825static bool
2826cycle_attr(int ch, unsigned *at_code, chtype *attr, ATTR_TBL * list, unsigned limit)
2827{
2828 bool result = TRUE;
2829
2830 switch (ch) {
2831 case 'v':
2832 if ((*at_code += 1) >= limit)
2833 *at_code = 0;
2834 break;
2835 case 'V':
2836 if (*at_code == 0)
2837 *at_code = limit - 1;
2838 else
2839 *at_code -= 1;
2840 break;
2841 default:
2842 result = FALSE;
2843 break;
2844 }
2845 if (result)
2846 *attr = list[*at_code].attr;
2847 return result;
2848}
2849
2850static bool
2851cycle_colors(int ch, int *fg, int *bg, NCURSES_PAIRS_T *pair)
2852{
2853 bool result = FALSE;
2854
2855 if (use_colors) {
2856 result = TRUE;
2857 switch (ch) {
2858 case 'F':
2859 if ((*fg -= 1) < 0)
2860 *fg = COLORS - 1;
2861 break;
2862 case 'f':
2863 if ((*fg += 1) >= COLORS)
2864 *fg = 0;
2865 break;
2866 case 'B':
2867 if ((*bg -= 1) < 0)
2868 *bg = COLORS - 1;
2869 break;
2870 case 'b':
2871 if ((*bg += 1) >= COLORS)
2872 *bg = 0;
2873 break;
2874 default:
2875 result = FALSE;
2876 break;
2877 }
2878 if (result) {
2879 *pair = (NCURSES_PAIRS_T) (*fg != COLOR_BLACK || *bg != COLOR_BLACK);
2880 if (*pair != 0) {
2881 *pair = 1;
2882 if (init_pair(*pair,
2883 (NCURSES_COLOR_T) *fg,
2884 (NCURSES_COLOR_T) *bg) == ERR) {
2885 result = FALSE;
2886 }
2887 }
2888 }
2889 }
2890 return result;
2891}
2892
2893/****************************************************************************
2894 *
2895 * Soft-key label test
2896 *
2897 ****************************************************************************/
2898
2899#if USE_SOFTKEYS
2900
2901#define SLK_HELP 17
2902#define SLK_WORK (SLK_HELP + 3)
2903
2904static void
2905slk_help(void)
2906{
2907 static const char *table[] =
2908 {
2909 "Available commands are:"
2910 ,""
2911 ,"^L -- repaint this message and activate soft keys"
2912 ,"a/d -- activate/disable soft keys"
2913 ,"c -- set centered format for labels"
2914 ,"l -- set left-justified format for labels"
2915 ,"r -- set right-justified format for labels"
2916 ,"[12345678] -- set label; labels are numbered 1 through 8"
2917 ,"e -- erase stdscr (should not erase labels)"
2918 ,"s -- test scrolling of shortened screen"
2919 ,"v/V -- cycle through video attributes"
2920#if HAVE_SLK_COLOR
2921 ,"F/f/B/b -- cycle through foreground/background colors"
2922#endif
2923 ,"ESC -- return to main menu"
2924 ,""
2925 ,"Note: if activating the soft keys causes your terminal to scroll up"
2926 ,"one line, your terminal auto-scrolls when anything is written to the"
2927 ,"last screen position. The ncurses code does not yet handle this"
2928 ,"gracefully."
2929 };
2930 unsigned j;
2931
2932 move(2, 0);
2933 for (j = 0; j < SIZEOF(table); ++j) {
2934 P(table[j]);
2935 }
2936 refresh();
2937}
2938
2939#if HAVE_SLK_COLOR
2940static void
2941call_slk_color(int fg, int bg)
2942{
2943 init_pair(1, (NCURSES_COLOR_T) bg, (NCURSES_COLOR_T) fg);
2944 slk_color(1);
2945 MvPrintw(SLK_WORK, 0, "Colors %d/%d\n", fg, bg);
2946 clrtoeol();
2947 slk_touch();
2948 slk_noutrefresh();
2949 refresh();
2950}
2951#endif
2952
2953static void
2954slk_test(void)
2955/* exercise the soft keys */
2956{
2957 int c, fmt = 1;
2958 char buf[9];
2959 char *s;
2960 chtype attr = A_NORMAL;
2961 unsigned at_code = 0;
2962#if HAVE_SLK_COLOR
2963 int fg = COLOR_BLACK;
2964 int bg = COLOR_WHITE;
2965 NCURSES_PAIRS_T pair = 0;
2966#endif
2967 ATTR_TBL my_list[SIZEOF(attrs_to_test)];
2968 unsigned my_size = init_attr_list(my_list, termattrs());
2969
2970 c = CTRL('l');
2971#if HAVE_SLK_COLOR
2972 if (use_colors) {
2973 call_slk_color(fg, bg);
2974 }
2975#endif
2976
2977 do {
2978 move(0, 0);
2979 switch (c) {
2980 case CTRL('l'):
2981 erase();
2982 attron(A_BOLD);
2983 MvAddStr(0, 20, "Soft Key Exerciser");
2984 attroff(A_BOLD);
2985
2986 slk_help();
2987 /* fall through */
2988
2989 case 'a':
2990 slk_restore();
2991 break;
2992
2993 case 'e':
2994 wclear(stdscr);
2995 break;
2996
2997 case 's':
2998 MvPrintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: ");
2999 while ((c = Getchar()) != 'Q' && (c != ERR))
3000 addch((chtype) c);
3001 break;
3002
3003 case 'd':
3004 slk_clear();
3005 break;
3006
3007 case 'l':
3008 fmt = 0;
3009 break;
3010
3011 case 'c':
3012 fmt = 1;
3013 break;
3014
3015 case 'r':
3016 fmt = 2;
3017 break;
3018
3019 case '1':
3020 case '2':
3021 case '3':
3022 case '4':
3023 case '5':
3024 case '6':
3025 case '7':
3026 case '8':
3027 MvAddStr(SLK_WORK, 0, "Please enter the label value: ");
3028 strcpy(buf, "");
3029 if ((s = slk_label(c - '0')) != 0) {
3030 strncpy(buf, s, (size_t) 8);
3031 }
3032 wGetstring(stdscr, buf, 8);
3033 slk_set((c - '0'), buf, fmt);
3034 slk_refresh();
3035 move(SLK_WORK, 0);
3036 clrtobot();
3037 break;
3038
3039 case case_QUIT:
3040 goto done;
3041
3042#if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
3043 case KEY_RESIZE:
3044 wnoutrefresh(stdscr);
3045 break;
3046#endif
3047
3048 default:
3049 if (cycle_attr(c, &at_code, &attr, my_list, my_size)) {
3050 slk_attrset(attr);
3051 slk_touch();
3052 slk_noutrefresh();
3053 break;
3054 }
3055#if HAVE_SLK_COLOR
3056 if (cycle_colors(c, &fg, &bg, &pair)) {
3057 if (use_colors) {
3058 call_slk_color(fg, bg);
3059 } else {
3060 beep();
3061 }
3062 break;
3063 }
3064#endif
3065 beep();
3066 break;
3067 }
3068 } while (!isQuit(c = Getchar()));
3069
3070 done:
3071 slk_clear();
3072 erase();
3073 endwin();
3074}
3075
3076#if USE_WIDEC_SUPPORT
3077#define SLKLEN 8
3078static void
3079wide_slk_test(void)
3080/* exercise the soft keys */
3081{
3082 int c, fmt = 1;
3083 wchar_t buf[SLKLEN + 1];
3084 char *s;
3085 chtype attr = A_NORMAL;
3086 unsigned at_code = 0;
3087 int fg = COLOR_BLACK;
3088 int bg = COLOR_WHITE;
3089 NCURSES_PAIRS_T pair = 0;
3090 ATTR_TBL my_list[SIZEOF(attrs_to_test)];
3091 unsigned my_size = init_attr_list(my_list, term_attrs());
3092
3093 c = CTRL('l');
3094 if (use_colors) {
3095 call_slk_color(fg, bg);
3096 }
3097 do {
3098 move(0, 0);
3099 switch (c) {
3100 case CTRL('l'):
3101 erase();
3102 attr_on(WA_BOLD, NULL);
3103 MvAddStr(0, 20, "Soft Key Exerciser");
3104 attr_off(WA_BOLD, NULL);
3105
3106 slk_help();
3107 /* fall through */
3108
3109 case 'a':
3110 slk_restore();
3111 break;
3112
3113 case 'e':
3114 wclear(stdscr);
3115 break;
3116
3117 case 's':
3118 MvPrintw(SLK_WORK, 0, "Press Q to stop the scrolling-test: ");
3119 while ((c = Getchar()) != 'Q' && (c != ERR))
3120 addch((chtype) c);
3121 break;
3122
3123 case 'd':
3124 slk_clear();
3125 break;
3126
3127 case 'l':
3128 fmt = 0;
3129 break;
3130
3131 case 'c':
3132 fmt = 1;
3133 break;
3134
3135 case 'r':
3136 fmt = 2;
3137 break;
3138
3139 case '1':
3140 case '2':
3141 case '3':
3142 case '4':
3143 case '5':
3144 case '6':
3145 case '7':
3146 case '8':
3147 MvAddStr(SLK_WORK, 0, "Please enter the label value: ");
3148 *buf = 0;
3149 if ((s = slk_label(c - '0')) != 0) {
3150 char *temp = strdup(s);
3151 size_t used = strlen(temp);
3152 size_t want = SLKLEN;
3153 size_t test;
3154#ifndef state_unused
3155 mbstate_t state;
3156#endif
3157
3158 buf[0] = L'\0';
3159 while (want > 0 && used != 0) {
3160 const char *base = s;
3161 reset_mbytes(state);
3162 test = count_mbytes(base, 0, &state);
3163 if (test == (size_t) -1) {
3164 temp[--used] = 0;
3165 } else if (test > want) {
3166 temp[--used] = 0;
3167 } else {
3168 reset_mbytes(state);
3169 trans_mbytes(buf, base, want, &state);
3170 break;
3171 }
3172 }
3173 free(temp);
3174 }
3175 wGet_wstring(stdscr, buf, SLKLEN);
3176 slk_wset((c - '0'), buf, fmt);
3177 slk_refresh();
3178 move(SLK_WORK, 0);
3179 clrtobot();
3180 break;
3181
3182 case case_QUIT:
3183 goto done;
3184
3185 case 'F':
3186 if (use_colors) {
3187 fg = (NCURSES_COLOR_T) ((fg + 1) % COLORS);
3188 call_slk_color(fg, bg);
3189 }
3190 break;
3191 case 'B':
3192 if (use_colors) {
3193 bg = (NCURSES_COLOR_T) ((bg + 1) % COLORS);
3194 call_slk_color(fg, bg);
3195 }
3196 break;
3197#if defined(NCURSES_VERSION) && defined(KEY_RESIZE) && HAVE_WRESIZE
3198 case KEY_RESIZE:
3199 wnoutrefresh(stdscr);
3200 break;
3201#endif
3202 default:
3203 if (cycle_attr(c, &at_code, &attr, my_list, my_size)) {
3204 slk_attr_set(attr, (NCURSES_COLOR_T) (fg || bg), NULL);
3205 slk_touch();
3206 slk_noutrefresh();
3207 break;
3208 }
3209#if HAVE_SLK_COLOR
3210 if (cycle_colors(c, &fg, &bg, &pair)) {
3211 if (use_colors) {
3212 call_slk_color(fg, bg);
3213 } else {
3214 beep();
3215 }
3216 break;
3217 }
3218#endif
3219 beep();
3220 break;
3221 }
3222 } while (!isQuit(c = Getchar()));
3223
3224 done:
3225 slk_clear();
3226 erase();
3227 endwin();
3228}
3229#endif
3230#endif /* SLK_INIT */
3231
3232static void
3233show_256_chars(int repeat, attr_t attr, NCURSES_PAIRS_T pair)
3234{
3235 unsigned first = 0;
3236 unsigned last = 255;
3237 unsigned code;
3238 int count;
3239
3240 erase();
3241 attron(A_BOLD);
3242 MvPrintw(0, 20, "Display of Character Codes %#0x to %#0x",
3243 first, last);
3244 attroff(A_BOLD);
3245 refresh();
3246
3247 for (code = first; code <= last; ++code) {
3248 int row = (int) (2 + (code / 16));
3249 int col = (int) (5 * (code % 16));
3250 IGNORE_RC(mvaddch(row, col, colored_chtype(code, attr, pair)));
3251 for (count = 1; count < repeat; ++count) {
3252 addch(colored_chtype(code, attr, pair));
3253 }
3254 }
3255
3256}
3257
3258/*
3259 * Show a slice of 32 characters, allowing those to be repeated up to the
3260 * screen's width.
3261 *
3262 * ISO 6429: codes 0x80 to 0x9f may be control characters that cause the
3263 * terminal to perform functions. The remaining codes can be graphic.
3264 */
3265static void
3266show_upper_chars(int base, int pagesize, int repeat, attr_t attr, NCURSES_PAIRS_T pair)
3267{
3268 unsigned code;
3269 unsigned first = (unsigned) base;
3270 unsigned last = first + (unsigned) pagesize - 2;
3271 bool C1 = (first == 128);
3272 int reply;
3273
3274 erase();
3275 attron(A_BOLD);
3276 MvPrintw(0, 20, "Display of %s Character Codes %d to %d",
3277 C1 ? "C1" : "GR", first, last);
3278 attroff(A_BOLD);
3279 refresh();
3280
3281 for (code = first; code <= last; code++) {
3282 int count = repeat;
3283 int row = 2 + ((int) (code - first) % (pagesize / 2));
3284 int col = ((int) (code - first) / (pagesize / 2)) * COLS / 2;
3285 char tmp[80];
3286 sprintf(tmp, "%3u (0x%x)", code, code);
3287 MvPrintw(row, col, "%*s: ", COLS / 4, tmp);
3288
3289 do {
3290 if (C1)
3291 nodelay(stdscr, TRUE);
3292 echochar(colored_chtype(code, attr, pair));
3293 if (C1) {
3294 /* (yes, this _is_ crude) */
3295 while ((reply = Getchar()) != ERR) {
3296 addch(UChar(reply));
3297 napms(10);
3298 }
3299 nodelay(stdscr, FALSE);
3300 }
3301 } while (--count > 0);
3302 }
3303}
3304
3305#define PC_COLS 4
3306
3307static void
3308show_pc_chars(int repeat, attr_t attr, NCURSES_PAIRS_T pair)
3309{
3310 unsigned code;
3311
3312 erase();
3313 attron(A_BOLD);
3314 MvPrintw(0, 20, "Display of PC Character Codes");
3315 attroff(A_BOLD);
3316 refresh();
3317
3318 for (code = 0; code < 16; ++code) {
3319 MvPrintw(2, (int) code * PC_COLS + 8, "%X", code);
3320 }
3321 for (code = 0; code < 256; code++) {
3322 int count = repeat;
3323 int row = 3 + (int) (code / 16) + (code >= 128);
3324 int col = 8 + (int) (code % 16) * PC_COLS;
3325 if ((code % 16) == 0)
3326 MvPrintw(row, 0, "0x%02x:", code);
3327 move(row, col);
3328 do {
3329 switch (code) {
3330 case '\n':
3331 case '\r':
3332 case '\b':
3333 case '\f':
3334 case '\033':
3335 case 0x9b:
3336 /*
3337 * Skip the ones that do not work.
3338 */
3339 break;
3340 default:
3341 addch(colored_chtype(code, A_ALTCHARSET | attr, pair));
3342 break;
3343 }
3344 } while (--count > 0);
3345 }
3346}
3347
3348static void
3349show_box_chars(int repeat, attr_t attr, NCURSES_PAIRS_T pair)
3350{
3351 (void) repeat;
3352
3353 attr |= (attr_t) COLOR_PAIR(pair);
3354
3355 erase();
3356 attron(A_BOLD);
3357 MvAddStr(0, 20, "Display of the ACS Line-Drawing Set");
3358 attroff(A_BOLD);
3359 refresh();
3360 /* *INDENT-OFF* */
3361 wborder(stdscr,
3362 colored_chtype(ACS_VLINE, attr, pair),
3363 colored_chtype(ACS_VLINE, attr, pair),
3364 colored_chtype(ACS_HLINE, attr, pair),
3365 colored_chtype(ACS_HLINE, attr, pair),
3366 colored_chtype(ACS_ULCORNER, attr, pair),
3367 colored_chtype(ACS_URCORNER, attr, pair),
3368 colored_chtype(ACS_LLCORNER, attr, pair),
3369 colored_chtype(ACS_LRCORNER, attr, pair));
3370 MvHLine(LINES / 2, 0, colored_chtype(ACS_HLINE, attr, pair), COLS);
3371 MvVLine(0, COLS / 2, colored_chtype(ACS_VLINE, attr, pair), LINES);
3372 MvAddCh(0, COLS / 2, colored_chtype(ACS_TTEE, attr, pair));
3373 MvAddCh(LINES / 2, COLS / 2, colored_chtype(ACS_PLUS, attr, pair));
3374 MvAddCh(LINES - 1, COLS / 2, colored_chtype(ACS_BTEE, attr, pair));
3375 MvAddCh(LINES / 2, 0, colored_chtype(ACS_LTEE, attr, pair));
3376 MvAddCh(LINES / 2, COLS - 1, colored_chtype(ACS_RTEE, attr, pair));
3377 /* *INDENT-ON* */
3378
3379}
3380
3381static int
3382show_1_acs(int n, int repeat, const char *name, chtype code)
3383{
3384 const int height = 16;
3385 int row = 2 + (n % height);
3386 int col = (n / height) * COLS / 2;
3387
3388 MvPrintw(row, col, "%*s : ", COLS / 4, name);
3389 do {
3390 addch(code);
3391 } while (--repeat > 0);
3392 return n + 1;
3393}
3394
3395static void
3396show_acs_chars(int repeat, attr_t attr, NCURSES_PAIRS_T pair)
3397/* display the ACS character set */
3398{
3399 int n;
3400
3401#define BOTH(name) #name, colored_chtype(name, attr, (chtype) pair)
3402
3403 erase();
3404 attron(A_BOLD);
3405 MvAddStr(0, 20, "Display of the ACS Character Set");
3406 attroff(A_BOLD);
3407 refresh();
3408
3409 n = show_1_acs(0, repeat, BOTH(ACS_ULCORNER));
3410 n = show_1_acs(n, repeat, BOTH(ACS_URCORNER));
3411 n = show_1_acs(n, repeat, BOTH(ACS_LLCORNER));
3412 n = show_1_acs(n, repeat, BOTH(ACS_LRCORNER));
3413
3414 n = show_1_acs(n, repeat, BOTH(ACS_LTEE));
3415 n = show_1_acs(n, repeat, BOTH(ACS_RTEE));
3416 n = show_1_acs(n, repeat, BOTH(ACS_TTEE));
3417 n = show_1_acs(n, repeat, BOTH(ACS_BTEE));
3418
3419 n = show_1_acs(n, repeat, BOTH(ACS_HLINE));
3420 n = show_1_acs(n, repeat, BOTH(ACS_VLINE));
3421
3422 /*
3423 * HPUX's ACS definitions are broken here. Just give up.
3424 */
3425#if !(defined(__hpux) && !defined(NCURSES_VERSION))
3426 n = show_1_acs(n, repeat, BOTH(ACS_LARROW));
3427 n = show_1_acs(n, repeat, BOTH(ACS_RARROW));
3428 n = show_1_acs(n, repeat, BOTH(ACS_UARROW));
3429 n = show_1_acs(n, repeat, BOTH(ACS_DARROW));
3430
3431 n = show_1_acs(n, repeat, BOTH(ACS_BLOCK));
3432 n = show_1_acs(n, repeat, BOTH(ACS_BOARD));
3433 n = show_1_acs(n, repeat, BOTH(ACS_LANTERN));
3434 n = show_1_acs(n, repeat, BOTH(ACS_BULLET));
3435 n = show_1_acs(n, repeat, BOTH(ACS_CKBOARD));
3436 n = show_1_acs(n, repeat, BOTH(ACS_DEGREE));
3437 n = show_1_acs(n, repeat, BOTH(ACS_DIAMOND));
3438 n = show_1_acs(n, repeat, BOTH(ACS_PLMINUS));
3439 n = show_1_acs(n, repeat, BOTH(ACS_PLUS));
3440
3441 n = show_1_acs(n, repeat, BOTH(ACS_GEQUAL));
3442 n = show_1_acs(n, repeat, BOTH(ACS_NEQUAL));
3443 n = show_1_acs(n, repeat, BOTH(ACS_LEQUAL));
3444
3445 n = show_1_acs(n, repeat, BOTH(ACS_STERLING));
3446 n = show_1_acs(n, repeat, BOTH(ACS_PI));
3447 n = show_1_acs(n, repeat, BOTH(ACS_S1));
3448 n = show_1_acs(n, repeat, BOTH(ACS_S3));
3449 n = show_1_acs(n, repeat, BOTH(ACS_S7));
3450 (void) show_1_acs(n, repeat, BOTH(ACS_S9));
3451#endif
3452}
3453
3454static void
3455acs_display(void)
3456{
3457 int c = 'a';
3458 int pagesize = 32;
3459 char *term = getenv("TERM");
3460 const char *pch_kludge = ((term != 0 && strstr(term, "linux"))
3461 ? "p=PC, "
3462 : "");
3463 chtype attr = A_NORMAL;
3464 int digit = 0;
3465 int repeat = 1;
3466 int fg = COLOR_BLACK;
3467 int bg = COLOR_BLACK;
3468 unsigned at_code = 0;
3469 NCURSES_PAIRS_T pair = 0;
3470 void (*last_show_acs) (int, attr_t, NCURSES_PAIRS_T) = 0;
3471 ATTR_TBL my_list[SIZEOF(attrs_to_test)];
3472 unsigned my_size = init_attr_list(my_list, termattrs());
3473
3474 do {
3475 switch (c) {
3476 case CTRL('L'):
3477 Repaint();
3478 break;
3479 case 'a':
3480 ToggleAcs(last_show_acs, show_acs_chars);
3481 break;
3482 case 'p':
3483 if (*pch_kludge)
3484 ToggleAcs(last_show_acs, show_pc_chars);
3485 else
3486 beep();
3487 break;
3488 case 'w':
3489 if (pagesize == 32) {
3490 pagesize = 256;
3491 } else {
3492 pagesize = 32;
3493 }
3494 break;
3495 case 'x':
3496 ToggleAcs(last_show_acs, show_box_chars);
3497 break;
3498 case '0':
3499 case '1':
3500 case '2':
3501 case '3':
3502 digit = (c - '0');
3503 last_show_acs = 0;
3504 break;
3505 case '-':
3506 if (digit > 0) {
3507 --digit;
3508 last_show_acs = 0;
3509 } else {
3510 beep();
3511 }
3512 break;
3513 case '+':
3514 if (digit < 3) {
3515 ++digit;
3516 last_show_acs = 0;
3517 } else {
3518 beep();
3519 }
3520 break;
3521 case '>':
3522 if (repeat < (COLS / 4))
3523 ++repeat;
3524 break;
3525 case '<':
3526 if (repeat > 1)
3527 --repeat;
3528 break;
3529 default:
3530 if (cycle_attr(c, &at_code, &attr, my_list, my_size)
3531 || cycle_colors(c, &fg, &bg, &pair)) {
3532 break;
3533 } else {
3534 beep();
3535 }
3536 break;
3537 }
3538 if (pagesize != 32) {
3539 show_256_chars(repeat, attr, pair);
3540 } else if (last_show_acs != 0) {
3541 last_show_acs(repeat, attr, pair);
3542 } else {
3543 show_upper_chars(digit * pagesize + 128, pagesize, repeat, attr, pair);
3544 }
3545
3546 MvPrintw(LINES - 3, 0,
3547 "Note: ANSI terminals may not display C1 characters.");
3548 MvPrintw(LINES - 2, 0,
3549 "Select: a=ACS, w=all x=box, %s0=C1, 1-3,+/- non-ASCII, </> repeat, ESC=quit",
3550 pch_kludge);
3551 if (use_colors) {
3552 MvPrintw(LINES - 1, 0,
3553 "v/V, f/F, b/B cycle through video attributes (%s) and color %d/%d.",
3554 my_list[at_code].name,
3555 fg, bg);
3556 } else {
3557 MvPrintw(LINES - 1, 0,
3558 "v/V cycles through video attributes (%s).",
3559 my_list[at_code].name);
3560 }
3561 refresh();
3562 } while (!isQuit(c = Getchar()));
3563
3564 Pause();
3565 erase();
3566 endwin();
3567}
3568
3569#if USE_WIDEC_SUPPORT
3570static cchar_t *
3571merge_wide_attr(cchar_t *dst, const cchar_t *src, attr_t attr, NCURSES_PAIRS_T pair)
3572{
3573 int count;
3574
3575 *dst = *src;
3576 do {
3577 TEST_CCHAR(src, count, {
3578 attr |= (test_attrs & A_ALTCHARSET);
3579 setcchar(dst, test_wch, attr, pair, NULL);
3580 }
3581 , {
3582 ;
3583 });
3584 } while (0);
3585 return dst;
3586}
3587
3588/*
3589 * Header/legend take up no more than 8 lines, leaving 16 lines on a 24-line
3590 * display. If there are no repeats, we could normally display 16 lines of 64
3591 * characters (1024 total). However, taking repeats and double-width cells
3592 * into account, use 256 characters for the page.
3593 */
3594static void
3595show_paged_widechars(int base,
3596 int pagesize,
3597 int repeat,
3598 int space,
3599 attr_t attr,
3600 NCURSES_PAIRS_T pair)
3601{
3602 int first = base * pagesize;
3603 int last = first + pagesize - 1;
3604 int per_line = 16;
3605 cchar_t temp;
3606 wchar_t code;
3607 wchar_t codes[10];
3608
3609 erase();
3610 attron(A_BOLD);
3611 MvPrintw(0, 20, "Display of Character Codes %#x to %#x", first, last);
3612 attroff(A_BOLD);
3613
3614 for (code = (wchar_t) first; (int) code <= last; code++) {
3615 int row = (2 + ((int) code - first) / per_line);
3616 int col = 5 * ((int) code % per_line);
3617 int count;
3618
3619 memset(&codes, 0, sizeof(codes));
3620 codes[0] = code;
3621 setcchar(&temp, codes, attr, pair, 0);
3622 move(row, col);
3623 if (wcwidth(code) == 0 && code != 0) {
3624 addch((chtype) space |
3625 (A_REVERSE ^ attr) |
3626 (attr_t) COLOR_PAIR(pair));
3627 }
3628 add_wch(&temp);
3629 for (count = 1; count < repeat; ++count) {
3630 add_wch(&temp);
3631 }
3632 }
3633}
3634
3635static void
3636show_upper_widechars(int first, int repeat, int space, attr_t attr, NCURSES_PAIRS_T pair)
3637{
3638 cchar_t temp;
3639 wchar_t code;
3640 int last = first + 31;
3641
3642 erase();
3643 attron(A_BOLD);
3644 MvPrintw(0, 20, "Display of Character Codes %d to %d", first, last);
3645 attroff(A_BOLD);
3646
3647 for (code = (wchar_t) first; (int) code <= last; code++) {
3648 int row = 2 + ((code - first) % 16);
3649 int col = ((code - first) / 16) * COLS / 2;
3650 wchar_t codes[10];
3651 char tmp[80];
3652 int count = repeat;
3653 int y, x;
3654
3655 sprintf(tmp, "%3ld (0x%lx)", (long) code, (long) code);
3656 MvPrintw(row, col, "%*s: ", COLS / 4, tmp);
3657
3658 memset(&codes, 0, sizeof(codes));
3659 codes[0] = code;
3660 setcchar(&temp, codes, attr, pair, 0);
3661
3662 do {
3663 /*
3664 * Give non-spacing characters something to combine with. If we
3665 * don't, they'll bunch up in a heap on the space after the ":".
3666 * Mark them with reverse-video to make them simpler to find on
3667 * the display.
3668 */
3669 if (wcwidth(code) == 0) {
3670 addch((chtype) space |
3671 (A_REVERSE ^ attr) |
3672 (attr_t) COLOR_PAIR(pair));
3673 }
3674 /*
3675 * This uses echo_wchar(), for comparison with the normal 'f'
3676 * test (and to make a test-case for echo_wchar()). The screen
3677 * may flicker because the erase() at the top of the function
3678 * is met by the builtin refresh() in echo_wchar().
3679 */
3680 echo_wchar(&temp);
3681 /*
3682 * The repeat-count may make text wrap - avoid that.
3683 */
3684 getyx(stdscr, y, x);
3685 (void) y;
3686 if (x >= col + (COLS / 2) - 2)
3687 break;
3688 } while (--count > 0);
3689 }
3690}
3691
3692static int
3693show_1_wacs(int n, int repeat, const char *name, const cchar_t *code)
3694{
3695 const int height = 16;
3696 int row = 2 + (n % height);
3697 int col = (n / height) * COLS / 2;
3698
3699 MvPrintw(row, col, "%*s : ", COLS / 4, name);
3700 while (--repeat >= 0) {
3701 add_wch(code);
3702 }
3703 return n + 1;
3704}
3705
3706#define MERGE_ATTR(wch) merge_wide_attr(&temp, wch, attr, pair)
3707
3708static void
3709show_wacs_chars(int repeat, attr_t attr, NCURSES_PAIRS_T pair)
3710/* display the wide-ACS character set */
3711{
3712 cchar_t temp;
3713
3714 int n;
3715
3716/*#define BOTH2(name) #name, &(name) */
3717#define BOTH2(name) #name, MERGE_ATTR(name)
3718
3719 erase();
3720 attron(A_BOLD);
3721 MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3722 attroff(A_BOLD);
3723 refresh();
3724
3725 n = show_1_wacs(0, repeat, BOTH2(WACS_ULCORNER));
3726 n = show_1_wacs(n, repeat, BOTH2(WACS_URCORNER));
3727 n = show_1_wacs(n, repeat, BOTH2(WACS_LLCORNER));
3728 n = show_1_wacs(n, repeat, BOTH2(WACS_LRCORNER));
3729
3730 n = show_1_wacs(n, repeat, BOTH2(WACS_LTEE));
3731 n = show_1_wacs(n, repeat, BOTH2(WACS_RTEE));
3732 n = show_1_wacs(n, repeat, BOTH2(WACS_TTEE));
3733 n = show_1_wacs(n, repeat, BOTH2(WACS_BTEE));
3734
3735 n = show_1_wacs(n, repeat, BOTH2(WACS_HLINE));
3736 n = show_1_wacs(n, repeat, BOTH2(WACS_VLINE));
3737
3738 n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3739 n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3740 n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3741 n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3742
3743 n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3744 n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3745 n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3746 n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3747 n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3748 n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3749 n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3750 n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3751 n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3752
3753#ifdef CURSES_WACS_ARRAY
3754 n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3755 n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3756 n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3757
3758 n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3759 n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3760 n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3761 n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3762 n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3763 (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3764#endif
3765}
3766
3767#ifdef WACS_D_PLUS
3768static void
3769show_wacs_chars_double(int repeat, attr_t attr, NCURSES_PAIRS_T pair)
3770/* display the wide-ACS character set */
3771{
3772 cchar_t temp;
3773
3774 int n;
3775
3776/*#define BOTH2(name) #name, &(name) */
3777#define BOTH2(name) #name, MERGE_ATTR(name)
3778
3779 erase();
3780 attron(A_BOLD);
3781 MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3782 attroff(A_BOLD);
3783 refresh();
3784
3785 n = show_1_wacs(0, repeat, BOTH2(WACS_D_ULCORNER));
3786 n = show_1_wacs(n, repeat, BOTH2(WACS_D_URCORNER));
3787 n = show_1_wacs(n, repeat, BOTH2(WACS_D_LLCORNER));
3788 n = show_1_wacs(n, repeat, BOTH2(WACS_D_LRCORNER));
3789
3790 n = show_1_wacs(n, repeat, BOTH2(WACS_D_LTEE));
3791 n = show_1_wacs(n, repeat, BOTH2(WACS_D_RTEE));
3792 n = show_1_wacs(n, repeat, BOTH2(WACS_D_TTEE));
3793 n = show_1_wacs(n, repeat, BOTH2(WACS_D_BTEE));
3794
3795 n = show_1_wacs(n, repeat, BOTH2(WACS_D_HLINE));
3796 n = show_1_wacs(n, repeat, BOTH2(WACS_D_VLINE));
3797
3798 n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3799 n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3800 n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3801 n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3802
3803 n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3804 n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3805 n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3806 n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3807 n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3808 n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3809 n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3810 n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3811 n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3812
3813#ifdef CURSES_WACS_ARRAY
3814 n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3815 n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3816 n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3817
3818 n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3819 n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3820 n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3821 n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3822 n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3823 (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3824#endif
3825}
3826#endif
3827
3828#ifdef WACS_T_PLUS
3829static void
3830show_wacs_chars_thick(int repeat, attr_t attr, NCURSES_PAIRS_T pair)
3831/* display the wide-ACS character set */
3832{
3833 cchar_t temp;
3834
3835 int n;
3836
3837/*#define BOTH2(name) #name, &(name) */
3838#define BOTH2(name) #name, MERGE_ATTR(name)
3839
3840 erase();
3841 attron(A_BOLD);
3842 MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3843 attroff(A_BOLD);
3844 refresh();
3845
3846 n = show_1_wacs(0, repeat, BOTH2(WACS_T_ULCORNER));
3847 n = show_1_wacs(n, repeat, BOTH2(WACS_T_URCORNER));
3848 n = show_1_wacs(n, repeat, BOTH2(WACS_T_LLCORNER));
3849 n = show_1_wacs(n, repeat, BOTH2(WACS_T_LRCORNER));
3850
3851 n = show_1_wacs(n, repeat, BOTH2(WACS_T_LTEE));
3852 n = show_1_wacs(n, repeat, BOTH2(WACS_T_RTEE));
3853 n = show_1_wacs(n, repeat, BOTH2(WACS_T_TTEE));
3854 n = show_1_wacs(n, repeat, BOTH2(WACS_T_BTEE));
3855
3856 n = show_1_wacs(n, repeat, BOTH2(WACS_T_HLINE));
3857 n = show_1_wacs(n, repeat, BOTH2(WACS_T_VLINE));
3858
3859 n = show_1_wacs(n, repeat, BOTH2(WACS_LARROW));
3860 n = show_1_wacs(n, repeat, BOTH2(WACS_RARROW));
3861 n = show_1_wacs(n, repeat, BOTH2(WACS_UARROW));
3862 n = show_1_wacs(n, repeat, BOTH2(WACS_DARROW));
3863
3864 n = show_1_wacs(n, repeat, BOTH2(WACS_BLOCK));
3865 n = show_1_wacs(n, repeat, BOTH2(WACS_BOARD));
3866 n = show_1_wacs(n, repeat, BOTH2(WACS_LANTERN));
3867 n = show_1_wacs(n, repeat, BOTH2(WACS_BULLET));
3868 n = show_1_wacs(n, repeat, BOTH2(WACS_CKBOARD));
3869 n = show_1_wacs(n, repeat, BOTH2(WACS_DEGREE));
3870 n = show_1_wacs(n, repeat, BOTH2(WACS_DIAMOND));
3871 n = show_1_wacs(n, repeat, BOTH2(WACS_PLMINUS));
3872 n = show_1_wacs(n, repeat, BOTH2(WACS_PLUS));
3873
3874#ifdef CURSES_WACS_ARRAY
3875 n = show_1_wacs(n, repeat, BOTH2(WACS_GEQUAL));
3876 n = show_1_wacs(n, repeat, BOTH2(WACS_NEQUAL));
3877 n = show_1_wacs(n, repeat, BOTH2(WACS_LEQUAL));
3878
3879 n = show_1_wacs(n, repeat, BOTH2(WACS_STERLING));
3880 n = show_1_wacs(n, repeat, BOTH2(WACS_PI));
3881 n = show_1_wacs(n, repeat, BOTH2(WACS_S1));
3882 n = show_1_wacs(n, repeat, BOTH2(WACS_S3));
3883 n = show_1_wacs(n, repeat, BOTH2(WACS_S7));
3884 (void) show_1_wacs(n, repeat, BOTH2(WACS_S9));
3885#endif
3886}
3887#endif
3888
3889#undef MERGE_ATTR
3890
3891#define MERGE_ATTR(n,wch) merge_wide_attr(&temp[n], wch, attr, pair)
3892
3893static void
3894show_wbox_chars(int repeat, attr_t attr, NCURSES_PAIRS_T pair)
3895{
3896 cchar_t temp[8];
3897
3898 (void) repeat;
3899 erase();
3900 attron(A_BOLD);
3901 MvAddStr(0, 20, "Display of the Wide-ACS Line-Drawing Set");
3902 attroff(A_BOLD);
3903 refresh();
3904
3905 wborder_set(stdscr,
3906 MERGE_ATTR(0, WACS_VLINE),
3907 MERGE_ATTR(1, WACS_VLINE),
3908 MERGE_ATTR(2, WACS_HLINE),
3909 MERGE_ATTR(3, WACS_HLINE),
3910 MERGE_ATTR(4, WACS_ULCORNER),
3911 MERGE_ATTR(5, WACS_URCORNER),
3912 MERGE_ATTR(6, WACS_LLCORNER),
3913 MERGE_ATTR(7, WACS_LRCORNER));
3914 /* *INDENT-OFF* */
3915 (void) mvhline_set(LINES / 2, 0, MERGE_ATTR(0, WACS_HLINE), COLS);
3916 (void) mvvline_set(0, COLS / 2, MERGE_ATTR(0, WACS_VLINE), LINES);
3917 (void) mvadd_wch(0, COLS / 2, MERGE_ATTR(0, WACS_TTEE));
3918 (void) mvadd_wch(LINES / 2, COLS / 2, MERGE_ATTR(0, WACS_PLUS));
3919 (void) mvadd_wch(LINES - 1, COLS / 2, MERGE_ATTR(0, WACS_BTEE));
3920 (void) mvadd_wch(LINES / 2, 0, MERGE_ATTR(0, WACS_LTEE));
3921 (void) mvadd_wch(LINES / 2, COLS - 1, MERGE_ATTR(0, WACS_RTEE));
3922 /* *INDENT-ON* */
3923
3924}
3925
3926#undef MERGE_ATTR
3927
3928static int
3929show_2_wacs(int n, const char *name, const char *code, attr_t attr, NCURSES_PAIRS_T pair)
3930{
3931 const int height = 16;
3932 int row = 2 + (n % height);
3933 int col = (n / height) * COLS / 2;
3934 char temp[80];
3935
3936 MvPrintw(row, col, "%*s : ", COLS / 4, name);
3937 (void) attr_set(attr, pair, 0);
3938 addstr(strncpy(temp, code, 20));
3939 (void) attr_set(A_NORMAL, 0, 0);
3940 return n + 1;
3941}
3942
3943#define SHOW_UTF8(n, name, code) show_2_wacs(n, name, code, attr, pair)
3944
3945static void
3946show_utf8_chars(int repeat, attr_t attr, NCURSES_PAIRS_T pair)
3947{
3948 int n;
3949
3950 (void) repeat;
3951 erase();
3952 attron(A_BOLD);
3953 MvAddStr(0, 20, "Display of the Wide-ACS Character Set");
3954 attroff(A_BOLD);
3955 refresh();
3956 /* *INDENT-OFF* */
3957 n = SHOW_UTF8(0, "WACS_ULCORNER", "\342\224\214");
3958 n = SHOW_UTF8(n, "WACS_URCORNER", "\342\224\220");
3959 n = SHOW_UTF8(n, "WACS_LLCORNER", "\342\224\224");
3960 n = SHOW_UTF8(n, "WACS_LRCORNER", "\342\224\230");
3961
3962 n = SHOW_UTF8(n, "WACS_LTEE", "\342\224\234");
3963 n = SHOW_UTF8(n, "WACS_RTEE", "\342\224\244");
3964 n = SHOW_UTF8(n, "WACS_TTEE", "\342\224\254");
3965 n = SHOW_UTF8(n, "WACS_BTEE", "\342\224\264");
3966
3967 n = SHOW_UTF8(n, "WACS_HLINE", "\342\224\200");
3968 n = SHOW_UTF8(n, "WACS_VLINE", "\342\224\202");
3969
3970 n = SHOW_UTF8(n, "WACS_LARROW", "\342\206\220");
3971 n = SHOW_UTF8(n, "WACS_RARROW", "\342\206\222");
3972 n = SHOW_UTF8(n, "WACS_UARROW", "\342\206\221");
3973 n = SHOW_UTF8(n, "WACS_DARROW", "\342\206\223");
3974
3975 n = SHOW_UTF8(n, "WACS_BLOCK", "\342\226\256");
3976 n = SHOW_UTF8(n, "WACS_BOARD", "\342\226\222");
3977 n = SHOW_UTF8(n, "WACS_LANTERN", "\342\230\203");
3978 n = SHOW_UTF8(n, "WACS_BULLET", "\302\267");
3979 n = SHOW_UTF8(n, "WACS_CKBOARD", "\342\226\222");
3980 n = SHOW_UTF8(n, "WACS_DEGREE", "\302\260");
3981 n = SHOW_UTF8(n, "WACS_DIAMOND", "\342\227\206");
3982 n = SHOW_UTF8(n, "WACS_PLMINUS", "\302\261");
3983 n = SHOW_UTF8(n, "WACS_PLUS", "\342\224\274");
3984 n = SHOW_UTF8(n, "WACS_GEQUAL", "\342\211\245");
3985 n = SHOW_UTF8(n, "WACS_NEQUAL", "\342\211\240");
3986 n = SHOW_UTF8(n, "WACS_LEQUAL", "\342\211\244");
3987
3988 n = SHOW_UTF8(n, "WACS_STERLING", "\302\243");
3989 n = SHOW_UTF8(n, "WACS_PI", "\317\200");
3990 n = SHOW_UTF8(n, "WACS_S1", "\342\216\272");
3991 n = SHOW_UTF8(n, "WACS_S3", "\342\216\273");
3992 n = SHOW_UTF8(n, "WACS_S7", "\342\216\274");
3993 (void) SHOW_UTF8(n, "WACS_S9", "\342\216\275");
3994 /* *INDENT-ON* */
3995
3996}
3997
3998/* display the wide-ACS character set */
3999static void
4000wide_acs_display(void)
4001{
4002 int c = 'a';
4003 int digit = 0;
4004 int repeat = 1;
4005 int space = ' ';
4006 int pagesize = 32;
4007 chtype attr = A_NORMAL;
4008 int fg = COLOR_BLACK;
4009 int bg = COLOR_BLACK;
4010 unsigned at_code = 0;
4011 NCURSES_PAIRS_T pair = 0;
4012 void (*last_show_wacs) (int, attr_t, NCURSES_PAIRS_T) = 0;
4013 ATTR_TBL my_list[SIZEOF(attrs_to_test)];
4014 unsigned my_size = init_attr_list(my_list, term_attrs());
4015
4016 do {
4017 switch (c) {
4018 case CTRL('L'):
4019 Repaint();
4020 break;
4021 case 'a':
4022 ToggleAcs(last_show_wacs, show_wacs_chars);
4023 break;
4024#ifdef WACS_D_PLUS
4025 case 'd':
4026 ToggleAcs(last_show_wacs, show_wacs_chars_double);
4027 break;
4028#endif
4029#ifdef WACS_T_PLUS
4030 case 't':
4031 ToggleAcs(last_show_wacs, show_wacs_chars_thick);
4032 break;
4033#endif
4034 case 'w':
4035 if (pagesize == 32) {
4036 pagesize = 256;
4037 } else {
4038 pagesize = 32;
4039 }
4040 break;
4041 case 'x':
4042 ToggleAcs(last_show_wacs, show_wbox_chars);
4043 break;
4044 case 'u':
4045 ToggleAcs(last_show_wacs, show_utf8_chars);
4046 break;
4047 default:
4048 if (c < 256 && isdigit(c)) {
4049 digit = (c - '0');
4050 last_show_wacs = 0;
4051 } else if (c == '+') {
4052 ++digit;
4053 last_show_wacs = 0;
4054 } else if (c == '-' && digit > 0) {
4055 --digit;
4056 last_show_wacs = 0;
4057 } else if (c == '>' && repeat < (COLS / 4)) {
4058 ++repeat;
4059 } else if (c == '<' && repeat > 1) {
4060 --repeat;
4061 } else if (c == '_') {
4062 space = (space == ' ') ? '_' : ' ';
4063 last_show_wacs = 0;
4064 } else if (cycle_attr(c, &at_code, &attr, my_list, my_size)
4065 || cycle_colors(c, &fg, &bg, &pair)) {
4066 if (last_show_wacs != 0)
4067 break;
4068 } else {
4069 beep();
4070 break;
4071 }
4072 break;
4073 }
4074 if (pagesize != 32) {
4075 show_paged_widechars(digit, pagesize, repeat, space, attr, pair);
4076 } else if (last_show_wacs != 0) {
4077 last_show_wacs(repeat, attr, pair);
4078 } else {
4079 show_upper_widechars(digit * 32 + 128, repeat, space, attr, pair);
4080 }
4081
4082 MvPrintw(LINES - 4, 0,
4083 "Select: a/d/t WACS, w=all x=box, u UTF-8, ^L repaint");
4084 MvPrintw(LINES - 3, 2,
4085 "0-9,+/- non-ASCII, </> repeat, _ space, ESC=quit");
4086 if (use_colors) {
4087 MvPrintw(LINES - 2, 2,
4088 "v/V, f/F, b/B cycle through video attributes (%s) and color %d/%d.",
4089 my_list[at_code].name,
4090 fg, bg);
4091 } else {
4092 MvPrintw(LINES - 2, 2,
4093 "v/V cycles through video attributes (%s).",
4094 my_list[at_code].name);
4095 }
4096 refresh();
4097 } while (!isQuit(c = Getchar()));
4098
4099 Pause();
4100 erase();
4101 endwin();
4102}
4103
4104#endif
4105
4106/*
4107 * Graphic-rendition test (adapted from vttest)
4108 */
4109static void
4110test_sgr_attributes(void)
4111{
4112 int pass;
4113
4114 for (pass = 0; pass < 2; pass++) {
4115 chtype normal = ((pass == 0 ? A_NORMAL : A_REVERSE)) | BLANK;
4116
4117 /* Use non-default colors if possible to exercise bce a little */
4118 if (use_colors) {
4119 init_pair(1, COLOR_WHITE, COLOR_BLUE);
4120 normal |= (chtype) COLOR_PAIR(1);
4121 }
4122 bkgdset(normal);
4123 erase();
4124 MvPrintw(1, 20, "Graphic rendition test pattern:");
4125
4126 MvPrintw(4, 1, "vanilla");
4127
4128#define set_sgr(mask) bkgdset((normal^(mask)));
4129 set_sgr(A_BOLD);
4130 MvPrintw(4, 40, "bold");
4131
4132 set_sgr(A_UNDERLINE);
4133 MvPrintw(6, 6, "underline");
4134
4135 set_sgr(A_BOLD | A_UNDERLINE);
4136 MvPrintw(6, 45, "bold underline");
4137
4138 set_sgr(A_BLINK);
4139 MvPrintw(8, 1, "blink");
4140
4141 set_sgr(A_BLINK | A_BOLD);
4142 MvPrintw(8, 40, "bold blink");
4143
4144 set_sgr(A_UNDERLINE | A_BLINK);
4145 MvPrintw(10, 6, "underline blink");
4146
4147 set_sgr(A_BOLD | A_UNDERLINE | A_BLINK);
4148 MvPrintw(10, 45, "bold underline blink");
4149
4150 set_sgr(A_REVERSE);
4151 MvPrintw(12, 1, "negative");
4152
4153 set_sgr(A_BOLD | A_REVERSE);
4154 MvPrintw(12, 40, "bold negative");
4155
4156 set_sgr(A_UNDERLINE | A_REVERSE);
4157 MvPrintw(14, 6, "underline negative");
4158
4159 set_sgr(A_BOLD | A_UNDERLINE | A_REVERSE);
4160 MvPrintw(14, 45, "bold underline negative");
4161
4162 set_sgr(A_BLINK | A_REVERSE);
4163 MvPrintw(16, 1, "blink negative");
4164
4165 set_sgr(A_BOLD | A_BLINK | A_REVERSE);
4166 MvPrintw(16, 40, "bold blink negative");
4167
4168 set_sgr(A_UNDERLINE | A_BLINK | A_REVERSE);
4169 MvPrintw(18, 6, "underline blink negative");
4170
4171 set_sgr(A_BOLD | A_UNDERLINE | A_BLINK | A_REVERSE);
4172 MvPrintw(18, 45, "bold underline blink negative");
4173
4174 bkgdset(normal);
4175 MvPrintw(LINES - 2, 1, "%s background. ", pass == 0 ? "Dark" :
4176 "Light");
4177 clrtoeol();
4178 Pause();
4179 }
4180
4181 bkgdset(A_NORMAL | BLANK);
4182 erase();
4183 endwin();
4184}
4185
4186/****************************************************************************
4187 *
4188 * Windows and scrolling tester.
4189 *
4190 ****************************************************************************/
4191
4192#define BOTLINES 4 /* number of line stolen from screen bottom */
4193
4194typedef struct {
4195 int y, x;
4196} pair;
4197
4198#define FRAME struct frame
4199FRAME
4200{
4201 FRAME *next, *last;
4202 bool do_scroll;
4203 bool do_keypad;
4204 WINDOW *wind;
4205};
4206
4207#if defined(NCURSES_VERSION)
4208#if (NCURSES_VERSION_PATCH < 20070331) && NCURSES_EXT_FUNCS
4209#define is_keypad(win) (win)->_use_keypad
4210#define is_scrollok(win) (win)->_scroll
4211#elif !defined(is_keypad)
4212#define is_keypad(win) FALSE
4213#define is_scrollok(win) FALSE
4214#endif
4215#else
4216#define is_keypad(win) FALSE
4217#define is_scrollok(win) FALSE
4218#endif
4219
4220static WINDOW *
4221frame_win(FRAME * curp)
4222{
4223 return (curp != 0) ? curp->wind : stdscr;
4224}
4225
4226/* We need to know if these flags are actually set, so don't look in FRAME.
4227 * These names are known to work with SVr4 curses as well as ncurses. The
4228 * _use_keypad name does not work with Solaris 8.
4229 */
4230static bool
4231HaveKeypad(FRAME * curp)
4232{
4233 WINDOW *win = frame_win(curp);
4234 (void) win;
4235 return is_keypad(win);
4236}
4237
4238static bool
4239HaveScroll(FRAME * curp)
4240{
4241 WINDOW *win = frame_win(curp);
4242 (void) win;
4243 return is_scrollok(win);
4244}
4245
4246static void
4247newwin_legend(FRAME * curp)
4248{
4249 static const struct {
4250 const char *msg;
4251 int code;
4252 } legend[] = {
4253 {
4254 "^C = create window", 0
4255 },
4256 {
4257 "^N = next window", 0
4258 },
4259 {
4260 "^P = previous window", 0
4261 },
4262 {
4263 "^F = scroll forward", 0
4264 },
4265 {
4266 "^B = scroll backward", 0
4267 },
4268 {
4269 "^K = keypad(%s)", 1
4270 },
4271 {
4272 "^S = scrollok(%s)", 2
4273 },
4274 {
4275 "^W = save window to file", 0
4276 },
4277 {
4278 "^R = restore window", 0
4279 },
4280#if HAVE_WRESIZE
4281 {
4282 "^X = resize", 0
4283 },
4284#endif
4285 {
4286 "^Q%s = exit", 3
4287 }
4288 };
4289 size_t n;
4290 int x;
4291 bool do_keypad = HaveKeypad(curp);
4292 bool do_scroll = HaveScroll(curp);
4293 char buf[BUFSIZ];
4294
4295 move(LINES - 4, 0);
4296 for (n = 0; n < SIZEOF(legend); n++) {
4297 switch (legend[n].code) {
4298 default:
4299 strcpy(buf, legend[n].msg);
4300 break;
4301 case 1:
4302 sprintf(buf, legend[n].msg, do_keypad ? "yes" : "no");
4303 break;
4304 case 2:
4305 sprintf(buf, legend[n].msg, do_scroll ? "yes" : "no");
4306 break;
4307 case 3:
4308 sprintf(buf, legend[n].msg, do_keypad ? "/ESC" : "");
4309 break;
4310 }
4311 x = getcurx(stdscr);
4312 addstr((COLS < (x + 3 + (int) strlen(buf))) ? "\n" : (n ? ", " : ""));
4313 addstr(buf);
4314 }
4315 clrtoeol();
4316}
4317
4318static void
4319transient(FRAME * curp, NCURSES_CONST char *msg)
4320{
4321 newwin_legend(curp);
4322 if (msg) {
4323 MvAddStr(LINES - 1, 0, msg);
4324 refresh();
4325 napms(1000);
4326 }
4327
4328 move(LINES - 1, 0);
4329 printw("%s characters are echoed, window should %sscroll.",
4330 HaveKeypad(curp) ? "Non-arrow" : "All other",
4331 HaveScroll(curp) ? "" : "not ");
4332 clrtoeol();
4333}
4334
4335static void
4336newwin_report(FRAME * curp)
4337/* report on the cursor's current position, then restore it */
4338{
4339 WINDOW *win = frame_win(curp);
4340 int y, x;
4341
4342 if (win != stdscr)
4343 transient(curp, (char *) 0);
4344 getyx(win, y, x);
4345 move(LINES - 1, COLS - 17);
4346 printw("Y = %2d X = %2d", y, x);
4347 if (win != stdscr)
4348 refresh();
4349 else
4350 wmove(win, y, x);
4351}
4352
4353static pair *
4354selectcell(int uli, int ulj, int lri, int lrj)
4355/* arrows keys move cursor, return location at current on non-arrow key */
4356{
4357 static pair res; /* result cell */
4358 int si = lri - uli + 1; /* depth of the select area */
4359 int sj = lrj - ulj + 1; /* width of the select area */
4360 int i = 0, j = 0; /* offsets into the select area */
4361
4362 res.y = uli;
4363 res.x = ulj;
4364 for (;;) {
4365 move(uli + i, ulj + j);
4366 newwin_report((FRAME *) 0);
4367
4368 switch (Getchar()) {
4369 case KEY_UP:
4370 i += si - 1;
4371 break;
4372 case KEY_DOWN:
4373 i++;
4374 break;
4375 case KEY_LEFT:
4376 j += sj - 1;
4377 break;
4378 case KEY_RIGHT:
4379 j++;
4380 break;
4381 case case_QUIT:
4382 return ((pair *) 0);
4383#ifdef NCURSES_MOUSE_VERSION
4384 case KEY_MOUSE:
4385 {
4386 MEVENT event;
4387
4388 getmouse(&event);
4389 if (event.y > uli && event.x > ulj) {
4390 i = event.y - uli;
4391 j = event.x - ulj;
4392 } else {
4393 beep();
4394 break;
4395 }
4396 }
4397 /* FALLTHRU */
4398#endif
4399 default:
4400 res.y = uli + i;
4401 res.x = ulj + j;
4402 return (&res);
4403 }
4404 i %= si;
4405 j %= sj;
4406 }
4407}
4408
4409static void
4410outerbox(pair ul, pair lr, bool onoff)
4411/* draw or erase a box *outside* the given pair of corners */
4412{
4413 MvAddCh(ul.y - 1, lr.x - 1, onoff ? ACS_ULCORNER : ' ');
4414 MvAddCh(ul.y - 1, lr.x + 1, onoff ? ACS_URCORNER : ' ');
4415 MvAddCh(lr.y + 1, lr.x + 1, onoff ? ACS_LRCORNER : ' ');
4416 MvAddCh(lr.y + 1, ul.x - 1, onoff ? ACS_LLCORNER : ' ');
4417 move(ul.y - 1, ul.x);
4418 hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1);
4419 move(ul.y, ul.x - 1);
4420 vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1);
4421 move(lr.y + 1, ul.x);
4422 hline(onoff ? ACS_HLINE : ' ', lr.x - ul.x + 1);
4423 move(ul.y, lr.x + 1);
4424 vline(onoff ? ACS_VLINE : ' ', lr.y - ul.y + 1);
4425}
4426
4427static WINDOW *
4428getwindow(void)
4429/* Ask user for a window definition */
4430{
4431 WINDOW *rwindow;
4432 pair ul, lr, *tmp;
4433
4434 move(0, 0);
4435 clrtoeol();
4436 addstr("Use arrows to move cursor, anything else to mark corner 1");
4437 refresh();
4438 if ((tmp = selectcell(2, 1, LINES - BOTLINES - 2, COLS - 2)) == (pair *) 0)
4439 return ((WINDOW *) 0);
4440 memcpy(&ul, tmp, sizeof(pair));
4441 MvAddCh(ul.y - 1, ul.x - 1, ACS_ULCORNER);
4442 move(0, 0);
4443 clrtoeol();
4444 addstr("Use arrows to move cursor, anything else to mark corner 2");
4445 refresh();
4446 if ((tmp = selectcell(ul.y, ul.x, LINES - BOTLINES - 2, COLS - 2)) ==
4447 (pair *) 0)
4448 return ((WINDOW *) 0);
4449 memcpy(&lr, tmp, sizeof(pair));
4450
4451 rwindow = subwin(stdscr, lr.y - ul.y + 1, lr.x - ul.x + 1, ul.y, ul.x);
4452
4453 outerbox(ul, lr, TRUE);
4454 refresh();
4455
4456 if (rwindow != 0)
4457 wrefresh(rwindow);
4458
4459 move(0, 0);
4460 clrtoeol();
4461 return (rwindow);
4462}
4463
4464static void
4465newwin_move(FRAME * curp, int dy, int dx)
4466{
4467 WINDOW *win = frame_win(curp);
4468 int cur_y, cur_x;
4469 int max_y, max_x;
4470
4471 getyx(win, cur_y, cur_x);
4472 getmaxyx(win, max_y, max_x);
4473 if ((cur_x += dx) < 0)
4474 cur_x = 0;
4475 else if (cur_x >= max_x)
4476 cur_x = max_x - 1;
4477 if ((cur_y += dy) < 0)
4478 cur_y = 0;
4479 else if (cur_y >= max_y)
4480 cur_y = max_y - 1;
4481 wmove(win, cur_y, cur_x);
4482}
4483
4484static FRAME *
4485delete_framed(FRAME * fp, bool showit)
4486{
4487 FRAME *np = 0;
4488
4489 if (fp != 0) {
4490 fp->last->next = fp->next;
4491 fp->next->last = fp->last;
4492
4493 if (showit) {
4494 werase(fp->wind);
4495 wrefresh(fp->wind);
4496 }
4497 delwin(fp->wind);
4498
4499 np = (fp == fp->next) ? 0 : fp->next;
4500 free(fp);
4501 }
4502 return np;
4503}
4504
4505static void
4506acs_and_scroll(void)
4507/* Demonstrate windows */
4508{
4509 int c;
4510 FRAME *current = (FRAME *) 0, *neww;
4511 WINDOW *usescr;
4512#if HAVE_PUTWIN && HAVE_GETWIN
4513 FILE *fp;
4514#endif
4515
4516#define DUMPFILE "screendump"
4517
4518#ifdef NCURSES_MOUSE_VERSION
4519 mousemask(BUTTON1_CLICKED, (mmask_t *) 0);
4520#endif
4521 c = CTRL('C');
4522 raw();
4523 do {
4524 transient((FRAME *) 0, (char *) 0);
4525 switch (c) {
4526 case CTRL('C'):
4527 if ((neww = typeCalloc(FRAME, (size_t) 1)) == 0) {
4528 failed("acs_and_scroll");
4529 goto breakout;
4530 }
4531 if ((neww->wind = getwindow()) == (WINDOW *) 0) {
4532 failed("acs_and_scroll");
4533 free(neww);
4534 goto breakout;
4535 }
4536
4537 if (current == 0) { /* First element, */
4538 neww->next = neww; /* so point it at itself */
4539 neww->last = neww;
4540 } else {
4541 neww->next = current->next;
4542 neww->last = current;
4543 neww->last->next = neww;
4544 neww->next->last = neww;
4545 }
4546 current = neww;
4547 /* SVr4 curses sets the keypad on all newly-created windows to
4548 * false. Someone reported that PDCurses makes new windows inherit
4549 * this flag. Remove the following 'keypad()' call to test this
4550 */
4551 keypad(current->wind, TRUE);
4552 current->do_keypad = HaveKeypad(current);
4553 current->do_scroll = HaveScroll(current);
4554 break;
4555
4556 case CTRL('N'): /* go to next window */
4557 if (current)
4558 current = current->next;
4559 break;
4560
4561 case CTRL('P'): /* go to previous window */
4562 if (current)
4563 current = current->last;
4564 break;
4565
4566 case CTRL('F'): /* scroll current window forward */
4567 if (current)
4568 wscrl(frame_win(current), 1);
4569 break;
4570
4571 case CTRL('B'): /* scroll current window backwards */
4572 if (current)
4573 wscrl(frame_win(current), -1);
4574 break;
4575
4576 case CTRL('K'): /* toggle keypad mode for current */
4577 if (current) {
4578 current->do_keypad = !current->do_keypad;
4579 keypad(current->wind, current->do_keypad);
4580 }
4581 break;
4582
4583 case CTRL('S'):
4584 if (current) {
4585 current->do_scroll = !current->do_scroll;
4586 scrollok(current->wind, current->do_scroll);
4587 }
4588 break;
4589
4590#if HAVE_PUTWIN && HAVE_GETWIN
4591 case CTRL('W'): /* save and delete window */
4592 if ((current != 0) && (current == current->next)) {
4593 transient(current, "Will not save/delete ONLY window");
4594 break;
4595 } else if ((fp = fopen(DUMPFILE, "w")) == (FILE *) 0) {
4596 transient(current, "Can't open screen dump file");
4597 } else {
4598 (void) putwin(frame_win(current), fp);
4599 (void) fclose(fp);
4600
4601 current = delete_framed(current, TRUE);
4602 }
4603 break;
4604
4605 case CTRL('R'): /* restore window */
4606 if ((fp = fopen(DUMPFILE, "r")) == (FILE *) 0) {
4607 transient(current, "Can't open screen dump file");
4608 } else {
4609 if ((neww = typeCalloc(FRAME, (size_t) 1)) != 0) {
4610
4611 neww->next = current ? current->next : 0;
4612 neww->last = current;
4613 if (neww->last != 0)
4614 neww->last->next = neww;
4615 if (neww->next != 0)
4616 neww->next->last = neww;
4617
4618 neww->wind = getwin(fp);
4619
4620 wrefresh(neww->wind);
4621 } else {
4622 failed("acs_and_scroll");
4623 }
4624 (void) fclose(fp);
4625 }
4626 break;
4627#endif
4628
4629#if HAVE_WRESIZE
4630 case CTRL('X'): /* resize window */
4631 if (current) {
4632 pair *tmp, ul, lr;
4633 int i, mx, my;
4634
4635 move(0, 0);
4636 clrtoeol();
4637 addstr("Use arrows to move cursor, anything else to mark new corner");
4638 refresh();
4639
4640 getbegyx(current->wind, ul.y, ul.x);
4641
4642 tmp = selectcell(ul.y, ul.x, LINES - BOTLINES - 2, COLS - 2);
4643 if (tmp == (pair *) 0) {
4644 beep();
4645 break;
4646 }
4647
4648 getmaxyx(current->wind, lr.y, lr.x);
4649 lr.y += (ul.y - 1);
4650 lr.x += (ul.x - 1);
4651 outerbox(ul, lr, FALSE);
4652 wnoutrefresh(stdscr);
4653
4654 /* strictly cosmetic hack for the test */
4655 getmaxyx(current->wind, my, mx);
4656 if (my > tmp->y - ul.y) {
4657 getyx(current->wind, lr.y, lr.x);
4658 wmove(current->wind, tmp->y - ul.y + 1, 0);
4659 wclrtobot(current->wind);
4660 wmove(current->wind, lr.y, lr.x);
4661 }
4662 if (mx > tmp->x - ul.x)
4663 for (i = 0; i < my; i++) {
4664 wmove(current->wind, i, tmp->x - ul.x + 1);
4665 wclrtoeol(current->wind);
4666 }
4667 wnoutrefresh(current->wind);
4668
4669 memcpy(&lr, tmp, sizeof(pair));
4670 (void) wresize(current->wind, lr.y - ul.y + 0, lr.x - ul.x + 0);
4671
4672 getbegyx(current->wind, ul.y, ul.x);
4673 getmaxyx(current->wind, lr.y, lr.x);
4674 lr.y += (ul.y - 1);
4675 lr.x += (ul.x - 1);
4676 outerbox(ul, lr, TRUE);
4677 wnoutrefresh(stdscr);
4678
4679 wnoutrefresh(current->wind);
4680 move(0, 0);
4681 clrtoeol();
4682 doupdate();
4683 }
4684 break;
4685#endif /* HAVE_WRESIZE */
4686
4687 case KEY_F(10): /* undocumented --- use this to test area clears */
4688 selectcell(0, 0, LINES - 1, COLS - 1);
4689 clrtobot();
4690 refresh();
4691 break;
4692
4693 case KEY_UP:
4694 newwin_move(current, -1, 0);
4695 break;
4696 case KEY_DOWN:
4697 newwin_move(current, 1, 0);
4698 break;
4699 case KEY_LEFT:
4700 newwin_move(current, 0, -1);
4701 break;
4702 case KEY_RIGHT:
4703 newwin_move(current, 0, 1);
4704 break;
4705
4706 case KEY_BACKSPACE:
4707 /* FALLTHROUGH */
4708 case KEY_DC:
4709 {
4710 int y, x;
4711 getyx(frame_win(current), y, x);
4712 if (--x < 0) {
4713 if (--y < 0)
4714 break;
4715 x = getmaxx(frame_win(current)) - 1;
4716 }
4717 (void) mvwdelch(frame_win(current), y, x);
4718 }
4719 break;
4720
4721 case '\r':
4722 c = '\n';
4723 /* FALLTHROUGH */
4724
4725 default:
4726 if (current)
4727 waddch(current->wind, (chtype) c);
4728 else
4729 beep();
4730 break;
4731 }
4732 newwin_report(current);
4733 usescr = frame_win(current);
4734 wrefresh(usescr);
4735 } while
4736 (!isQuit(c = wGetchar(usescr))
4737 && (c != ERR));
4738
4739 breakout:
4740 while (current != 0)
4741 current = delete_framed(current, FALSE);
4742
4743 scrollok(stdscr, TRUE); /* reset to driver's default */
4744#ifdef NCURSES_MOUSE_VERSION
4745 mousemask(0, (mmask_t *) 0);
4746#endif
4747 noraw();
4748 erase();
4749 endwin();
4750}
4751
4752/****************************************************************************
4753 *
4754 * Panels tester
4755 *
4756 ****************************************************************************/
4757
4758#if USE_LIBPANEL
4759static int nap_msec = 1;
4760
4761static NCURSES_CONST char *mod[] =
4762{
4763 "test ",
4764 "TEST ",
4765 "(**) ",
4766 "*()* ",
4767 "<--> ",
4768 "LAST "
4769};
4770
4771/*+-------------------------------------------------------------------------
4772 wait_a_while(msec)
4773--------------------------------------------------------------------------*/
4774static void
4775wait_a_while(int msec GCC_UNUSED)
4776{
4777#if HAVE_NAPMS
4778 if (nap_msec == 1)
4779 wGetchar(stdscr);
4780 else
4781 napms(nap_msec);
4782#else
4783 if (nap_msec == 1)
4784 wGetchar(stdscr);
4785 else if (msec > 1000)
4786 sleep((unsigned) msec / 1000);
4787 else
4788 sleep(1);
4789#endif
4790} /* end of wait_a_while */
4791
4792/*+-------------------------------------------------------------------------
4793 saywhat(text)
4794--------------------------------------------------------------------------*/
4795static void
4796saywhat(NCURSES_CONST char *text)
4797{
4798 wmove(stdscr, LINES - 1, 0);
4799 wclrtoeol(stdscr);
4800 if (text != 0 && *text != '\0') {
4801 waddstr(stdscr, text);
4802 waddstr(stdscr, "; ");
4803 }
4804 waddstr(stdscr, "press any key to continue");
4805} /* end of saywhat */
4806
4807/*+-------------------------------------------------------------------------
4808 mkpanel(rows,cols,tly,tlx) - alloc a win and panel and associate them
4809--------------------------------------------------------------------------*/
4810static PANEL *
4811mkpanel(NCURSES_COLOR_T color, int rows, int cols, int tly, int tlx)
4812{
4813 WINDOW *win;
4814 PANEL *pan = 0;
4815
4816 if ((win = newwin(rows, cols, tly, tlx)) != 0) {
4817 if ((pan = new_panel(win)) == 0) {
4818 delwin(win);
4819 } else if (use_colors) {
4820 NCURSES_COLOR_T fg = (NCURSES_COLOR_T) ((color == COLOR_BLUE)
4821 ? COLOR_WHITE
4822 : COLOR_BLACK);
4823 NCURSES_COLOR_T bg = color;
4824
4825 init_pair(color, fg, bg);
4826 wbkgdset(win, (attr_t) (COLOR_PAIR(color) | ' '));
4827 } else {
4828 wbkgdset(win, A_BOLD | ' ');
4829 }
4830 }
4831 return pan;
4832} /* end of mkpanel */
4833
4834/*+-------------------------------------------------------------------------
4835 rmpanel(pan)
4836--------------------------------------------------------------------------*/
4837static void
4838rmpanel(PANEL * pan)
4839{
4840 WINDOW *win = panel_window(pan);
4841 del_panel(pan);
4842 delwin(win);
4843} /* end of rmpanel */
4844
4845/*+-------------------------------------------------------------------------
4846 pflush()
4847--------------------------------------------------------------------------*/
4848static void
4849pflush(void)
4850{
4851 update_panels();
4852 doupdate();
4853} /* end of pflush */
4854
4855/*+-------------------------------------------------------------------------
4856 fill_panel(win)
4857--------------------------------------------------------------------------*/
4858static void
4859init_panel(WINDOW *win)
4860{
4861 register int y, x;
4862
4863 for (y = 0; y < LINES - 1; y++) {
4864 for (x = 0; x < COLS; x++)
4865 wprintw(win, "%d", (y + x) % 10);
4866 }
4867}
4868
4869static void
4870fill_panel(PANEL * pan)
4871{
4872 WINDOW *win = panel_window(pan);
4873 const char *userptr = (const char *) panel_userptr(pan);
4874 int num = (userptr && *userptr) ? userptr[1] : '?';
4875 int y, x;
4876
4877 wmove(win, 1, 1);
4878 wprintw(win, "-pan%c-", num);
4879 wclrtoeol(win);
4880 box(win, 0, 0);
4881 for (y = 2; y < getmaxy(win) - 1; y++) {
4882 for (x = 1; x < getmaxx(win) - 1; x++) {
4883 wmove(win, y, x);
4884 waddch(win, UChar(num));
4885 }
4886 }
4887}
4888
4889#if USE_WIDEC_SUPPORT
4890static void
4891init_wide_panel(WINDOW *win)
4892{
4893 int digit;
4894 cchar_t temp[10];
4895
4896 for (digit = 0; digit < 10; ++digit)
4897 make_fullwidth_digit(&temp[digit], digit);
4898
4899 do {
4900 int y, x;
4901 getyx(stdscr, y, x);
4902 digit = (y + x / 2) % 10;
4903 } while (wadd_wch(win, &temp[digit]) != ERR);
4904}
4905
4906static void
4907fill_wide_panel(PANEL * pan)
4908{
4909 WINDOW *win = panel_window(pan);
4910 const char *userptr = (const char *) panel_userptr(pan);
4911 int num = (userptr && *userptr) ? userptr[1] : '?';
4912 int y, x;
4913
4914 wmove(win, 1, 1);
4915 wprintw(win, "-pan%c-", num);
4916 wclrtoeol(win);
4917 box(win, 0, 0);
4918 for (y = 2; y < getmaxy(win) - 1; y++) {
4919 for (x = 1; x < getmaxx(win) - 1; x++) {
4920 wmove(win, y, x);
4921 waddch(win, UChar(num));
4922 }
4923 }
4924}
4925#endif
4926
4927#define MAX_PANELS 5
4928
4929static void
4930canned_panel(PANEL * px[MAX_PANELS + 1], NCURSES_CONST char *cmd)
4931{
4932 int which = cmd[1] - '0';
4933
4934 saywhat(cmd);
4935 switch (*cmd) {
4936 case 'h':
4937 hide_panel(px[which]);
4938 break;
4939 case 's':
4940 show_panel(px[which]);
4941 break;
4942 case 't':
4943 top_panel(px[which]);
4944 break;
4945 case 'b':
4946 bottom_panel(px[which]);
4947 break;
4948 case 'd':
4949 rmpanel(px[which]);
4950 break;
4951 }
4952 pflush();
4953 wait_a_while(nap_msec);
4954}
4955
4956static void
4957demo_panels(void (*InitPanel) (WINDOW *), void (*FillPanel) (PANEL *))
4958{
4959 int count;
4960 int itmp;
4961 PANEL *px[MAX_PANELS + 1];
4962
4963 scrollok(stdscr, FALSE); /* we don't want stdscr to scroll! */
4964 refresh();
4965
4966 InitPanel(stdscr);
4967 for (count = 0; count < 5; count++) {
4968 px[1] = mkpanel(COLOR_RED,
4969 LINES / 2 - 2,
4970 COLS / 8 + 1,
4971 0,
4972 0);
4973 set_panel_userptr(px[1], (NCURSES_CONST void *) "p1");
4974
4975 px[2] = mkpanel(COLOR_GREEN,
4976 LINES / 2 + 1,
4977 COLS / 7,
4978 LINES / 4,
4979 COLS / 10);
4980 set_panel_userptr(px[2], (NCURSES_CONST void *) "p2");
4981
4982 px[3] = mkpanel(COLOR_YELLOW,
4983 LINES / 4,
4984 COLS / 10,
4985 LINES / 2,
4986 COLS / 9);
4987 set_panel_userptr(px[3], (NCURSES_CONST void *) "p3");
4988
4989 px[4] = mkpanel(COLOR_BLUE,
4990 LINES / 2 - 2,
4991 COLS / 8,
4992 LINES / 2 - 2,
4993 COLS / 3);
4994 set_panel_userptr(px[4], (NCURSES_CONST void *) "p4");
4995
4996 px[5] = mkpanel(COLOR_MAGENTA,
4997 LINES / 2 - 2,
4998 COLS / 8,
4999 LINES / 2,
5000 COLS / 2 - 2);
5001 set_panel_userptr(px[5], (NCURSES_CONST void *) "p5");
5002
5003 FillPanel(px[1]);
5004 FillPanel(px[2]);
5005 FillPanel(px[3]);
5006 FillPanel(px[4]);
5007 FillPanel(px[5]);
5008
5009 hide_panel(px[4]);
5010 hide_panel(px[5]);
5011 pflush();
5012 saywhat("");
5013 wait_a_while(nap_msec);
5014
5015 saywhat("h3 s1 s2 s4 s5");
5016 move_panel(px[1], 0, 0);
5017 hide_panel(px[3]);
5018 show_panel(px[1]);
5019 show_panel(px[2]);
5020 show_panel(px[4]);
5021 show_panel(px[5]);
5022 pflush();
5023 wait_a_while(nap_msec);
5024
5025 canned_panel(px, "s1");
5026 canned_panel(px, "s2");
5027
5028 saywhat("m2");
5029 move_panel(px[2], LINES / 3 + 1, COLS / 8);
5030 pflush();
5031 wait_a_while(nap_msec);
5032
5033 canned_panel(px, "s3");
5034
5035 saywhat("m3");
5036 move_panel(px[3], LINES / 4 + 1, COLS / 15);
5037 pflush();
5038 wait_a_while(nap_msec);
5039
5040 canned_panel(px, "b3");
5041 canned_panel(px, "s4");
5042 canned_panel(px, "s5");
5043 canned_panel(px, "t3");
5044 canned_panel(px, "t1");
5045 canned_panel(px, "t2");
5046 canned_panel(px, "t3");
5047 canned_panel(px, "t4");
5048
5049 for (itmp = 0; itmp < 6; itmp++) {
5050 WINDOW *w4 = panel_window(px[4]);
5051 WINDOW *w5 = panel_window(px[5]);
5052
5053 saywhat("m4");
5054 wmove(w4, LINES / 8, 1);
5055 waddstr(w4, mod[itmp]);
5056 move_panel(px[4], LINES / 6, itmp * (COLS / 8));
5057 wmove(w5, LINES / 6, 1);
5058 waddstr(w5, mod[itmp]);
5059 pflush();
5060 wait_a_while(nap_msec);
5061
5062 saywhat("m5");
5063 wmove(w4, LINES / 6, 1);
5064 waddstr(w4, mod[itmp]);
5065 move_panel(px[5], LINES / 3 - 1, (itmp * 10) + 6);
5066 wmove(w5, LINES / 8, 1);
5067 waddstr(w5, mod[itmp]);
5068 pflush();
5069 wait_a_while(nap_msec);
5070 }
5071
5072 saywhat("m4");
5073 move_panel(px[4], LINES / 6, itmp * (COLS / 8));
5074 pflush();
5075 wait_a_while(nap_msec);
5076
5077 canned_panel(px, "t5");
5078 canned_panel(px, "t2");
5079 canned_panel(px, "t1");
5080 canned_panel(px, "d2");
5081 canned_panel(px, "h3");
5082 canned_panel(px, "d1");
5083 canned_panel(px, "d4");
5084 canned_panel(px, "d5");
5085 canned_panel(px, "d3");
5086
5087 wait_a_while(nap_msec);
5088 if (nap_msec == 1)
5089 break;
5090 nap_msec = 100L;
5091 }
5092
5093 erase();
5094 endwin();
5095}
5096#endif /* USE_LIBPANEL */
5097
5098/****************************************************************************
5099 *
5100 * Pad tester
5101 *
5102 ****************************************************************************/
5103
5104#define GRIDSIZE 3
5105
5106static bool pending_pan = FALSE;
5107static bool show_panner_legend = TRUE;
5108
5109static int
5110panner_legend(int line)
5111{
5112 static const char *const legend[] =
5113 {
5114 "Use arrow keys (or U,D,L,R) to pan, ESC to quit, ! to shell-out.",
5115 "Use +,- (or j,k) to grow/shrink the panner vertically.",
5116 "Use <,> (or h,l) to grow/shrink the panner horizontally.",
5117 "Number repeats. Toggle legend:? filler:a timer:t scrollmark:s."
5118 };
5119 int n = ((int) SIZEOF(legend) - (LINES - line));
5120 if (n >= 0) {
5121 if (move(line, 0) != ERR) {
5122 if (show_panner_legend)
5123 printw("%s", legend[n]);
5124 clrtoeol();
5125 return show_panner_legend;
5126 }
5127 }
5128 return FALSE;
5129}
5130
5131static void
5132panner_h_cleanup(int from_y, int from_x, int to_x)
5133{
5134 if (!panner_legend(from_y))
5135 do_h_line(from_y, from_x, ' ', to_x);
5136}
5137
5138static void
5139panner_v_cleanup(int from_y, int from_x, int to_y)
5140{
5141 if (!panner_legend(from_y))
5142 do_v_line(from_y, from_x, ' ', to_y);
5143}
5144
5145static void
5146fill_pad(WINDOW *panpad, bool pan_lines, bool colored)
5147{
5148 int y, x;
5149 unsigned gridcount = 0;
5150 chtype fill = 0;
5151#ifdef A_COLOR
5152 if (colored)
5153 fill = (chtype) COLOR_PAIR(1);
5154#endif
5155
5156 wmove(panpad, 0, 0);
5157 for (y = 0; y < getmaxy(panpad); y++) {
5158 for (x = 0; x < getmaxx(panpad); x++) {
5159 if (y % GRIDSIZE == 0 && x % GRIDSIZE == 0) {
5160 if (y == 0 && x == 0)
5161 waddch(panpad, pan_lines ? ACS_ULCORNER : '+');
5162 else if (y == 0)
5163 waddch(panpad, pan_lines ? ACS_TTEE : '+');
5164 else if (y == 0 || x == 0)
5165 waddch(panpad, pan_lines ? ACS_LTEE : '+');
5166 else
5167 waddch(panpad, (chtype) ((pan_lines ? 'a' : 'A') +
5168 (int) (gridcount++ % 26)) | fill);
5169 } else if (y % GRIDSIZE == 0)
5170 waddch(panpad, pan_lines ? ACS_HLINE : '-');
5171 else if (x % GRIDSIZE == 0)
5172 waddch(panpad, pan_lines ? ACS_VLINE : '|');
5173 else
5174 waddch(panpad, ' ');
5175 }
5176 }
5177}
5178
5179static void
5180panner(WINDOW *pad,
5181 int top_x, int top_y, int porty, int portx,
5182 int (*pgetc) (WINDOW *),
5183 bool colored)
5184{
5185#if HAVE_GETTIMEOFDAY
5186 struct timeval before, after;
5187 bool timing = TRUE;
5188#endif
5189 bool pan_lines = FALSE;
5190 bool scrollers = TRUE;
5191 int basex = 0;
5192 int basey = 0;
5193 int pxmax, pymax, lowend, highend, c;
5194
5195 getmaxyx(pad, pymax, pxmax);
5196 scrollok(stdscr, FALSE); /* we don't want stdscr to scroll! */
5197
5198 c = KEY_REFRESH;
5199 do {
5200#ifdef NCURSES_VERSION
5201 /*
5202 * During shell-out, the user may have resized the window. Adjust
5203 * the port size of the pad to accommodate this. Ncurses automatically
5204 * resizes all of the normal windows to fit on the new screen.
5205 */
5206 if (top_x > COLS)
5207 top_x = COLS;
5208 if (portx > COLS)
5209 portx = COLS;
5210 if (top_y > LINES)
5211 top_y = LINES;
5212 if (porty > LINES)
5213 porty = LINES;
5214#endif
5215 switch (c) {
5216 case KEY_REFRESH:
5217 erase();
5218
5219 /* FALLTHRU */
5220 case '?':
5221 if (c == '?')
5222 show_panner_legend = !show_panner_legend;
5223 panner_legend(LINES - 4);
5224 panner_legend(LINES - 3);
5225 panner_legend(LINES - 2);
5226 panner_legend(LINES - 1);
5227 break;
5228 case 'a':
5229 pan_lines = !pan_lines;
5230 fill_pad(pad, pan_lines, colored);
5231 pending_pan = FALSE;
5232 break;
5233
5234#if HAVE_GETTIMEOFDAY
5235 case 't':
5236 timing = !timing;
5237 if (!timing)
5238 panner_legend(LINES - 1);
5239 break;
5240#endif
5241 case 's':
5242 scrollers = !scrollers;
5243 break;
5244
5245 /* Move the top-left corner of the pad, keeping the bottom-right
5246 * corner fixed.
5247 */
5248 case 'h': /* increase-columns: move left edge to left */
5249 if (top_x <= 0)
5250 beep();
5251 else {
5252 panner_v_cleanup(top_y, top_x, porty);
5253 top_x--;
5254 }
5255 break;
5256
5257 case 'j': /* decrease-lines: move top-edge down */
5258 if (top_y >= porty)
5259 beep();
5260 else {
5261 panner_h_cleanup(top_y - 1, top_x - (top_x > 0), portx);
5262 top_y++;
5263 }
5264 break;
5265
5266 case 'k': /* increase-lines: move top-edge up */
5267 if (top_y <= 0)
5268 beep();
5269 else {
5270 top_y--;
5271 panner_h_cleanup(top_y, top_x, portx);
5272 }
5273 break;
5274
5275 case 'l': /* decrease-columns: move left-edge to right */
5276 if (top_x >= portx)
5277 beep();
5278 else {
5279 panner_v_cleanup(top_y - (top_y > 0), top_x - 1, porty);
5280 top_x++;
5281 }
5282 break;
5283
5284 /* Move the bottom-right corner of the pad, keeping the top-left
5285 * corner fixed.
5286 */
5287 case KEY_IC: /* increase-columns: move right-edge to right */
5288 if (portx >= pxmax || portx >= COLS)
5289 beep();
5290 else {
5291 panner_v_cleanup(top_y - (top_y > 0), portx - 1, porty);
5292 ++portx;
5293 }
5294 break;
5295
5296 case KEY_IL: /* increase-lines: move bottom-edge down */
5297 if (porty >= pymax || porty >= LINES)
5298 beep();
5299 else {
5300 panner_h_cleanup(porty - 1, top_x - (top_x > 0), portx);
5301 ++porty;
5302 }
5303 break;
5304
5305 case KEY_DC: /* decrease-columns: move bottom edge up */
5306 if (portx <= top_x)
5307 beep();
5308 else {
5309 portx--;
5310 panner_v_cleanup(top_y - (top_y > 0), portx, porty);
5311 }
5312 break;
5313
5314 case KEY_DL: /* decrease-lines */
5315 if (porty <= top_y)
5316 beep();
5317 else {
5318 porty--;
5319 panner_h_cleanup(porty, top_x - (top_x > 0), portx);
5320 }
5321 break;
5322
5323 case KEY_LEFT: /* pan leftwards */
5324 if (basex > 0)
5325 basex--;
5326 else
5327 beep();
5328 break;
5329
5330 case KEY_RIGHT: /* pan rightwards */
5331 if (basex + portx - (pymax > porty) < pxmax)
5332 basex++;
5333 else
5334 beep();
5335 break;
5336
5337 case KEY_UP: /* pan upwards */
5338 if (basey > 0)
5339 basey--;
5340 else
5341 beep();
5342 break;
5343
5344 case KEY_DOWN: /* pan downwards */
5345 if (basey + porty - (pxmax > portx) < pymax)
5346 basey++;
5347 else
5348 beep();
5349 break;
5350
5351 case 'H':
5352 case KEY_HOME:
5353 case KEY_FIND:
5354 basey = 0;
5355 break;
5356
5357 case 'E':
5358 case KEY_END:
5359 case KEY_SELECT:
5360 basey = pymax - porty;
5361 if (basey < 0)
5362 basey = 0;
5363 break;
5364
5365 default:
5366 beep();
5367 break;
5368 }
5369
5370 MvAddCh(top_y - 1, top_x - 1, ACS_ULCORNER);
5371 do_v_line(top_y, top_x - 1, ACS_VLINE, porty);
5372 do_h_line(top_y - 1, top_x, ACS_HLINE, portx);
5373
5374 if (scrollers && (pxmax > portx - 1)) {
5375 int length = (portx - top_x - 1);
5376 float ratio = ((float) length) / ((float) pxmax);
5377
5378 lowend = (int) ((float) top_x + ((float) basex * ratio));
5379 highend = (int) ((float) top_x + ((float) (basex + length) * ratio));
5380
5381 do_h_line(porty - 1, top_x, ACS_HLINE, lowend);
5382 if (highend < portx) {
5383 attron(A_REVERSE);
5384 do_h_line(porty - 1, lowend, ' ', highend + 1);
5385 attroff(A_REVERSE);
5386 do_h_line(porty - 1, highend + 1, ACS_HLINE, portx);
5387 }
5388 } else
5389 do_h_line(porty - 1, top_x, ACS_HLINE, portx);
5390
5391 if (scrollers && (pymax > porty - 1)) {
5392 int length = (porty - top_y - 1);
5393 float ratio = ((float) length) / ((float) pymax);
5394
5395 lowend = (int) ((float) top_y + ((float) basey * ratio));
5396 highend = (int) ((float) top_y + ((float) (basey + length) * ratio));
5397
5398 do_v_line(top_y, portx - 1, ACS_VLINE, lowend);
5399 if (highend < porty) {
5400 attron(A_REVERSE);
5401 do_v_line(lowend, portx - 1, ' ', highend + 1);
5402 attroff(A_REVERSE);
5403 do_v_line(highend + 1, portx - 1, ACS_VLINE, porty);
5404 }
5405 } else
5406 do_v_line(top_y, portx - 1, ACS_VLINE, porty);
5407
5408 MvAddCh(top_y - 1, portx - 1, ACS_URCORNER);
5409 MvAddCh(porty - 1, top_x - 1, ACS_LLCORNER);
5410 MvAddCh(porty - 1, portx - 1, ACS_LRCORNER);
5411
5412 if (!pending_pan) {
5413#if HAVE_GETTIMEOFDAY
5414 gettimeofday(&before, 0);
5415#endif
5416 wnoutrefresh(stdscr);
5417
5418 pnoutrefresh(pad,
5419 basey, basex,
5420 top_y, top_x,
5421 porty - (pxmax > portx) - 1,
5422 portx - (pymax > porty) - 1);
5423
5424 doupdate();
5425#if HAVE_GETTIMEOFDAY
5426#define TIMEVAL2S(data) ((double) data.tv_sec + ((double) data.tv_usec / 1.0e6))
5427 if (timing) {
5428 double elapsed;
5429 gettimeofday(&after, 0);
5430 elapsed = (TIMEVAL2S(after) - TIMEVAL2S(before));
5431 move(LINES - 1, COLS - 12);
5432 printw("Secs: %2.03f", elapsed);
5433 refresh();
5434 }
5435#endif
5436 }
5437
5438 } while
5439 ((c = pgetc(pad)) != KEY_EXIT);
5440
5441 scrollok(stdscr, TRUE); /* reset to driver's default */
5442}
5443
5444static int
5445padgetch(WINDOW *win)
5446{
5447 static int count;
5448 static int last;
5449 int c;
5450
5451 if ((pending_pan = (count > 0)) != FALSE) {
5452 count--;
5453 pending_pan = (count != 0);
5454 } else {
5455 for (;;) {
5456 switch (c = wGetchar(win)) {
5457 case '!':
5458 ShellOut(FALSE);
5459 /* FALLTHRU */
5460 case CTRL('r'):
5461 endwin();
5462 refresh();
5463 c = KEY_REFRESH;
5464 break;
5465 case CTRL('l'):
5466 c = KEY_REFRESH;
5467 break;
5468 case 'U':
5469 c = KEY_UP;
5470 break;
5471 case 'D':
5472 c = KEY_DOWN;
5473 break;
5474 case 'R':
5475 c = KEY_RIGHT;
5476 break;
5477 case 'L':
5478 c = KEY_LEFT;
5479 break;
5480 case '+':
5481 c = KEY_IL;
5482 break;
5483 case '-':
5484 c = KEY_DL;
5485 break;
5486 case '>':
5487 c = KEY_IC;
5488 break;
5489 case '<':
5490 c = KEY_DC;
5491 break;
5492 case ERR: /* FALLTHRU */
5493 case case_QUIT:
5494 count = 0;
5495 c = KEY_EXIT;
5496 break;
5497 default:
5498 if (c >= '0' && c <= '9') {
5499 count = count * 10 + (c - '0');
5500 continue;
5501 }
5502 break;
5503 }
5504 last = c;
5505 break;
5506 }
5507 if (count > 0)
5508 count--;
5509 }
5510 return (last);
5511}
5512
5513#define PAD_HIGH 200
5514#define PAD_WIDE 200
5515
5516static void
5517demo_pad(bool colored)
5518/* Demonstrate pads. */
5519{
5520 WINDOW *panpad = newpad(PAD_HIGH, PAD_WIDE);
5521
5522 if (panpad == 0) {
5523 Cannot("cannot create requested pad");
5524 return;
5525 }
5526
5527#ifdef A_COLOR
5528 if (colored && use_colors) {
5529 init_pair(1, COLOR_BLACK, COLOR_GREEN);
5530 init_pair(2, COLOR_CYAN, COLOR_BLUE);
5531 wbkgd(panpad, (chtype) (COLOR_PAIR(2) | ' '));
5532 }
5533#endif
5534 fill_pad(panpad, FALSE, colored);
5535
5536 panner_legend(LINES - 4);
5537 panner_legend(LINES - 3);
5538 panner_legend(LINES - 2);
5539 panner_legend(LINES - 1);
5540
5541 keypad(panpad, TRUE);
5542
5543 /* Make the pad (initially) narrow enough that a trace file won't wrap.
5544 * We'll still be able to widen it during a test, since that's required
5545 * for testing boundaries.
5546 */
5547 panner(panpad, 2, 2, LINES - 5, COLS - 15, padgetch, colored);
5548
5549 delwin(panpad);
5550 endwin();
5551 erase();
5552}
5553
5554/****************************************************************************
5555 *
5556 * Tests from John Burnell's PDCurses tester
5557 *
5558 ****************************************************************************/
5559
5560static void
5561Continue(WINDOW *win)
5562{
5563 noecho();
5564 wmove(win, 10, 1);
5565 MvWAddStr(win, 10, 1, " Press any key to continue");
5566 wrefresh(win);
5567 wGetchar(win);
5568}
5569
5570static void
5571flushinp_test(WINDOW *win)
5572/* Input test, adapted from John Burnell's PDCurses tester */
5573{
5574 int w, h, bx, by, sw, sh, i;
5575
5576 WINDOW *subWin;
5577 wclear(win);
5578
5579 getmaxyx(win, h, w);
5580 getbegyx(win, by, bx);
5581 sw = w / 3;
5582 sh = h / 3;
5583 if ((subWin = subwin(win, sh, sw, by + h - sh - 2, bx + w - sw - 2)) == 0)
5584 return;
5585
5586#ifdef A_COLOR
5587 if (use_colors) {
5588 init_pair(2, COLOR_CYAN, COLOR_BLUE);
5589 wbkgd(subWin, (chtype) (COLOR_PAIR(2) | ' '));
5590 }
5591#endif
5592 (void) wattrset(subWin, A_BOLD);
5593 box(subWin, ACS_VLINE, ACS_HLINE);
5594 MvWAddStr(subWin, 2, 1, "This is a subwindow");
5595 wrefresh(win);
5596
5597 /*
5598 * This used to set 'nocbreak()'. However, Alexander Lukyanov says that
5599 * it only happened to "work" on SVr4 because that implementation does not
5600 * emulate nocbreak+noecho mode, whereas ncurses does. To get the desired
5601 * test behavior, we're using 'cbreak()', which will allow a single
5602 * character to return without needing a newline. - T.Dickey 1997/10/11.
5603 */
5604 cbreak();
5605 MvWAddStr(win, 0, 1, "This is a test of the flushinp() call.");
5606
5607 MvWAddStr(win, 2, 1, "Type random keys for 5 seconds.");
5608 MvWAddStr(win, 3, 1,
5609 "These should be discarded (not echoed) after the subwindow goes away.");
5610 wrefresh(win);
5611
5612 for (i = 0; i < 5; i++) {
5613 MvWPrintw(subWin, 1, 1, "Time = %d", i);
5614 wrefresh(subWin);
5615 napms(1000);
5616 flushinp();
5617 }
5618
5619 delwin(subWin);
5620 werase(win);
5621 flash();
5622 wrefresh(win);
5623 napms(1000);
5624
5625 MvWAddStr(win, 2, 1,
5626 "If you were still typing when the window timer expired,");
5627 MvWAddStr(win, 3, 1,
5628 "or else you typed nothing at all while it was running,");
5629 MvWAddStr(win, 4, 1,
5630 "test was invalid. You'll see garbage or nothing at all. ");
5631 MvWAddStr(win, 6, 1, "Press a key");
5632 wmove(win, 9, 10);
5633 wrefresh(win);
5634 echo();
5635 wGetchar(win);
5636 flushinp();
5637 MvWAddStr(win, 12, 0,
5638 "If you see any key other than what you typed, flushinp() is broken.");
5639 Continue(win);
5640
5641 wmove(win, 9, 10);
5642 wdelch(win);
5643 wrefresh(win);
5644 wmove(win, 12, 0);
5645 clrtoeol();
5646 waddstr(win,
5647 "What you typed should now have been deleted; if not, wdelch() failed.");
5648 Continue(win);
5649
5650 cbreak();
5651}
5652
5653/****************************************************************************
5654 *
5655 * Menu test
5656 *
5657 ****************************************************************************/
5658
5659#if USE_LIBMENU
5660
5661#define MENU_Y 8
5662#define MENU_X 8
5663
5664static int
5665menu_virtualize(int c)
5666{
5667 if (c == '\n' || c == KEY_EXIT)
5668 return (MAX_COMMAND + 1);
5669 else if (c == 'u')
5670 return (REQ_SCR_ULINE);
5671 else if (c == 'd')
5672 return (REQ_SCR_DLINE);
5673 else if (c == 'b' || c == KEY_NPAGE)
5674 return (REQ_SCR_UPAGE);
5675 else if (c == 'f' || c == KEY_PPAGE)
5676 return (REQ_SCR_DPAGE);
5677 else if (c == 'n' || c == KEY_DOWN)
5678 return (REQ_NEXT_ITEM);
5679 else if (c == 'p' || c == KEY_UP)
5680 return (REQ_PREV_ITEM);
5681 else if (c == ' ')
5682 return (REQ_TOGGLE_ITEM);
5683 else {
5684 if (c != KEY_MOUSE)
5685 beep();
5686 return (c);
5687 }
5688}
5689
5690static CONST_MENUS char *animals[] =
5691{
5692 "Lions",
5693 "Tigers",
5694 "Bears",
5695 "(Oh my!)",
5696 "Newts",
5697 "Platypi",
5698 "Lemurs",
5699 "(Oh really?!)",
5700 "Leopards",
5701 "Panthers",
5702 "Pumas",
5703 "Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs",
5704 "Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs, Lions, Tigers, Bears, (Oh my!), Newts, Platypi, Lemurs",
5705 (char *) 0
5706};
5707
5708static void
5709menu_test(void)
5710{
5711 MENU *m;
5712 ITEM *items[SIZEOF(animals)];
5713 ITEM **ip = items;
5714 CONST_MENUS char **ap;
5715 int mrows, mcols, c;
5716 WINDOW *menuwin;
5717
5718#ifdef NCURSES_MOUSE_VERSION
5719 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
5720#endif
5721 MvAddStr(0, 0, "This is the menu test:");
5722 MvAddStr(2, 0, " Use up and down arrow to move the select bar.");
5723 MvAddStr(3, 0, " 'n' and 'p' act like arrows.");
5724 MvAddStr(4, 0,
5725 " 'b' and 'f' scroll up/down (page), 'u' and 'd' (line).");
5726 MvAddStr(5, 0, " Press return to exit.");
5727 refresh();
5728
5729 for (ap = animals; *ap; ap++) {
5730 if ((*ip = new_item(*ap, "")) != 0)
5731 ++ip;
5732 }
5733 *ip = (ITEM *) 0;
5734
5735 m = new_menu(items);
5736
5737 set_menu_format(m, (SIZEOF(animals) + 1) / 2, 1);
5738 scale_menu(m, &mrows, &mcols);
5739
5740 menuwin = newwin(mrows + 2, mcols + 2, MENU_Y, MENU_X);
5741 set_menu_win(m, menuwin);
5742 keypad(menuwin, TRUE);
5743 box(menuwin, 0, 0);
5744
5745 set_menu_sub(m, derwin(menuwin, mrows, mcols, 1, 1));
5746
5747 post_menu(m);
5748
5749 while ((c = menu_driver(m, menu_virtualize(wGetchar(menuwin)))) != E_UNKNOWN_COMMAND) {
5750 if (c == E_NOT_POSTED)
5751 break;
5752 if (c == E_REQUEST_DENIED)
5753 beep();
5754 continue;
5755 }
5756
5757 MvPrintw(LINES - 2, 0,
5758 "You chose: %s\n", item_name(current_item(m)));
5759 (void) addstr("Press any key to continue...");
5760 wGetchar(stdscr);
5761
5762 unpost_menu(m);
5763 delwin(menuwin);
5764
5765 free_menu(m);
5766 for (ip = items; *ip; ip++)
5767 free_item(*ip);
5768#ifdef NCURSES_MOUSE_VERSION
5769 mousemask(0, (mmask_t *) 0);
5770#endif
5771}
5772
5773#ifdef TRACE
5774#define T_TBL(name) { #name, name }
5775static struct {
5776 const char *name;
5777 unsigned mask;
5778} t_tbl[] = {
5779
5780 T_TBL(TRACE_DISABLE),
5781 T_TBL(TRACE_TIMES),
5782 T_TBL(TRACE_TPUTS),
5783 T_TBL(TRACE_UPDATE),
5784 T_TBL(TRACE_MOVE),
5785 T_TBL(TRACE_CHARPUT),
5786 T_TBL(TRACE_ORDINARY),
5787 T_TBL(TRACE_CALLS),
5788 T_TBL(TRACE_VIRTPUT),
5789 T_TBL(TRACE_IEVENT),
5790 T_TBL(TRACE_BITS),
5791 T_TBL(TRACE_ICALLS),
5792 T_TBL(TRACE_CCALLS),
5793 T_TBL(TRACE_DATABASE),
5794 T_TBL(TRACE_ATTRS),
5795 T_TBL(TRACE_MAXIMUM),
5796 {
5797 (char *) 0, 0
5798 }
5799};
5800
5801static char *
5802tracetrace(unsigned tlevel)
5803{
5804 static char *buf;
5805 int n;
5806
5807 if (buf == 0) {
5808 size_t need = 12;
5809 for (n = 0; t_tbl[n].name != 0; n++)
5810 need += strlen(t_tbl[n].name) + 2;
5811 buf = typeMalloc(char, need);
5812 if (!buf)
5813 failed("tracetrace");
5814 }
5815 sprintf(buf, "0x%02x = {", tlevel);
5816 if (tlevel == 0) {
5817 sprintf(buf + strlen(buf), "%s, ", t_tbl[0].name);
5818 } else {
5819 for (n = 1; t_tbl[n].name != 0; n++)
5820 if ((tlevel & t_tbl[n].mask) == t_tbl[n].mask) {
5821 strcat(buf, t_tbl[n].name);
5822 strcat(buf, ", ");
5823 }
5824 }
5825 if (buf[strlen(buf) - 2] == ',')
5826 buf[strlen(buf) - 2] = '\0';
5827 return (strcat(buf, "}"));
5828}
5829
5830/* fake a dynamically reconfigurable menu using the 0th entry to deselect
5831 * the others
5832 */
5833static int
5834run_trace_menu(MENU * m)
5835{
5836 ITEM **items;
5837 ITEM *i, **p;
5838
5839 for (;;) {
5840 bool changed = FALSE;
5841 switch (menu_driver(m, menu_virtualize(wGetchar(menu_win(m))))) {
5842 case E_UNKNOWN_COMMAND:
5843 return FALSE;
5844 default:
5845 items = menu_items(m);
5846 i = current_item(m);
5847 if (i == items[0]) {
5848 if (item_value(i)) {
5849 for (p = items + 1; *p != 0; p++)
5850 if (item_value(*p)) {
5851 set_item_value(*p, FALSE);
5852 changed = TRUE;
5853 }
5854 }
5855 } else {
5856 for (p = items + 1; *p != 0; p++)
5857 if (item_value(*p)) {
5858 set_item_value(items[0], FALSE);
5859 changed = TRUE;
5860 break;
5861 }
5862 }
5863 if (!changed)
5864 return TRUE;
5865 }
5866 }
5867}
5868
5869static void
5870trace_set(void)
5871/* interactively set the trace level */
5872{
5873 MENU *m;
5874 ITEM *items[SIZEOF(t_tbl)];
5875 ITEM **ip = items;
5876 int mrows, mcols;
5877 unsigned newtrace;
5878 int n;
5879 WINDOW *menuwin;
5880
5881 MvAddStr(0, 0, "Interactively set trace level:");
5882 MvAddStr(2, 0, " Press space bar to toggle a selection.");
5883 MvAddStr(3, 0, " Use up and down arrow to move the select bar.");
5884 MvAddStr(4, 0, " Press return to set the trace level.");
5885 MvPrintw(6, 0, "(Current trace level is %s)", tracetrace(_nc_tracing));
5886
5887 refresh();
5888
5889 for (n = 0; t_tbl[n].name != 0; n++) {
5890 if ((*ip = new_item(t_tbl[n].name, "")) != 0) {
5891 ++ip;
5892 }
5893 }
5894 *ip = (ITEM *) 0;
5895
5896 m = new_menu(items);
5897
5898 set_menu_format(m, 0, 2);
5899 scale_menu(m, &mrows, &mcols);
5900
5901 menu_opts_off(m, O_ONEVALUE);
5902 menuwin = newwin(mrows + 2, mcols + 2, MENU_Y, MENU_X);
5903 set_menu_win(m, menuwin);
5904 keypad(menuwin, TRUE);
5905 box(menuwin, 0, 0);
5906
5907 set_menu_sub(m, derwin(menuwin, mrows, mcols, 1, 1));
5908
5909 post_menu(m);
5910
5911 for (ip = menu_items(m); *ip; ip++) {
5912 unsigned mask = t_tbl[item_index(*ip)].mask;
5913 if (mask == 0)
5914 set_item_value(*ip, _nc_tracing == 0);
5915 else if ((mask & _nc_tracing) == mask)
5916 set_item_value(*ip, TRUE);
5917 }
5918
5919 while (run_trace_menu(m))
5920 continue;
5921
5922 newtrace = 0;
5923 for (ip = menu_items(m); *ip; ip++)
5924 if (item_value(*ip))
5925 newtrace |= t_tbl[item_index(*ip)].mask;
5926 trace(newtrace);
5927 Trace(("trace level interactively set to %s", tracetrace(_nc_tracing)));
5928
5929 MvPrintw(LINES - 2, 0,
5930 "Trace level is %s\n", tracetrace(_nc_tracing));
5931 (void) addstr("Press any key to continue...");
5932 wGetchar(stdscr);
5933
5934 unpost_menu(m);
5935 delwin(menuwin);
5936
5937 free_menu(m);
5938 for (ip = items; *ip; ip++)
5939 free_item(*ip);
5940}
5941#endif /* TRACE */
5942#endif /* USE_LIBMENU */
5943
5944/****************************************************************************
5945 *
5946 * Forms test
5947 *
5948 ****************************************************************************/
5949#if USE_LIBFORM
5950static FIELD *
5951make_label(int frow, int fcol, NCURSES_CONST char *label)
5952{
5953 FIELD *f = new_field(1, (int) strlen(label), frow, fcol, 0, 0);
5954
5955 if (f) {
5956 set_field_buffer(f, 0, label);
5957 set_field_opts(f, (int) ((unsigned) field_opts(f) & ~O_ACTIVE));
5958 }
5959 return (f);
5960}
5961
5962static FIELD *
5963make_field(int frow, int fcol, int rows, int cols, bool secure)
5964{
5965 FIELD *f = new_field(rows, cols, frow, fcol, 0, secure ? 1 : 0);
5966
5967 if (f) {
5968 set_field_back(f, A_UNDERLINE);
5969 set_field_userptr(f, (void *) 0);
5970 }
5971 return (f);
5972}
5973
5974static void
5975display_form(FORM * f)
5976{
5977 WINDOW *w;
5978 int rows, cols;
5979
5980 scale_form(f, &rows, &cols);
5981
5982 if ((w = newwin(rows + 2, cols + 4, 0, 0)) != (WINDOW *) 0) {
5983 set_form_win(f, w);
5984 set_form_sub(f, derwin(w, rows, cols, 1, 2));
5985 box(w, 0, 0);
5986 keypad(w, TRUE);
5987 if (post_form(f) != E_OK)
5988 wrefresh(w);
5989 }
5990}
5991
5992static void
5993erase_form(FORM * f)
5994{
5995 WINDOW *w = form_win(f);
5996 WINDOW *s = form_sub(f);
5997
5998 unpost_form(f);
5999 werase(w);
6000 wrefresh(w);
6001 delwin(s);
6002 delwin(w);
6003}
6004
6005static int
6006edit_secure(FIELD * me, int c)
6007{
6008 int rows, cols, frow, fcol, nrow, nbuf;
6009
6010 if (field_info(me, &rows, &cols, &frow, &fcol, &nrow, &nbuf) == E_OK
6011 && nbuf > 0) {
6012 char *source = field_buffer(me, 1);
6013 size_t have = (source ? strlen(source) : 0) + 1;
6014 size_t need = 80 + have;
6015 char *temp = malloc(need);
6016 size_t len;
6017
6018 if (temp != 0) {
6019 strncpy(temp, source ? source : "", have + 1);
6020 len = (size_t) (char *) field_userptr(me);
6021 if (c <= KEY_MAX) {
6022 if (isgraph(c) && (len + 1) < sizeof(temp)) {
6023 temp[len++] = (char) c;
6024 temp[len] = 0;
6025 set_field_buffer(me, 1, temp);
6026 c = '*';
6027 } else {
6028 c = 0;
6029 }
6030 } else {
6031 switch (c) {
6032 case REQ_BEG_FIELD:
6033 case REQ_CLR_EOF:
6034 case REQ_CLR_EOL:
6035 case REQ_DEL_LINE:
6036 case REQ_DEL_WORD:
6037 case REQ_DOWN_CHAR:
6038 case REQ_END_FIELD:
6039 case REQ_INS_CHAR:
6040 case REQ_INS_LINE:
6041 case REQ_LEFT_CHAR:
6042 case REQ_NEW_LINE:
6043 case REQ_NEXT_WORD:
6044 case REQ_PREV_WORD:
6045 case REQ_RIGHT_CHAR:
6046 case REQ_UP_CHAR:
6047 c = 0; /* we don't want to do inline editing */
6048 break;
6049 case REQ_CLR_FIELD:
6050 if (len) {
6051 temp[0] = 0;
6052 set_field_buffer(me, 1, temp);
6053 }
6054 break;
6055 case REQ_DEL_CHAR:
6056 case REQ_DEL_PREV:
6057 if (len) {
6058 temp[--len] = 0;
6059 set_field_buffer(me, 1, temp);
6060 }
6061 break;
6062 }
6063 }
6064 set_field_userptr(me, (void *) len);
6065 free(temp);
6066 }
6067 }
6068 return c;
6069}
6070
6071static int
6072form_virtualize(FORM * f, WINDOW *w)
6073{
6074 /* *INDENT-OFF* */
6075 static const struct {
6076 int code;
6077 int result;
6078 } lookup[] = {
6079 { CTRL('A'), REQ_NEXT_CHOICE },
6080 { CTRL('B'), REQ_PREV_WORD },
6081 { CTRL('C'), REQ_CLR_EOL },
6082 { CTRL('D'), REQ_DOWN_FIELD },
6083 { CTRL('E'), REQ_END_FIELD },
6084 { CTRL('F'), REQ_NEXT_PAGE },
6085 { CTRL('G'), REQ_DEL_WORD },
6086 { CTRL('H'), REQ_DEL_PREV },
6087 { CTRL('I'), REQ_INS_CHAR },
6088 { CTRL('K'), REQ_CLR_EOF },
6089 { CTRL('L'), REQ_LEFT_FIELD },
6090 { CTRL('M'), REQ_NEW_LINE },
6091 { CTRL('N'), REQ_NEXT_FIELD },
6092 { CTRL('O'), REQ_INS_LINE },
6093 { CTRL('P'), REQ_PREV_FIELD },
6094 { CTRL('R'), REQ_RIGHT_FIELD },
6095 { CTRL('S'), REQ_BEG_FIELD },
6096 { CTRL('U'), REQ_UP_FIELD },
6097 { CTRL('V'), REQ_DEL_CHAR },
6098 { CTRL('W'), REQ_NEXT_WORD },
6099 { CTRL('X'), REQ_CLR_FIELD },
6100 { CTRL('Y'), REQ_DEL_LINE },
6101 { CTRL('Z'), REQ_PREV_CHOICE },
6102 { ESCAPE, MAX_FORM_COMMAND + 1 },
6103 { KEY_BACKSPACE, REQ_DEL_PREV },
6104 { KEY_DOWN, REQ_DOWN_CHAR },
6105 { KEY_END, REQ_LAST_FIELD },
6106 { KEY_HOME, REQ_FIRST_FIELD },
6107 { KEY_LEFT, REQ_LEFT_CHAR },
6108 { KEY_LL, REQ_LAST_FIELD },
6109 { KEY_NEXT, REQ_NEXT_FIELD },
6110 { KEY_NPAGE, REQ_NEXT_PAGE },
6111 { KEY_PPAGE, REQ_PREV_PAGE },
6112 { KEY_PREVIOUS, REQ_PREV_FIELD },
6113 { KEY_RIGHT, REQ_RIGHT_CHAR },
6114 { KEY_UP, REQ_UP_CHAR },
6115 { QUIT, MAX_FORM_COMMAND + 1 }
6116 };
6117 /* *INDENT-ON* */
6118
6119 static int mode = REQ_INS_MODE;
6120 int c = wGetchar(w);
6121 unsigned n;
6122 FIELD *me = current_field(f);
6123 bool current = TRUE;
6124
6125 if (c == CTRL(']')) {
6126 if (mode == REQ_INS_MODE) {
6127 mode = REQ_OVL_MODE;
6128 } else {
6129 mode = REQ_INS_MODE;
6130 }
6131 c = mode;
6132 } else {
6133 for (n = 0; n < SIZEOF(lookup); n++) {
6134 if (lookup[n].code == c) {
6135 c = lookup[n].result;
6136 break;
6137 }
6138 }
6139 }
6140 MvPrintw(0, COLS - 6, "(%s)", mode == REQ_INS_MODE ? "INS" : "OVL");
6141
6142 /*
6143 * Force the field that the user is typing into to be in reverse video,
6144 * while the other fields are shown underlined.
6145 */
6146 switch (c) {
6147 case REQ_BEG_FIELD:
6148 case REQ_CLR_EOF:
6149 case REQ_CLR_EOL:
6150 case REQ_CLR_FIELD:
6151 case REQ_DEL_CHAR:
6152 case REQ_DEL_LINE:
6153 case REQ_DEL_PREV:
6154 case REQ_DEL_WORD:
6155 case REQ_END_FIELD:
6156 case REQ_INS_CHAR:
6157 case REQ_INS_LINE:
6158 case REQ_LEFT_CHAR:
6159 case REQ_LEFT_FIELD:
6160 case REQ_NEXT_WORD:
6161 case REQ_RIGHT_CHAR:
6162 current = TRUE;
6163 break;
6164 default:
6165 current = (c < KEY_MAX);
6166 break;
6167 }
6168 if (current) {
6169 c = edit_secure(me, c);
6170 set_field_back(me, A_REVERSE);
6171 } else {
6172 c = edit_secure(me, c);
6173 set_field_back(me, A_UNDERLINE);
6174 }
6175 return c;
6176}
6177
6178static int
6179my_form_driver(FORM * form, int c)
6180{
6181 if (c == (MAX_FORM_COMMAND + 1)
6182 && form_driver(form, REQ_VALIDATION) == E_OK)
6183 return (TRUE);
6184 else {
6185 beep();
6186 return (FALSE);
6187 }
6188}
6189
6190#ifdef NCURSES_VERSION
6191#define FIELDCHECK_CB(func) bool func(FIELD * fld, const void * data GCC_UNUSED)
6192#define CHAR_CHECK_CB(func) bool func(int ch, const void *data GCC_UNUSED)
6193#else
6194#define FIELDCHECK_CB(func) int func(FIELD * fld, char * data GCC_UNUSED)
6195#define CHAR_CHECK_CB(func) int func(int ch, char *data GCC_UNUSED)
6196#endif
6197
6198/*
6199 * Allow a middle initial, optionally with a '.' to end it.
6200 */
6201static
6202FIELDCHECK_CB(mi_field_check)
6203{
6204 char *s = field_buffer(fld, 0);
6205 int state = 0;
6206 int n;
6207
6208 for (n = 0; s[n] != '\0'; ++n) {
6209 switch (state) {
6210 case 0:
6211 if (s[n] == '.') {
6212 if (n != 1)
6213 return FALSE;
6214 state = 2;
6215 } else if (isspace(UChar(s[n]))) {
6216 state = 2;
6217 }
6218 break;
6219 case 2:
6220 if (!isspace(UChar(s[n])))
6221 return FALSE;
6222 break;
6223 }
6224 }
6225
6226 /* force the form to display a leading capital */
6227 if (islower(UChar(s[0]))) {
6228 s[0] = (char) toupper(UChar(s[0]));
6229 set_field_buffer(fld, 0, s);
6230 }
6231 return TRUE;
6232}
6233
6234static
6235CHAR_CHECK_CB(mi_char_check)
6236{
6237 return ((isalpha(ch) || ch == '.') ? TRUE : FALSE);
6238}
6239
6240/*
6241 * Passwords should be at least 6 characters.
6242 */
6243static
6244FIELDCHECK_CB(pw_field_check)
6245{
6246 char *s = field_buffer(fld, 0);
6247 int n;
6248
6249 for (n = 0; s[n] != '\0'; ++n) {
6250 if (isspace(UChar(s[n]))) {
6251 if (n < 6)
6252 return FALSE;
6253 }
6254 }
6255 return TRUE;
6256}
6257
6258static
6259CHAR_CHECK_CB(pw_char_check)
6260{
6261 return (isgraph(ch) ? TRUE : FALSE);
6262}
6263
6264static void
6265demo_forms(void)
6266{
6267 WINDOW *w;
6268 FORM *form;
6269 FIELD *f[12], *secure;
6270 FIELDTYPE *fty_middle = new_fieldtype(mi_field_check, mi_char_check);
6271 FIELDTYPE *fty_passwd = new_fieldtype(pw_field_check, pw_char_check);
6272 int finished = 0, c;
6273 unsigned n = 0;
6274
6275#ifdef NCURSES_MOUSE_VERSION
6276 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
6277#endif
6278
6279 move(18, 0);
6280 addstr("Defined edit/traversal keys: ^Q/ESC- exit form\n");
6281 addstr("^N -- go to next field ^P -- go to previous field\n");
6282 addstr("Home -- go to first field End -- go to last field\n");
6283 addstr("^L -- go to field to left ^R -- go to field to right\n");
6284 addstr("^U -- move upward to field ^D -- move downward to field\n");
6285 addstr("^W -- go to next word ^B -- go to previous word\n");
6286 addstr("^S -- go to start of field ^E -- go to end of field\n");
6287 addstr("^H -- delete previous char ^Y -- delete line\n");
6288 addstr("^G -- delete current word ^C -- clear to end of line\n");
6289 addstr("^K -- clear to end of field ^X -- clear field\n");
6290 addstr("Arrow keys move within a field as you would expect. ^] toggles overlay mode.");
6291
6292 MvAddStr(4, 57, "Forms Entry Test");
6293
6294 refresh();
6295
6296 /* describe the form */
6297 memset(f, 0, sizeof(f));
6298 f[n++] = make_label(0, 15, "Sample Form");
6299
6300 f[n++] = make_label(2, 0, "Last Name");
6301 f[n++] = make_field(3, 0, 1, 18, FALSE);
6302 set_field_type(f[n - 1], TYPE_ALPHA, 1);
6303
6304 f[n++] = make_label(2, 20, "First Name");
6305 f[n++] = make_field(3, 20, 1, 12, FALSE);
6306 set_field_type(f[n - 1], TYPE_ALPHA, 1);
6307
6308 f[n++] = make_label(2, 34, "Middle Name");
6309 f[n++] = make_field(3, 34, 1, 12, FALSE);
6310 set_field_type(f[n - 1], fty_middle);
6311
6312 f[n++] = make_label(5, 0, "Comments");
6313 f[n++] = make_field(6, 0, 4, 46, FALSE);
6314
6315 f[n++] = make_label(5, 20, "Password:");
6316 secure =
6317 f[n++] = make_field(5, 30, 1, 9, TRUE);
6318 set_field_type(f[n - 1], fty_passwd);
6319 f[n] = (FIELD *) 0;
6320
6321 if ((form = new_form(f)) != 0) {
6322
6323 display_form(form);
6324
6325 w = form_win(form);
6326 raw();
6327 nonl(); /* lets us read ^M's */
6328 while (!finished) {
6329 switch (form_driver(form, c = form_virtualize(form, w))) {
6330 case E_OK:
6331 MvAddStr(5, 57, field_buffer(secure, 1));
6332 clrtoeol();
6333 refresh();
6334 break;
6335 case E_UNKNOWN_COMMAND:
6336 finished = my_form_driver(form, c);
6337 break;
6338 default:
6339 beep();
6340 break;
6341 }
6342 }
6343
6344 erase_form(form);
6345
6346 free_form(form);
6347 }
6348 for (c = 0; f[c] != 0; c++)
6349 free_field(f[c]);
6350 free_fieldtype(fty_middle);
6351 free_fieldtype(fty_passwd);
6352 noraw();
6353 nl();
6354
6355#ifdef NCURSES_MOUSE_VERSION
6356 mousemask(ALL_MOUSE_EVENTS, (mmask_t *) 0);
6357#endif
6358}
6359#endif /* USE_LIBFORM */
6360
6361/****************************************************************************
6362 *
6363 * Overlap test
6364 *
6365 ****************************************************************************/
6366
6367static void
6368fillwin(WINDOW *win, char ch)
6369{
6370 int y, x;
6371 int y1, x1;
6372
6373 getmaxyx(win, y1, x1);
6374 for (y = 0; y < y1; y++) {
6375 wmove(win, y, 0);
6376 for (x = 0; x < x1; x++)
6377 waddch(win, UChar(ch));
6378 }
6379}
6380
6381static void
6382crosswin(WINDOW *win, char ch)
6383{
6384 int y, x;
6385 int y1, x1;
6386
6387 getmaxyx(win, y1, x1);
6388 for (y = 0; y < y1; y++) {
6389 for (x = 0; x < x1; x++)
6390 if (((x > (x1 - 1) / 3) && (x <= (2 * (x1 - 1)) / 3))
6391 || (((y > (y1 - 1) / 3) && (y <= (2 * (y1 - 1)) / 3)))) {
6392 wmove(win, y, x);
6393 waddch(win, UChar(ch));
6394 }
6395 }
6396}
6397
6398#define OVERLAP_FLAVORS 5
6399
6400static void
6401overlap_helpitem(int state, int item, char *message)
6402{
6403 int row = (item / 2);
6404 int col = ((item % 2) ? COLS / 2 : 0);
6405
6406 move(LINES - 6 + row, col);
6407 printw("%c%c = %s", state == row ? '>' : ' ', 'a' + item, message);
6408 clrtoeol();
6409}
6410
6411static void
6412overlap_test_1_attr(WINDOW *win, int flavor, int col)
6413{
6414 NCURSES_PAIRS_T cpair = (NCURSES_PAIRS_T) (1 + (flavor * 2) + col);
6415
6416 switch (flavor) {
6417 case 0:
6418 (void) wattrset(win, A_NORMAL);
6419 break;
6420 case 1:
6421 (void) wattrset(win, A_BOLD);
6422 break;
6423 case 2:
6424 init_pair(cpair, COLOR_BLUE, COLOR_WHITE);
6425 (void) wattrset(win, AttrArg(COLOR_PAIR(cpair), A_NORMAL));
6426 break;
6427 case 3:
6428 init_pair(cpair, COLOR_WHITE, COLOR_BLUE);
6429 (void) wattrset(win, AttrArg(COLOR_PAIR(cpair), A_BOLD));
6430 break;
6431 }
6432}
6433
6434static void
6435overlap_test_2_attr(WINDOW *win, int flavor, int col)
6436{
6437 NCURSES_PAIRS_T cpair = (NCURSES_PAIRS_T) (9 + (flavor * 2) + col);
6438
6439 switch (flavor) {
6440 case 0:
6441 /* no effect */
6442 break;
6443 case 1:
6444 /* no effect */
6445 break;
6446 case 2:
6447 init_pair(cpair, COLOR_RED, COLOR_GREEN);
6448 wbkgdset(win, colored_chtype(' ', A_BLINK, cpair));
6449 break;
6450 case 3:
6451 wbkgdset(win, ' ' | A_NORMAL);
6452 break;
6453 }
6454}
6455
6456static int
6457overlap_help(int state, int flavors[OVERLAP_FLAVORS])
6458{
6459 int row;
6460 int col;
6461 int item;
6462 const char *ths, *tht;
6463 char msg[80];
6464
6465 if (state < 0)
6466 state += OVERLAP_FLAVORS;
6467 state = state % OVERLAP_FLAVORS;
6468 assert(state >= 0 && state < OVERLAP_FLAVORS);
6469
6470 for (item = 0; item < (2 * OVERLAP_FLAVORS); ++item) {
6471 row = item / 2;
6472 col = item % 2;
6473 ths = col ? "B" : "A";
6474 tht = col ? "A" : "B";
6475
6476 switch (row) {
6477 case 0:
6478 flavors[row] = 0;
6479 sprintf(msg, "refresh %s, then %s, then doupdate.", ths, tht);
6480 break;
6481 case 1:
6482 if (use_colors) {
6483 flavors[row] %= 4;
6484 } else {
6485 flavors[row] %= 2;
6486 }
6487 overlap_test_1_attr(stdscr, flavors[row], col);
6488 sprintf(msg, "fill window %s with letter %s.", ths, ths);
6489 break;
6490 case 2:
6491 if (use_colors) {
6492 flavors[row] %= 4;
6493 } else {
6494 flavors[row] %= 2;
6495 }
6496 switch (flavors[row]) {
6497 case 0:
6498 sprintf(msg, "cross pattern in window %s.", ths);
6499 break;
6500 case 1:
6501 sprintf(msg, "draw box in window %s.", ths);
6502 break;
6503 case 2:
6504 sprintf(msg, "set background of window %s.", ths);
6505 break;
6506 case 3:
6507 sprintf(msg, "reset background of window %s.", ths);
6508 break;
6509 }
6510 break;
6511 case 3:
6512 flavors[row] = 0;
6513 sprintf(msg, "clear window %s.", ths);
6514 break;
6515 case 4:
6516 flavors[row] %= 4;
6517 switch (flavors[row]) {
6518 case 0:
6519 sprintf(msg, "overwrite %s onto %s.", ths, tht);
6520 break;
6521 case 1:
6522 sprintf(msg, "copywin(FALSE) %s onto %s.", ths, tht);
6523 break;
6524 case 2:
6525 sprintf(msg, "copywin(TRUE) %s onto %s.", ths, tht);
6526 break;
6527 case 3:
6528 sprintf(msg, "overlay %s onto %s.", ths, tht);
6529 break;
6530 }
6531 break;
6532 }
6533 overlap_helpitem(state, item, msg);
6534 (void) wattrset(stdscr, A_NORMAL);
6535 wbkgdset(stdscr, ' ' | A_NORMAL);
6536 }
6537 move(LINES - 1, 0);
6538 printw("^Q/ESC = terminate test. Up/down/space select test variations (%d %d).",
6539 state, flavors[state]);
6540
6541 return state;
6542}
6543
6544static void
6545overlap_test_0(WINDOW *a, WINDOW *b)
6546{
6547 touchwin(a);
6548 touchwin(b);
6549 wnoutrefresh(a);
6550 wnoutrefresh(b);
6551 doupdate();
6552}
6553
6554static void
6555overlap_test_1(int flavor, int col, WINDOW *a, char fill)
6556{
6557 overlap_test_1_attr(a, flavor, col);
6558 fillwin(a, fill);
6559 (void) wattrset(a, A_NORMAL);
6560}
6561
6562static void
6563overlap_test_2(int flavor, int col, WINDOW *a, char fill)
6564{
6565 overlap_test_2_attr(a, flavor, col);
6566 switch (flavor) {
6567 case 0:
6568 crosswin(a, fill);
6569 break;
6570 case 1:
6571 box(a, 0, 0);
6572 break;
6573 case 2:
6574 /* done in overlap_test_2_attr */
6575 break;
6576 case 3:
6577 /* done in overlap_test_2_attr */
6578 break;
6579 }
6580}
6581
6582static void
6583overlap_test_3(WINDOW *a)
6584{
6585 wclear(a);
6586 wmove(a, 0, 0);
6587}
6588
6589static void
6590overlap_test_4(int flavor, WINDOW *a, WINDOW *b)
6591{
6592 switch (flavor) {
6593 case 0:
6594 overwrite(a, b);
6595 break;
6596 case 1:
6597 copywin(a, b, 0, 0, 0, 0, getmaxy(b), getmaxx(b), FALSE);
6598 break;
6599 case 2:
6600 copywin(a, b, 0, 0, 0, 0, getmaxy(b), getmaxx(b), TRUE);
6601 break;
6602 case 3:
6603 overlay(a, b);
6604 break;
6605 }
6606}
6607
6608/* test effects of overlapping windows */
6609static void
6610overlap_test(void)
6611{
6612 int ch;
6613 int state, flavor[OVERLAP_FLAVORS];
6614
6615 WINDOW *win1 = newwin(9, 20, 3, 3);
6616 WINDOW *win2 = newwin(9, 20, 9, 16);
6617
6618 curs_set(0);
6619 raw();
6620 refresh();
6621 move(0, 0);
6622 printw("This test shows the behavior of wnoutrefresh() with respect to\n");
6623 printw("the shared region of two overlapping windows A and B. The cross\n");
6624 printw("pattern in each window does not overlap the other.\n");
6625
6626 memset(flavor, 0, sizeof(flavor));
6627 state = overlap_help(0, flavor);
6628
6629 while (!isQuit(ch = Getchar()))
6630 switch (ch) {
6631 case 'a': /* refresh window A first, then B */
6632 overlap_test_0(win1, win2);
6633 break;
6634
6635 case 'b': /* refresh window B first, then A */
6636 overlap_test_0(win2, win1);
6637 break;
6638
6639 case 'c': /* fill window A so it's visible */
6640 overlap_test_1(flavor[1], 0, win1, 'A');
6641 break;
6642
6643 case 'd': /* fill window B so it's visible */
6644 overlap_test_1(flavor[1], 1, win2, 'B');
6645 break;
6646
6647 case 'e': /* cross test pattern in window A */
6648 overlap_test_2(flavor[2], 0, win1, 'A');
6649 break;
6650
6651 case 'f': /* cross test pattern in window A */
6652 overlap_test_2(flavor[2], 1, win2, 'B');
6653 break;
6654
6655 case 'g': /* clear window A */
6656 overlap_test_3(win1);
6657 break;
6658
6659 case 'h': /* clear window B */
6660 overlap_test_3(win2);
6661 break;
6662
6663 case 'i': /* overwrite A onto B */
6664 overlap_test_4(flavor[4], win1, win2);
6665 break;
6666
6667 case 'j': /* overwrite B onto A */
6668 overlap_test_4(flavor[4], win2, win1);
6669 break;
6670
6671 case CTRL('n'):
6672 case KEY_DOWN:
6673 state = overlap_help(state + 1, flavor);
6674 break;
6675
6676 case CTRL('p'):
6677 case KEY_UP:
6678 state = overlap_help(state - 1, flavor);
6679 break;
6680
6681 case ' ':
6682 flavor[state] += 1;
6683 state = overlap_help(state, flavor);
6684 break;
6685
6686 case '?':
6687 state = overlap_help(state, flavor);
6688 break;
6689
6690 default:
6691 beep();
6692 break;
6693 }
6694
6695 delwin(win2);
6696 delwin(win1);
6697 erase();
6698 curs_set(1);
6699 endwin();
6700}
6701
6702/****************************************************************************
6703 *
6704 * Main sequence
6705 *
6706 ****************************************************************************/
6707
6708static bool
6709do_single_test(const char c)
6710/* perform a single specified test */
6711{
6712 switch (c) {
6713 case 'a':
6714 getch_test();
6715 break;
6716
6717#if USE_WIDEC_SUPPORT
6718 case 'A':
6719 get_wch_test();
6720 break;
6721#endif
6722
6723 case 'b':
6724 attr_test();
6725 break;
6726
6727#if USE_WIDEC_SUPPORT
6728 case 'B':
6729 wide_attr_test();
6730 break;
6731#endif
6732
6733 case 'c':
6734 if (!use_colors)
6735 Cannot("does not support color.");
6736 else
6737 color_test();
6738 break;
6739
6740#if USE_WIDEC_SUPPORT
6741 case 'C':
6742 if (!use_colors)
6743 Cannot("does not support color.");
6744 else
6745 wide_color_test();
6746 break;
6747#endif
6748
6749 case 'd':
6750 if (!use_colors)
6751 Cannot("does not support color.");
6752 else if (!can_change_color())
6753 Cannot("has hardwired color values.");
6754 else
6755 color_edit();
6756 break;
6757
6758#if USE_SOFTKEYS
6759 case 'e':
6760 slk_test();
6761 break;
6762
6763#if USE_WIDEC_SUPPORT
6764 case 'E':
6765 wide_slk_test();
6766 break;
6767#endif
6768#endif
6769
6770 case 'f':
6771 acs_display();
6772 break;
6773
6774#if USE_WIDEC_SUPPORT
6775 case 'F':
6776 wide_acs_display();
6777 break;
6778#endif
6779
6780#if USE_LIBPANEL
6781 case 'o':
6782 demo_panels(init_panel, fill_panel);
6783 break;
6784#endif
6785
6786#if USE_WIDEC_SUPPORT && USE_LIBPANEL
6787 case 'O':
6788 demo_panels(init_wide_panel, fill_wide_panel);
6789 break;
6790#endif
6791
6792 case 'g':
6793 acs_and_scroll();
6794 break;
6795
6796 case 'i':
6797 flushinp_test(stdscr);
6798 break;
6799
6800 case 'k':
6801 test_sgr_attributes();
6802 break;
6803
6804#if USE_LIBMENU
6805 case 'm':
6806 menu_test();
6807 break;
6808#endif
6809
6810 case 'p':
6811 demo_pad(FALSE);
6812 break;
6813
6814 case 'P':
6815 demo_pad(TRUE);
6816 break;
6817
6818#if USE_LIBFORM
6819 case 'r':
6820 demo_forms();
6821 break;
6822#endif
6823
6824 case 's':
6825 overlap_test();
6826 break;
6827
6828#if USE_LIBMENU && defined(TRACE)
6829 case 't':
6830 trace_set();
6831 break;
6832#endif
6833
6834 case '?':
6835 break;
6836
6837 default:
6838 return FALSE;
6839 }
6840
6841 return TRUE;
6842}
6843
6844static void
6845usage(void)
6846{
6847 static const char *const tbl[] =
6848 {
6849 "Usage: ncurses [options]"
6850 ,""
6851 ,"Options:"
6852#ifdef NCURSES_VERSION
6853 ," -a f,b set default-colors (assumed white-on-black)"
6854 ," -d use default-colors if terminal supports them"
6855#endif
6856#if HAVE_USE_ENV
6857 ," -E call use_env(FALSE) to ignore $LINES and $COLUMNS"
6858#endif
6859#if USE_SOFTKEYS
6860 ," -e fmt specify format for soft-keys test (e)"
6861#endif
6862#if HAVE_RIPOFFLINE
6863 ," -f rip-off footer line (can repeat)"
6864 ," -h rip-off header line (can repeat)"
6865#endif
6866 ," -m do not use colors"
6867 ," -p file rgb values to use in 'd' rather than ncurses's builtin"
6868#if USE_LIBPANEL
6869 ," -s msec specify nominal time for panel-demo (default: 1, to hold)"
6870#endif
6871#if defined(NCURSES_VERSION_PATCH) && (NCURSES_VERSION_PATCH >= 20120714) && !defined(__MINGW32__)
6872 ," -T call use_tioctl(TRUE) to allow SIGWINCH to override environment"
6873#endif
6874#ifdef TRACE
6875 ," -t mask specify default trace-level (may toggle with ^T)"
6876#endif
6877 };
6878 size_t n;
6879 for (n = 0; n < SIZEOF(tbl); n++)
6880 fprintf(stderr, "%s\n", tbl[n]);
6881 ExitProgram(EXIT_FAILURE);
6882}
6883
6884static void
6885set_terminal_modes(void)
6886{
6887 noraw();
6888 cbreak();
6889 noecho();
6890 scrollok(stdscr, TRUE);
6891 idlok(stdscr, TRUE);
6892 keypad(stdscr, TRUE);
6893}
6894
6895#ifdef SIGUSR1
6896static void
6897announce_sig(int sig)
6898{
6899 (void) fprintf(stderr, "Handled signal %d\r\n", sig);
6900}
6901#endif
6902
6903#if HAVE_RIPOFFLINE
6904static int
6905rip_footer(WINDOW *win, int cols)
6906{
6907 wbkgd(win, A_REVERSE);
6908 werase(win);
6909 wmove(win, 0, 0);
6910 wprintw(win, "footer: window %p, %d columns", (void *) win, cols);
6911 wnoutrefresh(win);
6912 return OK;
6913}
6914
6915static int
6916rip_header(WINDOW *win, int cols)
6917{
6918 wbkgd(win, A_REVERSE);
6919 werase(win);
6920 wmove(win, 0, 0);
6921 wprintw(win, "header: window %p, %d columns", (void *) win, cols);
6922 wnoutrefresh(win);
6923 return OK;
6924}
6925#endif /* HAVE_RIPOFFLINE */
6926
6927static void
6928main_menu(bool top)
6929{
6930 char command;
6931
6932 do {
6933 (void) puts("This is the ncurses main menu");
6934 (void) puts("a = keyboard and mouse input test");
6935#if USE_WIDEC_SUPPORT
6936 (void) puts("A = wide-character keyboard and mouse input test");
6937#endif
6938 (void) puts("b = character attribute test");
6939#if USE_WIDEC_SUPPORT
6940 (void) puts("B = wide-character attribute test");
6941#endif
6942 (void) puts("c = color test pattern");
6943#if USE_WIDEC_SUPPORT
6944 (void) puts("C = color test pattern using wide-character calls");
6945#endif
6946 if (top)
6947 (void) puts("d = edit RGB color values");
6948#if USE_SOFTKEYS
6949 (void) puts("e = exercise soft keys");
6950#if USE_WIDEC_SUPPORT
6951 (void) puts("E = exercise soft keys using wide-characters");
6952#endif
6953#endif
6954 (void) puts("f = display ACS characters");
6955#if USE_WIDEC_SUPPORT
6956 (void) puts("F = display Wide-ACS characters");
6957#endif
6958 (void) puts("g = display windows and scrolling");
6959 (void) puts("i = test of flushinp()");
6960 (void) puts("k = display character attributes");
6961#if USE_LIBMENU
6962 (void) puts("m = menu code test");
6963#endif
6964#if USE_LIBPANEL
6965 (void) puts("o = exercise panels library");
6966#if USE_WIDEC_SUPPORT
6967 (void) puts("O = exercise panels with wide-characters");
6968#endif
6969#endif
6970 (void) puts("p = exercise pad features");
6971 (void) puts("P = exercise pad features, using color");
6972 (void) puts("q = quit");
6973#if USE_LIBFORM
6974 (void) puts("r = exercise forms code");
6975#endif
6976 (void) puts("s = overlapping-refresh test");
6977#if USE_LIBMENU && defined(TRACE)
6978 (void) puts("t = set trace level");
6979#endif
6980 (void) puts("? = repeat this command summary");
6981
6982 (void) fputs("> ", stdout);
6983 (void) fflush(stdout); /* necessary under SVr4 curses */
6984
6985 /*
6986 * This used to be an 'fgets()' call (until 1996/10). However with
6987 * some runtime libraries, mixing stream I/O and 'read()' causes the
6988 * input stream to be flushed when switching between the two.
6989 */
6990 command = 0;
6991 for (;;) {
6992 char ch = '\0';
6993 if (read(fileno(stdin), &ch, (size_t) 1) <= 0) {
6994 if (command == 0)
6995 command = 'q';
6996 break;
6997 } else if (command == 0 && !isspace(UChar(ch))) {
6998 command = ch;
6999 } else if (ch == '\n' || ch == '\r') {
7000 if ((command == 'd') && !top) {
7001 (void) fputs("Do not nest test-d\n", stdout);
7002 command = 0;
7003 }
7004 if (command != 0)
7005 break;
7006 (void) fputs("> ", stdout);
7007 (void) fflush(stdout);
7008 }
7009 }
7010
7011 if (do_single_test(command)) {
7012 /*
7013 * This may be overkill; it's intended to reset everything back
7014 * to the initial terminal modes so that tests don't get in
7015 * each other's way.
7016 */
7017 flushinp();
7018 set_terminal_modes();
7019 reset_prog_mode();
7020 clear();
7021 refresh();
7022 endwin();
7023 if (command == '?') {
7024 (void) puts("This is the ncurses capability tester.");
7025 (void)
7026 puts("You may select a test from the main menu by typing the");
7027 (void)
7028 puts("key letter of the choice (the letter to left of the =)");
7029 (void)
7030 puts("at the > prompt. Type `q' to exit.");
7031 }
7032 continue;
7033 }
7034 } while
7035 (command != 'q');
7036}
7037
7038/*+-------------------------------------------------------------------------
7039 main(argc,argv)
7040--------------------------------------------------------------------------*/
7041
7042#define okCOLOR(n) ((n) >= 0 && (n) < max_colors)
7043#define okRGB(n) ((n) >= 0 && (n) <= 1000)
7044
7045int
7046main(int argc, char *argv[])
7047{
7048 int c;
7049 int my_e_param = 1;
7050#ifdef NCURSES_VERSION
7051 int default_fg = COLOR_WHITE;
7052 int default_bg = COLOR_BLACK;
7053 bool assumed_colors = FALSE;
7054 bool default_colors = FALSE;
7055#endif
7056 char *palette_file = 0;
7057 bool monochrome = FALSE;
7058
7059 setlocale(LC_ALL, "");
7060
7061 while ((c = getopt(argc, argv, "a:dEe:fhmp:s:Tt:")) != -1) {
7062 switch (c) {
7063#ifdef NCURSES_VERSION
7064 case 'a':
7065 assumed_colors = TRUE;
7066 switch (sscanf(optarg, "%d,%d", &default_fg, &default_bg)) {
7067 case 0:
7068 default_fg = COLOR_WHITE;
7069 /* FALLTHRU */
7070 case 1:
7071 default_bg = COLOR_BLACK;
7072 break;
7073 }
7074 break;
7075 case 'd':
7076 default_colors = TRUE;
7077 break;
7078#endif
7079#if HAVE_USE_ENV
7080 case 'E':
7081 use_env(FALSE);
7082 break;
7083#endif
7084 case 'e':
7085 my_e_param = atoi(optarg);
7086#ifdef NCURSES_VERSION
7087 if (my_e_param > 3) /* allow extended layouts */
7088 usage();
7089#else
7090 if (my_e_param > 1)
7091 usage();
7092#endif
7093 break;
7094#if HAVE_RIPOFFLINE
7095 case 'f':
7096 ripoffline(-1, rip_footer);
7097 break;
7098 case 'h':
7099 ripoffline(1, rip_header);
7100 break;
7101#endif /* HAVE_RIPOFFLINE */
7102 case 'm':
7103 monochrome = TRUE;
7104 break;
7105 case 'p':
7106 palette_file = optarg;
7107 break;
7108#if USE_LIBPANEL
7109 case 's':
7110 nap_msec = (int) atol(optarg);
7111 break;
7112#endif
7113#if defined(NCURSES_VERSION_PATCH) && (NCURSES_VERSION_PATCH >= 20120714) && !defined(__MINGW32__)
7114 case 'T':
7115 use_tioctl(TRUE);
7116 break;
7117#endif
7118#ifdef TRACE
7119 case 't':
7120 save_trace = (unsigned) strtol(optarg, 0, 0);
7121 break;
7122#endif
7123 default:
7124 usage();
7125 }
7126 }
7127
7128 /*
7129 * If there's no menus (unlikely for ncurses!), then we'll have to set
7130 * tracing on initially, just in case the user wants to test something that
7131 * doesn't involve wGetchar.
7132 */
7133#ifdef TRACE
7134 /* enable debugging */
7135#if !USE_LIBMENU
7136 trace(save_trace);
7137#else
7138 if (!isatty(fileno(stdin)))
7139 trace(save_trace);
7140#endif /* USE_LIBMENU */
7141#endif /* TRACE */
7142
7143#if USE_SOFTKEYS
7144 /* tell it we're going to play with soft keys */
7145 slk_init(my_e_param);
7146#endif
7147
7148#ifdef SIGUSR1
7149 /* set up null signal catcher so we can see what interrupts to getch do */
7150 signal(SIGUSR1, announce_sig);
7151#endif
7152
7153 /* we must initialize the curses data structure only once */
7154 initscr();
7155 bkgdset(BLANK);
7156
7157 /* tests, in general, will want these modes */
7158 use_colors = (bool) (monochrome ? FALSE : has_colors());
7159
7160 if (use_colors) {
7161 start_color();
7162#ifdef NCURSES_VERSION_PATCH
7163 max_colors = COLORS; /* was > 16 ? 16 : COLORS */
7164#if HAVE_USE_DEFAULT_COLORS
7165 if (default_colors) {
7166 use_default_colors();
7167 min_colors = -1;
7168 }
7169#if HAVE_ASSUME_DEFAULT_COLORS
7170 if (assumed_colors)
7171 assume_default_colors(default_fg, default_bg);
7172#endif
7173#endif
7174#else /* normal SVr4 curses */
7175 max_colors = COLORS; /* was > 8 ? 8 : COLORS */
7176#endif
7177 max_pairs = COLOR_PAIRS; /* was > 256 ? 256 : COLOR_PAIRS */
7178
7179 if (can_change_color()) {
7180 NCURSES_PAIRS_T cp;
7181 all_colors = typeMalloc(RGB_DATA, (unsigned) max_colors);
7182 if (!all_colors)
7183 failed("all_colors");
7184 for (cp = 0; cp < max_colors; ++cp) {
7185 color_content(cp,
7186 &all_colors[cp].red,
7187 &all_colors[cp].green,
7188 &all_colors[cp].blue);
7189 }
7190 if (palette_file != 0) {
7191 FILE *fp = fopen(palette_file, "r");
7192 if (fp != 0) {
7193 char buffer[BUFSIZ];
7194 int red, green, blue;
7195 int scale = 1000;
7196 while (fgets(buffer, sizeof(buffer), fp) != 0) {
7197 if (sscanf(buffer, "scale:%d", &c) == 1) {
7198 scale = c;
7199 } else if (sscanf(buffer, "%d:%d %d %d",
7200 &c,
7201 &red,
7202 &green,
7203 &blue) == 4
7204 && okCOLOR(c)
7205 && okRGB(red)
7206 && okRGB(green)
7207 && okRGB(blue)) {
7208#define Scaled(n) (NCURSES_COLOR_T) (((n) * 1000) / scale)
7209 all_colors[c].red = Scaled(red);
7210 all_colors[c].green = Scaled(green);
7211 all_colors[c].blue = Scaled(blue);
7212 }
7213 }
7214 fclose(fp);
7215 }
7216 }
7217 }
7218 }
7219 set_terminal_modes();
7220 def_prog_mode();
7221
7222 /*
7223 * Return to terminal mode, so we're guaranteed of being able to
7224 * select terminal commands even if the capabilities are wrong.
7225 */
7226 endwin();
7227
7228#if HAVE_CURSES_VERSION
7229 (void) printf("Welcome to %s. Press ? for help.\n", curses_version());
7230#elif defined(NCURSES_VERSION_MAJOR) && defined(NCURSES_VERSION_MINOR) && defined(NCURSES_VERSION_PATCH)
7231 (void) printf("Welcome to ncurses %d.%d.%d. Press ? for help.\n",
7232 NCURSES_VERSION_MAJOR,
7233 NCURSES_VERSION_MINOR,
7234 NCURSES_VERSION_PATCH);
7235#else
7236 (void) puts("Welcome to ncurses. Press ? for help.");
7237#endif
7238
7239 main_menu(TRUE);
7240
7241 ExitProgram(EXIT_SUCCESS);
7242}
7243
7244/* ncurses.c ends here */