1 /* $Id: charsets.c,v 1.60 2018/07/26 00:20:16 tom Exp $ */
2
3 /*
4 * Test character-sets (e.g., SCS control, DECNRCM mode)
5 */
6 #include <vttest.h>
7 #include <esc.h>
8
9 /* the values, where specified, correspond to the keyboard-language codes */
10 typedef enum {
11 ASCII = 1,
12 British = 2,
13 Flemish = 3,
14 French_Canadian = 4,
15 Danish = 5,
16 Finnish = 6,
17 German = 7,
18 Dutch = 8,
19 Italian = 9,
20 Swiss_French = 10,
21 Swiss_German = 11,
22 Swiss,
23 Swedish = 12,
24 Norwegian_Danish = 13,
25 French = 14,
26 Spanish = 15,
27 Portugese = 16,
28 Hebrew = 17,
29 British_Latin_1,
30 Cyrillic,
31 DEC_Alt_Chars,
32 DEC_Alt_Graphics,
33 DEC_Spec_Graphic,
34 DEC_Supp,
35 DEC_Supp_Graphic,
36 DEC_Tech,
37 Greek,
38 Greek_Supp,
39 Hebrew_Supp,
40 Latin_5_Supp,
41 Latin_Cyrillic,
42 Russian,
43 Turkish,
44 SCS_NRCS,
45 Unknown
46 } National;
47
48 typedef struct {
49 National code; /* internal name (chosen to sort 'name' member) */
50 int allow96; /* flag for 96-character sets (e.g., GR mapping) */
51 int order; /* check-column so we can mechanically-sort this table */
52 int first; /* first model: 0=base, 2=vt220, 3=vt320, etc. */
53 int last; /* lastmodel: 0=base, 2=vt220, 3=vt320, etc. */
54 const char *final; /* end of SCS string */
55 const char *name; /* the string we'll show the user */
56 const char *not11; /* cells which are not 1-1 with ISO-8859-1 */
57 } CHARSETS;
58 /* *INDENT-OFF* */
59
60 /* compare mappings using only 7-bits */
61 #define Not11(a,b) (((a) & 0x7f) == ((b) & 0x7f))
62
63 /*
64 * The VT220 and VT340 reference manuals show tables and details for the
65 * character sets. The VT520 reference manual does not show these details, so
66 * mappings for the VT5xx character sets are not highlighted by this program.
67 */
68 static const char map_pound[] = "#";
69 static const char map_all94[] = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
70 static const char map_DEC_Supp[] = "$&,-./48>GHIJKLMNOPW^pw}~";
71 static const char map_Spec_Graphic[] = "`abcdefghijklmnopqrstuvwxyz{|}~";
72 static const char map_Supp_Graphic[] = "$&,-./48>PW^p}~\177";
73 static const char map_Dutch[] = "#@[\\]{|}~";
74 static const char map_Finnish[] = "`[\\]^{|}~";
75 static const char map_French[] = "#@[\\]{|}~";
76 static const char map_French_Canadian[] = "@`[\\]^{|}~";
77 static const char map_German[] = "@[\\]{|}~";
78 static const char map_Italian[] = "#@`[\\]{|}~";
79 static const char map_Norwegian[] = "@`[\\]^{|}~";
80 static const char map_Portuguese[] = "[\\]{|}";
81 static const char map_Spanish[] = "@[\\]{|}";
82 static const char map_Swedish[] = "@`[\\]^{|}~";
83 static const char map_Swiss[] = "#@`[\\]^_{|}~";
84
85 static const CHARSETS KnownCharsets[] = {
86 { ASCII, 0, 0, 0, 9, "B", "US ASCII", 0 },
87 { British, 0, 0, 0, 9, "A", "British", map_pound },
88 { British_Latin_1, 1, 0, 3, 9, "A", "ISO Latin-1", 0 },
89 { Cyrillic, 0, 0, 5, 9, "&4", "Cyrillic (DEC)", 0 },
90 { DEC_Spec_Graphic, 0, 0, 0, 9, "0", "DEC Special graphics and line drawing", map_Spec_Graphic },
91 { DEC_Alt_Chars, 0, 0, 0, 0, "1", "DEC Alternate character ROM standard characters", 0 },
92 { DEC_Alt_Graphics, 0, 0, 0, 0, "2", "DEC Alternate character ROM special graphics", 0 },
93 { DEC_Supp, 0, 0, 2, 9, "<", "DEC Supplemental", map_DEC_Supp },
94 { DEC_Supp_Graphic, 0, 0, 3, 9, "%5", "DEC Supplemental Graphic", map_Supp_Graphic },
95 { DEC_Tech, 0, 0, 3, 9, ">", "DEC Technical", map_all94 },
96 { Dutch, 0, 0, 2, 9, "4", "Dutch", map_Dutch },
97 { Finnish, 0, 0, 2, 9, "5", "Finnish", map_Finnish },
98 { Finnish, 0, 1, 2, 9, "C", "Finnish", map_French },
99 { French, 0, 0, 2, 9, "R", "French", map_French },
100 { French, 0, 1, 2, 9, "f", "French", map_French }, /* Kermit (vt340 model?) */
101 { French_Canadian, 0, 0, 2, 9, "Q", "French Canadian", map_French_Canadian },
102 { French_Canadian, 0, 1, 3, 9, "9", "French Canadian", map_French_Canadian },
103 { German, 0, 0, 2, 9, "K", "German", map_German },
104 { Greek, 0, 0, 5, 9, "\"?", "Greek (DEC)", 0 },
105 { Greek_Supp, 1, 0, 5, 9, "F", "ISO Greek Supplemental", 0 },
106 { Hebrew, 0, 0, 5, 9, "\"4", "Hebrew (DEC)", 0 },
107 { Hebrew, 0, 1, 5, 9, "%=", "Hebrew NRCS", 0 },
108 { Hebrew_Supp, 1, 0, 5, 9, "H", "ISO Hebrew Supplemental", 0 },
109 { Italian, 0, 0, 2, 9, "Y", "Italian", map_Italian },
110 { Latin_5_Supp, 1, 0, 5, 9, "M", "ISO Latin-5 Supplemental", 0 },
111 { Latin_Cyrillic, 1, 0, 5, 9, "L", "ISO Latin-Cyrillic", 0 },
112 { Norwegian_Danish, 0, 0, 3, 9, "`", "Norwegian/Danish", map_Norwegian },
113 { Norwegian_Danish, 0, 1, 2, 9, "E", "Norwegian/Danish", map_Norwegian },
114 { Norwegian_Danish, 0, 2, 2, 9, "6", "Norwegian/Danish", map_Norwegian },
115 { Portugese, 0, 0, 3, 9, "%6", "Portugese", map_Portuguese },
116 { Russian, 0, 0, 5, 9, "&5", "Russian", 0 },
117 { SCS_NRCS, 0, 0, 5, 9, "%3", "SCS NRCS", 0 },
118 { Spanish, 0, 0, 2, 9, "Z", "Spanish", map_Spanish },
119 { Swedish, 0, 0, 2, 9, "7", "Swedish", map_Swedish },
120 { Swedish, 0, 1, 2, 9, "H", "Swedish", map_Swedish },
121 { Swiss, 0, 0, 2, 9, "=", "Swiss", map_Swiss },
122 { Turkish, 0, 0, 5, 9, "%0", "Turkish (DEC)", 0 },
123 { Turkish, 0, 1, 5, 9, "%2", "Turkish NRCS", 0 },
124 { Unknown, 0, 0,-1,-1, "?", "Unknown", 0 }
125 };
126 /* *INDENT-ON* */
127
128 static int hilite_not11;
129 static int national;
130 static int cleanup;
131
132 static char sgr_hilite[10];
133 static char sgr_reset[10];
134
135 static int current_Gx[4];
136
137 static int
lookupCode(National code)138 lookupCode(National code)
139 {
140 int n;
141 for (n = 0; n < TABLESIZE(KnownCharsets); n++) {
142 if (KnownCharsets[n].code == code)
143 return n;
144 }
145 return lookupCode(ASCII);
146 }
147
148 static const CHARSETS *
lookupCharset(int g,int n)149 lookupCharset(int g, int n)
150 {
151 const CHARSETS *result = 0;
152 if (n >= 0 && n < TABLESIZE(KnownCharsets)) {
153 if (!strcmp(KnownCharsets[n].final, "A")) {
154 if (national || (g == 0)) {
155 n = lookupCode(British);
156 } else {
157 n = lookupCode(British_Latin_1);
158 }
159 }
160 result = &KnownCharsets[n];
161 }
162 return result;
163 }
164
165 static const char *
charset_name(int g,int n)166 charset_name(int g, int n)
167 {
168 return lookupCharset(g, n)->name;
169 }
170
171 static int
append_sgr(char * buffer,int used,const char * sgr_string)172 append_sgr(char *buffer, int used, const char *sgr_string)
173 {
174 strcpy(buffer + used, sgr_string);
175 used += (int) strlen(sgr_string);
176 return used;
177 }
178
179 static void
send32(int row,int upper,const char * not11)180 send32(int row, int upper, const char *not11)
181 {
182 int col;
183 int used = 0;
184 int hilited = 0;
185 char buffer[33 * 8];
186
187 if (LOG_ENABLED) {
188 fprintf(log_fp, "Note: send32 row %d, upper %d, not11:%s\n",
189 row, upper, not11 ? not11 : "");
190 }
191 for (col = 0; col <= 31; col++) {
192 char ch = (char) (row * 32 + upper + col);
193 if (not11 != 0 && hilite_not11) {
194 const char *p;
195 int found = 0;
196 for (p = not11; *p; ++p) {
197 if (Not11(*p, ch)) {
198 found = 1;
199 break;
200 }
201 }
202 if (found) {
203 if (!hilited) {
204 used = append_sgr(buffer, used, sgr_hilite);
205 hilited = 1;
206 }
207 } else {
208 if (hilited) {
209 used = append_sgr(buffer, used, sgr_reset);
210 hilited = 0;
211 }
212 }
213 }
214 buffer[used++] = ch;
215 }
216 if (hilited) {
217 used = append_sgr(buffer, used, sgr_reset);
218 }
219 buffer[used] = 0;
220 tprintf("%s", buffer);
221 }
222
223 static char *
scs_params(char * dst,int g)224 scs_params(char *dst, int g)
225 {
226 const CHARSETS *tbl = lookupCharset(g, current_Gx[g]);
227
228 sprintf(dst, "%c%s",
229 ((tbl->allow96 && get_level() > 2)
230 ? "?-./"[g]
231 : "()*+"[g]),
232 tbl->final);
233 return dst;
234 }
235
236 static void
do_scs(int g)237 do_scs(int g)
238 {
239 char buffer[80];
240
241 esc(scs_params(buffer, g));
242 }
243
244 /* reset given Gg back to sane setting */
245 static int
sane_cs(int g)246 sane_cs(int g)
247 {
248 return lookupCode(((g == 0) || (get_level() <= 1))
249 ? ASCII
250 : (get_level() < 3
251 ? British
252 : British_Latin_1)); /* ...to get 8-bit codes 128-255 */
253 }
254
255 /* reset given Gg back to sane setting */
256 static int
reset_scs(int g)257 reset_scs(int g)
258 {
259 int n = sane_cs(g);
260 do_scs(n);
261 return n;
262 }
263
264 /* reset all of the Gn to sane settings */
265 static int
reset_charset(MENU_ARGS)266 reset_charset(MENU_ARGS)
267 {
268 int n;
269
270 decnrcm(national = FALSE);
271 for (n = 0; n < 4; n++) {
272 int m = sane_cs(cleanup ? 0 : n);
273 if (m != current_Gx[n] || (m == 0)) {
274 current_Gx[n] = m;
275 do_scs(n);
276 }
277 }
278 return MENU_NOHOLD;
279 }
280
281 static int the_code;
282 static int the_list[TABLESIZE(KnownCharsets) + 2];
283
284 static int
lookup_Gx(MENU_ARGS)285 lookup_Gx(MENU_ARGS)
286 {
287 int n;
288 the_code = -1;
289 for (n = 0; n < TABLESIZE(KnownCharsets); n++) {
290 if (the_list[n]
291 && !strcmp(the_title, KnownCharsets[n].name)) {
292 the_code = n;
293 break;
294 }
295 }
296 return MENU_NOHOLD;
297 }
298
299 static void
specify_any_Gx(MENU_ARGS,int g)300 specify_any_Gx(MENU_ARGS, int g)
301 {
302 MENU my_menu[TABLESIZE(KnownCharsets) + 2];
303 int n, m;
304
305 /*
306 * Build up a menu of the character sets we will allow the user to specify.
307 * There are a couple of tentative table entries (the "?" ones), which we
308 * won't show in any event. Beyond that, we limit some of the character sets
309 * based on the emulation level (vt220 implements national replacement
310 * character sets, for example, but not the 96-character ISO Latin-1).
311 */
312 for (n = m = 0; n < TABLESIZE(KnownCharsets); n++) {
313 the_list[n] = 0;
314 if (!strcmp(KnownCharsets[n].final, "?"))
315 continue;
316 if (get_level() < KnownCharsets[n].first)
317 continue;
318 if (get_level() > KnownCharsets[n].last)
319 continue;
320 if (((g == 0) || national) && KnownCharsets[n].allow96)
321 continue;
322 if (((g != 0) && !national) && (KnownCharsets[n].code == British))
323 continue;
324 if (m && !strcmp(my_menu[m - 1].description, KnownCharsets[n].name))
325 continue;
326 my_menu[m].description = KnownCharsets[n].name;
327 my_menu[m].dispatch = lookup_Gx;
328 the_list[n] = 1;
329 m++;
330 }
331 my_menu[m].description = "";
332 my_menu[m].dispatch = 0;
333
334 do {
335 vt_clear(2);
336 __(title(0), println(the_title));
337 __(title(2), println("Choose character-set:"));
338 } while (menu(my_menu) && the_code < 0);
339
340 current_Gx[g] = the_code;
341 }
342
343 static int
toggle_hilite(MENU_ARGS)344 toggle_hilite(MENU_ARGS)
345 {
346 hilite_not11 = !hilite_not11;
347 if (hilite_not11) {
348 sprintf(sgr_hilite, "%s7m", csi_output());
349 sprintf(sgr_reset, "%sm", csi_output());
350 }
351 return MENU_NOHOLD;
352 }
353
354 static int
toggle_nrc(MENU_ARGS)355 toggle_nrc(MENU_ARGS)
356 {
357 national = !national;
358 decnrcm(national);
359 return MENU_NOHOLD;
360 }
361
362 static int
specify_G0(MENU_ARGS)363 specify_G0(MENU_ARGS)
364 {
365 specify_any_Gx(PASS_ARGS, 0);
366 return MENU_NOHOLD;
367 }
368
369 static int
specify_G1(MENU_ARGS)370 specify_G1(MENU_ARGS)
371 {
372 specify_any_Gx(PASS_ARGS, 1);
373 return MENU_NOHOLD;
374 }
375
376 static int
specify_G2(MENU_ARGS)377 specify_G2(MENU_ARGS)
378 {
379 specify_any_Gx(PASS_ARGS, 2);
380 return MENU_NOHOLD;
381 }
382
383 static int
specify_G3(MENU_ARGS)384 specify_G3(MENU_ARGS)
385 {
386 specify_any_Gx(PASS_ARGS, 3);
387 return MENU_NOHOLD;
388 }
389
390 static int
tst_layout(MENU_ARGS)391 tst_layout(MENU_ARGS)
392 {
393 char buffer[80];
394 return tst_keyboard_layout(scs_params(buffer, 0));
395 }
396
397 static int
tst_vt100_charsets(MENU_ARGS)398 tst_vt100_charsets(MENU_ARGS)
399 {
400 /* Test of:
401 * SCS (Select character Set)
402 */
403 int i, g, count, cset;
404
405 __(cup(1, 10), printf("Selected as G0 (with SI)"));
406 __(cup(1, 48), printf("Selected as G1 (with SO)"));
407 for (count = cset = 0; count < TABLESIZE(KnownCharsets); count++) {
408 const CHARSETS *tbl = KnownCharsets + count;
409 if (tbl->first == 0) {
410 int row = 3 + (4 * cset);
411
412 scs(1, 'B');
413 cup(row, 1);
414 sgr("1");
415 tprintf("Character set %s (%s)", tbl->final, tbl->name);
416 sgr("0");
417 for (g = 0; g <= 1; g++) {
418 int set_nrc = (get_level() >= 2 && tbl->final[0] == 'A');
419 if (set_nrc)
420 decnrcm(TRUE);
421 scs(g, (int) tbl->final[0]);
422 for (i = 1; i <= 3; i++) {
423 cup(row + i, 10 + 38 * g);
424 send32(i, 0, tbl->not11);
425 }
426 if (set_nrc != national)
427 decnrcm(national);
428 }
429 ++cset;
430 }
431 }
432 scs_normal();
433 __(cup(max_lines, 1), printf("These are the installed character sets. "));
434 return MENU_HOLD;
435 }
436
437 static int
tst_shift_in_out(MENU_ARGS)438 tst_shift_in_out(MENU_ARGS)
439 {
440 /* Test of:
441 SCS (Select character Set)
442 */
443 static const char *label[] =
444 {
445 "Selected as G0 (with SI)",
446 "Selected as G1 (with SO)"
447 };
448 int i, cset;
449 char buffer[80];
450
451 __(cup(1, 10), printf("These are the G0 and G1 character sets."));
452 for (cset = 0; cset < 2; cset++) {
453 const CHARSETS *tbl = lookupCharset(cset, current_Gx[cset]);
454 int row = 3 + (4 * cset);
455
456 scs(cset, 'B');
457 cup(row, 1);
458 sgr("1");
459 tprintf("Character set %s (%s)", tbl->final, tbl->name);
460 sgr("0");
461
462 cup(row, 48);
463 tprintf("%s", label[cset]);
464
465 esc(scs_params(buffer, cset));
466 for (i = 1; i <= 3; i++) {
467 cup(row + i, 10);
468 send32(i, 0, tbl->not11);
469 }
470 scs(cset, 'B');
471 }
472 cup(max_lines, 1);
473 return MENU_HOLD;
474 }
475
476 #define map_g1_to_gr() esc("~") /* LS1R */
477
478 static int
tst_vt220_locking(MENU_ARGS)479 tst_vt220_locking(MENU_ARGS)
480 {
481 /* *INDENT-OFF* */
482 static const struct {
483 int upper;
484 int mapped;
485 const char *code;
486 const char *msg;
487 } table[] = {
488 { 1, 1, "~", "G1 into GR (LS1R)" },
489 { 0, 2, "n", "G2 into GL (LS2)" }, /* "{" vi */
490 { 1, 2, "}", "G2 into GR (LS2R)" },
491 { 0, 3, "o", "G3 into GL (LS3)" },
492 { 1, 3, "|", "G3 into GR (LS3R)" },
493 };
494 /* *INDENT-ON* */
495
496 int i, cset;
497
498 __(cup(1, 10), tprintf("Locking shifts, with NRC %s:",
499 STR_ENABLED(national)));
500 for (cset = 0; cset < TABLESIZE(table); cset++) {
501 int row = 3 + (4 * cset);
502 int map = table[cset].mapped;
503 const CHARSETS *tbl = lookupCharset(map, current_Gx[map]);
504 int map_gl = (strstr(table[cset].msg, "into GL") != 0);
505
506 scs_normal();
507 cup(row, 1);
508 sgr("1");
509 tprintf("Character set %s (%s) in G%d", tbl->final, tbl->name, map);
510 sgr("0");
511
512 cup(row, 48);
513 tprintf("Maps %s", table[cset].msg);
514
515 for (i = 1; i <= 3; i++) {
516 if (table[cset].upper) {
517 scs_normal();
518 map_g1_to_gr();
519 } else {
520 do_scs(map);
521 esc(table[cset].code);
522 }
523 cup(row + i, 5);
524 send32(i, 0, map_gl ? tbl->not11 : 0);
525
526 if (table[cset].upper) {
527 do_scs(map);
528 esc(table[cset].code);
529 } else {
530 scs_normal();
531 map_g1_to_gr();
532 }
533 cup(row + i, 40);
534 send32(i, 128, map_gl ? 0 : tbl->not11);
535 }
536 reset_scs(cset);
537 }
538 scs_normal();
539 cup(max_lines, 1);
540 return MENU_HOLD;
541 }
542
543 static int
tst_vt220_single(MENU_ARGS)544 tst_vt220_single(MENU_ARGS)
545 {
546 int pass, x, y;
547
548 for (pass = 0; pass < 2; pass++) {
549 int g = pass + 2;
550 const CHARSETS *tbl = lookupCharset(g, current_Gx[g]);
551
552 vt_clear(2);
553 cup(1, 1);
554 tprintf("Testing single-shift G%d into GL (SS%d) with NRC %s\n",
555 g, g, STR_ENABLED(national));
556 tprintf("G%d is %s", g, tbl->name);
557
558 do_scs(g);
559 for (y = 0; y < 16; y++) {
560 for (x = 0; x < 6; x++) {
561 int ch = y + (x * 16) + 32;
562 int hilited = 0;
563
564 cup(y + 5, (x * 12) + 5);
565 tprintf("%3d: (", ch);
566 esc(pass ? "O" : "N"); /* SS3 or SS2 */
567 if (tbl->not11 && hilite_not11) {
568 const char *p;
569 for (p = tbl->not11; *p; ++p) {
570 if (Not11(*p, ch)) {
571 tprintf("%s", sgr_hilite);
572 hilited = 1;
573 break;
574 }
575 }
576 }
577 tprintf("%c", ch);
578 if (ch == 127 && !tbl->allow96)
579 tprintf(" "); /* DEL should have been eaten - skip past */
580 if (hilited) {
581 tprintf("%s", sgr_reset);
582 }
583 tprintf(")");
584 }
585 }
586
587 cup(max_lines, 1);
588 holdit();
589 }
590
591 return MENU_NOHOLD;
592 }
593
594 /******************************************************************************/
595
596 /*
597 * For parsing DECCIR response. The end of the response consists of so-called
598 * intermediate and final bytes as used by the SCS controls. Most of the
599 * strings fit into that description, but note that '<', '=' and '>' do not,
600 * since they are used to denote private parameters rather than final bytes.
601 * (But ECMA-48 hedges this by stating that the format in those cases is not
602 * specified).
603 */
604 const char *
parse_Sdesig(const char * source,int * offset)605 parse_Sdesig(const char *source, int *offset)
606 {
607 int j;
608 const char *first = source + (*offset);
609 const char *result = 0;
610 size_t limit = strlen(first);
611
612 for (j = 0; j < TABLESIZE(KnownCharsets); ++j) {
613 if (KnownCharsets[j].code != Unknown) {
614 size_t check = strlen(KnownCharsets[j].final);
615 if (check <= limit
616 && !strncmp(KnownCharsets[j].final, first, check)) {
617 result = KnownCharsets[j].name;
618 *offset += (int) check;
619 break;
620 }
621 }
622 }
623 if (result == 0) {
624 static char temp[80];
625 sprintf(temp, "? %#x\n", *source);
626 *offset += 1;
627 result = temp;
628 }
629 return result;
630 }
631
632 /*
633 * Reset G0 to ASCII
634 * Reset G1 to ASCII
635 * Shift-in.
636 */
637 void
scs_normal(void)638 scs_normal(void)
639 {
640 scs(0, 'B');
641 }
642
643 /*
644 * Set G0 to Line Graphics
645 * Reset G1 to ASCII
646 * Shift-in.
647 */
648 void
scs_graphics(void)649 scs_graphics(void)
650 {
651 scs(0, '0');
652 }
653
654 int
tst_characters(MENU_ARGS)655 tst_characters(MENU_ARGS)
656 {
657 static char whatis_Gx[4][80];
658 static char hilite_mesg[80];
659 static char nrc_mesg[80];
660 /* *INDENT-OFF* */
661 static MENU my_menu[] = {
662 { "Exit", 0 },
663 { "Reset (ASCII for G0, G1, no NRC mode)", reset_charset },
664 { hilite_mesg, toggle_hilite },
665 { nrc_mesg, toggle_nrc },
666 { whatis_Gx[0], specify_G0 },
667 { whatis_Gx[1], specify_G1 },
668 { whatis_Gx[2], specify_G2 },
669 { whatis_Gx[3], specify_G3 },
670 { "Test VT100 Character Sets", tst_vt100_charsets },
671 { "Test Shift In/Shift Out (SI/SO)", tst_shift_in_out },
672 { "Test VT220 Locking Shifts", tst_vt220_locking },
673 { "Test VT220 Single Shifts", tst_vt220_single },
674 { "Test Soft Character Sets", not_impl },
675 { "Test Keyboard Layout with G0 Selection", tst_layout },
676 { "", 0 }
677 };
678 /* *INDENT-ON* */
679
680 cleanup = 0;
681 hilite_not11 = 1;
682 toggle_hilite(PASS_ARGS);
683 reset_charset(PASS_ARGS); /* make the menu consistent */
684
685 if (get_level() > 1 || input_8bits || output_8bits) {
686 int n;
687
688 do {
689 vt_clear(2);
690 __(title(0), printf("Character-Set Tests"));
691 __(title(2), println("Choose test type:"));
692 sprintf(hilite_mesg, "%s highlighting of non-ISO-8859-1 mapping",
693 STR_ENABLE(hilite_not11));
694 sprintf(nrc_mesg, "%s National Replacement Character (NRC) mode",
695 STR_ENABLE(national));
696 for (n = 0; n < 4; n++) {
697 sprintf(whatis_Gx[n], "Specify G%d (now %s)",
698 n, charset_name(n, current_Gx[n]));
699 }
700 } while (menu(my_menu));
701 cleanup = 1;
702 /* tidy in case a "vt100" emulator does not ignore SCS */
703 vt_clear(1);
704 return reset_charset(PASS_ARGS);
705 } else {
706 return tst_vt100_charsets(PASS_ARGS);
707 }
708 }
709