home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / tip / remcap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-18  |  9.6 KB  |  427 lines

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