Don't fail if the file flags of source and copied symlinks don't match.
[dragonfly.git] / contrib / ncurses-5.4 / tack / ansi.c
blob807bc539a6c89c3cdc04a4332d07b9769411b46a
1 /*
2 ** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
3 **
4 ** This file is part of TACK.
5 **
6 ** TACK is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License as published by
8 ** the Free Software Foundation; either version 2, or (at your option)
9 ** any later version.
10 **
11 ** TACK is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with TACK; see the file COPYING. If not, write to
18 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 ** Boston, MA 02111-1307, USA.
22 #include <tack.h>
24 MODULE_ID("$Id: ansi.c,v 1.9 2001/06/18 18:44:17 tom Exp $")
27 * Standalone tests for ANSI terminals. Three entry points:
28 * test_ansi_graphics(), test_ansi_reports() and test_ansi_sgr().
31 /*****************************************************************************
33 * Test ANSI status reports
35 *****************************************************************************/
37 /* ASCII control characters */
38 #define A_DC1 0x11 /* Control Q */
39 #define A_DC3 0x13 /* Control S */
40 #define A_ESC 0x1b
41 #define A_DCS 0x90
42 #define A_CSI 0x9b
43 #define A_ST 0x9c
45 #define MAX_MODES 256
47 static char default_bank[] = "\033(B\017";
48 static int private_use, ape, terminal_class;
49 static short ansi_value[256];
50 static unsigned char ansi_buf[512], pack_buf[512];
52 struct ansi_reports {
53 int lvl, final;
54 const char *text;
55 const char *request;
58 static struct ansi_reports report_list[] = {
59 {0, 'c', "(DA) Primary device attributes", "\033[0c"},
60 {1, 0, "(DSR) Terminal status", "\033[5n"},
61 {1, 'R', "(DSR) Cursor position", "\033[6n"},
62 {62, 0, "(DA) Secondary device attributes", "\033[>0c"},
63 {62, 0, "(DSR) Printer status", "\033[?15n"},
64 {62, 0, "(DSR) Function key definition", "\033[?25n"},
65 {62, 0, "(DSR) Keyboard language", "\033[?26n"},
66 {63, 0, "(DECRQSS) Data destination", "\033P$q$}\033\\"},
67 {63, 0, "(DECRQSS) Status line type", "\033P$q$~\033\\"},
68 {63, 0, "(DECRQSS) Erase attribute", "\033P$q\"q\033\\"},
69 {63, 0, "(DECRQSS) Personality", "\033P$q\"p\033\\"},
70 {63, 0, "(DECRQSS) Top and bottom margins", "\033P$qr\033\\"},
71 {63, 0, "(DECRQSS) Character attributes", "\033P$qm\033\\"},
72 {63, 0, "(DECRQSS) Illegal request", "\033P$q@\033\\"},
73 {63, 0, "(DECRQUPSS) User pref supplemental set", "\033[&u"},
74 {63, 0, "(DECRQPSR) Cursor information", "\033[1$w"},
75 {63, 0, "(DECRQPSR) Tab stop information", "\033[2$w"},
76 {64, 0, "(DA) Tertiary device attributes", "\033[=0c"},
77 {64, 0, "(DSR) Extended cursor position", "\033[?6n"},
78 {64, 0, "(DSR) Macro space", "\033[?62n"},
79 {64, 0, "(DSR) Memory checksum", "\033[?63n"},
80 {64, 0, "(DSR) Data integrity", "\033[?75n"},
81 {64, 0, "(DSR) Multiple session status", "\033[?85n"},
82 {64, 0, "(DECRQSS) Attribute change extent", "\033P$q*x\033\\"},
83 {64, 0, "(DECRQSS) Columns per page", "\033P$q$|\033\\"},
84 {64, 0, "(DECRQSS) Lines per page", "\033P$qt\033\\"},
85 {64, 0, "(DECRQSS) Lines per screen", "\033P$q*|\033\\"},
86 {64, 0, "(DECRQSS) Left and right margins", "\033P$qs\033\\"},
87 {64, 0, "(DECRQSS) Local functions", "\033P$q+q\033\\"},
88 {64, 0, "(DECRQSS) Local function key control", "\033P$q=}\033\\"},
89 {64, 0, "(DECRQSS) Select modifier key reporting", "\033P$q+r\033\\"},
90 {64, 0, "(DECRQDE) Window report", "\033[\"v"},
91 {0, 0, 0, 0}
94 struct request_control {
95 const char *text;
96 const char *expect;
97 const char *request;
98 const char *set_mode;
99 const char *reset_mode;
102 /* Request control function selection or setting */
103 static const struct request_control rqss[] = {
104 {"Data sent to screen", "0", "$}", "\033[0$}", 0},
105 {"Data sent to disabled status line", "0", "$}", 0, 0},
106 {"\033[0$~\033[1$}", "\033[0$}", 0, 0, 0},
107 {"Data sent to enabled status line", "1", "$}", 0, 0},
108 {"\033[2$~\033[1$}", "\033[0$}", 0, 0, 0},
109 {"Disable status line", "0", "$~", "\033[0$~", 0},
110 {"Top status line", "1", "$~", "\033[1$~", 0},
111 {"Bottom status line", "2", "$~", "\033[2$~", 0},
112 {"Erasable character", "0", "\"q", "\033[0\"q", 0},
113 {"Nonerasable character", "1", "\"q", "\033[1\"q", "\033[0\"q"},
114 {"Top and bottom margins", "3;10", "r", "\0337\033[3;10r", 0},
115 {"\033[r\0338", 0, 0, 0, 0},
116 {"Top and bottom margins", "default", "r", "\0337\033[r", "\0338"},
117 {"Character attributes, dim, bold", "1", "m", "\033[2;1m", "\033[m"},
118 {"Character attributes, bold, dim", "2", "m", "\033[1;2m", "\033[m"},
119 {"Character attributes, under, rev", "4;7", "m", "\033[4;7m", "\033[m"},
120 {"Character attributes, color", "35;42", "m", "\033[35;42m", "\033[m"},
121 {"All character attributes", "", "m", "\033[1;2;3;4;5;6;7;8;9m", 0},
122 {"\033[m", 0, 0, 0, 0},
123 {0, 0, 0, 0, 0}
128 ** read_ansi()
130 ** read an ANSI status report from terminal
132 static void
133 read_ansi(void)
135 int ch, i, j, last_escape;
137 fflush(stdout);
138 read_key((char *)ansi_buf, sizeof(ansi_buf));
139 /* Throw away control characters inside CSI sequences.
140 Convert two character 7-bit sequences into 8-bit sequences. */
141 for (i = j = last_escape = 0; (ch = ansi_buf[i]) != 0; i++) {
142 if (ch == A_ESC) {
143 if (last_escape == A_ESC) {
144 pack_buf[j++] = A_ESC;
146 last_escape = A_ESC;
147 } else
148 if (last_escape == A_ESC && ch >= '@' && ch <= '_') {
149 pack_buf[j++] = last_escape = ch + 0x40;
150 } else
151 if (last_escape != A_CSI || (ch > 0x20 && ch != 0x80)) {
152 if (last_escape == A_ESC) {
153 pack_buf[j++] = A_ESC;
155 if (ch > 0x80 && ch < 0xa0) {
156 last_escape = ch;
158 pack_buf[j++] = ch;
161 if (last_escape == A_ESC) {
162 pack_buf[j++] = A_ESC;
164 pack_buf[j] = '\0';
165 return;
169 ** valid_mode(expected)
171 ** read a terminal mode status report and parse the result
172 ** Return TRUE if we got the expected terminating character.
174 static int
175 valid_mode(int expected)
177 unsigned char *s;
178 int ch, terminator;
180 read_ansi();
182 ape = 0;
183 ch = UChar(pack_buf[0]);
184 ansi_value[0] = 0;
185 if (ch != A_CSI && ch != A_DCS)
186 return FALSE;
188 s = pack_buf + 1;
189 private_use = 0;
190 if ((*s >= '<') & (*s <= '?')) {
191 private_use = *s++;
193 terminator = 0;
194 for (; (ch = *s); s++) {
195 if (ch >= '0' && ch <= '9')
196 ansi_value[ape] = ansi_value[ape] * 10 + ch - '0';
197 else if (ch == ';' || ch == ':')
198 ansi_value[++ape] = 0;
199 else if (ch >= '<' && ch <= '?')
200 private_use = ch;
201 else if (ch >= ' ')
202 terminator = (terminator << 8) | ch;
203 else
204 break;
206 return terminator == expected;
210 ** read_reports()
212 ** read all the reports in the ANSI report structure
214 static int
215 read_reports(void)
217 int i, j, k, tc, vcr, lc;
218 char *s;
219 const char *t;
221 lc = 5;
222 terminal_class = tc = 0;
223 for (i = 0; report_list[i].text; i++, lc++) {
224 if (terminal_class < report_list[i].lvl &&
225 tc < report_list[i].lvl) {
226 put_crlf();
227 menu_prompt();
228 ptext("/status [q] > ");
229 j = wait_here();
230 if (j != 'n' && j != 'N')
231 return 0;
232 tc = report_list[i].lvl;
233 lc = 1;
234 } else if (lc + 2 >= lines) {
235 put_crlf();
236 ptext("Hit any key to continue ");
237 (void) wait_here();
238 lc = 1;
240 sprintf(temp, "%s (%s) ", report_list[i].text,
241 expand_command(report_list[i].request));
242 ptext(temp);
243 for (j = strlen(temp); j < 49; j++)
244 putchp(' ');
245 tc_putp(report_list[i].request);
246 vcr = 0;
247 if (report_list[i].final == 0) {
248 read_ansi();
249 } else if (valid_mode(report_list[i].final))
250 switch (report_list[i].final) {
251 case 'c':
252 terminal_class = ansi_value[0];
253 break;
254 case 'R':
255 vcr = TRUE;
256 break;
258 j = UChar(pack_buf[0]);
259 if (j != A_CSI && j != A_DCS) {
260 put_crlf();
261 t = "*** The above request gives illegal response ***";
262 ptext(t);
263 for (j = strlen(t); j < 49; j++)
264 putchp(' ');
266 s = expand((const char *)ansi_buf);
267 if (char_count + expand_chars >= columns) {
268 put_str("\r\n ");
269 lc++;
271 putln(s);
272 if (vcr) { /* find out how big the screen is */
273 tc_putp(report_list[i].request);
274 if (!valid_mode('R'))
275 continue;
276 j = ansi_value[0];
277 k = ansi_value[1];
278 tc_putp("\033[255B\033[255C\033[6n");
279 if (!valid_mode('R'))
280 continue;
281 sprintf(temp, "\033[%d;%dH", j, k);
282 tc_putp(temp);
283 ptext("(DSR) Screen size (CSI 6 n)");
284 for (j = char_count; j < 50; j++)
285 putchp(' ');
286 sprintf(temp, "%d x %d", ansi_value[1], ansi_value[0]);
287 ptextln(temp);
291 menu_prompt();
292 ptext("/status r->repeat test, <return> to continue > ");
293 return wait_here();
297 ** request_cfss()
299 ** Request Control function selection or settings
301 static int
302 request_cfss(void)
304 int i, j, k, l, ch;
305 char *s;
307 put_clear();
308 ptextln("Request Expected Received");
309 put_crlf();
310 for (i = 0; rqss[i].text; i++) {
311 ptext(rqss[i].text);
312 j = strlen(rqss[i].text) + strlen(rqss[i].expect);
313 putchp(' ');
314 for (j++; j < 40; j++)
315 putchp(' ');
316 ptext(rqss[i].expect);
317 putchp(' ');
318 tc_putp(rqss[i].set_mode);
319 sprintf(temp, "\033P$q%s\033\\", rqss[i].request);
320 tc_putp(temp);
321 read_ansi();
322 tc_putp(rqss[i].reset_mode);
323 putchp(' ');
324 for (j = 0; ansi_buf[j]; j++) {
325 if (ansi_buf[j] == 'r') {
326 for (k = j++; (ch = UChar(ansi_buf[k])) != 0; k++)
327 if (ch == A_ESC) {
328 break;
329 } else if (ch == A_ST) {
330 break;
332 ansi_buf[k] = '\0';
333 s = expand((const char *)&ansi_buf[j]);
334 if (char_count + expand_chars >= columns)
335 put_str("\r\n ");
336 put_str(s);
339 put_crlf();
341 /* calculate the valid attributes */
342 ptext("Valid attributes: 0");
343 j = 0;
344 for (i = 1; i < 20; i++) {
345 sprintf(temp, "\033[0;%dm\033P$qm\033\\", i);
346 tc_putp(temp);
347 (void) valid_mode('m');
348 if (ape > 0) {
349 j = i;
350 sprintf(temp, "\033[0m; %d", i);
351 tc_putp(temp);
354 put_crlf();
355 /* calculate how many parameters can be sent */
356 ptext("Max number of parameters: ");
357 sprintf(temp, "%dm\033P$qm\033\\", j);
358 l = -1;
359 if (j > 0)
360 for (l = 1; l < 33; l++) {
361 tc_putp("\033[0");
362 for (ch = 1; ch <= l; ch++)
363 put_this(';');
364 tc_putp(temp);
365 (void) valid_mode('m');
366 if (ape == 0)
367 break;
369 tc_putp("\033[m");
370 if (l >= 0) {
371 sprintf(temp, "%d", l);
372 ptext(temp);
373 } else
374 ptext("unknown");
375 put_crlf();
376 return wait_here();
380 ** mode_display(puc, mode, initial, set, reset)
382 ** print the mode display entry
384 static void
385 mode_display(const char *p, int n, int c, char s, char r)
387 int k;
389 sprintf(temp, "%s%d (%c, %c, %c)", p, n, c, s, r);
390 k = strlen(temp);
391 if (char_count + k >= columns)
392 put_crlf();
393 for (; k < 14; k++)
394 putchp(' ');
395 put_str(temp);
399 ** terminal_state()
401 ** test DECRQM status reports
403 static void
404 terminal_state(void)
406 static const char *puc[] = {"", "<", "=", ">", "?", 0};
408 int i, j, k, l, modes_found;
409 char *s;
410 char buf[256], tms[256];
411 int mode_puc[MAX_MODES], mode_number[MAX_MODES];
412 char set_value[MAX_MODES], reset_value[MAX_MODES];
413 char current_value[MAX_MODES];
415 ptext("Testing terminal mode status. (CSI 0 $ p)");
416 tc_putp("\033[0$p");
417 modes_found = 0;
418 tms[0] = '\0';
419 if (valid_mode(('$' << 8) | 'y')) {
420 for (i = 0; puc[i]; i++) {
421 put_crlf();
422 if (i) {
423 sprintf(temp, "Private use: %c", puc[i][0]);
424 } else {
425 strcpy(temp, "Standard modes:");
427 k = strlen(temp);
428 ptext(temp);
429 for (j = 0; j < (int) sizeof(buf); buf[j++] = ' ')
431 for (j = l = 0; j < 255 && j - l < 50; j++) {
432 sprintf(temp, "\033[%s%d$p", puc[i], j);
433 tc_putp(temp);
434 if (!valid_mode(('$' << 8) | 'y')) {
435 /* not valid, save terminating value */
436 s = expand((const char *)ansi_buf);
437 sprintf(tms, "%s%s%d %s ", tms,
438 puc[i], j, s);
439 break;
441 if (private_use != puc[i][0])
442 break;
443 if (ansi_value[0] != j)
444 break;
445 if (ansi_value[1]) {
446 l = j;
447 if (k > 70) {
448 buf[k] = '\0';
449 put_crlf();
450 ptextln(buf);
451 for (k = 0; k < (int) sizeof(buf);) {
452 buf[k++] = ' ';
454 k = 0;
456 sprintf(temp, " %d", j);
457 ptext(temp);
458 k += strlen(temp);
459 buf[k - 1] = ansi_value[1] + '0';
460 if (modes_found >= MAX_MODES)
461 continue;
462 current_value[modes_found] =
463 ansi_value[1] + '0';
464 /* some modes never return */
465 if ((i == 0 && j == 13) /* control execution */
466 || (puc[i][0] == '?' && j == 2)) /* VT52 */
467 set_value[modes_found] =
468 reset_value[modes_found] = '-';
469 else
470 set_value[modes_found] =
471 reset_value[modes_found] = ' ';
472 mode_puc[modes_found] = i;
473 mode_number[modes_found++] = j;
476 buf[k] = '\0';
477 if (buf[k - 1] != ' ') {
478 put_crlf();
479 ptext(buf);
483 if ((i = modes_found) != 0) {
484 put_crlf();
485 put_crlf();
486 if (tms[0]) {
487 ptextln(tms);
489 ptext("Hit 'Y' to test mode set/reset states: ");
490 i = wait_here();
492 if (i == 'y' || i == 'Y')
493 while (1) {
494 #ifdef STATUSFIX
495 FILE *fp;
497 #ifdef TEDANSI
498 fp = fopen("ted.ansi", "w");
499 #else
500 fp = fopen("/dev/console", "w");
501 #endif
502 #endif
503 for (i = j = 0; j < modes_found; j = ++i >> 1) {
504 if (set_value[j] == '-')
505 continue;
506 k = (current_value[j] ^ i) & 1;
507 sprintf(temp, "\033[%s%d%c\033[%s%d$p",
508 puc[mode_puc[j]], mode_number[j],
509 k ? 'l' : 'h',
510 puc[mode_puc[j]], mode_number[j]);
511 #ifdef STATUSFIX
512 if (fp) {
513 fprintf(fp, "%s\n", expand(temp));
514 fflush(fp);
516 #endif
517 tc_putp(temp);
518 if (!valid_mode(('$' << 8) | 'y'))
519 continue;
520 if (k) {
521 reset_value[j] = ansi_value[1] + '0';
522 } else {
523 set_value[j] = ansi_value[1] + '0';
526 put_str("\033[30l"); /* added for GORT bug
527 (WY-185) */
528 #ifdef STATUSFIX
529 if (fp)
530 fclose(fp);
531 #endif
532 tty_set();
533 /* print the results */
534 put_clear();
535 putln("mode (initial, set, reset)");
536 for (j = 0; j < modes_found; j++) {
537 mode_display(puc[mode_puc[j]], mode_number[j],
538 current_value[j], set_value[j], reset_value[j]);
540 ptext("\n\nHit 'R' to repeat test. 'S' to sort results: ");
541 i = wait_here();
542 if (i == 's' || i == 'S') { /* print the same stuff,
543 sorted by
544 current_value */
545 put_crlf();
546 for (i = '1'; i <= '4'; i++) {
547 for (j = 0; j < modes_found; j++) {
548 if (current_value[j] == i)
549 mode_display(puc[mode_puc[j]],
550 mode_number[j], current_value[j],
551 set_value[j], reset_value[j]);
554 ptext("\n\nHit 'R' to repeat test: ");
555 i = wait_here();
557 if (i != 'r' && i != 'R')
558 break;
559 tty_raw(1, char_mask);
561 } else {
562 tty_set();
568 ** ansi_report_help()
570 ** Display the informational data for the ANSI report test.
572 static void
573 ansi_report_help(void)
575 ptext("Begin ANSI status report testing. ");
576 ptext(" Parity bit set will be displayed in reverse video. ");
577 ptext(" If the terminal hangs, hit any alphabetic key. ");
578 ptextln(" Use n to continue testing. Use q to quit.");
579 put_crlf();
583 ** test_ansi_reports()
585 ** Test the ANSI status report functions
587 void
588 tools_status(
589 struct test_list *t GCC_UNUSED,
590 int *state GCC_UNUSED,
591 int *ch)
593 int i;
595 put_clear();
596 ansi_report_help();
597 tty_raw(1, char_mask);
599 do {
600 i = read_reports();
601 if (i != 'r' && i != 'R') {
602 *ch = i;
603 return;
605 } while (i);
607 if (terminal_class >= 63) {
608 do {
609 i = request_cfss();
610 } while (i == 'r' || i == 'R');
611 *ch = i;
612 terminal_state();
613 } else {
614 tty_set();
620 ** display_sgr()
622 ** Test a range of ANSI sgr attributes
623 ** puc -> Private Use Character
625 static void
626 display_sgr(int puc)
628 int k;
630 temp[0] = puc;
631 temp[1] = '\0';
632 for (k = 0; k < 80; k++) {
633 if (char_count + 8 > 80)
634 put_crlf();
635 else if (char_count + 8 > columns)
636 put_crlf();
637 else if (k > 0)
638 printf(" ");
639 printf("\033[%s%dmMode %2d\033[0m", temp, k, k);
640 char_count += 8;
641 if (puc == '\0') {
642 if (k == 19)
643 printf("\033[10m");
644 if (k == 39)
645 printf("\033[37m");
646 if (k == 49)
647 printf("\033[40m");
650 put_crlf();
651 if (puc == '<')
652 printf("\033[<1m");
653 else if (puc)
654 printf("\033[%s0m", temp);
655 set_attr(0);
659 ** print_sgr20(on, off)
661 ** print the sgr line for sgr20()
663 static void
664 print_sgr20(int on, int off)
666 if (char_count > columns - 13) {
667 put_crlf();
668 } else if (char_count) {
669 put_str(" ");
671 char_count += 11;
672 printf("%d/%d \033[%dmon\033[%dm off\033[0m", on, off, on, off);
676 ** sgr20(void)
678 ** display the enter/exit attributes 1-9 and 20-29
680 static void
681 sgr20(void)
683 int k;
685 put_crlf();
686 ptextln("Test enter/exit attributes 1-9 and 21-29.");
687 for (k = 1; k < 10; k++) {
688 print_sgr20(k, k + 20);
690 print_sgr20(1, 22); /* bold */
691 print_sgr20(2, 22); /* dim */
692 print_sgr20(8, 22); /* blank */
693 printf("\033[0m");
694 set_attr(0);
698 ** tools_sgr(testlist, state, ch)
700 ** Run the ANSI graphics rendition mode tool
701 ** Return the last character typed.
703 void
704 tools_sgr(
705 struct test_list *t GCC_UNUSED,
706 int *state GCC_UNUSED,
707 int *ch)
709 int k;
711 put_clear();
712 for (k = 0;;) {
713 display_sgr(k);
714 put_crlf();
715 menu_prompt();
716 ptext("/sgr Enter =><?r [<cr>] > ");
717 k = wait_here();
718 if ((k == 'r') || (k == 'R')) {
719 k = 0;
720 } else if ((k < '<') || (k > '?')) {
721 break;
724 sgr20();
726 put_newlines(2);
727 *ch = REQUEST_PROMPT;
730 /*****************************************************************************
732 * Test ANSI graphics
734 *****************************************************************************/
736 ** select_bank(bank)
738 ** select a graphics character set for ANSI terminals
740 static void
741 select_bank(char *bank)
743 tc_putp(bank);
744 switch (bank[1] & 3) {
745 case 0:
746 putchp('O' & 0x1f); /* control O */
747 break;
748 case 1:
749 putchp('N' & 0x1f); /* control N */
750 tc_putp("\033~");
751 break;
752 case 2:
753 tc_putp("\033n\033}");
754 break;
755 case 3:
756 tc_putp("\033o\033|");
757 break;
762 ** show_characters(bank, bias)
764 ** print the ANSI graphics characters
766 static void
767 show_characters(char *bank, int bias)
769 int i;
771 sprintf(temp, "G%d GL ", bank[1] & 3);
772 ptext(temp);
773 select_bank(bank);
774 for (i = ' '; i < 0x80; i++) {
775 if (char_count >= columns ||
776 (i != ' ' && (i & 31) == 0))
777 put_str("\n ");
778 putchp(i + bias);
780 select_bank(default_bank);
781 put_str(" DEL <");
782 select_bank(bank);
783 putchp(0x7f + bias);
784 select_bank(default_bank);
785 putchp('>');
786 put_crlf();
787 put_crlf();
791 /* ANSI graphics test
792 94 96 character sets
793 G0 ( ,
794 G1 ) -
795 G2 * .
796 G3 + /
798 Standard Definitions
799 A UK
800 B US ASCII
802 Dec extended definitions
803 0 Special graphics
808 ** tools_charset(testlist, state, ch)
810 ** Run the ANSI alt-charset mode tool
812 void
813 tools_charset(
814 struct test_list *t GCC_UNUSED,
815 int *state GCC_UNUSED,
816 int *chp GCC_UNUSED)
818 int j, ch;
819 char bank[32];
821 put_clear();
822 ptext("Enter the bank ()*+,-./ followed by the character set");
823 ptext(" 0123456789:;<=>? for private use, and");
824 ptextln(" @A...Z[\\]^_`a...z{|}~ for standard sets.");
825 strcpy(bank, "\033)0");
826 for (; bank[0];) {
827 put_crlf();
828 show_characters(bank, 0);
830 /* G0 will not print in GR */
831 if (bank[1] & 3) {
832 show_characters(bank, 0x80);
834 ptext("bank+set> ");
835 for (j = 1; (ch = getchp(char_mask)); j++) {
836 if (ch == EOF)
837 break;
838 putchp(ch);
839 if (j == 1 && ch > '/')
840 j++;
841 bank[j] = ch;
842 if (ch < ' ' || ch > '/')
843 break;
844 if (j + 1 >= (int) sizeof(bank))
845 break;
847 if (j == 1)
848 break;
849 if (bank[j] < '0' || bank[j] > '~')
850 break;
851 bank[j + 1] = '\0';
853 put_crlf();