home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / vgrind / vgrindefs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-16  |  7.6 KB  |  327 lines

  1. /*
  2.  * Copyright (c) 1980 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)vgrindefs.c    5.3 (Berkeley) 6/1/90";
  36. #endif /* not lint */
  37.  
  38. #define    BUFSIZ    1024
  39. #define MAXHOP    32    /* max number of tc= indirections */
  40.  
  41. #include <ctype.h>
  42. /*
  43.  * grindcap - routines for dealing with the language definitions data base
  44.  *    (code stolen almost totally from termcap)
  45.  *
  46.  * BUG:        Should use a "last" pointer in tbuf, so that searching
  47.  *        for capabilities alphabetically would not be a n**2/2
  48.  *        process when large numbers of capabilities are given.
  49.  * Note:    If we add a last pointer now we will screw up the
  50.  *        tc capability. We really should compile termcap.
  51.  *
  52.  * Essentially all the work here is scanning and decoding escapes
  53.  * in string capabilities.  We don't use stdio because the editor
  54.  * doesn't, and because living w/o it is not hard.
  55.  */
  56.  
  57. static    char *tbuf;
  58. static    char *filename;
  59. static    int hopcount;    /* detect infinite loops in termcap, init 0 */
  60. char    *tskip();
  61. char    *tgetstr();
  62. char    *tdecode();
  63. char    *getenv();
  64.  
  65. /*
  66.  * Get an entry for terminal name in buffer bp,
  67.  * from the termcap file.  Parse is very rudimentary;
  68.  * we just notice escaped newlines.
  69.  */
  70. tgetent(bp, name, file)
  71.     char *bp, *name, *file;
  72. {
  73.     register char *cp;
  74.     register int c;
  75.     register int i = 0, cnt = 0;
  76.     char ibuf[BUFSIZ];
  77.     char *cp2;
  78.     int tf;
  79.  
  80.     tbuf = bp;
  81.     tf = 0;
  82.     filename = file;
  83.     tf = open(filename, 0);
  84.     if (tf < 0)
  85.         return (-1);
  86.     for (;;) {
  87.         cp = bp;
  88.         for (;;) {
  89.             if (i == cnt) {
  90.                 cnt = read(tf, ibuf, BUFSIZ);
  91.                 if (cnt <= 0) {
  92.                     close(tf);
  93.                     return (0);
  94.                 }
  95.                 i = 0;
  96.             }
  97.             c = ibuf[i++];
  98.             if (c == '\n') {
  99.                 if (cp > bp && cp[-1] == '\\'){
  100.                     cp--;
  101.                     continue;
  102.                 }
  103.                 break;
  104.             }
  105.             if (cp >= bp+BUFSIZ) {
  106.                 write(2,"Vgrind entry too long\n", 23);
  107.                 break;
  108.             } else
  109.                 *cp++ = c;
  110.         }
  111.         *cp = 0;
  112.  
  113.         /*
  114.          * The real work for the match.
  115.          */
  116.         if (tnamatch(name)) {
  117.             close(tf);
  118.             return(tnchktc());
  119.         }
  120.     }
  121. }
  122.  
  123. /*
  124.  * tnchktc: check the last entry, see if it's tc=xxx. If so,
  125.  * recursively find xxx and append that entry (minus the names)
  126.  * to take the place of the tc=xxx entry. This allows termcap
  127.  * entries to say "like an HP2621 but doesn't turn on the labels".
  128.  * Note that this works because of the left to right scan.
  129.  */
  130. tnchktc()
  131. {
  132.     register char *p, *q;
  133.     char tcname[16];    /* name of similar terminal */
  134.     char tcbuf[BUFSIZ];
  135.     char *holdtbuf = tbuf;
  136.     int l;
  137.  
  138.     p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
  139.     while (*--p != ':')
  140.         if (p<tbuf) {
  141.             write(2, "Bad vgrind entry\n", 18);
  142.             return (0);
  143.         }
  144.     p++;
  145.     /* p now points to beginning of last field */
  146.     if (p[0] != 't' || p[1] != 'c')
  147.         return(1);
  148.     strcpy(tcname,p+3);
  149.     q = tcname;
  150.     while (q && *q != ':')
  151.         q++;
  152.     *q = 0;
  153.     if (++hopcount > MAXHOP) {
  154.         write(2, "Infinite tc= loop\n", 18);
  155.         return (0);
  156.     }
  157.     if (tgetent(tcbuf, tcname, filename) != 1)
  158.         return(0);
  159.     for (q=tcbuf; *q != ':'; q++)
  160.         ;
  161.     l = p - holdtbuf + strlen(q);
  162.     if (l > BUFSIZ) {
  163.         write(2, "Vgrind entry too long\n", 23);
  164.         q[BUFSIZ - (p-tbuf)] = 0;
  165.     }
  166.     strcpy(p, q+1);
  167.     tbuf = holdtbuf;
  168.     return(1);
  169. }
  170.  
  171. /*
  172.  * Tnamatch deals with name matching.  The first field of the termcap
  173.  * entry is a sequence of names separated by |'s, so we compare
  174.  * against each such name.  The normal : terminator after the last
  175.  * name (before the first field) stops us.
  176.  */
  177. tnamatch(np)
  178.     char *np;
  179. {
  180.     register char *Np, *Bp;
  181.  
  182.     Bp = tbuf;
  183.     if (*Bp == '#')
  184.         return(0);
  185.     for (;;) {
  186.         for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
  187.             continue;
  188.         if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
  189.             return (1);
  190.         while (*Bp && *Bp != ':' && *Bp != '|')
  191.             Bp++;
  192.         if (*Bp == 0 || *Bp == ':')
  193.             return (0);
  194.         Bp++;
  195.     }
  196. }
  197.  
  198. /*
  199.  * Skip to the next field.  Notice that this is very dumb, not
  200.  * knowing about \: escapes or any such.  If necessary, :'s can be put
  201.  * into the termcap file in octal.
  202.  */
  203. static char *
  204. tskip(bp)
  205.     register char *bp;
  206. {
  207.  
  208.     while (*bp && *bp != ':')
  209.         bp++;
  210.     if (*bp == ':')
  211.         bp++;
  212.     return (bp);
  213. }
  214.  
  215. /*
  216.  * Return the (numeric) option id.
  217.  * Numeric options look like
  218.  *    li#80
  219.  * i.e. the option string is separated from the numeric value by
  220.  * a # character.  If the option is not found we return -1.
  221.  * Note that we handle octal numbers beginning with 0.
  222.  */
  223. tgetnum(id)
  224.     char *id;
  225. {
  226.     register int i, base;
  227.     register char *bp = tbuf;
  228.  
  229.     for (;;) {
  230.         bp = tskip(bp);
  231.         if (*bp == 0)
  232.             return (-1);
  233.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  234.             continue;
  235.         if (*bp == '@')
  236.             return(-1);
  237.         if (*bp != '#')
  238.             continue;
  239.         bp++;
  240.         base = 10;
  241.         if (*bp == '0')
  242.             base = 8;
  243.         i = 0;
  244.         while (isdigit(*bp))
  245.             i *= base, i += *bp++ - '0';
  246.         return (i);
  247.     }
  248. }
  249.  
  250. /*
  251.  * Handle a flag option.
  252.  * Flag options are given "naked", i.e. followed by a : or the end
  253.  * of the buffer.  Return 1 if we find the option, or 0 if it is
  254.  * not given.
  255.  */
  256. tgetflag(id)
  257.     char *id;
  258. {
  259.     register char *bp = tbuf;
  260.  
  261.     for (;;) {
  262.         bp = tskip(bp);
  263.         if (!*bp)
  264.             return (0);
  265.         if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
  266.             if (!*bp || *bp == ':')
  267.                 return (1);
  268.             else if (*bp == '@')
  269.                 return(0);
  270.         }
  271.     }
  272. }
  273.  
  274. /*
  275.  * Get a string valued option.
  276.  * These are given as
  277.  *    cl=^Z
  278.  * Much decoding is done on the strings, and the strings are
  279.  * placed in area, which is a ref parameter which is updated.
  280.  * No checking on area overflow.
  281.  */
  282. char *
  283. tgetstr(id, area)
  284.     char *id, **area;
  285. {
  286.     register char *bp = tbuf;
  287.  
  288.     for (;;) {
  289.         bp = tskip(bp);
  290.         if (!*bp)
  291.             return (0);
  292.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  293.             continue;
  294.         if (*bp == '@')
  295.             return(0);
  296.         if (*bp != '=')
  297.             continue;
  298.         bp++;
  299.         return (tdecode(bp, area));
  300.     }
  301. }
  302.  
  303. /*
  304.  * Tdecode does the grung work to decode the
  305.  * string capability escapes.
  306.  */
  307. static char *
  308. tdecode(str, area)
  309.     register char *str;
  310.     char **area;
  311. {
  312.     register char *cp;
  313.     register int c;
  314.     int i;
  315.  
  316.     cp = *area;
  317.     while (c = *str++) {
  318.         if (c == ':' && *(cp-1) != '\\')
  319.         break;
  320.         *cp++ = c;
  321.     }
  322.     *cp++ = 0;
  323.     str = *area;
  324.     *area = cp;
  325.     return (str);
  326. }
  327.