ncurses 5.0
[ncurses.git] / tack / charset.c
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.
20 */
21
22 #include <tack.h>
23
24 MODULE_ID("$Id: charset.c,v 1.2 1999/05/09 18:30:49 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 const 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         if (max_attributes >= 0) {
289                 sprintf(temp, "(ma) Maximum attributes %d  ", max_attributes);
290                 ptext(temp);
291         }
292         generic_done_message(t, state, ch);
293 }
294
295 /*
296 **      test_one_attr(mode-number, begin-string, end-string)
297 **
298 **      Display one attribute line.
299 */
300 static void
301 test_one_attr(
302         int n,
303         char *begin_mode,
304         char *end_mode)
305 {
306         int i;
307
308         sprintf(temp, "%-10s %s ", alt_modes[n].name, alt_modes[n].begin_mode);
309         ptext(temp);
310         for (; char_count < 19;) {
311                 putchp(' ');
312         }
313         if (begin_mode) {
314                 putchp('.');
315                 put_mode(begin_mode);
316                 put_str(alt_modes[n].name);
317                 for (i = strlen(alt_modes[n].name); i < 13; i++) {
318                         putchp(' ');
319                 }
320                 if (end_mode) {
321                         put_mode(end_mode);
322                         sprintf(temp, ". %s", alt_modes[n].end_mode);
323                 } else {
324                         set_attr(0);
325                         strcpy(temp, ". (sgr)");
326                 }
327                 ptextln(temp);
328         } else {
329                 for (i = 0; i < magic_cookie_glitch; i++)
330                         putchp('*');
331                 put_str("*** missing ***");
332                 for (i = 0; i < magic_cookie_glitch; i++)
333                         putchp('*');
334                 put_crlf();
335         }
336 }
337
338 /*
339 **      charset_attributes(test_list, status, ch)
340 **
341 **      Test SGR
342 */
343 static void
344 charset_attributes(
345         struct test_list *t,
346         int *state,
347         int *ch)
348 {
349         putln("Test video attributes");
350         test_one_attr(1, enter_standout_mode, exit_standout_mode);
351         test_one_attr(2, enter_underline_mode, exit_underline_mode);
352         test_one_attr(9, enter_alt_charset_mode, exit_alt_charset_mode);
353         if (!exit_attribute_mode && !set_attributes) {
354                 ptextln("(sgr0) exit attribute mode is not defined.");
355                 generic_done_message(t, state, ch);
356                 return;
357         }
358         test_one_attr(3, enter_reverse_mode, exit_attribute_mode);
359         test_one_attr(4, enter_blink_mode, exit_attribute_mode);
360         test_one_attr(5, enter_dim_mode, exit_attribute_mode);
361         test_one_attr(6, enter_bold_mode, exit_attribute_mode);
362         test_one_attr(7, enter_secure_mode, exit_attribute_mode);
363         test_one_attr(8, enter_protected_mode, exit_attribute_mode);
364         generic_done_message(t, state, ch);
365 }
366
367 #define GLYPHS 256
368
369 /*
370 **      charset_smacs(test_list, status, ch)
371 **
372 **      display all posible acs characters
373 **      (smacs) (rmacs)
374 */
375 static void
376 charset_smacs(
377         struct test_list *t,
378         int *state,
379         int *ch)
380 {
381         int i, c;
382
383         if (enter_alt_charset_mode) {
384                 put_clear();
385                 ptextln("The following characters are available. (smacs) (rmacs)");
386                 for (i = ' '; i <= '`'; i += 32) {
387                         put_crlf();
388                         put_mode(exit_alt_charset_mode);
389                         for (c = 0; c < 32; c++) {
390                                 putchp(c + i);
391                         }
392                         put_crlf();
393                         put_mode(enter_alt_charset_mode);
394                         for (c = 0; c < 32; c++) {
395                                 putchp(c + i);
396                         }
397                         put_mode(exit_alt_charset_mode);
398                         put_crlf();
399                 }
400                 put_mode(exit_alt_charset_mode);
401                 put_crlf();
402                 generic_done_message(t, state, ch);
403         }
404 }
405
406
407 static void
408 test_acs(
409         int attr)
410 {                               /* alternate character set */
411         int i, j;
412         char valid_glyph[GLYPHS];
413         char acs_table[GLYPHS];
414         static unsigned char vt100[] = "`afgjklmnopqrstuvwxyz{|}~";
415
416         line_count = 0;
417         for (i = 0; i < GLYPHS; i++) {
418                 valid_glyph[i] = FALSE;
419                 acs_table[i] = i;
420         }
421         if (acs_chars) {
422                 sprintf(temp, "Alternate character set map: %s",
423                         expand(acs_chars));
424                 putln(temp);
425                 for (i = 0; acs_chars[i]; i += 2) {
426                         if (acs_chars[i + 1] == 0) {
427                                 break;
428                         }
429                         for (j = 0;; j++) {
430                                 if (glyph[j].c == (unsigned char) acs_chars[i]) {
431                                         acs_table[glyph[j].c] = acs_chars[i + 1];
432                                         valid_glyph[glyph[j].c] = TRUE;
433                                         break;
434                                 }
435                                 if (glyph[j].name[0] == '\0') {
436                                         if (isgraph(acs_chars[i])) {
437                                                 sprintf(temp, "    %c",
438                                                         acs_chars[i]);
439                                         } else {
440                                                 sprintf(temp, " 0x%02x",
441                                                         (acs_chars[i] & 0xff));
442                                         }
443                                         strcpy(&temp[5], " *** has no mapping ***");
444                                         putln(temp);
445                                         break;
446                                 }
447                         }
448                 }
449         } else {
450                 ptextln("acs_chars not defined (acsc)");
451                 /* enable the VT-100 graphics characters (default) */
452                 for (i = 0; vt100[i]; i++) {
453                         valid_glyph[vt100[i]] = TRUE;
454                 }
455         }
456         if (attr) {
457                 set_attr(attr);
458         }
459         _nc_init_acs(); /* puts 'ena_acs' and incidentally links acs_map[] */
460         for (i = 0; glyph[i].name[0]; i++) {
461                 if (valid_glyph[glyph[i].c]) {
462                         put_mode(enter_alt_charset_mode);
463                         put_this(acs_table[glyph[i].c]);
464                         char_count++;
465                         put_mode(exit_alt_charset_mode);
466                         if (magic_cookie_glitch >= 1) {
467                                 sprintf(temp, " %-30.30s", glyph[i].name);
468                                 put_str(temp);
469                                 if (char_count + 33 >= columns)
470                                         put_crlf();
471                         } else {
472                                 sprintf(temp, " %-24.24s", glyph[i].name);
473                                 put_str(temp);
474                                 if (char_count + 26 >= columns)
475                                         put_crlf();
476                         }
477                         if (line_count >= lines) {
478                                 (void) wait_here();
479                                 put_clear();
480                         }
481                 }
482         }
483         if (char_count > 1) {
484                 put_crlf();
485         }
486 #ifdef ACS_ULCORNER
487         maybe_wait(5);
488         put_mode(enter_alt_charset_mode);
489         put_this(ACS_ULCORNER);
490         put_this(ACS_TTEE);
491         put_this(ACS_URCORNER);
492         put_this(ACS_ULCORNER);
493         put_this(ACS_HLINE);
494         put_this(ACS_URCORNER);
495         char_count += 6;
496         put_mode(exit_alt_charset_mode);
497         put_crlf();
498         put_mode(enter_alt_charset_mode);
499         put_this(ACS_LTEE);
500         put_this(ACS_PLUS);
501         put_this(ACS_RTEE);
502         put_this(ACS_VLINE);
503         if (magic_cookie_glitch >= 1)
504                 put_this(' ');
505         else {
506                 put_mode(exit_alt_charset_mode);
507                 put_this(' ');
508                 put_mode(enter_alt_charset_mode);
509         }
510         put_this(ACS_VLINE);
511         char_count += 6;
512         put_mode(exit_alt_charset_mode);
513         put_str("   Here are 2 boxes");
514         put_crlf();
515         put_mode(enter_alt_charset_mode);
516         put_this(ACS_LLCORNER);
517         put_this(ACS_BTEE);
518         put_this(ACS_LRCORNER);
519         put_this(ACS_LLCORNER);
520         put_this(ACS_HLINE);
521         put_this(ACS_LRCORNER);
522         char_count += 6;
523         put_mode(exit_alt_charset_mode);
524         put_crlf();
525 #endif
526 }
527
528 /*
529 **      charset_bel(test_list, status, ch)
530 **
531 **      (bel) test Bell
532 */
533 static void
534 charset_bel(
535         struct test_list *t,
536         int *state,
537         int *ch)
538 {
539         if (bell) {
540                 ptextln("Testing bell (bel)");
541                 tc_putp(bell);
542                 ptext("If you did not hear the Bell then (bel) has failed.  ");
543         } else {
544                 ptext("(bel) Bell is not defined.  ");
545         }
546         generic_done_message(t, state, ch);
547 }
548
549 /*
550 **      charset_flash(test_list, status, ch)
551 **
552 **      (flash) test Visual bell
553 */
554 static void
555 charset_flash(
556         struct test_list *t,
557         int *state,
558         int *ch)
559 {
560         if (flash_screen) {
561                 ptextln("Testing visual bell (flash)");
562                 tc_putp(flash_screen);
563                 ptext("If you did not see the screen flash then (flash) has failed.  ");
564         } else {
565                 ptext("(flash) Flash is not defined.  ");
566         }
567         generic_done_message(t, state, ch);
568 }
569
570 /*
571 **      charset_civis(test_list, status, ch)
572 **
573 **      (civis) test Cursor invisible
574 */
575 static void
576 charset_civis(
577         struct test_list *t,
578         int *state,
579         int *ch)
580 {
581         if (cursor_normal) {
582                 if (cursor_invisible) {
583                         ptext("(civis) Turn off the cursor.  ");
584                         tc_putp(cursor_invisible);
585                         ptext("If you can still see the cursor then (civis) has failed.  ");
586                 } else {
587                         ptext("(civis) Cursor-invisible is not defined.  ");
588                 }
589                 generic_done_message(t, state, ch);
590                 tc_putp(cursor_normal);
591         }
592 }
593
594 /*
595 **      charset_cvvis(test_list, status, ch)
596 **
597 **      (cvvis) test Cursor very visible
598 */
599 static void
600 charset_cvvis(
601         struct test_list *t,
602         int *state,
603         int *ch)
604 {
605         if (cursor_normal) {
606                 if (cursor_visible) {
607                         ptext("(cvvis) Make cursor very visible.  ");
608                         tc_putp(cursor_visible);
609                         ptext("If the cursor is not very visible then (cvvis) has failed.  ");
610                 } else {
611                         ptext("(cvvis) Cursor-very-visible is not defined.  ");
612                 }
613                 generic_done_message(t, state, ch);
614                 tc_putp(cursor_normal);
615         }
616 }
617
618 /*
619 **      charset_cnorm(test_list, status, ch)
620 **
621 **      (cnorm) test Cursor normal
622 */
623 static void
624 charset_cnorm(
625         struct test_list *t,
626         int *state,
627         int *ch)
628 {
629         if (cursor_normal) {
630                 ptext("(cnorm) Normal cursor.  ");
631                 tc_putp(cursor_normal);
632                 ptext("If the cursor is not normal then (cnorm) has failed.  ");
633         } else {
634                 ptext("(cnorm) Cursor-normal is not defined.  ");
635         }
636         generic_done_message(t, state, ch);
637 }
638
639 /*
640 **      charset_enacs(test_list, status, ch)
641 **
642 **      test Alternate character set mode and alternate characters
643 **      (acsc) (enacs) (smacs) (rmacs)
644 */
645 static void
646 charset_enacs(
647         struct test_list *t,
648         int *state,
649         int *ch)
650 {
651         int c, i;
652
653         if (enter_alt_charset_mode || acs_chars) {
654                 c = 0;
655                 while (1) {
656                         put_clear();
657                         /*
658                            for terminals that use separate fonts for
659                            attributes (such as X windows) the line
660                            drawing characters must be checked for
661                            each font.
662                         */
663                         if (c >= '0' && c <= '9') {
664                                 test_acs(alt_modes[c - '0'].number);
665                                 set_attr(0);
666                         } else {
667                                 test_acs(0);
668                         }
669
670                         while (1) {
671                                 ptextln("[r] to repeat, [012345789] to test with attributes on, [?] for a list of attributes, anything else to go to next test.  ");
672                                 generic_done_message(t, state, ch);
673                                 if (*ch != '?') {
674                                         break;
675                                 }
676                                 for (i = 0; i <= 9; i++) {
677                                         sprintf(temp, " %d %s %s", i, alt_modes[i].begin_mode,
678                                                 alt_modes[i].name);
679                                         ptextln(temp);
680                                 }
681                         }
682                         if (*ch >= '0' && *ch <= '9') {
683                                 c = *ch;
684                         } else
685                         if (*ch != 'r') {
686                                 break;
687                         }
688                 }
689         } else {
690                 ptext("(smacs) Enter-alt-char-set-mode and (acsc) Alternate-char-set are not defined.  ");
691                 generic_done_message(t, state, ch);
692         }
693 }
694
695 /*
696 **      charset_can_test()
697 **
698 **      Initialize the can_test data base
699 */
700 void
701 charset_can_test(void)
702 {
703         int i;
704
705         for (i = 0; i < 9; i++) {
706                 can_test(alt_modes[i].begin_mode, FLAG_CAN_TEST);
707                 can_test(alt_modes[i].end_mode, FLAG_CAN_TEST);
708         }
709 }