home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume25 / ted / part03 / control.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-06  |  36.4 KB  |  1,174 lines

  1. /*
  2. ** This software is Copyright (c) 1991 by Daniel Weaver.
  3. **
  4. ** Permission is hereby granted to copy, distribute or otherwise
  5. ** use any part of this package as long as you do not try to make
  6. ** money from it or pretend that you wrote it.  This copyright
  7. ** notice must be maintained in any copy made.
  8. **
  9. ** Use of this software constitutes acceptance for use in an AS IS
  10. ** condition. There are NO warranties with regard to this software.
  11. ** In no event shall the author be liable for any damages whatsoever
  12. ** arising out of or in connection with the use or performance of this
  13. ** software.  Any use of this software is at the user's own risk.
  14. **
  15. **  If you make modifications to this software that you feel
  16. **  increases it usefulness for the rest of the community, please
  17. **  email the changes, enhancements, bug fixes as well as any and
  18. **  all ideas to me. This software is going to be maintained and
  19. **  enhanced as deemed necessary by the community.
  20. */
  21. /* terminfo test program control subroutines */
  22.  
  23. #include "curses.h"
  24. #include "ted.h"
  25.  
  26. extern char * malloc();
  27. extern char letters[];
  28. /* CPMS_SHIFT defines the effective range for tty_cpms.
  29.    Low numbers are more accurate at high baud rates and high numbers
  30.    must be used for low baud rates.  The number should be in the
  31.    range of 7 to 11.
  32. */
  33. #define CPMS_SHIFT 11
  34. #define BUMP_CPMS (1 << (CPMS_SHIFT - 1))
  35. static int tty_cpms;  /* characters per micro second shifted left CPMS_SHIFT */
  36.  
  37. #ifdef ACCO
  38. extern FILE *fpacco;
  39. #endif
  40.  
  41. static void
  42. rate_status(tps, test_type, results)
  43. char *tps, *test_type, *results;
  44.    {  /* display the results of the baud rate test */
  45.       int j;
  46.  
  47.       if (has_status_line)
  48.          {
  49.             putp(tparm(to_status_line, 0));
  50.             ptext(test_type);
  51.             putchp(' ');
  52.             ptext(results);
  53.             j = columns - strlen(results) - strlen(test_type) - 2;
  54.             /* pad the line with blanks */
  55.                for ( ; --j > 0; ) putchp(' ');
  56.             putp(from_status_line);
  57.             home_down();
  58.             ptext(tps);
  59.             j = strlen(tps);
  60.          }
  61.       else
  62.          {
  63.             home_down();
  64.             ptext(tps);
  65.             putchp(' ');
  66.             ptext(results);
  67.             j = strlen(tps) + strlen(results) + 1;
  68.          }
  69.       /* pad the line with blanks */
  70.          for ( ; ++j < columns; ) putchp(' ');
  71.    }
  72.  
  73.  
  74. void
  75. find_baud_rate()
  76. {  /* calculate the baud rate from the number of characters sent */
  77.       int j, k, l, sync, upper, test_number;
  78.       long max_time, test_time;
  79.       char cur_num[16];
  80.       static char *test_item[] = {
  81.          "character", "line feed", "clear"};
  82.       long max_rate[3];
  83.       char text_rate[3][16], xxx_per_sec[3][64], summary[3][80];
  84.  
  85.       upper = test_number = reps = 0;
  86.       max_rate[0] = max_rate[1] = max_rate[2] = 0;
  87.       letter = letters[letter_number = 0];
  88.       max_time = 20;
  89.       rate_status("begin baud rate search. ", test_item[test_number], "");
  90.          for (l = 0; l < 3; l++) {
  91.             xxx_per_sec[l][0] = summary[l][0] = '\0';
  92.          }
  93.          for (l = 1; ; ++l) {
  94.             (void) tty_sync_error();
  95.             char_sent = ops = 0;
  96.             start_time = end_time = time(0);
  97.                for (sync = 0; start_time + max_time >= end_time; ) {
  98.                   ++sync;
  99.                   switch (test_number) {
  100.                   case 0:  /* full screen */
  101.                      go_home();
  102.                         for (j = 1; j < lines; j++) {
  103.                               for (k = 0; k < columns; k++)
  104.                                  if (k & 0xF) putchp(letter);
  105.                                  else putchp('.');
  106.                         }
  107.                      ops = char_sent;
  108.                      NEXT_LETTER;
  109.                      break;
  110.                   case 1:  /* scroll */
  111.                      sprintf(temp, "%d", sync);
  112.                      ptextln(temp);
  113.                         for (j = 0; j < reps; j++) {
  114.                            put_ind();
  115.                         }
  116.                      ops += reps;
  117.                      break;
  118.                   case 2:  /* clear */
  119.                      sprintf(temp, "%d", sync);
  120.                      ptext(temp);
  121.                         for (j = 0; j < reps; j++) {
  122.                            put_clear();
  123.                         }
  124.                      ops += reps;
  125.                      break;
  126.                   }
  127.                   if (sync >= upper)
  128.                      {
  129.                         if (tty_sync_error())
  130.                            {
  131.                               time_pad = FALSE;
  132.                               return;
  133.                            }
  134.                         end_time = time(0);
  135.                         if (start_time + max_time <= end_time) break;
  136.                      }
  137.                }
  138.             test_time = end_time - start_time;
  139.             j = (ops * 10) / test_time;
  140.             three_digit(cur_num, j);
  141.             sprintf(xxx_per_sec[test_number], "%s %ss per second.",
  142.                cur_num, test_item[test_number]);
  143.             if (test_number == 0)
  144.                {
  145.                   tty_baud_rate = j =
  146.                      ((char_sent >> 1) * tty_frame_size) / test_time;
  147.                   three_digit(cur_num, j * 10);
  148.                }
  149.             if (j > max_rate[test_number])
  150.                {
  151.                   max_rate[test_number] = j;
  152.                   strcpy(text_rate[test_number], cur_num);
  153.                }
  154.             sprintf(summary[test_number],
  155.                "test %d: %d sec. Cur: %s Max: %s",
  156.                l, end_time - start_time,
  157.                cur_num, text_rate[test_number]);
  158.             rate_status(xxx_per_sec[test_number], test_item[test_number],
  159.                summary[test_number]);
  160.             if (sync > upper)
  161.                {
  162.                   if (upper == 0 && reps != 0 && sync > test_time)
  163.                      {  /* this should help it converge */
  164.                         reps = ops / test_time;
  165.                         sync = test_time + 1;
  166.                      }
  167.                   upper = sync;
  168.                   continue;
  169.                }
  170.             j = wait_here();
  171.             if (j == 'r' | j == 'R') ;
  172.             else
  173.             if (j == '>')
  174.                {
  175.                   upper *= 2;
  176.                   max_time *= 2;
  177.                }
  178.             else
  179.             if (j == '<')
  180.                {
  181.                   upper = (upper + 1) / 2;
  182.                   max_time /= 2;
  183.                }
  184.             else
  185.             if (j >= '0' & j <= '2')
  186.                {
  187.                   j -= '0';
  188.                   if (j != test_number)
  189.                      {
  190.                         upper = 0;
  191.                         switch (j) {
  192.                            case 0:  reps = 0;  break;
  193.                            case 1:
  194.                               if (max_rate[j])
  195.                                  {
  196.                                     reps = max_rate[j] / 10;
  197.                                     upper = max_time;
  198.                                  }
  199.                               else reps = 100;
  200.                               break;
  201.                            case 2:
  202.                               if (max_rate[j])
  203.                                  {
  204.                                     reps = max_rate[j] / 10;
  205.                                     upper = max_time;
  206.                                  }
  207.                               else reps = 10;
  208.                               break;
  209.                         }
  210.                      }
  211.                   test_number = j;
  212.                   if (test_number != 0 && xon_xoff == 0)
  213.                      {
  214.                         ptext("\nWarning:  Terminal not set for XON/XOFF.");
  215.                         (void) wait_here();
  216.                      }
  217.                }
  218.             else break;
  219.             if (test_number == 0) rate_status(xxx_per_sec[test_number],
  220.                test_item[test_number], summary[test_number]);
  221.          }
  222.       tty_baud_rate = max_rate[0];
  223.       if (has_status_line) putp(dis_status_line);
  224.       put_clear();
  225.          for (l = 0; l < 3; l++) {
  226.             if (xxx_per_sec[l][0])
  227.                {
  228.                   ptext(xxx_per_sec[l]);
  229.                   putchp(' ');
  230.                   ptextln(summary[l]);
  231.                }
  232.          }
  233.    }
  234.  
  235.  
  236. void
  237. verify_time()
  238.    {  /* verify that the time tests are ready to run */
  239.       int i, j;
  240.       long read_time;
  241.  
  242.       if (stop_testing) return;
  243.       maybe_wait(6);
  244.       fflush(stdout);
  245.       sleep(1);
  246.       if (stty_query(TTY_CHAR_MODE))
  247.          put_str("Hit lower case g to start testing...");
  248.       else put_str("Hit lower case g and CR to start testing...");
  249.       i = tty_sync_error();
  250.       if (i == FALSE) i = getchp(STRIP_PARITY);
  251.       if (i != 'g')
  252.          {
  253.             /* Either the terminal did not respond or the user
  254.                does not like us.  If the terminal returned nothing
  255.                then (i & 255) will equal 'g'.  If the terminal
  256.                returned too many characters then we should scan
  257.                the input for the 'g'.  If the user refuses to type
  258.                a 'g' then try to cut him a break.  */
  259.             tty_can_sync = FALSE;
  260.             ptext("\nThis program expects the ENQ sequence to be");
  261.             ptext(" answered with the ACK character.  This will help");
  262.             ptext(" the program reestablish synchronization when");
  263.             ptextln(" the terminal is overrun with data."); 
  264.             ptext("\nENQ sequence: ");  putln(expand(tty_ENQ));
  265.             ptext("ACK recieved: ");  putln(expand(tty_ACK));
  266.             sprintf(temp, "Length of ACK %d.  Expected length of ACK %d.",
  267.                strlen(tty_ACK), junk_chars + 1);
  268.             ptextln(temp);
  269.             temp[0] = ACK_char;  temp[1] = '\0';
  270.             ptext("Terminating character: ");  putln(expand(temp));
  271.             j = wait_here();
  272.             if (!stty_query(TTY_CHAR_MODE) || (i & 255) == 'g') return;
  273.             read_time = time(0);
  274.                for (i = 1; i < 20 && j != 'g'; i++) {
  275.                   j = wait_here();
  276.                   if (time(0) - read_time > 2) break;
  277.                }
  278.             return;
  279.          }
  280.       tty_can_sync = 2;
  281.       if (tty_baud_rate == 0)
  282.          {
  283.             find_baud_rate();
  284.             if (tty_baud_rate == 0)
  285.                {
  286.                   ptextln("unable to determine baud rate.");
  287.                   (void) wait_here();
  288.                }
  289.          }
  290.    }
  291.  
  292.  
  293. void
  294. control_init()
  295.    {  /* called when baud rate or test length changes */
  296.       if (test_length <= 0) test_length = 1;
  297.       full_test = ((tty_baud_rate * test_length) / tty_frame_size) << 1;
  298.       char_max = full_test;
  299.       /* the following equation should read...
  300.                 (tty_baud_rate << CPMS_SHIFT) + (tty_frame_size / 2) * 5000)
  301.       tty_cpms = -----------------------------------------------------------
  302.                                 (tty_frame_size / 2) * 10000
  303.          but I rewrote it to work with integer arithmetic
  304.       */
  305.       tty_cpms = ((tty_baud_rate << (CPMS_SHIFT - 2)) + tty_frame_size * 625)
  306.          / (tty_frame_size * 1250);
  307.       rated_lines = (lines * tty_baud_rate) / 9600;
  308.       if (rated_lines < 3) rated_lines = 3;
  309.       else
  310.       if (rated_lines > lines) rated_lines = lines;
  311.    }
  312.  
  313.  
  314. #ifdef TESTCAP
  315. int
  316. cap_index(c, l)
  317. char *c;
  318. int l;
  319.    {  /* find the terminfo name in the captrans[] array */
  320.       int i;
  321.  
  322.          for (i = 0; captrans[i]; i++) {
  323.             if (!strncmp(c, captrans[i], l))
  324.                if (captrans[i][l] == ':') return i;
  325.          }
  326.       return -1;
  327.    }
  328.  
  329.  
  330. char *
  331. cap_to_info(c)
  332. char *c;
  333.    {  /* translate the termcap name to a terminfo name */
  334.       int i, j;
  335.       static char tinfo[16];
  336.  
  337.          for (i = 0; captrans[i]; i++) {
  338.                for (j = 0; captrans[i][j]; ) {
  339.                   if (captrans[i][j++] == ':') break;
  340.                }
  341.             if (!strcmp(c, &captrans[i][j])) {
  342.                strncpy(tinfo, captrans[i], j - 1);
  343.                return tinfo;
  344.             }
  345.          }
  346.       return (char *) 0;
  347.    }
  348.  
  349.  
  350. void
  351. pad_time(cap, star, plain)
  352. char *cap;
  353. int *star, *plain;
  354.    {  /* return the pad time in tens of miliseconds */
  355.       int val, dec;
  356.  
  357.       *star = *plain = 0;
  358.       if (!cap) return;
  359.          for (val = dec = 0; *cap; ++cap) {
  360.             if (*cap >= '0' & *cap <= '9') val = val * 10 + *cap - '0';
  361.             else
  362.             if (*cap == '.') dec = 1;
  363.             else break;
  364.          }
  365.       if (!dec) val *= 10;
  366.       if (*cap == '*') *star = val;
  367.       else *plain = val;
  368.    }
  369.  
  370.  
  371. char *
  372. liberated(cap)
  373. char *cap;
  374.    {  /* return the cap without the padding */
  375.       if (cap)
  376.          for ( ; *cap; ++cap) {
  377.             if (*cap != '.' && *cap != '*' &&
  378.                (*cap < '0' | *cap > '9')) break;
  379.          }
  380.       return cap;
  381.    }
  382.  
  383. #else  /* terminfo */
  384.  
  385. void
  386. pad_time(cap, star, plain)
  387. char *cap;
  388. int *star, *plain;
  389.    {  /* return the pad time in tens of miliseconds */
  390.       int dec, i;
  391.  
  392.       *star = *plain = 0;
  393.       if (!cap) return;
  394.          for ( ; *cap; ++cap) {
  395.             if (*cap == '$' & cap[1] == '<')
  396.                {
  397.                   cap += 2;
  398.                      for (i = dec = 0; ; ++cap) {
  399.                         if (!*cap) return;
  400.                         if (*cap >= '0' & *cap <= '9')
  401.                            i = i * 10 + *cap - '0';
  402.                         else
  403.                         if (*cap == '.') dec = 1;
  404.                         else
  405.                         if (*cap == '*')
  406.                            {
  407.                               if (!dec) i *= 10;
  408.                               *star += i;
  409.                               i = 0;
  410.                            }
  411.                         else
  412.                         if (*cap == '>')
  413.                            {
  414.                               if (!dec) i *= 10;
  415.                               *plain += i;
  416.                               break;
  417.                            }
  418.                         else
  419.                         if (*cap != '/') break;
  420.                      }
  421.                }
  422.                
  423.          }
  424.    }
  425.  
  426.  
  427. char *
  428. liberated(cap)
  429. char *cap;
  430.    {  /* return the cap without the padding */
  431.       static char cb[512];
  432.       char *ts, *ls;
  433.  
  434.       cb[0] = '\0';  ls = NULL;
  435.       if (cap)
  436.          for (ts = cb; *ts = *cap; ++cap) {
  437.             if (*cap == '$' && cap[1] == '<') ls = ts;
  438.             ++ts;
  439.             if (*cap == '>')
  440.                if (ls)
  441.                   {
  442.                      ts = ls;  ls = NULL;
  443.                   }
  444.          }
  445.       return cb;
  446.    }
  447. #endif
  448.  
  449.  
  450. int
  451. enter_cap(n, v)
  452. char *n, *v;
  453.    {  /* enter a cap into the cap_list (for time tests) */
  454.       int i;
  455.  
  456.       /* find an empty slot */
  457.          for (i = 0; cap_list[i].value; ++i) {
  458.             if (i >= CAP_MAX) return -1;
  459.             if (!strcmp(cap_list[i].value, v))
  460.                {
  461.                   if (cap_list[i].name && n &&
  462.                      strcmp(cap_list[i].name, n)) continue;
  463.                   if (!cap_list[i].name) cap_list[i].name = n;
  464.                   return i;
  465.                }
  466.          }
  467.       cap_list[i].value = v;
  468.       cap_list[i].name = n;
  469.       cap_list[i].new_star = cap_list[i].new_plain = 32767;
  470.       pad_time(v, &cap_list[i].cur_star, &cap_list[i].cur_plain);
  471.       return i;
  472.    }
  473.  
  474.  
  475. void
  476. print_cap_list()
  477.    {  /* print the cap list created by enter_cap() */
  478.       int i, j, l;
  479.       char b1[16], b2[16], b3[16], fn[128], *s;
  480.       FILE *fp;
  481.  
  482.       sprintf(temp, "Write summary of pad times to ted.%s.  Hit 'x' to abort.", tty_shortname);
  483.       ptext(temp);
  484.       i = wait_here();
  485.       if (i == 'x' | i == 'X') return;
  486.  
  487.       sprintf(fn, "ted.%s", tty_shortname);
  488.       if (!(fp = fopen(fn, "w"))) return;
  489.  
  490.          for (i = 0; cap_list[i].value; ++i) {
  491.             if (cap_list[i].cur_star == 0) b1[0] = '\0';
  492.             else sprintf(b1, "%3d.%d*",
  493.                cap_list[i].cur_star / 10,
  494.                cap_list[i].cur_star % 10);
  495.             if (cap_list[i].new_plain == 32767) b2[0] = '\0';
  496.             else sprintf(b2, "%3d.%d",
  497.                cap_list[i].new_plain / 10,
  498.                cap_list[i].new_plain % 10);
  499.             if (cap_list[i].new_star == 32767) b3[0] = '\0';
  500.             else sprintf(b3, "%3d.%d*",
  501.                cap_list[i].new_star / 10,
  502.                cap_list[i].new_star % 10);
  503.             if (cap_list[i].name)
  504.                {
  505.                   s = cap_list[i].name;
  506. #ifdef TESTCAP
  507.                   l = strlen(s);
  508.                   j = cap_index(s, l);
  509.                   if (j >= 0) s = &captrans[j][l + 1];
  510. #endif
  511.                }
  512.             else s = "";
  513.             sprintf(temp, "%-5s %3d.%d %6s %5s %6s %s", s,
  514.                cap_list[i].cur_plain / 10,
  515.                cap_list[i].cur_plain % 10,
  516.                b1, b2, b3, print_expand(cap_list[i].value));
  517.             fprintf(fp, "%s\n", temp);
  518.          }
  519.       fclose(fp);
  520.    }
  521.  
  522.  
  523. int
  524. begin_pad_char(clr)
  525. int clr;
  526.    {  /* handle beginning of test response character */
  527.       int ch;
  528.  
  529.          while (1) {
  530.             ch = wait_here();
  531.             if (ch == 'q' || ch == 'Q')
  532.                {
  533.                   ptext("Enter Y to quit:");
  534.                   ch = wait_here();
  535.                   if (ch == 'y' || ch == 'Y')
  536.                      {
  537.                         stop_testing = TRUE;
  538.                         return FALSE;
  539.                      }
  540.                }
  541.             else
  542.             if (ch == 'c' || ch == 'C')
  543.                {
  544.                   put_clear();
  545.                   continue;
  546.                }
  547.             else
  548.             if (ch == '>') test_length *= 2;
  549.             else
  550.             if (ch == '<') test_length /= 2;
  551.             else
  552.                {
  553.                   if (clr) put_clear();
  554.                   char_count = 0;
  555.                   start_time = time(0);
  556.                   return (ch != 'n' && ch != 'N');
  557.                }
  558.             control_init();
  559.             sprintf(temp, "\nPad test will run %d seconds.",
  560.                test_length);
  561.             ptext(temp);
  562.          }
  563.    }
  564.  
  565.  
  566. void
  567. kotex()
  568.    {  /* change the pads for the current test */
  569.       int i, v, ch, star, slash, change, dot;
  570.       char *value;
  571.  
  572.       put_clear();
  573.          for (i = 0; i < EDIT_MAX; i++) {
  574.             if (ced_name[i] && ced_value[i])
  575.                {
  576.                   sprintf(temp, "(%s) %s", ced_name[i], expand(*ced_value[i]));
  577.                   ptextln(temp);
  578.                }
  579.          }
  580.       if (line_count == 0)
  581.          {
  582.             ptext("No valid entry for edit.");
  583.             (void) wait_here();
  584.             return;
  585.          }
  586.       ptextln("Enter new pads.  0 for no pad.  CR for no change.");
  587.          for (i = 0; i < EDIT_MAX; i++) {
  588.             if (ced_name[i] && ced_value[i])
  589.                {
  590.                   sprintf(temp, "\n(%s) ", ced_name[i]);
  591.                   ptext(temp);
  592.                   star = slash = change = FALSE;
  593.                   dot = 0;
  594.                      for (v = 0; ch = getchp(STRIP_PARITY); ) {
  595.                         if (ch >= '0' & ch <= '9')
  596.                            {
  597.                               v = ch - '0' + v * 10;
  598.                               if (dot) dot++;
  599.                            }
  600.                         else
  601.                         if (ch == '*') star = TRUE;
  602. #ifndef TESTCAP
  603.                         else
  604.                         if (ch == '/') slash = TRUE;
  605.                         else
  606.                         if (ch == '.') dot = 1;
  607. #endif
  608.                         else break;
  609.                         change = TRUE;
  610.                         if (stty_query(TTY_NOECHO)) putch(ch);
  611.                      }
  612.                   if (!change) continue;
  613.                      while (dot > 2) {
  614.                         v /= 10;
  615.                         dot--;
  616.                      }
  617.                   if (v == 0) strcpy(temp, liberated(*ced_value[i]));
  618.                   else
  619. #ifdef TESTCAP
  620.                      sprintf(temp, "%d%s%s", v, star ? "*" : "",
  621.                         liberated(*ced_value[i]));
  622. #else
  623.                   if (dot == 2)
  624.                      sprintf(temp, "%s$<%d.%d%s%s>",
  625.                         liberated(*ced_value[i]), v / 10,
  626.                         v % 10, star ? "*" : "", slash ? "/" : "");
  627.                   else
  628.                      sprintf(temp, "%s$<%d%s%s>",
  629.                         liberated(*ced_value[i]),
  630.                         v, star ? "*" : "", slash ? "/" : "");
  631. #endif
  632.                   if (value = malloc(strlen(temp) + 1))
  633.                      strcpy(value, temp);
  634.                   strcpy(temp, liberated(*ced_value[i]));
  635.                   *ced_value[i] = value;
  636.  
  637.                   if (temp[0] == '\0')
  638. #ifdef TESTCAP
  639.                      value = "";
  640. #else
  641.                      value = "$<>";
  642. #endif
  643.                   else
  644.                      {
  645.                         if (value = malloc(strlen(temp) + 1))
  646.                            strcpy(value, temp);
  647.                      }
  648.                   ch = enter_cap(ced_name[i], value);
  649.                   if (dot != 2) v *= 10;
  650.                   if (star) cap_list[ch].new_star = v;
  651.                   else cap_list[ch].new_plain = v;
  652.                   write_ted_file = TRUE;
  653.                }
  654.          }
  655.    }
  656.  
  657.  
  658. int
  659. end_pad_char(clr)
  660. int clr;
  661.    {  /* process the character(s) at the end of a test */
  662.       /* return FALSE if end of loop */
  663.       int ch;
  664.       static char *help[] = {
  665.           "c  -  continue",
  666.           "d  -  double the number of lines (or characters)",
  667.           "h  -  cut number of lines (or characters) in half",
  668.           "i  -  send the reset and init strings",
  669.           "p  -  change the padding for this capibility",
  670.           "q  -  quit (prompts for verification)",
  671.           "r  -  rerun test",
  672.           "n  -  go on to next test",
  673.           "?  -  print this help message",
  674.           "<  -  decrease the time for each test",
  675.           ">  -  increase the time for each test",
  676.           "<number> - change the number of lines (or characters)",
  677.           0};
  678.  
  679.       ch = wait_here();
  680.       set_attr(0);  /* just in case */
  681.          for ( ; ; ) {
  682.             switch (ch) {
  683.             case '?':
  684.                   for (ch = 0; help[ch]; ch++) {
  685.                      ptextln(help[ch]);
  686.                   }
  687.                sprintf(temp, "Tests will affect %d lines (or characters).",
  688.                   augment);
  689.                ptextln(temp);
  690.                sprintf(temp, "Tests will run %d seconds.", test_length);
  691.                ptextln(temp);
  692.                if (debug_level > 0)
  693.                   {
  694.                      sprintf(temp, "cpms = %f %d, pad_sent=%d, milli_pad=%d ",
  695.                         (float)tty_cpms / (float)(1 << CPMS_SHIFT), tty_cpms,
  696.                         pad_sent, milli_pad);
  697.                      ptextln(temp);
  698.                      sprintf(temp, "OUTPUT TRANS %d, NOECHO %d, CHAR MODE %d",
  699.                         stty_query(TTY_OUT_TRANS) != 0,
  700.                         stty_query(TTY_NOECHO) != 0,
  701.                         stty_query(TTY_CHAR_MODE) != 0);
  702.                      ptextln(temp);
  703.                   }
  704.  
  705.                /* in case the "Done" gets eaten */
  706.                ptext(done_test);
  707.                break;
  708.             case '>':
  709.             case '<':
  710.                if (ch == '>') test_length *= 2;
  711.                else test_length /= 2;
  712.                control_init();
  713.                sprintf(temp, "\nPad test will run %d seconds.",
  714.                   test_length);
  715.                ptext(temp);
  716.                break;
  717.             case 'C':
  718.                put_clear();
  719.             case 'c':
  720.                /* continue */
  721.                break;
  722.             case 'd':
  723.             case 'D':
  724.                /* double the test augment */
  725.                augment *= 2;
  726.                sprintf(temp, "\nPad test will affect %d lines (or characters).",
  727.                   augment);
  728.                ptext(temp);
  729.                break;
  730.             case 'h':
  731.             case 'H':
  732.                /* cut the test augment in half */
  733.                augment /= 2;
  734.                sprintf(temp, "\nPad test will affect %d lines (or characters).",
  735.                   augment);
  736.                ptext(temp);
  737.                break;
  738.             case 'i':
  739.             case 'I':
  740.                /* send the reset and init strings */
  741.                reset_init(TRUE);
  742.                putp(exit_insert_mode);
  743.                replace_mode = 1;
  744.                put_mode(exit_attribute_mode);
  745.                break;
  746.             case '0': case '1': case '2': case '3': case '4':
  747.             case '5': case '6': case '7': case '8': case '9':
  748.                /* read a new test augment */
  749.                augment = 0;
  750.                   while(ch >= '0' & ch <= '9')
  751.                      {
  752.                         if (stty_query(TTY_NOECHO)) putch(ch);
  753.                         augment = ch - '0' + augment * 10;
  754.                         ch = getchp(STRIP_PARITY);
  755.                      }
  756.                sprintf(temp, "\nPad test will affect %d lines (or characters).",
  757.                   augment);
  758.                ptext(temp);
  759.                break;
  760.             case 'p':
  761.             case 'P':
  762.                kotex();
  763.                break;
  764.             case 'q':
  765.             case 'Q':
  766.                ptext("Enter Y to quit:");
  767.                ch = wait_here();
  768.                if (ch == 'y' || ch == 'Y')
  769.                   {
  770.                      stop_testing = TRUE;
  771.                      return FALSE;
  772.                   }
  773.                break;
  774.             case 'r':
  775.             case 'R':
  776.                if (augment < 1) augment = 1;
  777.                char_max = full_test;
  778.                put_clear();
  779.                char_sent = 0;
  780.                if (time_pad) return enq_ack();
  781.                start_time = time(0);
  782.                return TRUE;
  783.             case 'n':
  784.             case 'N':
  785.                skip_next = TRUE;
  786.             default:
  787.                if (clr) put_clear();
  788.                return FALSE;
  789.             }
  790.             ptext("\nHit (c,d,h,i,n,p,q,r,<,>,?,<number>,CR) ");
  791.             ch = wait_here();
  792.          }
  793.    }
  794.  
  795.  
  796. int
  797. run_test(cap, msg, acknowledge)
  798. char *cap, *msg;
  799. int acknowledge;
  800.    {  /* used to begin execution of a string capibility test */
  801.       char *s;
  802.  
  803.       if (msg)
  804.          {
  805.             /* look the for first cap */
  806.                for (s = msg; *s && *s != '('; s++);
  807.             can_test(s);
  808.          }
  809.       if (stop_testing) return FALSE;
  810.       if (cap) return TRUE;
  811.       if (msg)
  812.          {
  813.             ptextln(msg);
  814.             if (acknowledge) (void) wait_here();
  815.          }
  816.       return FALSE;
  817.    }
  818.  
  819.  
  820. int
  821. run_mode(caps)
  822. char *caps;
  823.    {  /* used to begin execution of a boolean or numeric capibility */
  824.       can_test(caps);
  825.       if (stop_testing) return FALSE;
  826.       return TRUE;
  827.    }
  828.  
  829.  
  830. int
  831. repeat_test(clr)
  832. int clr;
  833.    {  /* used to end a test */
  834.       int ch;
  835.  
  836.       if (stop_testing) return FALSE;
  837.          for ( ; ; ) {
  838.             switch (ch = wait_here()) {
  839.             case 'C':
  840.                put_clear();
  841.             case 'c':
  842.                /* continue */
  843.                break;
  844.             case 'i':
  845.             case 'I':
  846.                /* send the reset and init strings */
  847.                reset_init(TRUE);
  848.                putp(exit_insert_mode);
  849.                replace_mode = 1;
  850.                put_mode(exit_attribute_mode);
  851.                break;
  852.             case 'q':
  853.             case 'Q':
  854.                ptext("Enter Y to quit:");
  855.                ch = wait_here();
  856.                if (ch == 'y' || ch == 'Y')
  857.                   {
  858.                      stop_testing = TRUE;
  859.                      return FALSE;
  860.                   }
  861.                break;
  862.             case 'r':
  863.             case 'R':
  864.                put_clear();
  865.                return TRUE;
  866.             case 'n':
  867.             case 'N':
  868.                skip_next = TRUE;
  869.             default:
  870.                if (clr) put_clear();
  871.                return FALSE;
  872.             }
  873.             ptext("\nHit (c,i,n,q,r,CR) ");
  874.          }
  875.    }
  876.  
  877.  
  878. void
  879. short_subject(r)
  880. int r;
  881.    {  /* set the value of pad_sent */
  882.       /* acco_pad() accumulates the pad counts in milli_reps and
  883.          milli_pad, then short_subject() converts them to characters and
  884.          stores the result in pad_sent.  Note: milli_pad and milli_rep
  885.          are in tenths of a milli-second. */
  886.  
  887.       pad_sent = 0;
  888.       if (xon_xoff | no_pad_char) pad_sent = ((milli_pad + milli_reps * r)
  889.          * tty_cpms + BUMP_CPMS) >> CPMS_SHIFT;
  890.    }
  891.  
  892.  
  893. int
  894. acco_pad(name, cap)
  895. char *name, *cap;
  896. {  /* ajust the length of the pad test if the user has XON/XOFF set */
  897.       int p;
  898.  
  899.       if ((p = enter_cap(name, cap)) != -1)
  900.          {
  901.             milli_reps += cap_list[p].cur_star;
  902.             milli_pad += cap_list[p].cur_plain;
  903.          }
  904.       short_subject(1);
  905.       return TRUE;
  906. }
  907.  
  908.  
  909. int
  910. begin_test(cap, name, long_name, alt, clr)
  911. char **cap, *name, *long_name, *alt;
  912. int clr;
  913.    {  /* clear the screen and start the test (special case) */
  914.       int ch;
  915.  
  916.       can_test(name);  can_test(alt);
  917.       if (stop_testing) return FALSE;
  918.       if (cap_select && strcmp(cap_select, name))
  919.          if (!alt || (strcmp(cap_select, alt) != 0)) return FALSE;
  920.       if (resume_testing) cap_select = NULL;
  921.       if (*cap)
  922.          {
  923.                for (ch = 0; ch < EDIT_MAX; ced_name[ch++] = NULL);
  924.             ced_value[0] = cap;
  925.             ced_name[0] = name;
  926.             letter = letters[letter_number = 0];
  927.             put_clear();
  928.             clear_select = -1;
  929.             char_max = full_test;
  930.             rerun = FALSE;
  931.             reps = ops = test_count = milli_pad = milli_reps = 0;
  932.             sprintf(done_test, "Done. (%s)", current_test = name);
  933.             capper = enter_cap(current_test, *cap);
  934.             (void) acco_pad(name, *cap);
  935.             if (time_pad) return enq_ack();
  936.             sprintf(temp,
  937.             "Begin (%s) pad test, hit CR to continue, n to skip test",
  938.                name);
  939.             ptext(temp);
  940.             return begin_pad_char(clr);
  941.          }
  942.       sprintf(temp, "(%s) %s, not present", name, long_name);
  943.       ptextln(temp);
  944.       if (!time_pad)
  945.          {
  946.             ch = wait_here();
  947.             if (ch == 'c' || ch == 'C') put_clear();
  948.          }
  949.       return FALSE;
  950.    }
  951.  
  952.  
  953. int
  954. multi_test(error_name, clr, or_bits, and_bits, acco_bits, num_caps,
  955.    cn1, cv1, cn2, cv2, cn3, cv3, cn4, cv4)
  956. int clr, or_bits, and_bits, acco_bits, num_caps;
  957. char *error_name;
  958. char *cn1, *cn2, *cn3, *cn4;
  959. char **cv1, **cv2, **cv3, **cv4;
  960.    {  /* clear the screen and start the test (general case) */
  961.       int ch, i, or_flag, and_flag, select_flag;
  962.       static char name_buffer[128];
  963.  
  964.       ced_name[0] = cn1;  ced_name[1] = cn2;
  965.       ced_name[2] = cn3;  ced_name[3] = cn4;
  966.       ced_value[0] = cv1;  ced_value[1] = cv2;
  967.       ced_value[2] = cv3;  ced_value[3] = cv4;
  968.          for (i = 0; i < num_caps; i++) {
  969.             can_test(ced_name[i]);
  970.          }
  971.       if (stop_testing) return FALSE;
  972.       test_count = milli_pad = milli_reps = 0;
  973.       or_flag = or_bits & 1;
  974.       and_flag = and_bits & 1;
  975.       select_flag = !cap_select;
  976.       name_buffer[0] = '\0';
  977.       ch = 0;
  978. #ifdef ACCO
  979.       fprintf(fpacco, "(");
  980.       if (or_flag)
  981.          fprintf(fpacco, "TRUE");
  982.       else
  983.          for (i = 0; i < num_caps; i++) {
  984.             if ((or_bits >> i) & 2)
  985.                {
  986.                   fprintf(fpacco, "%s", ced_name[i]);
  987.                   if ((or_bits >> i) & -4) fprintf(fpacco, "|");
  988.                }
  989.          }
  990.       fprintf(fpacco, ")|(");
  991.       if (and_flag)
  992.          for (i = 0; i < num_caps; i++) {
  993.             if ((and_bits >> i) & 2)
  994.                {
  995.                   fprintf(fpacco, "%s", ced_name[i]);
  996.                   if ((and_bits >> i) & -4) fprintf(fpacco, "&");
  997.                }
  998.          }
  999.       else
  1000.          fprintf(fpacco, "FALSE");
  1001.       fprintf(fpacco, ") ACCO(");
  1002.          for (i = 0; i < num_caps; i++) {
  1003.             if ((acco_bits >> i) & 2)
  1004.                {
  1005.                   fprintf(fpacco, "%s", ced_name[i]);
  1006.                   if ((acco_bits >> i) & -4) fprintf(fpacco, "+");
  1007.                }
  1008.          }
  1009.       fprintf(fpacco, ") %s\n", error_name ? error_name : "");
  1010. #endif
  1011.          for (i = 0; i < num_caps; i++) {
  1012.             if ((or_bits >> i) & 2)
  1013.                or_flag |= *ced_value[i] != NULL;
  1014.             if ((and_bits >> i) & 2)
  1015.                and_flag &= *ced_value[i] != NULL;
  1016.             if (*ced_value[i] && ((acco_bits >> i) & 2))
  1017.                {
  1018.                   ++ch;
  1019.                   capper = enter_cap(ced_name[i], *ced_value[i]);
  1020.                   (void) acco_pad(ced_name[i], *ced_value[i]);
  1021.                }
  1022.             if (cap_select)
  1023.                select_flag |= strcmp(cap_select, ced_name[i]) == 0;
  1024.             sprintf(&name_buffer[strlen(name_buffer)], "(%s) ", ced_name[i]);
  1025.          }
  1026.       if (!select_flag) return FALSE;
  1027.       if (resume_testing) cap_select = NULL;
  1028.       if (or_flag | and_flag)
  1029.          {
  1030.                for (i = num_caps; i < EDIT_MAX; ced_name[i++] = NULL);
  1031.             sprintf(done_test, "Done. %s", current_test = name_buffer);
  1032.             letter = letters[letter_number = 0];
  1033.             put_clear();
  1034.             clear_select = -1;
  1035.             char_max = full_test;
  1036.             reps = ops = 0;
  1037.             rerun = FALSE;
  1038.             if (ch != 1) capper = -1;
  1039.             if (time_pad) return enq_ack();
  1040.             put_str("Begin ");  ptext(name_buffer);
  1041.             ptext("pad test, hit CR to continue, n to skip test");
  1042.             return begin_pad_char(clr);
  1043.          }
  1044.       ptext(error_name);
  1045.       ptextln(", not present");
  1046.       if (!time_pad)
  1047.          {
  1048.             ch = wait_here();
  1049.             if (ch == 'c' || ch == 'C') put_clear();
  1050.          }
  1051.       return FALSE;
  1052.    }
  1053.  
  1054.  
  1055. static int
  1056. time_test_state(clr)
  1057. int clr;
  1058.    {   /* calculate and report the suggested pad times */
  1059.       long v;
  1060.  
  1061.       /* time is one of the things that UNIX does poorly.
  1062.          So I fuss around with sloppy numbers. */
  1063.       v = end_time - start_time -
  1064.          ((char_sent >> 1) * tty_frame_size) / tty_baud_rate;
  1065.       if (v <= 1 && !rerun) return 0;
  1066.       if (capper == -2)
  1067.          {  /* truely brain damaged terminals come here */
  1068.             v = ((char_sent >> 1) * tty_frame_size)
  1069.                 / (end_time - start_time);
  1070.             sprintf(temp, "This terminal has a maximum effective baud rate of %d. ", v);
  1071.             ptext(temp);
  1072.             ptext(" System load may be to high. ");
  1073.             ptextln(" The results of this test will be incorrect!");
  1074.             return 2;
  1075.          }
  1076.       else
  1077.          {
  1078.             if (ops) v = (v * 10000 + ops / 2) / ops;
  1079.             if (capper == -1) put_str("combined");
  1080.             else
  1081.                {
  1082.                   sprintf(temp, "(%s)", cap_list[capper].name);
  1083.                   ptext(temp);
  1084.                }
  1085.             put_dec(" pad time should be %d.%d milliseconds", v);
  1086.  
  1087.             if (reps)
  1088.                {
  1089.                   sprintf(temp, " for %d reps.", reps);
  1090.                   ptextln(temp);
  1091.                   put_dec("%d.%d* milliseconds per rep", v / reps);
  1092.                }
  1093.             put_crlf();
  1094.  
  1095.             if (capper >= 0)
  1096.                {
  1097.                   if (milli_pad < cap_list[capper].new_plain)
  1098.                      cap_list[capper].new_plain = v;
  1099.                   if (reps != 0 &&
  1100.                      v / reps < cap_list[capper].new_star)
  1101.                      cap_list[capper].new_star = v / reps;
  1102.                   /* if the terminal makes it here once
  1103.                      then we want to report each time.
  1104.                      This forces a smaller number into
  1105.                      the tables.  */
  1106.                   rerun = TRUE;
  1107.                }
  1108.             if (milli_reps != 0 && reps != 0)
  1109.                {
  1110.                   ptext("current value is ");
  1111.                   if (milli_pad)
  1112.                      put_dec("%d.%d milliseconds and ",
  1113.                      milli_pad);
  1114.                   put_dec("%d.%d* milliseconds per rep",
  1115.                      milli_reps);
  1116.                }
  1117.             else put_dec("current value is %d.%d milliseconds", milli_pad);
  1118.             put_crlf();
  1119.             if (clear_select != -1)
  1120.                {
  1121.                   clr_test_value[clear_select] = v;
  1122.                   clr_test_reps[clear_select] = reps;
  1123.                }
  1124.          }
  1125.       return 0;
  1126.    }
  1127.  
  1128.  
  1129. int
  1130. end_test(txt, clr)
  1131. char *txt;
  1132. int clr;
  1133.    {  /* This code is executed at the bottom of each test to print
  1134.          the "Done" message and control the looping of tests */
  1135.       int sync_error;
  1136.  
  1137.       test_count++;
  1138.       if (char_sent < char_max) return TRUE;
  1139.       if (txt) ptext(txt);
  1140.       cap_tested = 1;
  1141.       sync_error = 0;
  1142.       if (tty_can_sync) sync_error = tty_sync_error();
  1143.       if (xon_xoff && sync_error == 0 && test_length >= 10)
  1144.          {
  1145.             end_time = time(0);
  1146.             ptext(done_test);
  1147.             switch (time_test_state(clr)) {
  1148.                case 0:
  1149.                   if (time_pad) return FALSE;
  1150.                   break;
  1151.                case 1:
  1152.                   if (time_pad) return TRUE;
  1153.                   break;
  1154.                case 2:
  1155.                   break;
  1156.                }
  1157.          }
  1158.       else ptext(done_test);
  1159.       ops = 0;
  1160.       return end_pad_char(clr);
  1161.    }
  1162.  
  1163.  
  1164. void
  1165. page_loop()
  1166.    {  /* send CR/LF or go home and bump letter */
  1167.       if (line_count + 2 >= lines)
  1168.          {
  1169.             NEXT_LETTER;
  1170.             go_home();
  1171.          }
  1172.       else put_crlf();
  1173.    }
  1174.