home *** CD-ROM | disk | FTP | other *** search
/ Dream 45 / Amiga_Dream_45.iso / Amiga / Magazine / Dossier-LaTeX / lgrind-amiga.lha / lgrind / src / lgrindefs.c < prev    next >
C/C++ Source or Header  |  1996-08-04  |  7KB  |  311 lines

  1. #ifndef lint
  2. static char sccsid[] = "@(#)lgrindefs.c    4.3 (Berkeley) 12/11/84";
  3. static char Version[] =
  4.    "$Id: lgrindefs.c,v 1.2 91/10/01 00:29:08 gvr Exp $";
  5. #endif
  6.  
  7. /* Copyright (c) 1979 Regents of the University of California */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <ctype.h>
  11. #include <string.h>
  12. #include <unistd.h>
  13. /*
  14.  * grindcap --- routines for dealing with the language definitions data base
  15.  *    (code stolen almost totally from termcap)
  16.  *
  17.  * BUG:        Should use a "last" pointer in @tbuf@, so that searching
  18.  *        for capabilities alphabetically would not be a %$n^2/2$%
  19.  *        process when large numbers of capabilities are given.
  20.  * Note:    If we add a last pointer now we will screw up the
  21.  *        %|tc|% capability. We really should compile termcap.
  22.  *
  23.  * Essentially all the work here is scanning and decoding escapes
  24.  * in string capabilities.  We don't use stdio because the editor
  25.  * doesn't, and because living w/o it is not hard.
  26.  */
  27.  
  28. #include "lgrind.h"
  29. #include "regexp.h"
  30. #include "lgrindefs.h"
  31.  
  32. int tnchktc(void);
  33.  
  34. static    unsigned char *tbuf;
  35. static    unsigned char *filename;
  36. static    int hopcount = 0; /* detect infinite loops in termcap */
  37.  
  38.  
  39. /*
  40.  * Get an entry for terminal name in buffer @bp@,
  41.  * from the termcap file.  Parse is very rudimentary;
  42.  * we just notice escaped newlines.
  43.  */
  44. int tgetent(unsigned char *bp, unsigned char *name, unsigned char *file)
  45. {
  46.    register unsigned char *cp;
  47.    register int c;
  48.    register int i = 0, cnt = 0;
  49.    unsigned char ibuf[BUFFERSIZE];
  50.   /* unsigned char *cp2;*/
  51.    int tf;
  52.    
  53.    tbuf = bp;
  54.    tf = 0;
  55.    filename = file;
  56.    tf = open(filename, 0);
  57.    if (tf < 0)
  58.       return -1;
  59.    for (;;) {
  60.       cp = bp;
  61.       for (;;) {
  62.      if (i == cnt) {
  63.         cnt = read(tf, ibuf, BUFFERSIZE);
  64.         if (cnt <= 0) {
  65.            close(tf);
  66.            return 0;
  67.         }
  68.         i = 0;
  69.      }
  70.      c = ibuf[i++];
  71.      if (c == '\n') {
  72.         if (cp > bp && cp[-1] == '\\'){
  73.            cp--;
  74.            continue;
  75.         }
  76.         break;
  77.      }
  78.      if (cp >= bp+BUFFERSIZE) {
  79.         write(2,"LGrind entry too long\n", 23);
  80.         break;
  81.      } else
  82.         *cp++ = c;
  83.       }
  84.       *cp = '\0';
  85.       
  86.       /*
  87.        * The real work for the match.
  88.        */
  89.       if (tnamatch(name)) {
  90.      close(tf);
  91.      return tnchktc();
  92.       }
  93.    }
  94. }
  95.  
  96.  
  97.  
  98. /*
  99.  * @tnchktc@: check the last entry, see if it's %|tc=xxx|%. If so,
  100.  * recursively find %|xxx|% and append that entry (minus the names)
  101.  * to take the place of the %|tc=xxx|% entry. This allows termcap
  102.  * entries to say "like an HP2621 but doesn't turn on the labels".
  103.  * Note that this works because of the left to right scan.
  104.  */
  105.     int
  106. tnchktc(void)
  107. {
  108.    register unsigned char *p, *q;
  109.    unsigned char tcname[16];    /* name of similar terminal */
  110.    unsigned char tcbuf[BUFFERSIZE];
  111.    unsigned char *holdtbuf = tbuf;
  112.    int l;
  113.    
  114.    p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
  115.    while (*--p != ':')
  116.       if (p < tbuf) {
  117.      /* Not very informative. Wrong BTW (for the configs). Shut up. */ 
  118.      /* write(2, "Bad lgrind entry\n", 18); */
  119.      return 0;
  120.       }
  121.    p++;
  122.    /* @p@ now points to beginning of last field */
  123.    if (p[0] != 't' || p[1] != 'c')
  124.       return 1;
  125.    strcpy(tcname,p+3);
  126.    q = tcname;
  127.    while (q && *q != ':')
  128.       q++;
  129.    *q = '\0';
  130.    if (++hopcount > MAXHOP) {
  131.       write(2, "Infinite tc= loop\n", 18);
  132.       return 0;
  133.    }
  134.    if (tgetent(tcbuf, tcname, filename) != 1)
  135.       return 0;
  136.    for (q = tcbuf; *q != ':'; q++)
  137.       ;
  138.    l = p - holdtbuf + strlen(q);
  139.    if (l > BUFFERSIZE) {
  140.       write(2, "LGrind entry too long\n", 23);
  141.       q[BUFFERSIZE - (p-tbuf)] = '\0';
  142.    }
  143.    strcpy(p, q+1);
  144.    tbuf = holdtbuf;
  145.    return 1;
  146. }
  147.  
  148.  
  149.  
  150. /*
  151.  * @tnamatch@ deals with name matching.  The first field of the termcap
  152.  * entry is a sequence of names separated by %|||%'s, so we compare
  153.  * against each such name.  The normal %|:|% terminator after the last
  154.  * name (before the first field) stops us.
  155.  */
  156.    int
  157. tnamatch(unsigned char *np)
  158. {
  159.    register unsigned char *Np, *Bp;
  160.    
  161.    Bp = tbuf;
  162.    if (*Bp == '#')
  163.       return 0;
  164.    for (;;) {
  165.       for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
  166.      continue;
  167.       if (*Np == '\0' && (*Bp == '|' || *Bp == ':' || *Bp == '\0'))
  168.      return 1;
  169.       while (*Bp != '\0' && *Bp != ':' && *Bp != '|')
  170.      Bp++;
  171.       if (*Bp == '\0' || *Bp == ':')
  172.      return 0;
  173.       Bp++;
  174.    }
  175. }
  176.  
  177.  
  178.  
  179. /*
  180.  * Skip to the next field.  Notice that this is very dumb, not
  181.  * knowing about %|\:|% escapes or any such.  If necessary, %|:|%'s can
  182.  * be put into the termcap file in octal.
  183.  */
  184.    unsigned char *
  185. tskip(register unsigned char *bp)
  186. {
  187.    while (*bp && *bp != ':')
  188.       bp++;
  189.    if (*bp == ':')
  190.       bp++;
  191.    return bp;
  192. }
  193.  
  194.  
  195.  
  196. /*
  197.  * Return the (numeric) option id.
  198.  * Numeric options look like
  199.  *    %|li#80|%
  200.  * i.e. the option string is separated from the numeric value by
  201.  * a %|#|% character.  If the option is not found we return %$-1$%.
  202.  * Note that we handle octal numbers beginning with %$0$%.
  203.  */
  204.    int
  205. tgetnum(unsigned char *id)
  206. {
  207.    register int i, base;
  208.    register unsigned char *bp = tbuf;
  209.    
  210.    for (;;) {
  211.       bp = tskip(bp);
  212.       if (*bp == '\0')
  213.      return -1;
  214.       if (*bp++ != id[0] || *bp == '\0' || *bp++ != id[1])
  215.      continue;
  216.       if (*bp == '@')
  217.      return -1;
  218.       if (*bp != '#')
  219.      continue;
  220.       bp++;
  221.       base = 10;
  222.       if (*bp == '0')
  223.      base = 8;
  224.       i = 0;
  225.       while (isdigit(*bp))
  226.      i *= base, i += *bp++ - '0';
  227.       return i;
  228.    }
  229. }
  230.  
  231.  
  232.  
  233. /*
  234.  * Handle a flag option.
  235.  * Flag options are given "naked", i.e. followed by a %|:|% or the end
  236.  * of the buffer.  Return 1 if we find the option, or 0 if it is
  237.  * not given.
  238.  */
  239.    int
  240. tgetflag(unsigned char *id)
  241. {
  242.    register unsigned char *bp = tbuf;
  243.    
  244.    for (;;) {
  245.       bp = tskip(bp);
  246.       if (!*bp)
  247.      return 0;
  248.       if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
  249.      if (!*bp || *bp == ':')
  250.         return 1;
  251.      else if (*bp == '@')
  252.         return 0;
  253.       }
  254.    }
  255. }
  256.  
  257.  
  258.  
  259. /*
  260.  * Get a string valued option.
  261.  * These are given as
  262.  *    %|cl=^Z|%
  263.  * Much decoding is done on the strings, and the strings are
  264.  * placed in area, which is a ref parameter which is updated.
  265.  * No checking on area overflow.
  266.  */
  267.    unsigned char *
  268. tgetstr(unsigned char *id, unsigned char **area)
  269. {
  270.    register unsigned char *bp = tbuf;
  271.    
  272.    for (;;) {
  273.       bp = tskip(bp);
  274.       if (!*bp)
  275.      return 0;
  276.       if (*bp++ != id[0] || *bp == '\0' || *bp++ != id[1])
  277.      continue;
  278.       if (*bp == '@')
  279.      return 0;
  280.       if (*bp != '=')
  281.      continue;
  282.       bp++;
  283.       return tdecode(bp, area);
  284.    }
  285. }
  286.  
  287.  
  288.  
  289. /*
  290.  * @tdecode@ does the grunge work to decode the
  291.  * string capability escapes.
  292.  */
  293.    unsigned char *
  294. tdecode(register unsigned char *str, unsigned char **area)
  295. {
  296.    register unsigned char *cp;
  297.    register int c;
  298. /*   int i;*/
  299.    
  300.    cp = *area;
  301.    while (c = *str++) {
  302.       if (c == ':' && *(cp-1) != '\\')
  303.      break;
  304.       *cp++ = c;
  305.    }
  306.    *cp++ = '\0';
  307.    str = *area;
  308.    *area = cp;
  309.    return str;
  310. }
  311.