BSD 4_1c_2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Tue, 8 Jun 1982 12:09:28 +0000 (04:09 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Tue, 8 Jun 1982 12:09:28 +0000 (04:09 -0800)
Work on file usr/src/usr.lib/libg/dbxxx.s
Work on file usr/src/usr.lib/libg/Makefile
Work on file usr/src/usr.lib/libtermlib/tc1.c
Work on file usr/src/usr.lib/libtermlib/termcap.c
Work on file usr/src/usr.lib/libtermlib/tc2.c
Work on file usr/src/usr.lib/libtermlib/makefile
Work on file usr/src/usr.lib/libtermlib/tputs.c
Work on file usr/src/usr.lib/libtermlib/tc3.c

Synthesized-from: CSRG/cd1/4.1c.2

usr/src/usr.lib/libg/Makefile [new file with mode: 0644]
usr/src/usr.lib/libg/dbxxx.s [new file with mode: 0644]
usr/src/usr.lib/libtermlib/makefile [new file with mode: 0644]
usr/src/usr.lib/libtermlib/tc1.c [new file with mode: 0644]
usr/src/usr.lib/libtermlib/tc2.c [new file with mode: 0644]
usr/src/usr.lib/libtermlib/tc3.c [new file with mode: 0644]
usr/src/usr.lib/libtermlib/termcap.c [new file with mode: 0644]
usr/src/usr.lib/libtermlib/tputs.c [new file with mode: 0644]

diff --git a/usr/src/usr.lib/libg/Makefile b/usr/src/usr.lib/libg/Makefile
new file mode 100644 (file)
index 0000000..b2e17bf
--- /dev/null
@@ -0,0 +1,8 @@
+libg.a:        dbxxx.s
+       as dbxxx.s -o libg.a
+
+install: libg.a
+       install -c libg.a ${DESTDIR}/usr/lib
+
+clean:
+       rm -f libg.a
diff --git a/usr/src/usr.lib/libg/dbxxx.s b/usr/src/usr.lib/libg/dbxxx.s
new file mode 100644 (file)
index 0000000..a2f6757
--- /dev/null
@@ -0,0 +1,12 @@
+       .data
+       .comm   __dbargs,512
+       .text
+       .align  1
+       .globl  __dbsubc
+__dbsubc:
+       callg   __dbargs+4,*__dbargs
+       .globl  __dbsubn
+__dbsubn:
+       halt
+
+       .data
diff --git a/usr/src/usr.lib/libtermlib/makefile b/usr/src/usr.lib/libtermlib/makefile
new file mode 100644 (file)
index 0000000..7feed4b
--- /dev/null
@@ -0,0 +1,33 @@
+CFLAGS=        -O -DCM_N -DCM_GT -DCM_B -DCM_D
+LD = ld
+
+.c.o:
+       $(CC) $(CFLAGS) -c -p $*.c
+       $(LD) $(LDFLAGS) -x -r -o profiled/$*.o $*.o
+       $(CC) $(CFLAGS) -c $*.c
+       $(LD) $(LDFLAGS) -X -r $*.o
+       mv a.out $*.o
+
+termcap.a termcap_p.a: termcap.o tgoto.o tputs.o
+       ar cr termcap.a termcap.o tgoto.o tputs.o
+       cd profiled; ar cr ../termcap_p.a termcap.o tgoto.o tputs.o
+
+clean:
+       -rm -f *.o profiled/*.o
+       -rm -f termcap.a termcap_p.a
+
+install: termcap.a termcap_p.a
+       install -c termcap.a ${DESTDIR}/usr/lib/libtermcap.a
+       -rm -f ${DESTDIR}/usr/lib/libtermlib.a
+       ln ${DESTDIR}/usr/lib/libtermcap.a ${DESTDIR}/usr/lib/libtermlib.a
+       ranlib ${DESTDIR}/usr/lib/libtermcap.a
+       install -c termcap_p.a ${DESTDIR}/usr/lib/libtermcap_p.a
+       -rm -f ${DESTDIR}/usr/lib/libtermlib_p.a
+       ln ${DESTDIR}/usr/lib/libtermcap_p.a ${DESTDIR}/usr/lib/libtermlib_p.a
+       ranlib ${DESTDIR}/usr/lib/libtermcap_p.a
+
+VGRIND=        csh /usr/ucb/vgrind
+vgrind:
+       cp /dev/null index
+       ${VGRIND} -h "Termcap library" termcap.c tputs.c tgoto.c
+       ${VGRIND} -h "Termcap library" -x index
diff --git a/usr/src/usr.lib/libtermlib/tc1.c b/usr/src/usr.lib/libtermlib/tc1.c
new file mode 100644 (file)
index 0000000..6239578
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * tc1 [term]
+ * dummy program to test termlib.
+ * gets entry, counts it, and prints it.
+ */
+#include <stdio.h>
+char buf[1024];
+char *getenv();
+
+main(argc, argv) char **argv; {
+       char *p;
+       int rc;
+
+       if (argc < 2)
+               p = getenv("TERM");
+       else
+               p = argv[1];
+       rc = tgetent(buf,p);
+       printf("tgetent returns %d, len=%d, text=\n'%s'\n",rc,strlen(buf),buf);
+}
diff --git a/usr/src/usr.lib/libtermlib/tc2.c b/usr/src/usr.lib/libtermlib/tc2.c
new file mode 100644 (file)
index 0000000..cf76c37
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * tc2 [term]
+ * Dummy program to test out termlib.
+ * Commands are "tcc\n" where t is type (s for string, f for flag,
+ * or n for number) and cc is the name of the capability.
+ */
+#include <stdio.h>
+char buf[1024];
+char *getenv(), *tgetstr();
+
+main(argc, argv) char **argv; {
+       char *p, *q;
+       int rc;
+       char b[3], c;
+       char area[200];
+
+       if (argc < 2)
+               p = getenv("TERM");
+       else
+               p = argv[1];
+       rc = tgetent(buf,p);
+       for (;;) {
+               c = getchar();
+               if (c < 0)
+                       exit(0);
+               b[0] = getchar();
+               if (b[0] < ' ')
+                       exit(0);
+               b[1] = getchar();
+               b[2] = 0;
+               getchar();
+               switch(c) {
+                       case 'f':
+                               printf("%s: %d\n",b,tgetflag(b));
+                               break;
+                       case 'n':
+                               printf("%s: %d\n",b,tgetnum(b));
+                               break;
+                       case 's':
+                               q = area;
+                               printf("%s: %s\n",b,tgetstr(b,&q));
+                               break;
+                       default:
+                               exit(0);
+               }
+       }
+}
diff --git a/usr/src/usr.lib/libtermlib/tc3.c b/usr/src/usr.lib/libtermlib/tc3.c
new file mode 100644 (file)
index 0000000..bf0aaf2
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * tc3 [term]
+ * Dummy program to test out termlib.
+ * Input two numbers and it prints out the tgoto string generated.
+ */
+#include <stdio.h>
+char buf[1024];
+char *getenv(), *tgetstr();
+char *rdchar();
+char *tgoto();
+char *CM;
+char cmbuff[30];
+char *x;
+char *UP;
+char *tgout;
+
+main(argc, argv) char **argv; {
+       char *p;
+       int rc;
+       int row, col;
+
+       if (argc < 2)
+               p = getenv("TERM");
+       else
+               p = argv[1];
+       rc = tgetent(buf,p);
+       x = cmbuff;
+       UP = tgetstr("up", &x);
+       printf("UP = %x = ", UP); pr(UP); printf("\n");
+       if (UP && *UP==0)
+               UP = 0;
+       CM = tgetstr("cm", &x);
+       printf("CM = "); pr(CM); printf("\n");
+       for (;;) {
+               if (scanf("%d %d", &row, &col) < 2)
+                       exit(0);
+               tgout = tgoto(CM, row, col);
+               pr(tgout);
+               printf("\n");
+       }
+}
+
+pr(p)
+register char *p;
+{
+       for (; *p; p++)
+               printf("%s", rdchar(*p));
+}
+
+/*
+ * rdchar: returns a readable representation of an ASCII char, using ^ notation.
+ */
+#include <ctype.h>
+char *rdchar(c)
+char c;
+{
+       static char ret[4];
+       register char *p;
+
+       /*
+        * Due to a bug in isprint, this prints spaces as ^`, but this is OK
+        * because we want something to show up on the screen.
+        */
+       ret[0] = ((c&0377) > 0177) ? '\'' : ' ';
+       c &= 0177;
+       ret[1] = isprint(c) ? ' ' : '^';
+       ret[2] = isprint(c) ?  c  : c^0100;
+       ret[3] = 0;
+       for (p=ret; *p==' '; p++)
+               ;
+       return (p);
+}
diff --git a/usr/src/usr.lib/libtermlib/termcap.c b/usr/src/usr.lib/libtermlib/termcap.c
new file mode 100644 (file)
index 0000000..73db018
--- /dev/null
@@ -0,0 +1,337 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#define        BUFSIZ  1024
+#define MAXHOP 32      /* max number of tc= indirections */
+
+#include <ctype.h>
+#include "local/uparm.h"
+/*
+ * termcap - routines for dealing with the terminal capability data base
+ *
+ * BUG:                Should use a "last" pointer in tbuf, so that searching
+ *             for capabilities alphabetically would not be a n**2/2
+ *             process when large numbers of capabilities are given.
+ * Note:       If we add a last pointer now we will screw up the
+ *             tc capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities.  We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+static char *tbuf;
+static int hopcount;   /* detect infinite loops in termcap, init 0 */
+char   *tskip();
+char   *tgetstr();
+char   *tdecode();
+char   *getenv();
+
+/*
+ * Get an entry for terminal name in buffer bp,
+ * from the termcap file.  Parse is very rudimentary;
+ * we just notice escaped newlines.
+ */
+tgetent(bp, name)
+       char *bp, *name;
+{
+       register char *cp;
+       register int c;
+       register int i = 0, cnt = 0;
+       char ibuf[BUFSIZ];
+       char *cp2;
+       int tf;
+
+       tbuf = bp;
+       tf = 0;
+#ifndef V6
+       cp = getenv("TERMCAP");
+       /*
+        * TERMCAP can have one of two things in it. It can be the
+        * name of a file to use instead of /etc/termcap. In this
+        * case it better start with a "/". Or it can be an entry to
+        * use so we don't have to read the file. In this case it
+        * has to already have the newlines crunched out.
+        */
+       if (cp && *cp) {
+               if (*cp!='/') {
+                       cp2 = getenv("TERM");
+                       if (cp2==(char *) 0 || strcmp(name,cp2)==0) {
+                               strcpy(bp,cp);
+                               return(tnchktc());
+                       } else {
+                               tf = open(E_TERMCAP, 0);
+                       }
+               } else
+                       tf = open(cp, 0);
+       }
+       if (tf==0)
+               tf = open(E_TERMCAP, 0);
+#else
+       tf = open(E_TERMCAP, 0);
+#endif
+       if (tf < 0)
+               return (-1);
+       for (;;) {
+               cp = bp;
+               for (;;) {
+                       if (i == cnt) {
+                               cnt = read(tf, ibuf, BUFSIZ);
+                               if (cnt <= 0) {
+                                       close(tf);
+                                       return (0);
+                               }
+                               i = 0;
+                       }
+                       c = ibuf[i++];
+                       if (c == '\n') {
+                               if (cp > bp && cp[-1] == '\\'){
+                                       cp--;
+                                       continue;
+                               }
+                               break;
+                       }
+                       if (cp >= bp+BUFSIZ) {
+                               write(2,"Termcap entry too long\n", 23);
+                               break;
+                       } else
+                               *cp++ = c;
+               }
+               *cp = 0;
+
+               /*
+                * The real work for the match.
+                */
+               if (tnamatch(name)) {
+                       close(tf);
+                       return(tnchktc());
+               }
+       }
+}
+
+/*
+ * tnchktc: check the last entry, see if it's tc=xxx. If so,
+ * recursively find xxx and append that entry (minus the names)
+ * to take the place of the tc=xxx entry. This allows termcap
+ * entries to say "like an HP2621 but doesn't turn on the labels".
+ * Note that this works because of the left to right scan.
+ */
+tnchktc()
+{
+       register char *p, *q;
+       char tcname[16];        /* name of similar terminal */
+       char tcbuf[BUFSIZ];
+       char *holdtbuf = tbuf;
+       int l;
+
+       p = tbuf + strlen(tbuf) - 2;    /* before the last colon */
+       while (*--p != ':')
+               if (p<tbuf) {
+                       write(2, "Bad termcap entry\n", 18);
+                       return (0);
+               }
+       p++;
+       /* p now points to beginning of last field */
+       if (p[0] != 't' || p[1] != 'c')
+               return(1);
+       strcpy(tcname,p+3);
+       q = tcname;
+       while (q && *q != ':')
+               q++;
+       *q = 0;
+       if (++hopcount > MAXHOP) {
+               write(2, "Infinite tc= loop\n", 18);
+               return (0);
+       }
+       if (tgetent(tcbuf, tcname) != 1)
+               return(0);
+       for (q=tcbuf; *q != ':'; q++)
+               ;
+       l = p - holdtbuf + strlen(q);
+       if (l > BUFSIZ) {
+               write(2, "Termcap entry too long\n", 23);
+               q[BUFSIZ - (p-tbuf)] = 0;
+       }
+       strcpy(p, q+1);
+       tbuf = holdtbuf;
+       return(1);
+}
+
+/*
+ * Tnamatch deals with name matching.  The first field of the termcap
+ * entry is a sequence of names separated by |'s, so we compare
+ * against each such name.  The normal : terminator after the last
+ * name (before the first field) stops us.
+ */
+tnamatch(np)
+       char *np;
+{
+       register char *Np, *Bp;
+
+       Bp = tbuf;
+       if (*Bp == '#')
+               return(0);
+       for (;;) {
+               for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
+                       continue;
+               if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
+                       return (1);
+               while (*Bp && *Bp != ':' && *Bp != '|')
+                       Bp++;
+               if (*Bp == 0 || *Bp == ':')
+                       return (0);
+               Bp++;
+       }
+}
+
+/*
+ * Skip to the next field.  Notice that this is very dumb, not
+ * knowing about \: escapes or any such.  If necessary, :'s can be put
+ * into the termcap file in octal.
+ */
+static char *
+tskip(bp)
+       register char *bp;
+{
+
+       while (*bp && *bp != ':')
+               bp++;
+       if (*bp == ':')
+               bp++;
+       return (bp);
+}
+
+/*
+ * Return the (numeric) option id.
+ * Numeric options look like
+ *     li#80
+ * i.e. the option string is separated from the numeric value by
+ * a # character.  If the option is not found we return -1.
+ * Note that we handle octal numbers beginning with 0.
+ */
+tgetnum(id)
+       char *id;
+{
+       register int i, base;
+       register char *bp = tbuf;
+
+       for (;;) {
+               bp = tskip(bp);
+               if (*bp == 0)
+                       return (-1);
+               if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+                       continue;
+               if (*bp == '@')
+                       return(-1);
+               if (*bp != '#')
+                       continue;
+               bp++;
+               base = 10;
+               if (*bp == '0')
+                       base = 8;
+               i = 0;
+               while (isdigit(*bp))
+                       i *= base, i += *bp++ - '0';
+               return (i);
+       }
+}
+
+/*
+ * Handle a flag option.
+ * Flag options are given "naked", i.e. followed by a : or the end
+ * of the buffer.  Return 1 if we find the option, or 0 if it is
+ * not given.
+ */
+tgetflag(id)
+       char *id;
+{
+       register char *bp = tbuf;
+
+       for (;;) {
+               bp = tskip(bp);
+               if (!*bp)
+                       return (0);
+               if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
+                       if (!*bp || *bp == ':')
+                               return (1);
+                       else if (*bp == '@')
+                               return(0);
+               }
+       }
+}
+
+/*
+ * Get a string valued option.
+ * These are given as
+ *     cl=^Z
+ * Much decoding is done on the strings, and the strings are
+ * placed in area, which is a ref parameter which is updated.
+ * No checking on area overflow.
+ */
+char *
+tgetstr(id, area)
+       char *id, **area;
+{
+       register char *bp = tbuf;
+
+       for (;;) {
+               bp = tskip(bp);
+               if (!*bp)
+                       return (0);
+               if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
+                       continue;
+               if (*bp == '@')
+                       return(0);
+               if (*bp != '=')
+                       continue;
+               bp++;
+               return (tdecode(bp, area));
+       }
+}
+
+/*
+ * Tdecode does the grung work to decode the
+ * string capability escapes.
+ */
+static char *
+tdecode(str, area)
+       register char *str;
+       char **area;
+{
+       register char *cp;
+       register int c;
+       register char *dp;
+       int i;
+
+       cp = *area;
+       while ((c = *str++) && c != ':') {
+               switch (c) {
+
+               case '^':
+                       c = *str++ & 037;
+                       break;
+
+               case '\\':
+                       dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
+                       c = *str++;
+nextc:
+                       if (*dp++ == c) {
+                               c = *dp++;
+                               break;
+                       }
+                       dp++;
+                       if (*dp)
+                               goto nextc;
+                       if (isdigit(c)) {
+                               c -= '0', i = 2;
+                               do
+                                       c <<= 3, c |= *str++ - '0';
+                               while (--i && isdigit(*str));
+                       }
+                       break;
+               }
+               *cp++ = c;
+       }
+       *cp++ = 0;
+       str = *area;
+       *area = cp;
+       return (str);
+}
diff --git a/usr/src/usr.lib/libtermlib/tputs.c b/usr/src/usr.lib/libtermlib/tputs.c
new file mode 100644 (file)
index 0000000..6cace8b
--- /dev/null
@@ -0,0 +1,87 @@
+/* Copyright (c) 1979 Regents of the University of California */
+#include <sgtty.h>
+#include <ctype.h>
+
+/*
+ * The following array gives the number of tens of milliseconds per
+ * character for each speed as returned by gtty.  Thus since 300
+ * baud returns a 7, there are 33.3 milliseconds per char at 300 baud.
+ */
+static
+short  tmspc10[] = {
+       0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10
+};
+
+short  ospeed;
+char   PC;
+
+/*
+ * Put the character string cp out, with padding.
+ * The number of affected lines is affcnt, and the routine
+ * used to output one character is outc.
+ */
+tputs(cp, affcnt, outc)
+       register char *cp;
+       int affcnt;
+       int (*outc)();
+{
+       register int i = 0;
+       register int mspc10;
+
+       if (cp == 0)
+               return;
+
+       /*
+        * Convert the number representing the delay.
+        */
+       if (isdigit(*cp)) {
+               do
+                       i = i * 10 + *cp++ - '0';
+               while (isdigit(*cp));
+       }
+       i *= 10;
+       if (*cp == '.') {
+               cp++;
+               if (isdigit(*cp))
+                       i += *cp - '0';
+               /*
+                * Only one digit to the right of the decimal point.
+                */
+               while (isdigit(*cp))
+                       cp++;
+       }
+
+       /*
+        * If the delay is followed by a `*', then
+        * multiply by the affected lines count.
+        */
+       if (*cp == '*')
+               cp++, i *= affcnt;
+
+       /*
+        * The guts of the string.
+        */
+       while (*cp)
+               (*outc)(*cp++);
+
+       /*
+        * If no delay needed, or output speed is
+        * not comprehensible, then don't try to delay.
+        */
+       if (i == 0)
+               return;
+       if (ospeed <= 0 || ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
+               return;
+
+       /*
+        * Round up by a half a character frame,
+        * and then do the delay.
+        * Too bad there are no user program accessible programmed delays.
+        * Transmitting pad characters slows many
+        * terminals down and also loads the system.
+        */
+       mspc10 = tmspc10[ospeed];
+       i += mspc10 / 2;
+       for (i /= mspc10; i > 0; i--)
+               (*outc)(PC);
+}