home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume23 / mlpd / printcap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-01-08  |  6.7 KB  |  316 lines

  1. /*
  2.  * Copyright (c) 1983 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. static char sccsid[] = "@(#)printcap.c    5.3 (Berkeley) 6/30/88";
  20. #endif /* not lint */
  21.  
  22. #define    BUFSIZ    1024
  23. #define MAXHOP    32    /* max number of tc= indirections */
  24.  
  25. #include <ctype.h>
  26. #include <stdio.h>
  27. /*
  28.  * termcap - routines for dealing with the terminal capability data base
  29.  *
  30.  * BUG:        Should use a "last" pointer in tbuf, so that searching
  31.  *        for capabilities alphabetically would not be a n**2/2
  32.  *        process when large numbers of capabilities are given.
  33.  * Note:    If we add a last pointer now we will screw up the
  34.  *        tc capability. We really should compile termcap.
  35.  *
  36.  * Essentially all the work here is scanning and decoding escapes
  37.  * in string capabilities.  We don't use stdio because the editor
  38.  * doesn't, and because living w/o it is not hard.
  39.  */
  40.  
  41. #define PRINTCAP
  42.  
  43. #ifdef PRINTCAP
  44. #define tgetent    pgetent
  45. #define tskip    pskip
  46. #define tgetstr    pgetstr
  47. #define tdecode pdecode
  48. #define tdecode pdecode
  49. #define tnchktc    pnchktc
  50. #define    tnamatch pnamatch
  51. #undef E_TERMCAP
  52. #define E_TERMCAP "/etc/printcap"
  53. #define V6
  54. #endif
  55.  
  56. static    char *tbuf;
  57. static    int hopcount;        /* detect infinite loops in termcap, init 0 */
  58. char    *tskip();
  59. char    *tgetstr();
  60. char    *tdecode();
  61. char    *getenv();
  62.  
  63. /*
  64.  * Get an entry for terminal name in buffer bp,
  65.  * from the termcap file.  Parse is very rudimentary;
  66.  * we just notice escaped newlines.
  67.  */
  68. tgetent(bp, name)
  69.     char *bp, *name;
  70. {
  71.     register char *cp;
  72.     register int c;
  73.     register int i = 0, cnt = 0;
  74.     char ibuf[BUFSIZ];
  75. #ifndef lint
  76.     char *cp2;
  77. #endif
  78.     int tf;
  79.  
  80.     tbuf = bp;
  81.     tf = 0;
  82. #ifndef V6
  83.     cp = getenv("TERMCAP");
  84.     /*
  85.      * TERMCAP can have one of two things in it. It can be the
  86.      * name of a file to use instead of /etc/termcap. In this
  87.      * case it better start with a "/". Or it can be an entry to
  88.      * use so we don't have to read the file. In this case it
  89.      * has to already have the newlines crunched out.
  90.      */
  91.     if (cp && *cp) {
  92.         if (*cp!='/') {
  93.             cp2 = getenv("TERM");
  94.             if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
  95.                 (void)strcpy(bp,cp);
  96.                 return(tnchktc());
  97.             } else {
  98.                 tf = open(E_TERMCAP, 0);
  99.             }
  100.         } else
  101.             tf = open(cp, 0);
  102.     }
  103.     if (tf==0)
  104.         tf = open(E_TERMCAP, 0);
  105. #else
  106.     tf = open(E_TERMCAP, 0);
  107. #endif
  108.     if (tf < 0)
  109.         return (-1);
  110.     for (;;) {
  111.         cp = bp;
  112.         for (;;) {
  113.             if (i == cnt) {
  114.                 cnt = read(tf, ibuf, BUFSIZ);
  115.                 if (cnt <= 0) {
  116.                     (void)close(tf);
  117.                     return (0);
  118.                 }
  119.                 i = 0;
  120.             }
  121.             c = ibuf[i++];
  122.             if (c == '\n') {
  123.                 if (cp > bp && cp[-1] == '\\'){
  124.                     cp--;
  125.                     continue;
  126.                 }
  127.                 break;
  128.             }
  129.             if (cp >= bp+BUFSIZ) {
  130.                 (void)write(2,"Termcap entry too long\n", 23);
  131.                 break;
  132.             } else
  133.                 *cp++ = c;
  134.         }
  135.         *cp = 0;
  136.  
  137.         /*
  138.          * The real work for the match.
  139.          */
  140.         if (tnamatch(name)) {
  141.             (void)close(tf);
  142.             return(tnchktc());
  143.         }
  144.     }
  145. }
  146.  
  147. /*
  148.  * tnchktc: check the last entry, see if it's tc=xxx. If so,
  149.  * recursively find xxx and append that entry (minus the names)
  150.  * to take the place of the tc=xxx entry. This allows termcap
  151.  * entries to say "like an HP2621 but doesn't turn on the labels".
  152.  * Note that this works because of the left to right scan.
  153.  */
  154. tnchktc()
  155. {
  156.     register char *p, *q;
  157.     char tcname[16];    /* name of similar terminal */
  158.     char tcbuf[BUFSIZ];
  159.     char *holdtbuf = tbuf;
  160.     int l;
  161.  
  162.     p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
  163.     while (*--p != ':')
  164.         if (p<tbuf) {
  165.             (void)write(2, "Bad termcap entry\n", 18);
  166.             return (0);
  167.         }
  168.     p++;
  169.     /* p now points to beginning of last field */
  170.     if (p[0] != 't' || p[1] != 'c')
  171.         return(1);
  172.     (void)strcpy(tcname,p+3);
  173.     q = tcname;
  174.     while (q && *q != ':')
  175.         q++;
  176.     *q = 0;
  177.     if (++hopcount > MAXHOP) {
  178.         (void)write(2, "Infinite tc= loop\n", 18);
  179.         return (0);
  180.     }
  181.     if (tgetent(tcbuf, tcname) != 1)
  182.         return(0);
  183.     for (q=tcbuf; *q != ':'; q++)
  184.         ;
  185.     l = p - holdtbuf + strlen(q);
  186.     if (l > BUFSIZ) {
  187.         (void)write(2, "Termcap entry too long\n", 23);
  188.         q[BUFSIZ - (p-tbuf)] = 0;
  189.     }
  190.     (void)strcpy(p, q+1);
  191.     tbuf = holdtbuf;
  192.     return(1);
  193. }
  194.  
  195. /*
  196.  * Tnamatch deals with name matching.  The first field of the termcap
  197.  * entry is a sequence of names separated by |'s, so we compare
  198.  * against each such name.  The normal : terminator after the last
  199.  * name (before the first field) stops us.
  200.  */
  201. tnamatch(np)
  202.     char *np;
  203. {
  204.     register char *Np, *Bp;
  205.  
  206.     Bp = tbuf;
  207.     if (*Bp == '#')
  208.         return(0);
  209.     for (;;) {
  210.         for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
  211.             continue;
  212.         if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
  213.             return (1);
  214.         while (*Bp && *Bp != ':' && *Bp != '|')
  215.             Bp++;
  216.         if (*Bp == 0 || *Bp == ':')
  217.             return (0);
  218.         Bp++;
  219.     }
  220. }
  221.  
  222. /*
  223.  * Skip to the next field.  Notice that this is very dumb, not
  224.  * knowing about \: escapes or any such.  If necessary, :'s can be put
  225.  * into the termcap file in octal.
  226.  */
  227. static char *
  228. tskip(bp)
  229.     register char *bp;
  230. {
  231.  
  232.     while (*bp && *bp != ':')
  233.         bp++;
  234.     if (*bp == ':')
  235.         bp++;
  236.     return (bp);
  237. }
  238.  
  239. /*
  240.  * Get a string valued option.
  241.  * These are given as
  242.  *    cl=^Z
  243.  * Much decoding is done on the strings, and the strings are
  244.  * placed in area, which is a ref parameter which is updated.
  245.  * No checking on area overflow.
  246.  */
  247. char *
  248. tgetstr(id, area)
  249.     char *id, **area;
  250. {
  251.     register char *bp = tbuf;
  252.  
  253.     for (;;) {
  254.         bp = tskip(bp);
  255.         if (!*bp)
  256.             return (0);
  257.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  258.             continue;
  259.         if (*bp == '@')
  260.             return(0);
  261.         if (*bp != '=')
  262.             continue;
  263.         bp++;
  264.         return (tdecode(bp, area));
  265.     }
  266. }
  267.  
  268. /*
  269.  * Tdecode does the grung work to decode the
  270.  * string capability escapes.
  271.  */
  272. static char *
  273. tdecode(str, area)
  274.     register char *str;
  275.     char **area;
  276. {
  277.     register char *cp;
  278.     register int c;
  279.     register char *dp;
  280.     int i;
  281.  
  282.     cp = *area;
  283.     while ((c = *str++) && c != ':') {
  284.         switch (c) {
  285.  
  286.         case '^':
  287.             c = *str++ & 037;
  288.             break;
  289.  
  290.         case '\\':
  291.             dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
  292.             c = *str++;
  293. nextc:
  294.             if (*dp++ == c) {
  295.                 c = *dp++;
  296.                 break;
  297.             }
  298.             dp++;
  299.             if (*dp)
  300.                 goto nextc;
  301.             if (isdigit(c)) {
  302.                 c -= '0', i = 2;
  303.                 do
  304.                     c <<= 3, c |= *str++ - '0';
  305.                 while (--i && isdigit(*str));
  306.             }
  307.             break;
  308.         }
  309.         *cp++ = c;
  310.     }
  311.     *cp++ = 0;
  312.     str = *area;
  313.     *area = cp;
  314.     return (str);
  315. }
  316.