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., 51 Franklin Street, Fifth Floor, 19** Boston, MA 02110-1301, USA 20*/ 21 22#include <tack.h> 23 24MODULE_ID("$Id: ansi.c,v 1.10 2005/09/17 19:49:16 tom Exp $") 25 26/* 27 * Standalone tests for ANSI terminals. Three entry points: 28 * test_ansi_graphics(), test_ansi_reports() and test_ansi_sgr(). 29 */ 30 31/***************************************************************************** 32 * 33 * Test ANSI status reports 34 * 35 *****************************************************************************/ 36 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 44 45#define MAX_MODES 256 46 47static char default_bank[] = "\033(B\017"; 48static int private_use, ape, terminal_class; 49static short ansi_value[256]; 50static unsigned char ansi_buf[512], pack_buf[512]; 51 52struct ansi_reports { 53 int lvl, final; 54 const char *text; 55 const char *request; 56}; 57 58static 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} 92}; 93 94struct request_control { 95 const char *text; 96 const char *expect; 97 const char *request; 98 const char *set_mode; 99 const char *reset_mode; 100}; 101 102/* Request control function selection or setting */ 103static 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} 124}; 125 126 127/* 128** read_ansi() 129** 130** read an ANSI status report from terminal 131*/ 132static void 133read_ansi(void) 134{ 135 int ch, i, j, last_escape; 136 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; 145 } 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; 154 } 155 if (ch > 0x80 && ch < 0xa0) { 156 last_escape = ch; 157 } 158 pack_buf[j++] = ch; 159 } 160 } 161 if (last_escape == A_ESC) { 162 pack_buf[j++] = A_ESC; 163 } 164 pack_buf[j] = '\0'; 165 return; 166} 167 168/* 169** valid_mode(expected) 170** 171** read a terminal mode status report and parse the result 172** Return TRUE if we got the expected terminating character. 173*/ 174static int 175valid_mode(int expected) 176{ 177 unsigned char *s; 178 int ch, terminator; 179 180 read_ansi(); 181 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; 187 188 s = pack_buf + 1; 189 private_use = 0; 190 if ((*s >= '<') & (*s <= '?')) { 191 private_use = *s++; 192 } 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; 205 } 206 return terminator == expected; 207} 208 209/* 210** read_reports() 211** 212** read all the reports in the ANSI report structure 213*/ 214static int 215read_reports(void) 216{ 217 int i, j, k, tc, vcr, lc; 218 char *s; 219 const char *t; 220 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; 239 } 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; 257 } 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(' '); 265 } 266 s = expand((const char *)ansi_buf); 267 if (char_count + expand_chars >= columns) { 268 put_str("\r\n "); 269 lc++; 270 } 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); 288 289 } 290 } 291 menu_prompt(); 292 ptext("/status r->repeat test, <return> to continue > "); 293 return wait_here(); 294} 295 296/* 297** request_cfss() 298** 299** Request Control function selection or settings 300*/ 301static int 302request_cfss(void) 303{ 304 int i, j, k, l, ch; 305 char *s; 306 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; 331 } 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); 337 } 338 } 339 put_crlf(); 340 } 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); 352 } 353 } 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; 368 } 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(); 377} 378 379/* 380** mode_display(puc, mode, initial, set, reset) 381** 382** print the mode display entry 383*/ 384static void 385mode_display(const char *p, int n, int c, char s, char r) 386{ 387 int k; 388 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); 396} 397 398/* 399** terminal_state() 400** 401** test DECRQM status reports 402*/ 403static void 404terminal_state(void) 405{ 406 static const char *puc[] = {"", "<", "=", ">", "?", 0}; 407 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]; 414 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:"); 426 } 427 k = strlen(temp); 428 ptext(temp); 429 for (j = 0; j < (int) sizeof(buf); buf[j++] = ' ') 430 ; 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; 440 } 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++] = ' '; 453 } 454 k = 0; 455 } 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; 474 } 475 } 476 buf[k] = '\0'; 477 if (buf[k - 1] != ' ') { 478 put_crlf(); 479 ptext(buf); 480 } 481 } 482 483 if ((i = modes_found) != 0) { 484 put_crlf(); 485 put_crlf(); 486 if (tms[0]) { 487 ptextln(tms); 488 } 489 ptext("Hit 'Y' to test mode set/reset states: "); 490 i = wait_here(); 491 } 492 if (i == 'y' || i == 'Y') 493 while (1) { 494#ifdef STATUSFIX 495 FILE *fp; 496 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); 515 } 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'; 524 } 525 } 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]); 539 } 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]); 552 } 553 } 554 ptext("\n\nHit 'R' to repeat test: "); 555 i = wait_here(); 556 } 557 if (i != 'r' && i != 'R') 558 break; 559 tty_raw(1, char_mask); 560 } 561 } else { 562 tty_set(); 563 } 564} 565 566 567/* 568** ansi_report_help() 569** 570** Display the informational data for the ANSI report test. 571*/ 572static void 573ansi_report_help(void) 574{ 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(); 580} 581 582/* 583** test_ansi_reports() 584** 585** Test the ANSI status report functions 586*/ 587void 588tools_status( 589 struct test_list *t GCC_UNUSED, 590 int *state GCC_UNUSED, 591 int *ch) 592{ 593 int i; 594 595 put_clear(); 596 ansi_report_help(); 597 tty_raw(1, char_mask); 598 599 do { 600 i = read_reports(); 601 if (i != 'r' && i != 'R') { 602 *ch = i; 603 return; 604 } 605 } while (i); 606 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(); 615 } 616} 617 618 619/* 620** display_sgr() 621** 622** Test a range of ANSI sgr attributes 623** puc -> Private Use Character 624*/ 625static void 626display_sgr(int puc) 627{ 628 int k; 629 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"); 648 } 649 } 650 put_crlf(); 651 if (puc == '<') 652 printf("\033[<1m"); 653 else if (puc) 654 printf("\033[%s0m", temp); 655 set_attr(0); 656} 657 658/* 659** print_sgr20(on, off) 660** 661** print the sgr line for sgr20() 662*/ 663static void 664print_sgr20(int on, int off) 665{ 666 if (char_count > columns - 13) { 667 put_crlf(); 668 } else if (char_count) { 669 put_str(" "); 670 } 671 char_count += 11; 672 printf("%d/%d \033[%dmon\033[%dm off\033[0m", on, off, on, off); 673} 674 675/* 676** sgr20(void) 677** 678** display the enter/exit attributes 1-9 and 20-29 679*/ 680static void 681sgr20(void) 682{ 683 int k; 684 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); 689 } 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); 695} 696 697/* 698** tools_sgr(testlist, state, ch) 699** 700** Run the ANSI graphics rendition mode tool 701** Return the last character typed. 702*/ 703void 704tools_sgr( 705 struct test_list *t GCC_UNUSED, 706 int *state GCC_UNUSED, 707 int *ch) 708{ 709 int k; 710 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; 722 } 723 } 724 sgr20(); 725 726 put_newlines(2); 727 *ch = REQUEST_PROMPT; 728} 729 730/***************************************************************************** 731 * 732 * Test ANSI graphics 733 * 734 *****************************************************************************/ 735/* 736** select_bank(bank) 737** 738** select a graphics character set for ANSI terminals 739*/ 740static void 741select_bank(char *bank) 742{ 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; 758 } 759} 760 761/* 762** show_characters(bank, bias) 763** 764** print the ANSI graphics characters 765*/ 766static void 767show_characters(char *bank, int bias) 768{ 769 int i; 770 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); 779 } 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(); 788} 789 790 791/* ANSI graphics test 792 94 96 character sets 793 G0 ( , 794 G1 ) - 795 G2 * . 796 G3 + / 797 798Standard Definitions 799 A UK 800 B US ASCII 801 802Dec extended definitions 803 0 Special graphics 804 805 */ 806 807/* 808** tools_charset(testlist, state, ch) 809** 810** Run the ANSI alt-charset mode tool 811*/ 812void 813tools_charset( 814 struct test_list *t GCC_UNUSED, 815 int *state GCC_UNUSED, 816 int *chp GCC_UNUSED) 817{ 818 int j, ch; 819 char bank[32]; 820 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); 829 830 /* G0 will not print in GR */ 831 if (bank[1] & 3) { 832 show_characters(bank, 0x80); 833 } 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; 846 } 847 if (j == 1) 848 break; 849 if (bank[j] < '0' || bank[j] > '~') 850 break; 851 bank[j + 1] = '\0'; 852 } 853 put_crlf(); 854} 855