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