f1a066e23e616ea40ee4ff8a20775c762d315cbb
[ncurses.git] / tack / charset.c
1 /*
2 ** Copyright (C) 1991, 1997-2000 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
24 MODULE_ID("$Id: charset.c,v 1.10 2005/09/17 19:49:16 tom Exp $")
25
26 /*
27         Menu definitions for alternate character set and SGR tests.
28 */
29
30 static void charset_bel(struct test_list *t, int *state, int *ch);
31 static void charset_flash(struct test_list *t, int *state, int *ch);
32 static void charset_civis(struct test_list *t, int *state, int *ch);
33 static void charset_cvvis(struct test_list *t, int *state, int *ch);
34 static void charset_cnorm(struct test_list *t, int *state, int *ch);
35 static void charset_hs(struct test_list *t, int *state, int *ch);
36 static void charset_status(struct test_list *t, int *state, int *ch);
37 static void charset_dsl(struct test_list *t, int *state, int *ch);
38 static void charset_enacs(struct test_list *t, int *state, int *ch);
39 static void charset_smacs(struct test_list *t, int *state, int *ch);
40 static void charset_attributes(struct test_list *t, int *state, int *ch);
41 static void charset_sgr(struct test_list *t, int *state, int *ch);
42
43 struct test_list acs_test_list[] = {
44         {0, 0, 0, 0, "e) edit terminfo", 0, &edit_menu},
45         {MENU_NEXT, 3, "bel", 0, 0, charset_bel, 0},
46         {MENU_NEXT, 3, "flash", 0, 0, charset_flash, 0},
47         {MENU_NEXT, 3, "civis", 0, 0, charset_civis, 0},
48         {MENU_NEXT, 3, "cvvis", 0, 0, charset_cvvis, 0},
49         {MENU_NEXT, 3, "cnorm", 0, 0, charset_cnorm, 0},
50         {MENU_NEXT, 3, "hs", 0, 0, charset_hs, 0},
51         {MENU_NEXT, 3, "tsl) (fsl) (wsl", "hs", 0, charset_status, 0},
52         {MENU_NEXT, 3, "dsl", "hs", 0, charset_dsl, 0},
53         {MENU_NEXT, 0, "acsc) (enacs) (smacs) (rmacs", 0, 0, charset_enacs, 0},
54         {MENU_NEXT, 0, "smacs) (rmacs", 0, 0, charset_smacs, 0},
55         {MENU_NEXT, 11, 0, 0, 0, charset_attributes, 0},
56         {MENU_NEXT, 11, "sgr) (sgr0", "ma", 0, charset_sgr, 0},
57         {MENU_LAST, 0, 0, 0, 0, 0, 0}
58 };
59
60 const struct mode_list alt_modes[] = {
61         {"normal", "(sgr0)", "(sgr0)", 1},
62         {"standout", "(smso)", "(rmso)", 2},
63         {"underline", "(smul)", "(rmul)", 4},
64         {"reverse", "(rev)", "(sgr0)", 8},
65         {"blink", "(blink)", "(sgr0)", 16},
66         {"dim", "(dim)", "(sgr0)", 32},
67         {"bold", "(bold)", "(sgr0)", 64},
68         {"invis", "(invis)", "(sgr0)", 128},
69         {"protect", "(prot)", "(sgr0)", 256},
70         {"altcharset", "(smacs)", "(rmacs)", 512}
71 };
72
73 /* On many terminals the underline attribute is the last scan line.
74    This is OK unless the following line is reverse video.
75    Then the underline attribute does not show up.  The following map
76    will reorder the display so that the underline attribute will
77    show up. */
78 const int mode_map[10] = {0, 1, 3, 4, 5, 6, 7, 8, 9, 2};
79
80 struct graphics_pair {
81         unsigned char c;
82         const char *name;
83 };
84
85 static struct graphics_pair glyph[] = {
86         {'+', "arrow pointing right"},
87         {',', "arrow pointing left"},
88         {'.', "arrow pointing down"},
89         {'0', "solid square block"},
90         {'i', "lantern symbol"},
91         {'-', "arrow pointing up"},
92         {'`', "diamond"},
93         {'a', "checker board (stipple)"},
94         {'f', "degree symbol"},
95         {'g', "plus/minus"},
96         {'h', "board of squares"},
97         {'j', "lower right corner"},
98         {'k', "upper right corner"},
99         {'l', "upper left corner"},
100         {'m', "lower left corner"},
101         {'n', "plus"},
102         {'o', "scan line 1"},
103         {'p', "scan line 3"},
104         {'q', "horizontal line"},
105         {'r', "scan line 7"},
106         {'s', "scan line 9"},
107         {'t', "left tee (|-)"},
108         {'u', "right tee (-|)"},
109         {'v', "bottom tee(_|_)"},
110         {'w', "top tee (T)"},
111         {'x', "vertical line"},
112         {'y', "less/equal"},
113         {'z', "greater/equal"},
114         {'{', "Pi"},
115         {'|', "not equal"},
116         {'}', "UK pound sign"},
117         {'~', "bullet"},
118         {'\0', "\0"}
119 };
120
121 /*
122 **      charset_hs(test_list, status, ch)
123 **
124 **      (hs) test Has status line
125 */
126 static void
127 charset_hs(
128         struct test_list *t,
129         int *state,
130         int *ch)
131 {
132         if (has_status_line != 1) {
133                 ptext("(hs) Has-status line is not defined.  ");
134                 generic_done_message(t, state, ch);
135         }
136 }
137
138 /*
139 **      charset_status(test_list, status, ch)
140 **
141 **      (tsl) (fsl) (wsl) test Status line
142 */
143 static void
144 charset_status(
145         struct test_list *t,
146         int *state,
147         int *ch)
148 {
149         int i, max;
150         char *s;
151         static char m[] = "*** status line *** 123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.";
152
153         if (has_status_line != 1) {
154                 return;
155         }
156         put_clear();
157         max = width_status_line == -1 ? columns : width_status_line;
158         sprintf(temp, "Terminal has status line of %d characters", max);
159         ptextln(temp);
160
161         put_str("This line s");
162         s = tparm(to_status_line, 0);
163         tc_putp(s);
164         for (i = 0; i < max; i++)
165                 putchp(m[i]);
166         tc_putp(from_status_line);
167         putln("hould not be broken.");
168         ptextln("If the previous line is not a complete sentence then (tsl) to-status-line, (fsl) from-status-line, or (wsl) width-of-status-line is incorrect."  );
169         generic_done_message(t, state, ch);
170 }
171
172 /*
173 **      charset_dsl(test_list, status, ch)
174 **
175 **      (dsl) test Disable status line
176 */
177 static void
178 charset_dsl(
179         struct test_list *t,
180         int *state,
181         int *ch)
182 {
183         if (has_status_line != 1) {
184                 return;
185         }
186         if (dis_status_line) {
187                 ptextln("Disable status line (dsl)");
188                 tc_putp(dis_status_line);
189                 ptext("If you can still see the status line then (dsl) disable-status-line has failed.  ");
190         } else {
191                 ptext("(dsl) Disable-status-line is not defined.  ");
192         }
193         generic_done_message(t, state, ch);
194 }
195
196
197 void
198 eat_cookie(void)
199 {                               /* put a blank if this is not a magic cookie
200                                    terminal */
201         if (magic_cookie_glitch < 1)
202                 putchp(' ');
203 }
204
205
206 void
207 put_mode(char *s)
208 {                               /* send the attribute string (with or without
209                                    % execution) */
210         tc_putp(tparm(s));              /* allow % execution */
211 }
212
213
214 void
215 set_attr(int a)
216 {                               /* set the attribute from the bits in a */
217         int i, b[32];
218
219         if (magic_cookie_glitch > 0) {
220                 char_count += magic_cookie_glitch;
221         }
222         if (a == 0 && exit_attribute_mode) {
223                 put_mode(exit_attribute_mode);
224                 return;
225         }
226         for (i = 0; i < 31; i++) {
227                 b[i] = (a >> i) & 1;
228         }
229         tc_putp(tparm(set_attributes, b[1], b[2], b[3], b[4], b[5],
230                         b[6], b[7], b[8], b[9]));
231 }
232
233 /*
234 **      charset_sgr(test_list, status, ch)
235 **
236 **      (sgr) test Set Graphics Rendition
237 */
238 static void
239 charset_sgr(
240         struct test_list *t,
241         int *state,
242         int *ch)
243 {
244         int i, j;
245
246         if (!set_attributes) {
247                 ptext("(sgr) Set-graphics-rendition is not defined.  ");
248                 generic_done_message(t, state, ch);
249                 return;
250         }
251         if (!exit_attribute_mode) {
252                 ptextln("(sgr0) Set-graphics-rendition-zero is not defined.");
253                 /* go ahead and test anyway */
254         }
255         ptext("Test video attributes (sgr)");
256
257         for (i = 0; i < (int) (sizeof(alt_modes) / sizeof(struct mode_list));
258                 i++) {
259                 put_crlf();
260                 sprintf(temp, "%d %-20s", i, alt_modes[i].name);
261                 put_str(temp);
262                 set_attr(alt_modes[i].number);
263                 sprintf(temp, "%s", alt_modes[i].name);
264                 put_str(temp);
265                 set_attr(0);
266         }
267
268         putln("\n\nDouble mode test");
269         for (i = 0; i <= 9; i++) {
270                 sprintf(temp, " %2d ", mode_map[i]);
271                 put_str(temp);
272         }
273         for (i = 0; i <= 9; i++) {
274                 put_crlf();
275                 sprintf(temp, "%d", mode_map[i]);
276                 put_str(temp);
277                 for (j = 0; j <= 9; j++) {
278                         eat_cookie();
279                         set_attr((1 << mode_map[i]) | (1 << mode_map[j]));
280                         put_str("Aa");
281                         set_attr(0);
282                         if (j < 9)
283                                 eat_cookie();
284                 }
285         }
286         put_crlf();
287
288 #ifdef max_attributes
289         if (max_attributes >= 0) {
290                 sprintf(temp, "(ma) Maximum attributes %d  ", max_attributes);
291                 ptext(temp);
292         }
293 #endif
294         generic_done_message(t, state, ch);
295 }
296
297 /*
298 **      test_one_attr(mode-number, begin-string, end-string)
299 **
300 **      Display one attribute line.
301 */
302 static void
303 test_one_attr(
304         int n,
305         char *begin_mode,
306         char *end_mode)
307 {
308         int i;
309
310         sprintf(temp, "%-10s %s ", alt_modes[n].name, alt_modes[n].begin_mode);
311         ptext(temp);
312         for (; char_count < 19;) {
313                 putchp(' ');
314         }
315         if (begin_mode) {
316                 putchp('.');
317                 put_mode(begin_mode);
318                 put_str(alt_modes[n].name);
319                 for (i = strlen(alt_modes[n].name); i < 13; i++) {
320                         putchp(' ');
321                 }
322                 if (end_mode) {
323                         put_mode(end_mode);
324                         sprintf(temp, ". %s", alt_modes[n].end_mode);
325                 } else {
326                         set_attr(0);
327                         strcpy(temp, ". (sgr)");
328                 }
329                 ptextln(temp);
330         } else {
331                 for (i = 0; i < magic_cookie_glitch; i++)
332                         putchp('*');
333                 put_str("*** missing ***");
334                 for (i = 0; i < magic_cookie_glitch; i++)
335                         putchp('*');
336                 put_crlf();
337         }
338 }
339
340 /*
341 **      charset_attributes(test_list, status, ch)
342 **
343 **      Test SGR
344 */
345 static void
346 charset_attributes(
347         struct test_list *t,
348         int *state,
349         int *ch)
350 {
351         putln("Test video attributes");
352         test_one_attr(1, enter_standout_mode, exit_standout_mode);
353         test_one_attr(2, enter_underline_mode, exit_underline_mode);
354         test_one_attr(9, enter_alt_charset_mode, exit_alt_charset_mode);
355         if (!exit_attribute_mode && !set_attributes) {
356                 ptextln("(sgr0) exit attribute mode is not defined.");
357                 generic_done_message(t, state, ch);
358                 return;
359         }
360         test_one_attr(3, enter_reverse_mode, exit_attribute_mode);
361         test_one_attr(4, enter_blink_mode, exit_attribute_mode);
362         test_one_attr(5, enter_dim_mode, exit_attribute_mode);
363         test_one_attr(6, enter_bold_mode, exit_attribute_mode);
364         test_one_attr(7, enter_secure_mode, exit_attribute_mode);
365         test_one_attr(8, enter_protected_mode, exit_attribute_mode);
366         generic_done_message(t, state, ch);
367 }
368
369 #define GLYPHS 256
370
371 /*
372 **      charset_smacs(test_list, status, ch)
373 **
374 **      display all possible acs characters
375 **      (smacs) (rmacs)
376 */
377 static void
378 charset_smacs(
379         struct test_list *t,
380         int *state,
381         int *ch)
382 {
383         int i, c;
384
385         if (enter_alt_charset_mode) {
386                 put_clear();
387                 ptextln("The following characters are available. (smacs) (rmacs)");
388                 for (i = ' '; i <= '`'; i += 32) {
389                         put_crlf();
390                         put_mode(exit_alt_charset_mode);
391                         for (c = 0; c < 32; c++) {
392                                 putchp(c + i);
393                         }
394                         put_crlf();
395                         put_mode(enter_alt_charset_mode);
396                         for (c = 0; c < 32; c++) {
397                                 putchp(c + i);
398                         }
399                         put_mode(exit_alt_charset_mode);
400                         put_crlf();
401                 }
402                 put_mode(exit_alt_charset_mode);
403                 put_crlf();
404                 generic_done_message(t, state, ch);
405         }
406 }
407
408
409 static void
410 test_acs(
411         int attr)
412 {                               /* alternate character set */
413         int i, j;
414         char valid_glyph[GLYPHS];
415         char acs_table[GLYPHS];
416         static unsigned char vt100[] = "`afgjklmnopqrstuvwxyz{|}~";
417
418         line_count = 0;
419         for (i = 0; i < GLYPHS; i++) {
420                 valid_glyph[i] = FALSE;
421                 acs_table[i] = i;
422         }
423         if (acs_chars) {
424                 sprintf(temp, "Alternate character set map: %s",
425                         expand(acs_chars));
426                 putln(temp);
427                 for (i = 0; acs_chars[i]; i += 2) {
428                         if (acs_chars[i + 1] == 0) {
429                                 break;
430                         }
431                         for (j = 0;; j++) {
432                                 if (glyph[j].c == (unsigned char) acs_chars[i]) {
433                                         acs_table[glyph[j].c] = acs_chars[i + 1];
434                                         valid_glyph[glyph[j].c] = TRUE;
435                                         break;
436                                 }
437                                 if (glyph[j].name[0] == '\0') {
438                                         if (isgraph(UChar(acs_chars[i]))) {
439                                                 sprintf(temp, "    %c",
440                                                         acs_chars[i]);
441                                         } else {
442                                                 sprintf(temp, " 0x%02x",
443                                                         UChar(acs_chars[i]));
444                                         }
445                                         strcpy(&temp[5], " *** has no mapping ***");
446                                         putln(temp);
447                                         break;
448                                 }
449                         }
450                 }
451         } else {
452                 ptextln("acs_chars not defined (acsc)");
453                 /* enable the VT-100 graphics characters (default) */
454                 for (i = 0; vt100[i]; i++) {
455                         valid_glyph[vt100[i]] = TRUE;
456                 }
457         }
458         if (attr) {
459                 set_attr(attr);
460         }
461         _nc_init_acs(); /* puts 'ena_acs' and incidentally links acs_map[] */
462         for (i = 0; glyph[i].name[0]; i++) {
463                 if (valid_glyph[glyph[i].c]) {
464                         put_mode(enter_alt_charset_mode);
465                         put_this(acs_table[glyph[i].c]);
466                         char_count++;
467                         put_mode(exit_alt_charset_mode);
468                         if (magic_cookie_glitch >= 1) {
469                                 sprintf(temp, " %-30.30s", glyph[i].name);
470                                 put_str(temp);
471                                 if (char_count + 33 >= columns)
472                                         put_crlf();
473                         } else {
474                                 sprintf(temp, " %-24.24s", glyph[i].name);
475                                 put_str(temp);
476                                 if (char_count + 26 >= columns)
477                                         put_crlf();
478                         }
479                         if (line_count >= lines) {
480                                 (void) wait_here();
481                                 put_clear();
482                         }
483                 }
484         }
485         if (char_count > 1) {
486                 put_crlf();
487         }
488 #ifdef ACS_ULCORNER
489         maybe_wait(5);
490         put_mode(enter_alt_charset_mode);
491         put_that(ACS_ULCORNER);
492         put_that(ACS_TTEE);
493         put_that(ACS_URCORNER);
494         put_that(ACS_ULCORNER);
495         put_that(ACS_HLINE);
496         put_that(ACS_URCORNER);
497         char_count += 6;
498         put_mode(exit_alt_charset_mode);
499         put_crlf();
500         put_mode(enter_alt_charset_mode);
501         put_that(ACS_LTEE);
502         put_that(ACS_PLUS);
503         put_that(ACS_RTEE);
504         put_that(ACS_VLINE);
505         if (magic_cookie_glitch >= 1)
506                 put_this(' ');
507         else {
508                 put_mode(exit_alt_charset_mode);
509                 put_this(' ');
510                 put_mode(enter_alt_charset_mode);
511         }
512         put_that(ACS_VLINE);
513         char_count += 6;
514         put_mode(exit_alt_charset_mode);
515         put_str("   Here are 2 boxes");
516         put_crlf();
517         put_mode(enter_alt_charset_mode);
518         put_that(ACS_LLCORNER);
519         put_that(ACS_BTEE);
520         put_that(ACS_LRCORNER);
521         put_that(ACS_LLCORNER);
522         put_that(ACS_HLINE);
523         put_that(ACS_LRCORNER);
524         char_count += 6;
525         put_mode(exit_alt_charset_mode);
526         put_crlf();
527 #endif
528 }
529
530 /*
531 **      charset_bel(test_list, status, ch)
532 **
533 **      (bel) test Bell
534 */
535 static void
536 charset_bel(
537         struct test_list *t,
538         int *state,
539         int *ch)
540 {
541         if (bell) {
542                 ptextln("Testing bell (bel)");
543                 tc_putp(bell);
544                 ptext("If you did not hear the Bell then (bel) has failed.  ");
545         } else {
546                 ptext("(bel) Bell is not defined.  ");
547         }
548         generic_done_message(t, state, ch);
549 }
550
551 /*
552 **      charset_flash(test_list, status, ch)
553 **
554 **      (flash) test Visual bell
555 */
556 static void
557 charset_flash(
558         struct test_list *t,
559         int *state,
560         int *ch)
561 {
562         if (flash_screen) {
563                 ptextln("Testing visual bell (flash)");
564                 tc_putp(flash_screen);
565                 ptext("If you did not see the screen flash then (flash) has failed.  ");
566         } else {
567                 ptext("(flash) Flash is not defined.  ");
568         }
569         generic_done_message(t, state, ch);
570 }
571
572 /*
573 **      charset_civis(test_list, status, ch)
574 **
575 **      (civis) test Cursor invisible
576 */
577 static void
578 charset_civis(
579         struct test_list *t,
580         int *state,
581         int *ch)
582 {
583         if (cursor_normal) {
584                 if (cursor_invisible) {
585                         ptext("(civis) Turn off the cursor.  ");
586                         tc_putp(cursor_invisible);
587                         ptext("If you can still see the cursor then (civis) has failed.  ");
588                 } else {
589                         ptext("(civis) Cursor-invisible is not defined.  ");
590                 }
591                 generic_done_message(t, state, ch);
592                 tc_putp(cursor_normal);
593         }
594 }
595
596 /*
597 **      charset_cvvis(test_list, status, ch)
598 **
599 **      (cvvis) test Cursor very visible
600 */
601 static void
602 charset_cvvis(
603         struct test_list *t,
604         int *state,
605         int *ch)
606 {
607         if (cursor_normal) {
608                 if (cursor_visible) {
609                         ptext("(cvvis) Make cursor very visible.  ");
610                         tc_putp(cursor_visible);
611                         ptext("If the cursor is not very visible then (cvvis) has failed.  ");
612                 } else {
613                         ptext("(cvvis) Cursor-very-visible is not defined.  ");
614                 }
615                 generic_done_message(t, state, ch);
616                 tc_putp(cursor_normal);
617         }
618 }
619
620 /*
621 **      charset_cnorm(test_list, status, ch)
622 **
623 **      (cnorm) test Cursor normal
624 */
625 static void
626 charset_cnorm(
627         struct test_list *t,
628         int *state,
629         int *ch)
630 {
631         if (cursor_normal) {
632                 ptext("(cnorm) Normal cursor.  ");
633                 tc_putp(cursor_normal);
634                 ptext("If the cursor is not normal then (cnorm) has failed.  ");
635         } else {
636                 ptext("(cnorm) Cursor-normal is not defined.  ");
637         }
638         generic_done_message(t, state, ch);
639 }
640
641 /*
642 **      charset_enacs(test_list, status, ch)
643 **
644 **      test Alternate character set mode and alternate characters
645 **      (acsc) (enacs) (smacs) (rmacs)
646 */
647 static void
648 charset_enacs(
649         struct test_list *t,
650         int *state,
651         int *ch)
652 {
653         int c, i;
654
655         if (enter_alt_charset_mode || acs_chars) {
656                 c = 0;
657                 while (1) {
658                         put_clear();
659                         /*
660                            for terminals that use separate fonts for
661                            attributes (such as X windows) the line
662                            drawing characters must be checked for
663                            each font.
664                         */
665                         if (c >= '0' && c <= '9') {
666                                 test_acs(alt_modes[c - '0'].number);
667                                 set_attr(0);
668                         } else {
669                                 test_acs(0);
670                         }
671
672                         while (1) {
673                                 ptextln("[r] to repeat, [012345789] to test with attributes on, [?] for a list of attributes, anything else to go to next test.  ");
674                                 generic_done_message(t, state, ch);
675                                 if (*ch != '?') {
676                                         break;
677                                 }
678                                 for (i = 0; i <= 9; i++) {
679                                         sprintf(temp, " %d %s %s", i, alt_modes[i].begin_mode,
680                                                 alt_modes[i].name);
681                                         ptextln(temp);
682                                 }
683                         }
684                         if (*ch >= '0' && *ch <= '9') {
685                                 c = *ch;
686                         } else
687                         if (*ch != 'r') {
688                                 break;
689                         }
690                 }
691         } else {
692                 ptext("(smacs) Enter-alt-char-set-mode and (acsc) Alternate-char-set are not defined.  ");
693                 generic_done_message(t, state, ch);
694         }
695 }
696
697 /*
698 **      charset_can_test()
699 **
700 **      Initialize the can_test data base
701 */
702 void
703 charset_can_test(void)
704 {
705         int i;
706
707         for (i = 0; i < 9; i++) {
708                 can_test(alt_modes[i].begin_mode, FLAG_CAN_TEST);
709                 can_test(alt_modes[i].end_mode, FLAG_CAN_TEST);
710         }
711 }