peter@sugar.hackercorp.com (Peter da Silva) (03/13/91)
I've had several requests for this, so here it is again. : This archive contains the following files... : 'termlib.h' : 'tinit.c' : 'tgetnum.c' : 'tutil.c' : 'tvars.c' : 'tgoto.c' : 'tgetent.c' : 'tputs.c' : 'cur.c' : 'termcap.c' : 'tgetflag.c' : 'tgetstr.c' : 'Makefile' : To extract them, run the following through /bin/sh echo x - termlib.h sed 's/^X//' > termlib.h << '//END' X/* TERMLIB: Terminal independant database. X * X * Module: termlib.h X * X * Purpose: declare global variables and functions. X */ X X/* termlib.h X * Global variables for termlib X * X*/ X#ifndef AMIGA X#define AMIGA 0 X#endif X Xextern char *tent; /* Pointer to terminal entry, set by tgetent */ Xextern char PC; /* Pad character, default NULL */ Xextern char *UP, *BC; /* Pointers to UP and BC strings from database */ Xextern short ospeed; /* Baud rate (1-16, 1=300, 16=19200), as in stty */ X Xint tgetnum(); Xchar *tgoto(); Xint tgetent(); Xint tgetflag(); Xchar *tgetstr(); X Xchar *_find(); Xchar *_addfmt(); //END echo x - tinit.c sed 's/^X//' > tinit.c << '//END' X/* TERMLIB: Terminal independant database. X * X * Module: tinit X * X * Purpose: simplified terminal initialisation. X * X * Calling conventions: name is name of terminal. X * X * Returned values: none. X * X * Notes X * tinit calls tgetent, then sets up the global X * variables PC, UP, BC, ospeed appropriately. X * X */ X#include "termlib.h" X#include <stdio.h> X#if !AMIGA X#include <sgtty.h> X#endif X X/* tinit.c (libtermlib.a) X * X */ X Xchar tbuf[1024]; /* Buffer for termcap entry */ Xchar junkbuf[1024]; /* Big buffer for junk */ Xchar *junkptr; X Xtinit(name) Xchar *name; X{ X#if !AMIGA X struct sgttyb sgbuf; X#endif X char *ps; X X junkptr = junkbuf; X X tgetent(tbuf, name); X X ps = tgetstr("pc", &junkptr); X if(ps) PC = *ps; X UP = tgetstr("up", &junkptr); X BC = tgetstr("bc", &junkptr); X X#if AMIGA X ospeed=0; X#else X gtty(1, &sgbuf); X ospeed=sgbuf.sg_ospeed; X#endif X} //END echo x - tgetnum.c sed 's/^X//' > tgetnum.c << '//END' X/* TERMLIB: Terminal independant database. X * X * Module: tgetnum X * X * Purpose: get numeric value such as 'li' or 'co' from termcap. X * X * Calling conventions: id = 2 character id. X * X * Returned values: -1 for failure, else numerical value. X */ X#include <stdio.h> X#include <ctype.h> X#include "termlib.h" X X/* tgetnum.c (libtermlib.a) X * X */ X Xtgetnum(id) Xchar *id; X{ X char *ptr, buf[256]; X ptr = buf; X X if(tgetstr(id, &ptr)) X return atoi(buf); X else X return 0; X} //END echo x - tutil.c sed 's/^X//' > tutil.c << '//END' X/* TERMLIB: Terminal independant database. X * X * Module: tutil.c X * X * Purpose: Utility routines for TERMLIB functions. X * X */ X X/* tutil.c (libtermlib.a) X * Utility routines for termlib X * X */ X X_match(s1, s2) /* returns length of text common to s1 and s2 */ Xchar *s1, *s2; X{ X int i = 0; X X while(s1[i] && s1[i] == s2[i]) X i++; X X return i; X} X Xchar * X_find(s, set) /* finds next c in s that's a member of set, returns pointer */ Xchar *s, *set; X{ X for(; *s; s++) { X char *ptr = set; X X while(*ptr && *s != *ptr) X ptr++; X X if(*ptr) X return s; X } X X return s; X} X Xchar * X_addfmt(buf, fmt, val) /* add val to buf according to format fmt */ Xchar *buf, *fmt; Xint val; X{ X sprintf(buf, fmt, val); X while(*buf) X buf++; X return buf; X} //END echo x - tvars.c sed 's/^X//' > tvars.c << '//END' X/* TERMLIB: Terminal independant database. X * X * Module: tvars X * X * Purpose: supply actual global variables. X */ X X/* tvars.c (libtermlib.a) X * Global variables for termlib X * X*/ X Xchar *tent; /* Pointer to terminal entry, set by tgetent */ Xchar PC = 0; /* Pad character, default NULL */ Xchar *UP = 0, *BC = 0; /* Pointers to UP and BC strings from database */ Xshort ospeed; /* Baud rate (1-16, 1=300, 16=19200), as in stty */ //END echo x - tgoto.c sed 's/^X//' > tgoto.c << '//END' X/* TERMLIB: Terminal independant database. X * X * Module: tgoto X * X * Purpose: decode cm cursor motion string. X * X * Calling conventions: cm is cursor motion string. X * line, col, are the desired destination. X * X * Returned values: a string pointing to the decoded string, or X * "OOPS" if it cannot be decoded. X * X * Notes X * The accepted escapes are: X * %d as in printf, 0 origin. X * %2, %3 like %02d, %03d in printf. X * %. like %c X * %+x adds <x> to value, then %. X * %>xy if value>x, adds y. No output. X * %i increments line& col, no output. X * %r reverses order of line&col. No output. X * %% prints as a single %. X * %n exclusive or row & col with 0140. X * %B BCD, no output. X * %D reverse coding (x-2*(x%16)), no output. X */ X#include <stdio.h> X#include <ctype.h> X#include "termlib.h" X X/* tgoto.c (libtermlib.a) X * X */ X Xchar * Xtgoto(cm, col, line) Xchar *cm; /* cm string, from termcap */ Xint col, /* column, x position */ X line; /* line, y position */ X{ X char *_addfmt(), X gx, gy, /* x, y */ X *ptr, /* pointer in 'cm' */ X reverse = 0, /* reverse flag */ X *bufp, /* pointer in returned string */ X addup = 0, /* add upline */ X addbak = 0, /* add backup */ X c; X static char buffer[32]; X X if(!cm) X return "OOPS"; /* Kludge, but standard */ X X bufp = buffer; X ptr = cm; X X while(*ptr) { X if((c = *ptr++) != '%') { /* normal char */ X *bufp++ = c; X } else { /* % escape */ X switch(c = *ptr++) { X case 'd': /* decimal */ X bufp = _addfmt(bufp, "%d", line); X line = col; X break; X case '2': /* 2 digit decimal */ X bufp = _addfmt(bufp, "%02d", line); X line = col; X break; X case '3': /* 3 digit decimal */ X bufp = _addfmt(bufp, "%03d", line); X line = col; X break; X case '>': /* %>xy: if >x, add y */ X gx = *ptr++; X gy = *ptr++; X if(col>gx) col += gy; X if(line>gx) line += gy; X break; X case '+': /* %+c: add c */ X line += *ptr++; X case '.': /* print x/y */ X if(line=='\t' || /* these are */ X line == '\n' || /* chars that */ X line=='\004' || /* UNIX hates */ X line=='\0') { X line++; /* so go to next pos */ X if(reverse==(line==col)) X addup=1; /* and mark UP */ X else X addbak=1; /* or BC */ X } X *bufp++=line; X line = col; X break; X case 'r': /* r: reverse */ X gx = line; X line = col; X col = gx; X reverse = 1; X break; X case 'i': /* increment (1-origin screen) */ X col++; X line++; X break; X case '%': /* %%=% literally */ X *bufp++='%'; X break; X case 'n': /* magic DM2500 code */ X line ^= 0140; X col ^= 0140; X break; X case 'B': /* bcd encoding */ X line = line/10<<4+line%10; X col = col/10<<4+col%10; X break; X case 'D': /* magic Delta Data code */ X line = line-2*(line&15); X col = col-2*(col&15); X break; X default: /* Unknown escape */ X return "OOPS"; X } X } X } X X if(addup) /* add upline */ X if(UP) { X ptr=UP; X while(isdigit(*ptr) || *ptr=='.') X ptr++; X if(*ptr=='*') X ptr++; X while(*ptr) X *bufp++ = *ptr++; X } X X if(addbak) /* add backspace */ X if(BC) { X ptr=BC; X while(isdigit(*ptr) || *ptr=='.') X ptr++; X if(*ptr=='*') X ptr++; X while(*ptr) X *bufp++ = *ptr++; X } X else X *bufp++='\b'; X X *bufp = 0; X X return(buffer); X} //END echo x - tgetent.c sed 's/^X//' > tgetent.c << '//END' X/* TERMLIB: Terminal independant database. X * X * Module: tgetent X * X * Purpose: Get termcap entry for <term> into buffer at <tbuf>. X * X * Calling conventions: char tbuf[1024+], term=canonical name for X * terminal. X * X * Returned values: 1 = success, -1 = can't open file, X * 0 = can't find terminal. X * X * Notes X * Should probably supply static buffer. X * X * Uses environment variables "TERM" and X * "TERMCAP". If TERM = term (that is, if the argument X * matches the environment) then it looks at TERMCAP. X * If TERMCAP begins with a slash, then it assumes X * this is the file to search rather than /etc/termcap. X * If TERMCAP does not begin with a slash, and it X * matches TERM, then this is used as the entry. X * X * This could be simplified considerably for non-UNIX X * systems. X */ X#include <stdio.h> X#include <ctype.h> X#include "termlib.h" X X/* tgetent.c (libtermlib.a) X * X */ X#if AMIGA X#define TERMCAP "s:termcap" X#else X#define TERMCAP "/etc/termcap" X#endif X Xtgetent(tbuf, term) Xchar *tbuf, /* Buffer to hold termcap entry, 1024 bytes max */ X *term; /* Name of terminal */ X{ X char tcbuf[32], /* Temp buffer to handle */ X *tc, /* :tc=: entry for */ X *tcptr = tcbuf; /* extended entries */ X char *tcap = TERMCAP, /* Default termcap file */ X *getenv(); X char *tmp; X FILE *termcap; X X if((tmp=getenv("TERMCAP")) != NULL) { X if(*tmp == '/') /* TERMCAP = name of termcap file */ X tcap = tmp ; X else { /* TERMCAP = termcap entry itself */ X int tlen = strlen(term); X while(*tmp && *tmp != ':') {/* Check if TERM matches */ X while(*tmp == '|') X tmp++; X if(_match(tmp, term)==tlen) { X strcpy(tbuf, tmp); X tent=tbuf; X return 1; X } X else X tmp = _find(tmp, ":|"); X } X } X } X if(!(termcap=fopen(tcap, "r"))) { X strcpy(tbuf, tcap); X return -1; X } X X if(getent(tbuf, term, termcap)) { X if(tc=tgetstr("tc", &tcptr)) { /* extended entry */ X rewind(termcap); X if(getent(tbuf+strlen(tbuf), tc, termcap)) { X fclose(termcap); /* Completed */ X return 1; X } X else { X fclose(termcap); /* Incomplete */ X return 0; X } X } else { X fclose(termcap); /* non-extended entry */ X return 1; X } X } else { X fclose(termcap); /* No entry */ X return 0; X } X} X Xgetent(tbuf, term, termcap) Xchar *tbuf, *term; XFILE *termcap; X{ X char *tptr; X int tlen = strlen(term); X X while(nextent(tbuf, termcap)) { /* For each possible entry */ X tptr = tbuf; X while(*tptr && *tptr != ':') { /* : terminates name field */ X while(*tptr == '|') /* | seperates names */ X tptr++; X if(_match(tptr, term)==tlen) { /* FOUND! */ X fclose(termcap); X tent=tbuf; X return 1; X } X else /* Look for next name */ X tptr = _find(tptr, ":|"); X } X } X X return 0; X} X Xnextent(tbuf, termcap) /* Read 1 entry from TERMCAP file */ Xchar *tbuf; XFILE *termcap; X{ X char *lbuf = /* lbuf=line buffer */ X tbuf; /* read lines straight into buffer */ X X while(lbuf < tbuf+1024 && /* There's room and */ X fgets(lbuf, tbuf+1024-lbuf, termcap)) { /* another line */ X int llen = strlen(lbuf); X X if(*lbuf=='#') /* eat comments */ X continue; X if(lbuf[-1]==':' && /* and whitespace */ X lbuf[0]=='\t' && X lbuf[1]==':') { X strcpy(lbuf, lbuf+2); X llen -= 2; X } X if(lbuf[llen-2]=='\\') /* and continuations */ X lbuf += llen-2; X else { X lbuf[llen-1]=0; /* no continuation, return */ X return 1; X } X } X X return 0; /* ran into end of file */ X} //END echo x - tputs.c sed 's/^X//' > tputs.c << '//END' X/* TERMLIB: Terminal independant database. X * X * Module: tputs X * X * Purpose: decode padding information X * X * Calling conventions: cp = string to be padded, affcnt = # of items X * affected (lines, characters, whatever), X * outc = routine to output 1 character. X * X * Returned values: none X * X * Notes X * cp has padding information ahead of it, in the form X * nnnTEXT or nnn*TEXT. nnn is the number of milliseconds to delay, X * and may be a decimal (nnn.mmm). If the asterisk is given, then X * the delay is multiplied by afcnt. The delay is produced by outputting X * a number of nulls (or other padding char) after printing the X * TEXT. X * X */ X#include <stdio.h> X#include <ctype.h> X#include "termlib.h" X X/* tputs.c (libtermlib.a) X * X */ X Xlong _bauds[16]={ X 0, 50, 75, 110, X 134, 150, 200, 300, X 600, 1200, 1800, 2400, X 4800, 9600, 19200, 19200 }; X Xtputs(cp, affcnt, outc) Xchar *cp; /* string to print */ Xint affcnt; /* Number of lines affected */ Xint (*outc)(); /* routine to output 1 character */ X{ X long frac, /* 10^(#digits after decimal point) */ X counter, /* digits */ X atol(); X X if(isdigit(*cp)) { X counter = 0; X frac = 1000; X while(isdigit(*cp)) X counter = counter * 10L + (long)(*cp++ - '0'); X if(*cp=='.') X while(isdigit(*++cp)) { X counter = counter * 10L + (long)(*cp++ - '0'); X frac = frac * 10; X } X if(*cp!='*') { /* multiply by affected lines */ X if(affcnt>1) affcnt = 1; X } X else X cp++; X X /* Calculate number of characters for padding counter/frac ms delay */ X if(ospeed) X counter = (counter * _bauds[ospeed] * (long)affcnt) / frac; X X while(*cp) /* output string */ X (*outc)(*cp++); X if(ospeed) X while(counter--) /* followed by pad characters */ X (*outc)(PC); X } X else X while(*cp) X (*outc)(*cp++); X} //END echo x - cur.c sed 's/^X//' > cur.c << '//END' X/* Cur: Provide cursor addressing for shell scripts. X * X * Cur performs the same functions as echo, with 2 differences: X * 1. X * a. Arguments of the form -xx result in the generation of the capability X * string xx. The two special strings "cm" and "cs" are handled by X * cur ... -cm x y ... and ... -cs lo hi ... X * b. Arguments of the form #xx return the value of the numeric capability X * xx. X * c. Arguments of the form +terminal force cur to assume that as the X * terminal type. Any number of these can be included, and will be X * evaluated when encountered. X * 2. No newline is appended to the echoed string. X * X * Syntax: cur [string|-xx|#xx|+term]... X * X * Other notes: The code is obvious. X */ X#include <stdio.h> X#include "termlib.h" X Xextern char *junkptr; X Xmain(ac, av) Xint ac; char **av; X{ X int line, col, outch(); X char *val; X X tinit(getenv("TERM")); X X while(--ac) X if(**++av=='-') { X if(val=tgetstr(*av+1, &junkptr)) { X if(strcmp(*av+1, "cm") && X strcmp(*av+1, "cs")) X tputs(val, 1, outch); X else { X col = atoi(*++av); --ac; X line = atoi(*++av); --ac; X tputs(tgoto(val, col, line), 0, outch); X } X } X } else if(**av=='#') { X if(val = tgetstr(*av+1, &junkptr)) X fputs(val, stdout); X } else if(**av=='+') { X tinit(*av+1); X } else X fputs(*av, stdout); X} X Xoutch(c) char c; { putchar(c); } //END echo x - termcap.c sed 's/^X//' > termcap.c << '//END' X/* termcap... print current terminal capabilities. X * X * Termcap prints all the termcap capability strings for the terminal `term'. X * The output is in machine readable form, suitable for use in the construct: X * X * TERMCAP="`termcap`"; export TERMCAP X * X * Syntax: termcap [term] X */ X#include <stdio.h> X Xchar *tent; Xmain(ac, av) Xint ac; Xchar **av; X{ X char tbuf[1024]; X if(ac==1) if(tgetent(tbuf, getenv("TERM"))) { X puts(tbuf); X exit(0); X } else exit(-1); X if(tgetent(tbuf, av[1])) { X puts(tbuf); X exit(0); X } else exit(-1); X} //END echo x - tgetflag.c sed 's/^X//' > tgetflag.c << '//END' X/* The following software is (C) 1984 Peter da Silva, X the Mad Australian, in the public domain. It may X be re-distributed for any purpose with the inclusion X of this notice. */ X/* TERMLIB: Terminal independant database. X * X * Module: tgetflag X * X * Purpose: returns flag true or false as to the existence of a given X * entry. used with 'bs', 'am', etc... X * X * Calling conventions: id is the 2 character capability id. X * X * Returned values: 1 for success, 0 for failure. X */ X#include <stdio.h> X#include <ctype.h> X#include "termlib.h" X X/* tgetflag.c (libtermlib.a) X * XBUILD XOBJS=tinit.o tutil.o tvars.o \ X tgoto.o tputs.o tgetent.o tgetflag.o tgetnum.o tgetstr.o XCFLAGS=-O X Xlibtermlib.a: $(OBJS) termlib.h X ar cr libtermlib.a $(OBJS) X ranlib libtermlib.a X X$(OBJS):: termlib.h XEND X*/ X Xtgetflag(id) Xchar *id; X{ X char buf[256], *ptr = buf; X X return tgetstr(id, &ptr) ? 1 : 0; X} //END echo x - tgetstr.c sed 's/^X//' > tgetstr.c << '//END' X/* The following software is (C) 1984 Peter da Silva, X the Mad Australian, in the public domain. It may X be re-distributed for any purpose with the inclusion X of this notice. */ X/* TERMLIB: Terminal independant database. X * X * Module: tgetstr X * X * Purpose: get terminal capability string from database. X * X * Calling conventions: id is the two character capability id. X * (*buf) points into a hold buffer for the X * id. the capability is copied into the buffer X * and (*buf) is advanced to point to the next X * free byte in the buffer. X * X * Returned values: 0 = no such entry, otherwise returns original X * (*buf) (now a pointer to the string). X * X * Notes X * It also decodes certain escape sequences in the buffer. X * they should be obvious from the code: X * \E = escape. X * \n, \r, \t, \f, \b match the 'c' escapes. X * ^x matches control-x (^@...^_). X * \nnn matches nnn octal. X * \x, where x is anything else, matches x. I differ X * from the standard library here, in that I allow ^: to match X * :. X * X */ X#include <stdio.h> X#include <ctype.h> X#include "termlib.h" X X/* tgetstr.c (libtermlib.a) X * XBUILD XOBJS=tinit.o tutil.o tvars.o \ X tgoto.o tputs.o tgetent.o tgetflag.o tgetnum.o tgetstr.o XCFLAGS=-O X Xlibtermlib.a: $(OBJS) termlib.h X ar cr libtermlib.a $(OBJS) X ranlib libtermlib.a X X$(OBJS):: termlib.h XEND X*/ X Xchar * Xtgetstr(id, buf) Xchar *id, **buf; X{ X int len = strlen(id); X char *tmp=tent; X char *hold; X X do { X tmp = _find(tmp, ":"); /* For each field */ X while(*tmp==':') /* skip empty fields */ X tmp++; X if(!*tmp) X break; X X if(_match(id, tmp)==len) { X tmp += len; /* find '=' '@' or '#' */ X if(*tmp=='@') /* :xx@: entry for tc */ X return 0; /* deleted entry */ X hold= *buf; X while(*++tmp && *tmp != ':') {/* not at end of field */ X switch(*tmp) { X case '\\': /* Expand escapes here */ X switch(*++tmp) { X case 0: /* ignore backslashes */ X tmp--; /* at end of entry */ X break; /* shouldn't happen */ X case 'e': X case 'E': /* ESC */ X *(*buf)++ = '\033'; X break; X case 'n': /* \n */ X *(*buf)++ = '\n'; X break; X case 'r': /* \r */ X *(*buf)++ = '\r'; X break; X case 't': /* \t */ X *(*buf)++ = '\t'; X break; X case 'b': /* \b */ X *(*buf)++ = '\b'; X break; X case 'f': /* \f */ X *(*buf)++ = '\f'; X break; X case '0': /* \nnn */ X case '1': X case '2': X case '3': X case '4': X case '5': X case '6': X case '7': X case '8': X case '9': X **buf = 0; X while(isdigit(*tmp)) X **buf = **buf * 8 + *tmp++ - '0'; X (*buf)++; X tmp--; X break; X default: /* \x, for all other x */ X *(*buf)++= *tmp; X } X break; X case '^': /* control characters */ X *(*buf)++ = *++tmp - '@'; X break; X default: X *(*buf)++ = *tmp; X } X } X *(*buf)++ = 0; X return hold; X } X } while(*tmp); X X return 0; X} //END echo x - Makefile sed 's/^X//' > Makefile << '//END' X# X# The following module order is needed to create a properly sorted library X# for Manx X# X XOBJS=\ X tgetflag.o\ X tgetnum.o\ X tinit.o\ X tgoto.o\ X tputs.o\ X tvars.o\ X tgetent.o\ X tgetstr.o\ X tutil.o XSRC=\ X termlib.h\ X tinit.c\ X tgetnum.c\ X tutil.c\ X tvars.c\ X tgoto.c\ X tgetent.c\ X tputs.c\ X cur.c\ X termcap.c\ X tgetflag.c\ X tgetstr.c\ X Makefile X XCFLAGS= +P -B -DAMIGA=1 XLIB=termlibl32.lib X XLIBDIR=manx:lib XBINDIR=work:c X Xall: cur termcap X X$(LIB): $(OBJS) X lb $(LIB) $(OBJS) X Xtermcap: $(LIB) termcap.o X ln -o termcap termcap.o $(LIB) -lcl32 X Xcur: $(LIB) cur.o X ln -o cur cur.o $(LIB) -lcl32 X Xclean: X delete #?.o #?.lib termcap cur #?.bak X Xinstall: all X copy $(LIB) $(LIBDIR) X copy termcap $(BINDIR) X copy cur $(BINDIR) X Xtermlib.shar: $(SRC) X shar >termlib.shar $(SRC) //END : end of archive. exit 0 -- Peter da Silva. `-_-' <peter@sugar.hackercorp.com>.