]> ncurses.scripts.mit.edu Git - ncurses.git/blob - tack/fun.c
378887217ce91b3119e6b9e4eec93b5ce60607e3
[ncurses.git] / tack / fun.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., 51 Franklin Street, Fifth Floor,
19 ** Boston, MA 02110-1301, USA
20 */
21
22 #include <tack.h>
23
24 MODULE_ID("$Id: fun.c,v 1.9 2006/11/26 00:15:53 tom Exp $")
25
26 /*
27  * Test the function keys on the terminal.  The code for echo tests
28  * lives here too.
29  */
30
31 static void funkey_keys(struct test_list *, int *, int *);
32 static void funkey_meta(struct test_list *, int *, int *);
33 static void funkey_label(struct test_list *, int *, int *);
34 static void funkey_prog(struct test_list *, int *, int *);
35 static void funkey_local(struct test_list *, int *, int *);
36
37 struct test_list funkey_test_list[] = {
38         {0, 0, 0, 0, "e) edit terminfo", 0, &edit_menu},
39         {MENU_CLEAR + FLAG_FUNCTION_KEY, 0, 0, 0, "f) show a list of function keys", show_report, 0},
40         {MENU_NEXT | MENU_CLEAR, 0, "smkx) (rmkx", 0,
41                 "k) test function keys", funkey_keys, 0},
42         {MENU_NEXT, 10, "km", "smm rmm", 0, funkey_meta, 0},
43         {MENU_NEXT, 8, "nlab) (smln) (pln) (rmln", "lw lh", 0, funkey_label, 0},
44         {MENU_NEXT, 2, "pfx", 0, 0, funkey_prog, 0},
45         {MENU_NEXT, 2, "pfloc", 0, 0, funkey_local, 0},
46         {MENU_LAST, 0, 0, 0, 0, 0, 0}
47 };
48
49 static void printer_on(struct test_list *, int *, int *);
50 static void printer_mc0(struct test_list *, int *, int *);
51
52 struct test_list printer_test_list[] = {
53         {0, 0, 0, 0, "e) edit terminfo", 0, &edit_menu},
54         {MENU_NEXT | MENU_CLEAR, 0, "mc4) (mc5) (mc5i", 0, 0, printer_on, 0},
55         {MENU_NEXT | MENU_CLEAR, 0, "mc0", 0, 0, printer_mc0, 0},
56         {MENU_LAST, 0, 0, 0, 0, 0, 0}
57 };
58
59 /* local definitions */
60 static const char **fk_name;
61 static char **fkval;
62 static char **fk_label;         /* function key labels (if any) */
63 static int *fk_tested;
64 static int num_strings = 0;
65
66 static int fkmax = 1;           /* length of longest key */
67 static int got_labels = 0;      /* true if we have some labels */
68 static int key_count = 0;
69 static int end_state;
70
71 /* unknown function keys */
72 #define MAX_FK_UNK 50
73 static char *fk_unknown[MAX_FK_UNK];
74 static int fk_length[MAX_FK_UNK];
75 static int funk;
76
77 /*
78  * Initialize arrays that depend on the actual number of strings.
79  */
80 static void
81 alloc_strings(void)
82 {
83         if (num_strings != MAX_STRINGS) {
84                 num_strings = MAX_STRINGS;
85                 fk_name = (const char **)calloc(num_strings, sizeof(const char *));
86                 fkval = (char **)calloc(num_strings, sizeof(char *));
87                 fk_label = (char **)calloc(num_strings, sizeof(char *));
88                 fk_tested = (int *)calloc(num_strings, sizeof(int));
89         }
90 }
91
92 /*
93 **      keys_tested(first-time, show-help, hex-output)
94 **
95 **      Display a list of the keys not tested.
96 */
97 static void
98 keys_tested(
99         int first_time,
100         int show_help,
101         int hex_output)
102 {
103         int i, l;
104         char outbuf[256];
105
106         alloc_strings();
107         put_clear();
108         tty_set();
109         flush_input();
110         if (got_labels) {
111                 putln("Function key labels:");
112                 for (i = 0; i < key_count; ++i) {
113                         if (fk_label[i]) {
114                                 sprintf(outbuf, "%s %s",
115                                         fk_name[i] ? fk_name[i] : "??", fk_label[i]);
116                                 put_columns(outbuf, (int) strlen(outbuf), 16);
117                         }
118                 }
119                 put_newlines(2);
120         }
121         if (funk) {
122                 putln("The following keys are not defined:");
123                 for (i = 0; i < funk; ++i) {
124                         put_columns(fk_unknown[i], fk_length[i], 16);
125                 }
126                 put_mode(exit_attribute_mode);
127                 put_newlines(2);
128         }
129         if (first_time) {
130                 putln("The following keys are defined:");
131         } else {
132                 putln("The following keys have not been tested:");
133         }
134         if (scan_mode) {
135                 for (i = 0; scan_down[i]; i++) {
136                         if (!scan_tested[i]) {
137                                 if (hex_output) {
138                                         strcpy(outbuf, hex_expand_to(scan_down[i], 3));
139                                 } else {
140                                         strcpy(outbuf, expand(scan_down[i]));
141                                 }
142                                 l = expand_chars;
143                                 if (hex_output) {
144                                         strcat(outbuf, hex_expand_to(scan_up[i], 3));
145                                 } else {
146                                         strcat(outbuf, expand(scan_up[i]));
147                                 }
148                                 expand_chars += l;
149                                 l = strlen(scan_name[i]);
150                                 if (((char_count + 16) & ~15) +
151                                         ((expand_chars + 7) & ~7) + l >= columns) {
152                                         put_crlf();
153                                 } else
154                                 if (char_count + 24 > columns) {
155                                         put_crlf();
156                                 } else if (char_count) {
157                                         putchp(' ');
158                                 }
159                                 put_columns(outbuf, expand_chars, 16);
160                                 put_columns(scan_name[i], l, 8);
161                         }
162                 }
163         } else {
164                 for (i = 0; i < key_count; i++) {
165                         if (!fk_tested[i]) {
166                                 if (hex_output) {
167                                         strcpy(outbuf, hex_expand_to(fkval[i], 3));
168                                 } else {
169                                         strcpy(outbuf, expand(fkval[i]));
170                                 }
171                                 l = strlen(fk_name[i]);
172                                 if (((char_count + 16) & ~15) +
173                                         ((expand_chars + 7) & ~7) + l >= columns) {
174                                         put_crlf();
175                                 } else
176                                 if (char_count + 24 > columns) {
177                                         put_crlf();
178                                 } else
179                                 if (char_count) {
180                                         putchp(' ');
181                                 }
182                                 put_columns(outbuf, expand_chars, 16);
183                                 put_columns(fk_name[i], l, 8);
184                         }
185                 }
186         }
187         put_newlines(2);
188         if (show_help) {
189                 ptextln("Hit any function key.  Type 'end' to quit.  Type ? to update the display.");
190                 put_crlf();
191         }
192 }
193
194 /*
195 **      enter_key(name, value, label)
196 **
197 **      Enter a function key into the data base
198 */
199 void
200 enter_key(
201         const char *name,
202         char *value,
203         char *lab)
204 {
205         int j;
206
207         alloc_strings();
208         if (value) {
209                 j = strlen(value);
210                 fkmax = fkmax > j ? fkmax : j;
211                 /* do not permit duplicates */
212                 for (j = 0; j < key_count; j++) {
213                         if (!strcmp(fk_name[j], name)) {
214                                 return;
215                         }
216                 }
217                 fkval[key_count] = value;
218                 fk_tested[key_count] = 0;
219                 fk_label[key_count] = lab;
220                 fk_name[key_count++] = name;
221                 if (lab) {
222                         got_labels = TRUE;
223                 }
224         }
225 }
226
227
228 static void
229 fresh_line(void)
230 {                               /* clear the line for a new function key line */
231         if (over_strike) {
232                 put_crlf();
233         } else {
234                 put_cr();
235                 if (clr_eol) {
236                         tc_putp(clr_eol);
237                 } else {
238                         put_str("                    \r");
239                 }
240         }
241 }
242
243
244 static int
245 end_funky(int ch)
246 {                               /* return true if this is the end */
247         switch (ch) {
248         case 'e':
249         case 'E':
250                 end_state = 'e';
251                 break;
252         case 'n':
253         case 'N':
254                 if (end_state == 'e') {
255                         end_state = 'n';
256                 } else {
257                         end_state = 0;
258                 }
259                 break;
260         case 'd':
261         case 'D':
262                 if (end_state == 'n') {
263                         end_state = 'd';
264                 } else {
265                         end_state = 0;
266                 }
267                 break;
268         case 'l':
269         case 'L':
270                 if (end_state == 'l') {
271                         end_state = '?';
272                 } else {
273                         end_state = 'l';
274                 }
275                 break;
276         default:
277                 end_state = 0;
278                 break;
279         }
280         return end_state == 'd';
281 }
282
283
284 static int
285 found_match(char *s, int hx, int cc)
286 {                               /* return true if this string is a match */
287         int j, f;
288         char outbuf[256];
289
290         alloc_strings();
291         if (!*s) {
292                 return 0;
293         }
294         if (scan_mode) {
295                 for (j = f = 0; scan_down[j]; j++) {
296                         if (scan_length[j] == 0) {
297                                 continue;
298                         }
299                         if (!strncmp(s, scan_down[j], scan_length[j])) {
300                                 if (!f) {       /* first match */
301                                         put_cr();
302                                         if (hx) {
303                                                 put_str(hex_expand_to(s, 10));
304                                         } else {
305                                                 put_str(expand_to(s, 10));
306                                         }
307                                         f = 1;
308                                 }
309                                 (void) end_funky(scan_name[j][0]);
310                                 put_str(" ");
311                                 put_str(scan_name[j]);
312                                 scan_tested[j] = 1;
313                                 s += scan_length[j];
314                                 if (strncmp(s, scan_up[j], scan_length[j])) {
315                                         put_str(" scan down");
316                                 } else {
317                                         s += scan_length[j];
318                                 }
319                                 if (!*s) {
320                                         break;
321                                 }
322                                 j = -1;
323                         }
324                         if (!strncmp(s, scan_up[j], scan_length[j])) {
325                                 if (!f) {       /* first match */
326                                         put_cr();
327                                         if (hx) {
328                                                 put_str(hex_expand_to(s, 10));
329                                         } else {
330                                                 put_str(expand_to(s, 10));
331                                         }
332                                         f = 1;
333                                 }
334                                 put_str(" ");
335                                 put_str(scan_name[j]);
336                                 put_str(" scan up");
337                                 s += scan_length[j];
338                                 if (!*s) {
339                                         break;
340                                 }
341                                 j = -1;
342                         }
343                 }
344         } else {
345                 for (j = f = 0; j < key_count; j++) {
346                         if (!strcmp(s, fkval[j])) {
347                                 if (!f) {       /* first match */
348                                         put_cr();
349                                         if (hx) {
350                                                 put_str(hex_expand_to(s, 10));
351                                         } else {
352                                                 put_str(expand_to(s, 10));
353                                         }
354                                         f = 1;
355                                 }
356                                 sprintf(outbuf, " (%s)", fk_name[j]);
357                                 put_str(outbuf);
358                                 if (fk_label[j]) {
359                                         sprintf(outbuf, " <%s>", fk_label[j]);
360                                         put_str(outbuf);
361                                 }
362                                 fk_tested[j] = 1;
363                         }
364                 }
365         }
366         if (end_state == '?') {
367                 keys_tested(0, 1, hx);
368                 tty_raw(cc, char_mask);
369                 end_state = 0;
370         }
371         return f;
372 }
373
374
375 static int
376 found_exit(char *keybuf, int hx, int cc)
377 {                               /* return true if the user wants to exit */
378         int j, k;
379         char *s;
380
381
382         if (scan_mode) {
383                 if (*keybuf == '\0') {
384                         return TRUE;
385                 }
386         } else {
387                 /* break is a special case */
388                 if (*keybuf == '\0') {
389                         fresh_line();
390                         tty_set();
391                         ptext("Hit X to exit: ");
392                         if (wait_here() == 'X') {
393                                 return TRUE;
394                         }
395                         keys_tested(0, 1, hx);
396                         tty_raw(cc, char_mask);
397                         return FALSE;
398                 }
399                 /* is this the end? */
400                 for (k = 0; (j = (keybuf[k] & STRIP_PARITY)); k++) {
401                         if (end_funky(j)) {
402                                 return TRUE;
403                         }
404                 }
405
406                 j = TRUE;       /* does he need an updated list? */
407                 for (k = 0; keybuf[k]; k++) {
408                         j &= (keybuf[k] & STRIP_PARITY) == '?';
409                 }
410                 if (j || end_state == '?') {
411                         keys_tested(0, 1, hx);
412                         tty_raw(cc, char_mask);
413                         end_state = 0;
414                         return FALSE;
415                 }
416         }
417
418         put_cr();
419         if (hx) {
420                 s = hex_expand_to(keybuf, 10);
421         } else {
422                 s = expand_to(keybuf, 10);
423         }
424         sprintf(temp, "%s Unknown", s);
425         put_str(temp);
426         for (j = 0; j < MAX_FK_UNK; j++) {
427                 if (j == funk) {
428                         fk_length[funk] = expand_chars;
429                         if ((fk_unknown[funk] = (char *)malloc(strlen(s) + 1))) {
430                                 strcpy(fk_unknown[funk++], s);
431                         }
432                         break;
433                 }
434                 if (fk_length[j] == expand_chars) {
435                         if (!strcmp(fk_unknown[j], s)) {
436                                 break;
437                         }
438                 }
439         }
440         return FALSE;
441 }
442
443 /*
444 **      funkey_keys(test_list, status, ch)
445 **
446 **      Test function keys
447 */
448 static void
449 funkey_keys(
450         struct test_list *t,
451         int *state,
452         int *ch)
453 {
454         char keybuf[256];
455
456         if (keypad_xmit) {
457                 tc_putp(keypad_xmit);
458         }
459         keys_tested(1, 1, hex_out);     /* also clears screen */
460         keybuf[0] = '\0';
461         end_state = 0;
462         if (scan_mode) {
463                 fkmax = scan_max;
464         }
465         tty_raw(0, char_mask);
466         while (end_state != 'd') {
467                 read_key(keybuf, sizeof(keybuf));
468                 fresh_line();
469                 if (found_match(keybuf, hex_out, 0)) {
470                         continue;
471                 }
472                 if (found_exit(keybuf, hex_out, 0)) {
473                         break;
474                 }
475         }
476         if (keypad_local) {
477                 tc_putp(keypad_local);
478         }
479         keys_tested(0, 0, hex_out);
480         ptext("Function key test ");
481         generic_done_message(t, state, ch);
482 }
483
484 int
485 tty_meta_prep(void)
486 {                               /* print a warning before the meta key test */
487         if (not_a_tty) {
488                 return 0;
489         }
490         if (initial_stty_query(TTY_8_BIT)) {
491                 return 0;
492         }
493         ptext("The meta key test must be run with the");
494         ptext(" terminal set for 8 data bits.  Two stop bits");
495         ptext(" may also be needed for correct display.  I will");
496         ptext(" transmit 8 bit data but if the terminal is set for");
497         ptextln(" 7 bit data, garbage may appear on the screen.");
498         return 1;
499 }
500
501 /*
502 **      funkey_meta(test_list, status, ch)
503 **
504 **      Test meta key (km) (smm) (rmm)
505 */
506 static void
507 funkey_meta(
508         struct test_list *t,
509         int *state,
510         int *ch)
511 {
512         int i, j, k, len;
513         char outbuf[256];
514
515         if (has_meta_key) {
516                 put_crlf();
517                 if (char_mask != ALLOW_PARITY) {
518                         if (tty_meta_prep()) {
519                                 ptext("\nHit any key to continue > ");
520                                 (void) wait_here();
521                                 put_crlf();
522                         }
523                 }
524                 ptext("Begin meta key test. (km) (smm) (rmm)  Hit any key");
525                 ptext(" with the meta key.  The character will be");
526                 ptext(" displayed in hex.  If the meta key is working");
527                 ptext(" then the most significant bit will be set.  Type");
528                 ptextln(" 'end' to exit.");
529                 tty_raw(1, ALLOW_PARITY);
530                 tc_putp(meta_on);
531
532                 for (i = j = k = len = 0; i != 'e' || j != 'n' || k != 'd';) {
533                         i = j;
534                         j = k;
535                         k = getchp(ALLOW_PARITY);
536                         if (k == EOF) {
537                                 break;
538                         }
539                         if ((len += 3) >= columns) {
540                                 put_crlf();
541                                 len = 3;
542                         }
543                         sprintf(outbuf, "%02X ", k);
544                         put_str(outbuf);
545                         k &= STRIP_PARITY;
546                 }
547                 tc_putp(meta_off);
548                 put_crlf();
549                 tty_set();
550                 put_crlf();
551         } else {
552                 ptext("(km) Has-meta-key is not set.  ");
553         }
554         generic_done_message(t, state, ch);
555 }
556
557 /*
558 **      funkey_label(test_list, status, ch)
559 **
560 **      Test labels (nlab) (smln) (pln) (rmln) (lw) (lh)
561 */
562 static void
563 funkey_label(
564         struct test_list *t,
565         int *state,
566         int *ch)
567 {
568         int i;
569         char outbuf[256];
570
571         if (num_labels == -1) {
572                 ptextln("Your terminal has no labels. (nlab)");
573         } else {
574                 sprintf(temp, "Your terminal has %d labels (nlab) that are %d characters wide (lw) and %d lines high (lh)",
575                         num_labels, label_width, label_height);
576                 ptext(temp);
577                 ptextln(" Testing (smln) (pln) (rmln)");
578                 if (label_on) {
579                         tc_putp(label_on);
580                 }
581                 if (label_width <= 0) {
582                         label_width = sizeof(outbuf) - 1;
583                 }
584                 for (i = 1; i <= num_labels; i++) {
585                         sprintf(outbuf, "L%d..............................", i);
586                         outbuf[label_width] = '\0';
587                         tc_putp(TPARM_2(plab_norm, i, outbuf));
588                 }
589                 if (label_off) {
590                         ptext("Hit any key to remove the labels: ");
591                         (void) wait_here();
592                         tc_putp(label_off);
593                 }
594         }
595         generic_done_message(t, state, ch);
596 }
597
598 /*
599 **      funkey_prog(test_list, status, ch)
600 **
601 **      Test program function keys (pfx)
602 */
603 static void
604 funkey_prog(
605         struct test_list *t,
606         int *state,
607         int *ch)
608 {
609         int i, fk;
610         char mm[256];
611
612         fk = 1; /* use function key 1 for now */
613         if (pkey_xmit) {
614                 /* test program function key */
615                 sprintf(temp,
616                         "(pfx) Set function key %d to transmit abc\\n", fk);
617                 ptextln(temp);
618                 tc_putp(TPARM_2(pkey_xmit, fk, "abc\n"));
619                 sprintf(temp, "Hit function key %d\n", fk);
620                 ptextln(temp);
621                 for (i = 0; i < 4; ++i)
622                         mm[i] = getchp(STRIP_PARITY);
623                 mm[i] = '\0';
624                 put_crlf();
625                 if (mm[0] != 'a' || mm[1] != 'b' || mm[2] != 'c') {
626                         sprintf(temp, "Error string received was: %s", expand(mm));
627                         ptextln(temp);
628                 } else {
629                         putln("Thank you\n");
630                 }
631                 flush_input();
632                 if (key_f1) {
633                         tc_putp(TPARM_2(pkey_xmit, fk, key_f1));
634                 }
635         } else {
636                 ptextln("Function key transmit (pfx), not present.");
637         }
638         generic_done_message(t, state, ch);
639 }
640
641 /*
642 **      funkey_local(test_list, status, ch)
643 **
644 **      Test program local function keys (pfloc)
645 */
646 static void
647 funkey_local(
648         struct test_list *t,
649         int *state,
650         int *ch)
651 {
652         int fk;
653
654         fk = 1;
655         if (pkey_local) {
656                 /* test local function key */
657                 sprintf(temp,
658                         "(pfloc) Set function key %d to execute a clear and print \"Done!\"", fk);
659                 ptextln(temp);
660                 sprintf(temp, "%sDone!", liberated(clear_screen));
661                 tc_putp(TPARM_2(pkey_local, fk, temp));
662                 sprintf(temp, "Hit function key %d.  Then hit return.", fk);
663                 ptextln(temp);
664                 (void) wait_here();
665                 flush_input();
666                 if (key_f1 && pkey_xmit) {
667                         tc_putp(TPARM_2(pkey_xmit, fk, key_f1));
668                 }
669         } else {
670                 ptextln("Function key execute local (pfloc), not present.");
671         }
672
673         generic_done_message(t, state, ch);
674 }
675
676 /*
677 **      printer_on(test_list, status, ch)
678 **
679 **      Test printer on/off (mc4) (mc5) (mc5i)
680 */
681 static void
682 printer_on(
683         struct test_list *t,
684         int *state,
685         int *ch)
686 {
687         if (!prtr_on || !prtr_off) {
688                 ptextln("Printer on/off missing. (mc5) (mc4)");
689         } else if (prtr_silent) {
690                 ptextln("Your printer is silent. (mc5i) is set.");
691                 tc_putp(prtr_on);
692                 ptextln("This line should be on the printer but not your screen. (mc5)");
693                 tc_putp(prtr_off);
694                 ptextln("This line should be only on the screen. (mc4)");
695         } else {
696                 ptextln("Your printer is not silent. (mc5i) is reset.");
697                 tc_putp(prtr_on);
698                 ptextln("This line should be on the printer and the screen. (mc5)");
699                 tc_putp(prtr_off);
700                 ptextln("This line should only be on the screen. (mc4)");
701         }
702         generic_done_message(t, state, ch);
703 }
704
705 /*
706 **      printer_mc0(test_list, status, ch)
707 **
708 **      Test screen print (mc0)
709 */
710 static void
711 printer_mc0(
712         struct test_list *t,
713         int *state,
714         int *ch)
715 {
716         if (print_screen) {
717                 ptext("I am going to send the contents of the screen to");
718                 ptext(" the printer, then wait for a keystroke from you.");
719                 ptext("  All of the text that appears on the screen");
720                 ptextln(" should be printed. (mc0)");
721                 tc_putp(print_screen);
722         } else {
723                 ptext("(mc0) Print-screen is not present.  ");
724         }
725         generic_done_message(t, state, ch);
726 }
727
728
729 static void
730 line_pattern(void)
731 {                               /* put up a pattern that will help count the
732                                    number of lines */
733         int i, j;
734
735         put_clear();
736         if (over_strike) {
737                 for (i = 0; i < 100; i++) {
738                         if (i) {
739                                 put_crlf();
740                         }
741                         for (j = i / 10; j; j--) {
742                                 put_this(' ');
743                         }
744                         put_this('0' + ((i + 1) % 10));
745                 }
746         } else  /* I assume it will scroll */ {
747                 for (i = 100; i; i--) {
748                         sprintf(temp, "\r\n%d", i);
749                         put_str(temp);
750                 }
751         }
752 }
753
754
755 static void
756 column_pattern(void)
757 {                               /* put up a pattern that will help count the
758                                    number of columns */
759         int i, j;
760
761         put_clear();
762         for (i = 0; i < 20; i++) {
763                 for (j = 1; j < 10; j++) {
764                         put_this('0' + j);
765                 }
766                 put_this('.');
767         }
768 }
769
770 /*
771 **      report_help()
772 **
773 **      Print the help text for the echo tests
774 */
775 static void
776 report_help(int crx)
777 {
778         ptextln("The following commands may also be entered:");
779         ptextln(" clear   clear screen.");
780         ptextln(" columns print a test pattern to help count screen width.");
781         ptextln(" lines   print a test pattern to help count screen length.");
782         ptextln(" end     exit.");
783         ptextln(" echo    redisplay last report.");
784         if (crx) {
785                 ptextln(" hex     redisplay last report in hex.");
786         } else {
787                 ptextln(" hex     toggle hex display mode.");
788         }
789         ptextln(" help    display this list.");
790         ptextln(" high    toggle forced high bit (0x80).");
791         ptextln(" scan    toggle scan mode.");
792         ptextln(" one     echo one character after <cr> or <lf> as is. (report mode)");
793         ptextln(" two     echo two characters after <cr> or <lf> as is.");
794         ptextln(" all     echo all characters after <cr> or <lf> as is. (echo mode)");
795 }
796
797 /*
798 **      tools_report(testlist, state, ch)
799 **
800 **      Run the echo tool and report tool
801 */
802 void
803 tools_report(
804         struct test_list *t,
805         int *state GCC_UNUSED,
806         int *pch GCC_UNUSED)
807 {
808         int i, j, ch, crp, crx, high_bit, save_scan_mode, hex_display;
809         char buf[1024];
810         char txt[8];
811
812         hex_display = hex_out;
813         put_clear();
814         if ((crx = (t->flags & 255)) == 1) {
815                 ptext("Characters after a CR or LF will be echoed as");
816                 ptextln(" is.  All other characters will be expanded.");
817                 report_help(crx);
818         } else {        /* echo test */
819                 ptextln("Begin echo test.");
820                 report_help(crx);
821         }
822         memset(txt, 0, sizeof(txt));
823         save_scan_mode = scan_mode;
824         tty_raw(1, char_mask);
825         for (i = crp = high_bit = 0;;) {
826                 ch = getchp(char_mask);
827                 if (ch == EOF) {
828                         break;
829                 }
830                 if (i >= (int) sizeof(buf) - 1) {
831                         i = 0;
832                 }
833                 buf[i++] = ch;
834                 buf[i] = '\0';
835                 for (j = 0; j < (int) sizeof(txt) - 1; j++) {
836                         txt[j] = txt[j + 1];
837                 }
838                 txt[sizeof(txt) - 1] = ch & STRIP_PARITY;
839                 if (crx == 0) { /* echo test */
840                         if (hex_display) {
841                                 ptext(hex_expand_to(&buf[i - 1], 3));
842                         } else {
843                                 tc_putch(ch | high_bit);
844                         }
845                 } else /* status report test */
846                 if (ch == '\n' || ch == '\r') {
847                         put_crlf();
848                         crp = 0;
849                 } else if (crp++ < crx) {
850                         tc_putch(ch | high_bit);
851                 } else {
852                         put_str(expand(&buf[i - 1]));
853                 }
854                 if (!strncmp(&txt[sizeof(txt) - 7], "columns", 7)) {
855                         column_pattern();
856                         buf[i = 0] = '\0';
857                         crp = 0;
858                 }
859                 if (!strncmp(&txt[sizeof(txt) - 5], "lines", 5)) {
860                         line_pattern();
861                         buf[i = 0] = '\0';
862                         crp = 0;
863                 }
864                 if (!strncmp(&txt[sizeof(txt) - 5], "clear", 5)) {
865                         put_clear();
866                         buf[i = 0] = '\0';
867                         crp = 0;
868                 }
869                 if (!strncmp(&txt[sizeof(txt) - 4], "high", 4)) {
870                         high_bit ^= 0x80;
871                         if (high_bit) {
872                                 ptextln("\nParity bit set");
873                         } else {
874                                 ptextln("\nParity bit reset");
875                         }
876                 }
877                 if (!strncmp(&txt[sizeof(txt) - 4], "help", 4)) {
878                         put_crlf();
879                         report_help(crx);
880                 }
881                 if (!strncmp(&txt[sizeof(txt) - 4], "echo", 4)) {
882                         /* display the last status report */
883                         /* clear bypass condition on Tek terminals */
884                         put_crlf();
885                         if (i >= 4) {
886                                 buf[i -= 4] = '\0';
887                         }
888                         put_str(expand(buf));
889                 }
890                 if (save_scan_mode &&
891                         !strncmp(&txt[sizeof(txt) - 4], "scan", 4)) {
892                         /* toggle scan mode */
893                         scan_mode = !scan_mode;
894                 }
895                 if (!strncmp(&txt[sizeof(txt) - 3], "end", 3))
896                         break;
897                 if (!strncmp(&txt[sizeof(txt) - 3], "hex", 3)) {
898                         if (crx) {
899                                 /* display the last status report in hex */
900                                 /* clear bypass condition on Tek terminals */
901                                 put_crlf();
902                                 if (i >= 3) {
903                                         buf[i -= 3] = '\0';
904                                 }
905                                 put_str(hex_expand_to(buf, 3));
906                         } else {
907                                 hex_display = !hex_display;
908                         }
909                 }
910                 if (!strncmp(&txt[sizeof(txt) - 3], "two", 3))
911                         crx = 2;
912                 if (!strncmp(&txt[sizeof(txt) - 3], "one", 3))
913                         crx = 1;
914                 if (!strncmp(&txt[sizeof(txt) - 3], "all", 3))
915                         crx = 0;
916         }
917         scan_mode = save_scan_mode;
918         put_crlf();
919         tty_set();
920         if (crx) {
921                 ptextln("End of status report test.");
922         } else {
923                 ptextln("End of echo test.");
924         }
925 }