/* ** sync_clear(test_list, status, ch) ** ** How many clear-screens/second? */ static void sync_clear( struct test_list *t, int *state, int *ch) { int j; if (!clear_screen) { ptext("Terminal can not clear-screen. "); generic_done_message(t, state, ch); return; } if (skip_pad_test(t, state, ch, "(clear) Start clear-screen performance test")) { return; } pad_test_startup(0); repeats = 20; do { sprintf(temp, "%d", test_complete); put_str(temp); for (j = 0; j < repeats; j++) { put_clear(); } } while(still_testing()); pad_test_shutdown(t, 0); j = sliding_scale(tx_count[0], 1000000, usec_run_time); if (j > tty_clear_rate) { tty_clear_rate = j; } sprintf(temp, "%d clear-screens per second. ", j); ptext(temp); generic_done_message(t, state, ch); }
/* ** subtest_xt(test_list, status, ch) ** ** (xt) glitch */ static void subtest_xt( struct test_list *t, int *state, int *ch) { int tabat; /* the tab spacing we end up with */ int cc; tabat = set_tab ? 8 : init_tabs; if (!over_strike && (tabat > 0)) { ptext("(xt) should not "); put_cr(); ptext("(xt) should"); cc = char_count; while (cc < 16) { putchp('\t'); cc = ((cc / tabat) + 1) * tabat; } putln("be set."); sprintf(temp, "(xt) Destructive-tab is %s in the data base.", dest_tabs_magic_smso ? "true" : "false"); ptextln(temp); generic_done_message(t, state, ch); } }
/* ** funkey_keys(test_list, status, ch) ** ** Test function keys */ static void funkey_keys( TestList * t, int *state, int *ch) { char keybuf[256]; if (keypad_xmit) { tc_putp(keypad_xmit); } keys_tested(1, 1, hex_out); /* also clears screen */ keybuf[0] = '\0'; end_state = 0; if (scan_mode) { fkmax = scan_max; } tty_raw(0, char_mask); while (end_state != 'd') { read_key(keybuf, sizeof(keybuf)); fresh_line(); if (found_match(keybuf, hex_out, 0)) { continue; } if (found_exit(keybuf, hex_out, 0)) { break; } } if (keypad_local) { tc_putp(keypad_local); } keys_tested(0, 0, hex_out); ptext("Function key test "); generic_done_message(t, state, ch); }
/* ** subtest_xmc(test_list, status, ch) ** ** (xmc) magic cookie glitch */ static void subtest_xmc( struct test_list *t, int *state, int *ch) { int i, j; if (enter_standout_mode) { sprintf(temp, "\n(xmc) Magic-cookie-glitch is %d in the data base", magic_cookie_glitch); ptextln(temp); j = magic_cookie_glitch * 8; for (i = 0; i < j; i++) { put_str(" "); } ptextln(" These two lines should line up."); if (j > 0) { char_count += j; } for (i = 0; i < 4; i++) { put_mode(enter_standout_mode); putchp(' '); put_mode(exit_standout_mode); putchp(' '); } ptextln("These two lines should line up."); ptext("If they don't line up then (xmc) magic-cookie-glitch should be greater than zero. "); generic_done_message(t, state, ch); } }
/* ** sync_lines(test_list, status, ch) ** ** How many newlines/second? */ static void sync_lines( struct test_list *t, int *state, int *ch) { int j; if (skip_pad_test(t, state, ch, "(nel) Start scroll performance test")) { return; } pad_test_startup(0); repeats = 100; do { sprintf(temp, "%d", test_complete); put_str(temp); put_newlines(repeats); } while(still_testing()); pad_test_shutdown(t, 0); j = sliding_scale(tx_count[0], 1000000, usec_run_time); if (j > tty_newline_rate) { tty_newline_rate = j; } sprintf(temp, "%d linefeeds per second. ", j); ptext(temp); generic_done_message(t, state, ch); }
/* ** crum_os(test_list, status, ch) ** ** (cup) test Cursor position on overstrike terminals */ static void crum_os( struct test_list *t, int *state, int *ch) { int i; if (cursor_address && over_strike) { put_clear(); for (i = 0; i < columns - 2; i++) { tc_putch('|'); } for (i = 1; i < lines - 2; i++) { put_crlf(); tc_putch('_'); } for (i = 0; i < columns - 2; i++) { tputs(TPARM_2(cursor_address, 0, i), lines, tc_putch); tc_putch('+'); } for (i = 0; i < lines - 2; i++) { tputs(TPARM_2(cursor_address, i, 0), lines, tc_putch); tc_putch(']'); tc_putch('_'); } go_home(); put_newlines(3); ptext(" All the characters should look the same. "); generic_done_message(t, state, ch); put_clear(); } }
/* ** subtest_dadb(test_list, status, ch) ** ** (da) (db) data above, (db) data below */ static void subtest_dadb( struct test_list *t, int *state, int *ch) { if (can_clear_screen && scroll_reverse && scroll_forward) { put_clear(); if (scroll_reverse) ptext("(da) Data-above should be set\r"); home_down(); if (scroll_forward) ptext("(db) Data-below should be set\r"); tc_putp(scroll_forward); go_home(); tc_putp(scroll_reverse); tc_putp(scroll_reverse); home_down(); tc_putp(scroll_forward); go_home(); ptextln("\n\n\n\n\nIf the top line is blank then (da) should be false."); ptextln("If the bottom line is blank then (db) should be false."); sprintf(temp, "\n(da) Data-above is %s, and (db) Data-below is %s, in the data base.", memory_above ? "true" : "false", memory_below ? "true" : "false"); ptextln(temp); line_count = lines; } else { ptextln("(da) Data-above, (db) Data-below not tested, scrolls or (clear) is missing."); } generic_done_message(t, state, ch); }
/* ** funkey_local(test_list, status, ch) ** ** Test program local function keys (pfloc) */ static void funkey_local( TestList * t, int *state, int *ch) { if (pkey_local) { int fk = 1; /* test local function key */ sprintf(temp, "(pfloc) Set function key %d to execute a clear and print \"Done!\"", fk); ptextln(temp); sprintf(temp, "%sDone!", liberated(clear_screen)); tc_putp(TPARM_2(pkey_local, fk, temp)); sprintf(temp, "Hit function key %d. Then hit return.", fk); ptextln(temp); (void) wait_here(); flush_input(); if (key_f1 && pkey_xmit) { tc_putp(TPARM_2(pkey_xmit, fk, key_f1)); } } else { ptextln("Function key execute local (pfloc), not present."); } generic_done_message(t, state, ch); }
/* ** funkey_label(test_list, status, ch) ** ** Test labels (nlab) (smln) (pln) (rmln) (lw) (lh) */ static void funkey_label( struct test_list *t, int *state, int *ch) { int i; char outbuf[256]; if (num_labels == -1) { ptextln("Your terminal has no labels. (nlab)"); } else { sprintf(temp, "Your terminal has %d labels (nlab) that are %d characters wide (lw) and %d lines high (lh)", num_labels, label_width, label_height); ptext(temp); ptextln(" Testing (smln) (pln) (rmln)"); if (label_on) { tc_putp(label_on); } if (label_width <= 0) { label_width = sizeof(outbuf) - 1; } for (i = 1; i <= num_labels; i++) { sprintf(outbuf, "L%d..............................", i); outbuf[label_width] = '\0'; tc_putp(TPARM_2(plab_norm, i, outbuf)); } if (label_off) { ptext("Hit any key to remove the labels: "); (void) wait_here(); tc_putp(label_off); } } generic_done_message(t, state, ch); }
/* ** sync_home(test_list, status, ch) ** ** Baudrate test */ void sync_home( struct test_list *t, int *state, int *ch) { int j, k; unsigned long rate; if (!cursor_home && !cursor_address && !row_address) { ptext("Terminal can not home cursor. "); generic_done_message(t, state, ch); return; } if (skip_pad_test(t, state, ch, "(home) Start baudrate search")) { return; } pad_test_startup(1); do { go_home(); for (j = 1; j < lines; j++) { for (k = 0; k < columns; k++) { if (k & 0xF) { put_this(letter); } else { put_this('.'); } } SLOW_TERMINAL_EXIT; } NEXT_LETTER; } while(still_testing()); pad_test_shutdown(t, auto_right_margin == 0); /* note: tty_frame_size is the real framesize times two. This takes care of half bits. */ rate = (tx_cps * tty_frame_size) >> 1; if (rate > tty_baud_rate) { tty_baud_rate = rate; } if (tx_cps > tty_cps) { tty_cps = tx_cps; } sprintf(temp, "%d characters per second. Baudrate %d ", tx_cps, j); ptext(temp); generic_done_message(t, state, ch); }
/* ** funkey_meta(test_list, status, ch) ** ** Test meta key (km) (smm) (rmm) */ static void funkey_meta( TestList * t, int *state, int *ch) { if (has_meta_key) { int i, j, k, len; char outbuf[256]; put_crlf(); if (char_mask != ALLOW_PARITY) { if (tty_meta_prep()) { ptext("\nHit any key to continue > "); (void) wait_here(); put_crlf(); } } ptext("Begin meta key test. (km) (smm) (rmm) Hit any key"); ptext(" with the meta key. The character will be"); ptext(" displayed in hex. If the meta key is working"); ptext(" then the most significant bit will be set. Type"); ptextln(" 'end' to exit."); tty_raw(1, ALLOW_PARITY); tc_putp(meta_on); for (i = j = k = len = 0; i != 'e' || j != 'n' || k != 'd';) { i = j; j = k; k = getchp(ALLOW_PARITY); if (k == EOF) { break; } if ((len += 3) >= columns) { put_crlf(); len = 3; } sprintf(outbuf, "%02X ", k); put_str(outbuf); k &= STRIP_PARITY; } tc_putp(meta_off); put_crlf(); tty_set(); put_crlf(); } else { ptext("(km) Has-meta-key is not set. "); } generic_done_message(t, state, ch); }
/* ** subtest_os(test_list, status, ch) ** ** test over strike mode (os) */ static void subtest_os( struct test_list *t, int *state, int *ch) { ptext("(os) should be true, not false."); put_cr(); ptextln("(os) should be false."); sprintf(temp, "(os) over-strike is %s in the data base. ", over_strike ? "true" : "false"); ptext(temp); generic_done_message(t, state, ch); }
/* ** sync_summary(test_list, status, ch) ** ** Print out the test results. */ static void sync_summary( struct test_list *t, int *state, int *ch) { char size[32]; put_crlf(); ptextln("Terminal size characters/sec linefeeds/sec clears/sec"); sprintf(size, "%dx%d", columns, lines); sprintf(temp, "%-10s%-11s%11d %11d %11d", tty_basename, size, tty_cps, tty_newline_rate, tty_clear_rate); ptextln(temp); generic_done_message(t, state, ch); }
/* ** subtest_mir(test_list, status, ch) ** ** (mir) move in insert mode */ static void subtest_mir( struct test_list *t, int *state, int *ch) { int i; char *s; if (enter_insert_mode && exit_insert_mode && cursor_address) { put_clear(); i = line_count; put_str("\nXXX\nXXX\nXXX\nXXX"); tc_putp(enter_insert_mode); s = tparm(cursor_address, i + 1, 0); tputs(s, lines, tc_putch); putchp('X'); s = tparm(cursor_address, i + 2, 1); tputs(s, lines, tc_putch); putchp('X'); s = tparm(cursor_address, i + 3, 2); tputs(s, lines, tc_putch); putchp('X'); s = tparm(cursor_address, i + 4, 3); tputs(s, lines, tc_putch); putchp('X'); tc_putp(exit_insert_mode); put_newlines(2); ptextln("If you see a 4 by 4 block of X's then (mir) should be true."); sprintf(temp, "(mir) Move-in-insert-mode is %s in the data base", move_insert_mode ? "true" : "false"); ptextln(temp); } else { ptext("(mir) Move-in-insert-mode not tested, "); if (!enter_insert_mode) { ptext("(smir) "); } if (!exit_insert_mode) { ptext("(rmir) "); } if (!cursor_address) { ptext("(cup) "); } ptext("not present. "); } generic_done_message(t, state, ch); }
/* ** printer_mc0(test_list, status, ch) ** ** Test screen print (mc0) */ static void printer_mc0( TestList * t, int *state, int *ch) { if (print_screen) { ptext("I am going to send the contents of the screen to"); ptext(" the printer, then wait for a keystroke from you."); ptext(" All of the text that appears on the screen"); ptextln(" should be printed. (mc0)"); tc_putp(print_screen); } else { ptext("(mc0) Print-screen is not present. "); } generic_done_message(t, state, ch); }
/* ** subtest_msgr(test_list, status, ch) ** ** (msgr) move in sgr mode */ static void subtest_msgr( struct test_list *t, int *state, int *ch) { int i; if (cursor_address && ((enter_standout_mode && exit_standout_mode) || (enter_alt_charset_mode && exit_alt_charset_mode))) { put_crlf(); i = line_count + 1; tputs(tparm(cursor_address, i, 0), lines, tc_putch); put_mode(enter_alt_charset_mode); put_crlf(); /* some versions of the wy-120 can not clear lines or screen when in alt charset mode. If (el) and (ed) are defined then I can test them. If they are not defined then they can not break (msgr) */ tc_putp(clr_eos); tc_putp(clr_eol); put_mode(exit_alt_charset_mode); put_mode(enter_standout_mode); putchp('X'); tputs(tparm(cursor_address, i + 2, 1), lines, tc_putch); putchp('X'); tputs(tparm(cursor_address, i + 3, 2), lines, tc_putch); putchp('X'); tputs(tparm(cursor_address, i + 4, 3), lines, tc_putch); putchp('X'); put_mode(exit_standout_mode); put_crlf(); tc_putp(clr_eos); /* OK if missing */ put_crlf(); ptextln("If you see a diagonal line of standout X's then (msgr) should be true. If any of the blanks are standout then (msgr) should be false."); sprintf(temp, "(msgr) Move-in-SGR-mode is %s in the data base", move_standout_mode ? "true" : "false"); ptextln(temp); } else { ptextln("(smso) (rmso) (smacs) (rmacs) missing; (msgr) Move-in-SGR-mode not tested."); } generic_done_message(t, state, ch); }
/* ** subtest_uc(test_list, status, ch) ** ** test underline character (uc) */ static void subtest_uc( struct test_list *t, int *state, int *ch) { if (!over_strike) { if (underline_char) { ucprint("This text should be underlined."); put_crlf(); ptextln("If the above text is not underlined the (uc) has failed."); ptext("Underline-character "); } else { ptext("(uc) underline-character is not defined. "); } generic_done_message(t, state, ch); } }
/* ** funkey_prog(test_list, status, ch) ** ** Test program function keys (pfx) */ static void funkey_prog( TestList * t, int *state, int *ch) { if (pkey_xmit) { int i; int fk = 1; char mm[256]; /* test program function key */ sprintf(temp, "(pfx) Set function key %d to transmit abc\\n", fk); ptextln(temp); tc_putp(TPARM_2(pkey_xmit, fk, "abc\n")); sprintf(temp, "Hit function key %d\n", fk); ptextln(temp); memset(mm, 0, (size_t) 4); for (i = 0; i < 4; ++i) { int cc = getchp(STRIP_PARITY); if (cc == EOF) break; mm[i] = (char) cc; } mm[i] = '\0'; put_crlf(); if (mm[0] != 'a' || mm[1] != 'b' || mm[2] != 'c') { sprintf(temp, "Error string received was: %s", expand(mm)); ptextln(temp); } else { putln("Thank you\n"); } flush_input(); if (key_f1) { tc_putp(TPARM_2(pkey_xmit, fk, key_f1)); } } else { ptextln("Function key transmit (pfx), not present."); } generic_done_message(t, state, ch); }
/* ** subtest_am(test_list, status, ch) ** ** test automatic margins (am) */ static void subtest_am( struct test_list *t, int *state, int *ch) { int i, j; if (!can_go_home) { ptextln("(am) not tested, no way to home cursor. "); } else if (over_strike) { put_clear(); go_home(); ptext("\n(am) should "); i = char_count; ptext("not be set"); go_home(); for (j = -i; j < columns; j++) put_this(' '); put_str("@@@"); go_home(); put_newlines(2); sprintf(temp, "(am) is %s in the data base", auto_right_margin ? "true" : "false"); ptextln(temp); } else { put_clear(); go_home(); ptext("\n(am) should not be set"); go_home(); for (j = 0; j < columns; j++) put_this(' '); ptext("(am) should be set "); go_home(); put_str(" \n\n"); sprintf(temp, "(am) is %s in the data base", auto_right_margin ? "true" : "false"); ptextln(temp); } ptext("Automatic-right-margin "); generic_done_message(t, state, ch); }
/* ** subtest_xhp(test_list, status, ch) ** ** (xhp) erase does not clear standout mode */ static void subtest_xhp( struct test_list *t, int *state, int *ch) { if (enter_standout_mode) { put_crlf(); put_mode(enter_standout_mode); put_str("Stand out"); put_mode(exit_standout_mode); put_cr(); ptextln("If any part of this line is standout then (xhp) should be set."); sprintf(temp, "(xhp) Erase-standout-glitch is %s in the data base", ceol_standout_glitch ? "true" : "false"); ptextln(temp); generic_done_message(t, state, ch); } }
/* ** subtest_rmam(test_list, status, ch) ** ** test exit automatic margins mode (rmam) */ static void subtest_rmam( struct test_list *t, int *state, int *ch) { int j; if (!exit_am_mode) { ptext("(rmam) not present. "); } else if (!can_go_home) { ptext("(rmam) not tested, no way to home cursor. "); } else if (over_strike) { put_clear(); go_home(); tc_putp(exit_am_mode); ptext("\n(rmam) will reset (am)"); go_home(); for (j = 0; j < columns; j++) put_this(' '); ptext("(rmam) will not reset (am)"); go_home(); put_newlines(2); } else { put_clear(); go_home(); tc_putp(exit_am_mode); ptext("\n(rmam) will reset (am)"); go_home(); for (j = 0; j < columns; j++) put_this(' '); ptext("(rmam) will not reset (am) "); go_home(); put_str(" "); go_home(); put_newlines(2); } ptext("Exit-automatic-margins "); generic_done_message(t, state, ch); }
/* ** subtest_smam(test_list, status, ch) ** ** test enter automatic margins mode (smam) */ static void subtest_smam( struct test_list *t, int *state, int *ch) { int i, j; if (!enter_am_mode) { ptext("(smam) not present. "); } else if (!can_go_home) { ptext("(smam) not tested, no way to home cursor. "); } else if (over_strike) { put_clear(); go_home(); tc_putp(enter_am_mode); ptext("\n(smam) will "); i = char_count; ptext("not set (am)"); go_home(); for (j = -i; j < columns; j++) put_this(' '); put_str("@@@"); put_newlines(2); } else { put_clear(); go_home(); tc_putp(enter_am_mode); ptext("\n(smam) will not set (am)"); go_home(); for (j = 0; j < columns; j++) put_this(' '); ptext("(smam) will set (am) "); go_home(); put_str(" "); put_newlines(2); } ptext("Enter-automatic-margins "); generic_done_message(t, state, ch); }
/* ** crum_clear(test_list, status, ch) ** ** (clear) test Clear screen */ static void crum_clear( struct test_list *t, int *state, int *ch) { int i; if (clear_screen) { for (i = lines; i > 1; i--) { putln("garbage"); } put_clear(); ptextln("This line should start in the home position."); ptext("The rest of the screen should be clear. "); } else { ptextln("(clear) Clear screen is not defined. "); } generic_done_message(t, state, ch); }
/* ** subtest_ul(test_list, status, ch) ** ** test transparent underline (ul) */ static void subtest_ul( struct test_list *t, int *state, int *ch) { if (!over_strike) { /* (ul) is used only if (os) is reset */ put_crlf(); sprintf(temp, "This text should %sbe underlined.", transparent_underline ? "" : "not "); uprint(temp); put_crlf(); ptextln("If the above line is not underlined the (ul) should be false."); sprintf(temp, "(ul) Transparent-underline is %s in the data base", transparent_underline ? "true" : "false"); ptextln(temp); generic_done_message(t, state, ch); } }
/* ** subtest_eo(test_list, status, ch) ** ** (eo) erase overstrike */ static void subtest_eo( struct test_list *t, int *state, int *ch) { if (transparent_underline || over_strike || underline_char) { ptext("(eo) should "); if (underline_char) { ucprint("not"); } else { uprint("not"); } put_cr(); ptextln("(eo) should be set"); sprintf(temp, "\n(eo) Erase-overstrike is %s in the data base", erase_overstrike ? "true" : "false"); ptextln(temp); generic_done_message(t, state, ch); } }
/* ** dump_test_stats(test_list, status, ch) ** ** Dump the statistics about the last test */ void dump_test_stats( struct test_list *t, int *state, int *ch) { int i, j; char tbuf[32]; int x[32]; put_crlf(); if (tx_source && tx_source->caps_done) { cap_index(tx_source->caps_done, x); if (x[0] >= 0) { sprintf(temp, "Caps summary for (%s)", tx_source->caps_done); ptextln(temp); for (i = 0; x[i] >= 0; i++) { show_cap_results(x[i]); } put_crlf(); } } sprintf(tbuf, "%011u", usec_run_time); sprintf(temp, "Test time: %d.%s, characters per second %d, characters %d", usec_run_time / 1000000, &tbuf[5], tx_cps, tx_characters); ptextln(temp); for (i = 0; i < txp; i++) { if ((j = get_string_cap_byvalue(tx_cap[i])) >= 0) { sprintf(tbuf, "(%s)", strnames[j]); } else { strcpy(tbuf, "(?)"); } sprintf(temp, "%8d %3d $<%3d> %8s %s", tx_count[i], tx_affected[i], tx_delay[i], tbuf, expand(tx_cap[i])); putln(temp); } generic_done_message(t, state, ch); }
/* ** subtest_in(test_list, status, ch) ** ** (in) insert null glitch */ static void subtest_in( struct test_list *t, int *state, int *ch) { if (enter_insert_mode && exit_insert_mode) { ptextln("\nTesting (in) with (smir) and (rmir)"); putln("\tIf these two lines line up ..."); put_str("\tIf these two lines line up ..."); put_cr(); tc_putp(enter_insert_mode); putchp(' '); tc_putp(exit_insert_mode); ptext("\nthen (in) should be set. "); sprintf(temp, "(in) Insert-null-glitch is %s in the data base.", insert_null_glitch ? "true" : "false"); ptextln(temp); generic_done_message(t, state, ch); } }
/* ** subtest_cbt(test_list, status, ch) ** ** (cbt) back tab */ static void subtest_cbt( struct test_list *t, int *state, int *ch) { int i; if (back_tab) { put_clear(); ptext("Back-tab (cbt)"); go_home(); put_crlf(); for (i = 1; i < columns; i++) { putchp(' '); } for (i = 0; i < columns; i += 8) { tc_putp(back_tab); putchp('T'); tc_putp(back_tab); } go_home(); put_newlines(2); for (i = 1; i < columns; i++) { if (i % 8 == 1) { putchp('T'); } else { putchp(' '); } } go_home(); put_newlines(3); ptextln("The preceding two lines should be the same."); } else { ptextln("(cbt) Back-tab not present"); } generic_done_message(t, state, ch); }
/* ** subtest_bw(test_list, status, ch) ** ** test auto left margin (bw) */ static void subtest_bw( struct test_list *t, int *state, int *ch) { int i, j; if (over_strike) { /* test (bw) */ ptext("\n(bw) should "); i = char_count; ptextln("not be set."); for (j = i; j < columns; j++) put_str("\b"); put_str("@@@"); put_crlf(); sprintf(temp, "(bw) Auto-left-margin is %s in the data base", auto_left_margin ? "true" : "false"); ptextln(temp); } else { /* test (bw) */ ptextln("(bw) should not be set."); for (i = 12; i < columns; i++) put_str("\b"); if (delete_character) { for (i = 0; i < 4; i++) tc_putp(delete_character); } else { put_str(" "); } put_crlf(); sprintf(temp, "(bw) Auto-left-margin is %s in the data base", auto_left_margin ? "true" : "false"); ptextln(temp); } generic_done_message(t, state, ch); }
/* ** printer_on(test_list, status, ch) ** ** Test printer on/off (mc4) (mc5) (mc5i) */ static void printer_on( TestList * t, int *state, int *ch) { if (!prtr_on || !prtr_off) { ptextln("Printer on/off missing. (mc5) (mc4)"); } else if (prtr_silent) { ptextln("Your printer is silent. (mc5i) is set."); tc_putp(prtr_on); ptextln("This line should be on the printer but not your screen. (mc5)"); tc_putp(prtr_off); ptextln("This line should be only on the screen. (mc4)"); } else { ptextln("Your printer is not silent. (mc5i) is reset."); tc_putp(prtr_on); ptextln("This line should be on the printer and the screen. (mc5)"); tc_putp(prtr_off); ptextln("This line should only be on the screen. (mc4)"); } generic_done_message(t, state, ch); }