home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-B.05 / NETKIT-B / NetKit-B-0.05 / lpr / common_source / printcap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-17  |  9.6 KB  |  446 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, 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[] = "from: @(#)printcap.c    5.7 (Berkeley) 3/4/91";*/
  36. static char rcsid[] = "$Id: printcap.c,v 1.3 1993/08/01 17:59:12 mycroft Exp $";
  37. #endif /* not lint */
  38.  
  39. #include <ctype.h>
  40. #include <stdio.h>
  41. #include "pathnames.h"
  42.  
  43. #ifndef BUFSIZ
  44. #define    BUFSIZ    1024
  45. #endif
  46. #define MAXHOP    32    /* max number of tc= indirections */
  47.  
  48. /*
  49.  * termcap - routines for dealing with the terminal capability data base
  50.  *
  51.  * BUG:        Should use a "last" pointer in tbuf, so that searching
  52.  *        for capabilities alphabetically would not be a n**2/2
  53.  *        process when large numbers of capabilities are given.
  54.  * Note:    If we add a last pointer now we will screw up the
  55.  *        tc capability. We really should compile termcap.
  56.  *
  57.  * Essentially all the work here is scanning and decoding escapes
  58.  * in string capabilities.  We don't use stdio because the editor
  59.  * doesn't, and because living w/o it is not hard.
  60.  */
  61.  
  62. #define PRINTCAP
  63.  
  64. #ifdef PRINTCAP
  65. #define tgetent    pgetent
  66. #define tskip    pskip
  67. #define tgetstr    pgetstr
  68. #define tdecode pdecode
  69. #define tgetnum    pgetnum
  70. #define    tgetflag pgetflag
  71. #define tdecode pdecode
  72. #define tnchktc    pnchktc
  73. #define    tnamatch pnamatch
  74. #define V6
  75. #endif
  76.  
  77. static    FILE *pfp = NULL;    /* printcap data base file pointer */
  78. static    char *tbuf;
  79. static    int hopcount;        /* detect infinite loops in termcap, init 0 */
  80. static    char *tskip();
  81. char    *tgetstr();
  82. static    char *tdecode();
  83. char    *getenv();
  84.  
  85. /*
  86.  * Similar to tgetent except it returns the next enrty instead of
  87.  * doing a lookup.
  88.  */
  89. getprent(bp)
  90.     register char *bp;
  91. {
  92.     register int c, skip = 0;
  93.  
  94.     if (pfp == NULL && (pfp = fopen(_PATH_PRINTCAP, "r")) == NULL)
  95.         return(-1);
  96.     tbuf = bp;
  97.     for (;;) {
  98.         switch (c = getc(pfp)) {
  99.         case EOF:
  100.             fclose(pfp);
  101.             pfp = NULL;
  102.             return(0);
  103.         case '\n':
  104.             if (bp == tbuf) {
  105.                 skip = 0;
  106.                 continue;
  107.             }
  108.             if (bp[-1] == '\\') {
  109.                 bp--;
  110.                 continue;
  111.             }
  112.             *bp = '\0';
  113.             return(1);
  114.         case '#':
  115.             if (bp == tbuf)
  116.                 skip++;
  117.         default:
  118.             if (skip)
  119.                 continue;
  120.             if (bp >= tbuf+BUFSIZ) {
  121.                 write(2, "Termcap entry too long\n", 23);
  122.                 *bp = '\0';
  123.                 return(1);
  124.             }
  125.             *bp++ = c;
  126.         }
  127.     }
  128. }
  129.  
  130. endprent()
  131. {
  132.     if (pfp != NULL)
  133.         fclose(pfp);
  134. }
  135.  
  136. /*
  137.  * Get an entry for terminal name in buffer bp,
  138.  * from the termcap file.  Parse is very rudimentary;
  139.  * we just notice escaped newlines.
  140.  */
  141. tgetent(bp, name)
  142.     char *bp, *name;
  143. {
  144.     register char *cp;
  145.     register int c;
  146.     register int i = 0, cnt = 0;
  147.     char ibuf[BUFSIZ];
  148.     char *cp2;
  149.     int tf;
  150.  
  151.     tbuf = bp;
  152.     tf = 0;
  153. #ifndef V6
  154.     cp = getenv("TERMCAP");
  155.     /*
  156.      * TERMCAP can have one of two things in it. It can be the
  157.      * name of a file to use instead of /etc/termcap. In this
  158.      * case it better start with a "/". Or it can be an entry to
  159.      * use so we don't have to read the file. In this case it
  160.      * has to already have the newlines crunched out.
  161.      */
  162.     if (cp && *cp) {
  163.         if (*cp!='/') {
  164.             cp2 = getenv("TERM");
  165.             if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
  166.                 strcpy(bp,cp);
  167.                 return(tnchktc());
  168.             } else {
  169.                 tf = open(_PATH_PRINTCAP, 0);
  170.             }
  171.         } else
  172.             tf = open(cp, 0);
  173.     }
  174.     if (tf==0)
  175.         tf = open(_PATH_PRINTCAP, 0);
  176. #else
  177.     tf = open(_PATH_PRINTCAP, 0);
  178. #endif
  179.     if (tf < 0)
  180.         return (-1);
  181.     for (;;) {
  182.         cp = bp;
  183.         for (;;) {
  184.             if (i == cnt) {
  185.                 cnt = read(tf, ibuf, BUFSIZ);
  186.                 if (cnt <= 0) {
  187.                     close(tf);
  188.                     return (0);
  189.                 }
  190.                 i = 0;
  191.             }
  192.             c = ibuf[i++];
  193.             if (c == '\n') {
  194.                 if (cp > bp && cp[-1] == '\\'){
  195.                     cp--;
  196.                     continue;
  197.                 }
  198.                 break;
  199.             }
  200.             if (cp >= bp+BUFSIZ) {
  201.                 write(2,"Termcap entry too long\n", 23);
  202.                 break;
  203.             } else
  204.                 *cp++ = c;
  205.         }
  206.         *cp = 0;
  207.  
  208.         /*
  209.          * The real work for the match.
  210.          */
  211.         if (tnamatch(name)) {
  212.             close(tf);
  213.             return(tnchktc());
  214.         }
  215.     }
  216. }
  217.  
  218. /*
  219.  * tnchktc: check the last entry, see if it's tc=xxx. If so,
  220.  * recursively find xxx and append that entry (minus the names)
  221.  * to take the place of the tc=xxx entry. This allows termcap
  222.  * entries to say "like an HP2621 but doesn't turn on the labels".
  223.  * Note that this works because of the left to right scan.
  224.  */
  225. tnchktc()
  226. {
  227.     register char *p, *q;
  228.     char tcname[16];    /* name of similar terminal */
  229.     char tcbuf[BUFSIZ];
  230.     char *holdtbuf = tbuf;
  231.     int l;
  232.  
  233.     p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
  234.     while (*--p != ':')
  235.         if (p<tbuf) {
  236.             write(2, "Bad termcap entry\n", 18);
  237.             return (0);
  238.         }
  239.     p++;
  240.     /* p now points to beginning of last field */
  241.     if (p[0] != 't' || p[1] != 'c')
  242.         return(1);
  243.     strcpy(tcname,p+3);
  244.     q = tcname;
  245.     while (q && *q != ':')
  246.         q++;
  247.     *q = 0;
  248.     if (++hopcount > MAXHOP) {
  249.         write(2, "Infinite tc= loop\n", 18);
  250.         return (0);
  251.     }
  252.     if (tgetent(tcbuf, tcname) != 1)
  253.         return(0);
  254.     for (q=tcbuf; *q != ':'; q++)
  255.         ;
  256.     l = p - holdtbuf + strlen(q);
  257.     if (l > BUFSIZ) {
  258.         write(2, "Termcap entry too long\n", 23);
  259.         q[BUFSIZ - (p-tbuf)] = 0;
  260.     }
  261.     strcpy(p, q+1);
  262.     tbuf = holdtbuf;
  263.     return(1);
  264. }
  265.  
  266. /*
  267.  * Tnamatch deals with name matching.  The first field of the termcap
  268.  * entry is a sequence of names separated by |'s, so we compare
  269.  * against each such name.  The normal : terminator after the last
  270.  * name (before the first field) stops us.
  271.  */
  272. tnamatch(np)
  273.     char *np;
  274. {
  275.     register char *Np, *Bp;
  276.  
  277.     Bp = tbuf;
  278.     if (*Bp == '#')
  279.         return(0);
  280.     for (;;) {
  281.         for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
  282.             continue;
  283.         if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
  284.             return (1);
  285.         while (*Bp && *Bp != ':' && *Bp != '|')
  286.             Bp++;
  287.         if (*Bp == 0 || *Bp == ':')
  288.             return (0);
  289.         Bp++;
  290.     }
  291. }
  292.  
  293. /*
  294.  * Skip to the next field.  Notice that this is very dumb, not
  295.  * knowing about \: escapes or any such.  If necessary, :'s can be put
  296.  * into the termcap file in octal.
  297.  */
  298. static char *
  299. tskip(bp)
  300.     register char *bp;
  301. {
  302.  
  303.     while (*bp && *bp != ':')
  304.         bp++;
  305.     if (*bp == ':')
  306.         bp++;
  307.     return (bp);
  308. }
  309.  
  310. /*
  311.  * Return the (numeric) option id.
  312.  * Numeric options look like
  313.  *    li#80
  314.  * i.e. the option string is separated from the numeric value by
  315.  * a # character.  If the option is not found we return -1.
  316.  * Note that we handle octal numbers beginning with 0.
  317.  */
  318. tgetnum(id)
  319.     char *id;
  320. {
  321.     register int i, base;
  322.     register char *bp = tbuf;
  323.  
  324.     for (;;) {
  325.         bp = tskip(bp);
  326.         if (*bp == 0)
  327.             return (-1);
  328.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  329.             continue;
  330.         if (*bp == '@')
  331.             return(-1);
  332.         if (*bp != '#')
  333.             continue;
  334.         bp++;
  335.         base = 10;
  336.         if (*bp == '0')
  337.             base = 8;
  338.         i = 0;
  339.         while (isdigit(*bp))
  340.             i *= base, i += *bp++ - '0';
  341.         return (i);
  342.     }
  343. }
  344.  
  345. /*
  346.  * Handle a flag option.
  347.  * Flag options are given "naked", i.e. followed by a : or the end
  348.  * of the buffer.  Return 1 if we find the option, or 0 if it is
  349.  * not given.
  350.  */
  351. tgetflag(id)
  352.     char *id;
  353. {
  354.     register char *bp = tbuf;
  355.  
  356.     for (;;) {
  357.         bp = tskip(bp);
  358.         if (!*bp)
  359.             return (0);
  360.         if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
  361.             if (!*bp || *bp == ':')
  362.                 return (1);
  363.             else if (*bp == '@')
  364.                 return(0);
  365.         }
  366.     }
  367. }
  368.  
  369. /*
  370.  * Get a string valued option.
  371.  * These are given as
  372.  *    cl=^Z
  373.  * Much decoding is done on the strings, and the strings are
  374.  * placed in area, which is a ref parameter which is updated.
  375.  * No checking on area overflow.
  376.  */
  377. char *
  378. tgetstr(id, area)
  379.     char *id, **area;
  380. {
  381.     register char *bp = tbuf;
  382.  
  383.     for (;;) {
  384.         bp = tskip(bp);
  385.         if (!*bp)
  386.             return (0);
  387.         if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
  388.             continue;
  389.         if (*bp == '@')
  390.             return(0);
  391.         if (*bp != '=')
  392.             continue;
  393.         bp++;
  394.         return (tdecode(bp, area));
  395.     }
  396. }
  397.  
  398. /*
  399.  * Tdecode does the grung work to decode the
  400.  * string capability escapes.
  401.  */
  402. static char *
  403. tdecode(str, area)
  404.     register char *str;
  405.     char **area;
  406. {
  407.     register char *cp;
  408.     register int c;
  409.     register char *dp;
  410.     int i;
  411.  
  412.     cp = *area;
  413.     while ((c = *str++) && c != ':') {
  414.         switch (c) {
  415.  
  416.         case '^':
  417.             c = *str++ & 037;
  418.             break;
  419.  
  420.         case '\\':
  421.             dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
  422.             c = *str++;
  423. nextc:
  424.             if (*dp++ == c) {
  425.                 c = *dp++;
  426.                 break;
  427.             }
  428.             dp++;
  429.             if (*dp)
  430.                 goto nextc;
  431.             if (isdigit(c)) {
  432.                 c -= '0', i = 2;
  433.                 do
  434.                     c <<= 3, c |= *str++ - '0';
  435.                 while (--i && isdigit(*str));
  436.             }
  437.             break;
  438.         }
  439.         *cp++ = c;
  440.     }
  441.     *cp++ = 0;
  442.     str = *area;
  443.     *area = cp;
  444.     return (str);
  445. }
  446.