home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume16 / pcomm2 / part07 / vcs.c next >
Encoding:
C/C++ Source or Header  |  1988-09-14  |  9.9 KB  |  482 lines

  1. /*
  2.  * Routines for VCS detection.
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <curses.h>
  7. #include "config.h"
  8. #ifndef OLDCURSES
  9. #include <term.h>
  10. #endif /* OLDCURSES */
  11. #include "vcs.h"
  12.  
  13. static int putc_cnt;
  14. static char putc_buf[VCS_SIZE];
  15.  
  16. /*
  17.  * Test for possible VCS (video command sequence).  A character return
  18.  * code means no match.  An return code greater than 255 means a VCS
  19.  * was found.
  20.  */
  21.  
  22. int
  23. vcs_filter(c)
  24. char c;
  25. {
  26.     extern int vcs_codes[NUM_VCS][VCS_SIZE], vcs_leadin[NUM_VCS];
  27.     extern int num_leadin;
  28.     static int buf[VCS_SIZE];
  29.     static int ptr = 0;
  30.     register int i;
  31.     int maybe, possible;
  32.  
  33.                     /* see if possible */
  34.     possible = 0;
  35.     if (ptr == 0) {
  36.                     /* lead-in less than a space */
  37.         if (c >= ' ')
  38.             return(c & 0xff);
  39.                     /* check the list */
  40.         for (i=0; i<num_leadin; i++) {
  41.             if (c == vcs_leadin[i]) {
  42.                 possible++;
  43.                 break;
  44.             }
  45.         }
  46.         if (!possible)
  47.             return(c & 0xff);
  48.     }
  49.  
  50.                     /* build the string */
  51.     buf[ptr++] = c;
  52.     buf[ptr] = -1;
  53.                     /* test for match */
  54.     maybe = 0;
  55.     for (i=0; i<NUM_VCS; i++) {
  56.         switch (match_codes(buf, vcs_codes[i], i)) {
  57.             case YES:
  58.                 ptr = 0;
  59.                 return(i+256);
  60.             case NO:
  61.                 break;
  62.             case MAYBE:
  63.                 maybe++;
  64.                 break;
  65.         }
  66.     }
  67.                     /* abandon what you've got */
  68.     if (maybe && ptr == VCS_SIZE-1) {
  69.         ptr = 0;
  70.         return(c & 0xff);
  71.     }
  72.                     /* hang on, wait and see */
  73.     if (maybe)
  74.         return(MAYBE);
  75.                     /* a clean miss */
  76.     ptr = 0;
  77.     return(c & 0xff);
  78. }
  79.  
  80. /*
  81.  * See if the two integer arrays "match".  Character parameters are
  82.  * designated by codes > 1000 and ASCII digit parameters are designated
  83.  * by codes > 2000.  Uses a simple linear search, so if NUM_VCS grows
  84.  * this routine will have to mature a bit.
  85.  */
  86.  
  87. static int
  88. match_codes(test, code, k)
  89. int test[], code[], k;
  90. {
  91.     extern int vcs_param[NUM_VCS][5];
  92.     register int i, j;
  93.     int pos, done;
  94.                     /* doesn't exist */
  95.     if (code[0] == -1)
  96.         return(NO);
  97.  
  98.     i = 0;
  99.     j = 0;
  100.     while (i<VCS_SIZE && j<VCS_SIZE) {
  101.                     /* at the end (a match) */
  102.         if (test[i] == -1 && code[j] == -1)
  103.             return(YES);
  104.                     /* ran out of input */
  105.         if (test[i] == -1)
  106.             break;
  107.         /*
  108.          * The char parameter (code 1000) always matches the
  109.          * character.
  110.          */
  111.         if (code[j] >= 1000 && code[j] < 2000) {
  112.             pos = code[j] -1000;
  113.             vcs_param[k][pos] = test[i];
  114.             i++;
  115.             j++;
  116.             continue;
  117.         }
  118.         /*
  119.          * The digit parameter (code 2000) tries to match as many
  120.          * ASCII digits as it can.
  121.          */
  122.         if (code[j] >= 2000) {
  123.             pos = code[j] -2000;
  124.                     /* done with this number? */
  125.             if (vcs_param[k][pos])
  126.                 done = 1;
  127.             else
  128.                 done = 0;
  129.                     /* only digits */
  130.             while (test[i] >= 48 && test[i] <= 57) {
  131.                 if (!done)
  132.                     vcs_param[k][pos] = (vcs_param[k][pos] * 10) + test[i] -48;
  133.                 i++;
  134.             }
  135.                     /* ended in a digit */
  136.             if (test[i] == -1 && code[j+1] != -1) {
  137.                 vcs_param[k][pos] = 0;
  138.                 break;
  139.             }
  140.             j++;
  141.             continue;
  142.         }
  143.                     /* a clean miss */
  144.         if (test[i] != code[j]) {
  145.             for (j=0; j<5; j++)
  146.                 vcs_param[k][j] = 0;
  147.             return(NO);
  148.         }
  149.         i++;
  150.         j++;
  151.     }
  152.                     /* a maybe */
  153.     return(MAYBE);
  154. }
  155.  
  156. /*
  157.  * Build the table of VCS codes.  Actually we cheat... We tell curses(3)
  158.  * to build the strings to perform the function, and then we decipher
  159.  * what it did.
  160.  */
  161.  
  162. void
  163. vcs_table()
  164. {
  165.     extern int vcs_codes[NUM_VCS][VCS_SIZE], vcs_opt[NUM_VCS][10];
  166.     extern int vcs_leadin[NUM_VCS], num_leadin, max_row, max_col;
  167.     int i, j, k, match, temp[VCS_SIZE];
  168.     char *p, *strcpy(), buf[VCS_SIZE], *getenv(), *tparm();
  169.     void fake_it();
  170.  
  171. #ifdef OLDCURSES
  172.     char tcbuf[1024], tb[1024], *t, *cursor_home, *clr_eol, *clr_eos;
  173.     char *clear_screen, *cursor_up, *cursor_down, *cursor_right;
  174.     char *cursor_left, *cursor_address, *getenv(), *tgetstr(), *tgoto();
  175.  
  176.     tgetent(tb, getenv("TERM"));
  177.     t = tcbuf;
  178.  
  179.     cursor_home = tgetstr("ho", &t);
  180.     clr_eol = tgetstr("ce", &t);
  181.     clr_eos = tgetstr("cd", &t);
  182.     clear_screen = tgetstr("cl", &t);
  183.     cursor_up = tgetstr("up", &t);
  184.     cursor_down = tgetstr("do", &t);
  185.     cursor_right = tgetstr("nd", &t);
  186.     cursor_left = tgetstr("le", &t);
  187.     cursor_address = tgetstr("cm", &t);
  188.     max_row = tgetnum("li");
  189.     max_col = tgetnum("co");
  190. #else /* OLDCURSES */
  191.     setupterm(getenv("TERM"), 1, &i);
  192.     max_row = lines;
  193.     max_col = columns;
  194. #endif /* OLDCURSES */
  195.  
  196.     /*
  197.      * Do the easy ones first.  These don't take positional parameters,
  198.      * so all we have to do is strip the padding info.
  199.      */
  200.     for (i=0; i<NUM_VCS; i++) {
  201.         switch (i) {
  202.             case HOME:
  203.                 p = cursor_home;
  204.                 break;
  205.             case CLR_EOL:
  206.                 p = clr_eol;
  207.                 break;
  208.             case CLR_EOS:
  209.                 p = clr_eos;
  210.                 break;
  211.             case CLEAR:
  212.                 p = clear_screen;
  213.                 break;
  214.             case MV_UP:
  215.                 p = cursor_up;
  216.                 break;
  217.             case MV_DOWN:
  218.                 p = cursor_down;
  219.                 break;
  220.             case MV_RIGHT:
  221.                 p = cursor_right;
  222.                 break;
  223.             case MV_LEFT:
  224.                 p = cursor_left;
  225.                 break;
  226.             default:
  227.                 p = "";
  228.                 break;
  229.         }
  230.         /*
  231.          * Either the capability doesn't exist, or we're gonna
  232.          * do this one by hand (i.e.: ones with positional parameters)
  233.          */
  234.         if (!p) {
  235.             vcs_codes[i][0] = -1;
  236.             continue;
  237.         }
  238.                     /* fake an "output" */
  239.         fake_it(p);
  240.                     /* copy what it did */
  241.         j = 0;
  242.         while (putc_buf[j]) {
  243.             vcs_codes[i][j] = putc_buf[j];
  244.             j++;
  245.             if (j == VCS_SIZE-1)
  246.                 break;
  247.         }
  248.         vcs_codes[i][j] = -1;
  249.     }
  250.  
  251.     /*
  252.      * And now for the difficult ones.  The way it's done is: load the
  253.      * string with a few known parameters and then find where the
  254.      * parameters end up.  The vcs_opt[][] array is "free-flowing"
  255.      * and means something only to the routine being used.
  256.      */
  257.                     /* add one to the param */
  258.     if (substr(cursor_address, "%i") > 0)
  259.         vcs_opt[MV_DIRECT][0] = 1;
  260.                     /* decimal codes used */
  261.     if (substr(cursor_address, "%d") > 0)
  262.         vcs_opt[MV_DIRECT][1] = 1;
  263.                     /* character codes used */
  264.     if (substr(cursor_address, "%c") > 0)
  265.         vcs_opt[MV_DIRECT][2] = 1;
  266.                     /* add an offset */
  267.     if (substr(cursor_address, "%+") > 0)
  268.         vcs_opt[MV_DIRECT][3] = 1;
  269.                     /* subtract an offset */
  270.     if (substr(cursor_address, "%-") > 0)
  271.         vcs_opt[MV_DIRECT][4] = 1;
  272.                     /* load with parameters 12 & 34 */
  273. #ifdef OLDCURSES
  274.     fake_it(tgoto(cursor_address, 12, 34));
  275. #else /* OLDCURSES */
  276.     fake_it(tparm(cursor_address, 12, 34));
  277. #endif /* OLDCURSES */
  278.     j = 0;
  279.     while (putc_buf[j]) {
  280.         temp[j] = putc_buf[j];
  281.         j++;
  282.         if (j == VCS_SIZE-1)
  283.             break;
  284.     }
  285.     temp[j] = -1;
  286.                     /* if decimal parameters */
  287.     if (vcs_opt[MV_DIRECT][1]) {
  288.                     /* if add one */
  289.         if (vcs_opt[MV_DIRECT][0])
  290.             sprintf(buf, "13");
  291.         else
  292.             sprintf(buf, "12");
  293.                     /* where is the 12 (or 13)? */
  294.         if ((i = substr(putc_buf, buf)) > 0) {
  295.             temp[i] = 2000;
  296.             temp[i+1] = -2;
  297.         }
  298.         else
  299.             temp[0] = -1;
  300.                     /* if add one */
  301.         if (vcs_opt[MV_DIRECT][0])
  302.             sprintf(buf, "35");
  303.         else
  304.             sprintf(buf, "34");
  305.                     /* where is the 34 (or 35)? */
  306.         if ((i = substr(putc_buf, buf)) > 0) {
  307.             temp[i] = 2001;
  308.             temp[i+1] = -2;
  309.         }
  310.         else
  311.             temp[0] = -1;
  312.     }
  313.                     /* if character parameters */
  314.     if (vcs_opt[MV_DIRECT][2]) {
  315.                     /* original with 12 and 34 */
  316.         strcpy(buf, putc_buf);
  317.                     /* change 12 to 13 */
  318. #ifdef OLDCURSES
  319.         fake_it(tgoto(cursor_address, 13, 34));
  320. #else /* OLDCURSES */
  321.         fake_it(tparm(cursor_address, 13, 34));
  322. #endif /* OLDCURSES */
  323.                     /* where are they different */
  324.         i = 0;
  325.         while (buf[i] != NULL) {
  326.             if (buf[i] != putc_buf[i])
  327.                 break;
  328.             i++;
  329.         }
  330.                     /* sanity checking */
  331.         if (buf[i] == NULL)
  332.             temp[0] = -1;
  333.                     /* if add, what is offset? */
  334.         if (vcs_opt[MV_DIRECT][3])
  335.             vcs_opt[MV_DIRECT][5] = temp[i] - 13;
  336.  
  337.                     /* if subtract, what is offset? */
  338.         if (vcs_opt[MV_DIRECT][4])
  339.             vcs_opt[MV_DIRECT][5] = 13 - temp[i];
  340.  
  341.         temp[i] = 1000;
  342.                     /* change 34 to 35 */
  343. #ifdef OLDCURSES
  344.         fake_it(tgoto(cursor_address, 12, 35));
  345. #else /* OLDCURSES */
  346.         fake_it(tparm(cursor_address, 12, 35));
  347. #endif /* OLDCURSES */
  348.                     /* where are they different */
  349.         i = 0;
  350.         while (buf[i] != NULL) {
  351.             if (buf[i] != putc_buf[i])
  352.                 break;
  353.             i++;
  354.         }
  355.         temp[i] = 1001;
  356.         if (buf[i] == NULL)
  357.             temp[0] = -1;
  358.     }
  359.                     /* strip the -2's out, if any */
  360.     i = 0;
  361.     j = 0;
  362.     while (temp[i] != -1) {
  363.         if (temp[i] != -2)
  364.             vcs_codes[MV_DIRECT][j++] = temp[i];
  365.         i++;
  366.     }
  367.     vcs_codes[MV_DIRECT][j] = -1;
  368.  
  369.     /*
  370.      * Simplify the list.  Some codes are already handled by the
  371.      * virtual screen routines... no need to duplicate them.
  372.      */
  373.     if (vcs_codes[MV_DOWN][0] == '\n')
  374.         vcs_codes[MV_DOWN][0] = -1;
  375.  
  376.     if (vcs_codes[MV_LEFT][0] == 8)
  377.         vcs_codes[MV_LEFT][0] = -1;
  378.  
  379.     /*
  380.      * Often the "clear screen" sequence will contain the "home"
  381.      * sequence... if so, don't duplicate the "home" portion.
  382.      */
  383.     fake_it(cursor_home);
  384.     strcpy(buf, putc_buf);
  385.  
  386.     fake_it(clear_screen);
  387.                     /* if "home" inside "clear screen" */
  388.     if ((k = substr(putc_buf, buf)) >= 0) {
  389.                     /* if at the beginning */
  390.         if (k == 0) {
  391.             i = 0;
  392.             for (j=strlen(buf); j<VCS_SIZE; j++)
  393.                 vcs_codes[CLEAR][i++] = putc_buf[j];
  394.             vcs_codes[CLEAR][i] = -1;
  395.         }
  396.                     /* if at the end */
  397.         else if (strlen(buf)+k == strlen(putc_buf))
  398.             vcs_codes[CLEAR][k] = -1;
  399.     }
  400.                     /* is "clear screen" still unique */
  401.     k = 0;
  402.     for (i=0; i<NUM_VCS; i++) {
  403.         if (vcs_codes[CLEAR][i] == -1 || vcs_codes[CLR_EOS][i] == -1)
  404.             break;
  405.         if (vcs_codes[CLEAR][i] != vcs_codes[CLR_EOS][i]) {
  406.             k++;
  407.             break;
  408.         }
  409.     }
  410.     if (k == 0)
  411.         vcs_codes[CLEAR][0] = -1;
  412.  
  413.     /*
  414.      * Make a list of unique lead-in characters to be used as a
  415.      * simple hash table.
  416.      */
  417.     num_leadin = 0;
  418.     for (i=0; i<NUM_VCS; i++) {
  419.         if (vcs_codes[i][0] == -1)
  420.             continue;
  421.                     /* add any new lead-in character */
  422.         match = 0;
  423.         for (j=0; j<num_leadin; j++) {
  424.             if (vcs_leadin[j] == vcs_codes[i][0])
  425.                 match++;
  426.         }
  427.         if (!match)
  428.             vcs_leadin[num_leadin++] = vcs_codes[i][0];
  429.     }
  430.     return;
  431. }
  432.  
  433. /*
  434.  * The routines that fakes curses(3) into outputing the string info with
  435.  * the padding removed.
  436.  */
  437. static void
  438. fake_it(s)
  439. char *s;
  440. {
  441.     int fake_putc();
  442.  
  443.     putc_cnt = 0;
  444.     putc_buf[0] = NULL;
  445.     tputs(s, 1, fake_putc);
  446.     putc_buf[putc_cnt] = NULL;
  447.     return;
  448. }
  449. static int
  450. fake_putc(c)
  451. char c;
  452. {
  453.     putc_buf[putc_cnt++] = c;
  454.     return(c);
  455. }
  456.  
  457. /*
  458.  * Is string2 contained in string1?  If so, return the offset otherwise
  459.  * return a -1.
  460.  */
  461.  
  462. static int
  463. substr(s1, s2)
  464. char *s1, *s2;
  465. {
  466.     int i, len;
  467.  
  468.     len = strlen(s2);
  469.                     /* not possible */
  470.     if (len > strlen(s1))
  471.         return(-1);
  472.  
  473.     i = 0;
  474.     while (*s1) {
  475.         if (!strncmp(s1, s2, len))
  476.             return(i);
  477.         s1++;
  478.         i++;
  479.     }
  480.     return(-1);
  481. }
  482.