This is termcap.c in view mode; [Download] [Up]
/* TERMCAP database interface
Copyright (C) 1992 Joseph H. Allen
This file is part of JOE (Joe's Own Editor)
JOE is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 1, or (at your option) any later version.
JOE is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
JOE; see the file COPYING. If not, write to the Free Software Foundation,
675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "config.h"
#include "blocks.h"
#include "vs.h"
#include "va.h"
#include "zstr.h"
#include "queue.h"
#include "termcap.h"
int dopadding=0;
/* Return true if termcap line matches name */
static int match(s,name)
char *s, *name;
{
if(s[0]==0 || s[0]=='#') return 0;
do
{
int x;
for(x=0;s[x]==name[x] && name[x] && s[x];++x);
if(name[x]==0 && (s[x]==':' || s[x]=='|')) return 1;
while(s[x]!=':' && s[x]!='|' && s[x]) ++x;
s+=x+1;
}
while(s[-1]=='|');
return 0;
}
/* Find termcap entry in a file */
static char *lfind(s,pos,fd,name)
char *s, *name;
FILE *fd;
int pos;
{
int c,x;
if(!s) s=vsmk(1024);
loop:
while(c=getc(fd), c==' ' || c=='\t' || c=='#')
do c=getc(fd); while(!(c== -1 || c=='\n'));
if(c== -1) return s=vstrunc(s,pos);
ungetc(c,fd);
s=vstrunc(s,x=pos);
while(1)
{
c=getc(fd);
if(c== -1 || c=='\n')
if(x!=pos && s[x-1]=='\\')
{
--x;
if(!match(s+pos,name)) goto loop;
else break;
}
else
if(!match(s+pos,name)) goto loop;
else return vstrunc(s,x);
else if(c=='\r') ;
else s=vsset(s,x,c), ++x;
}
while(c=getc(fd), c!= -1)
if(c=='\n')
if(s[x-1]=='\\') --x;
else break;
else if(c=='\r') ;
else s=vsset(s,x,c), ++x;
s=vstrunc(s,x);
return s;
}
/* Lookup termcap entry in index */
static long findidx(file,name)
FILE *file;
char *name;
{
char buf[80];
long addr=0;
while(fgets(buf,80,file))
{
int x=0, flg=0, c, y, z;
do
{
for(y=x;buf[y] && buf[y]!=' ' && buf[y]!='\n';++y);
c=buf[y]; buf[y]=0;
if(c=='\n' || !c)
{
z=0; sscanf(buf+x,"%x",&z);
addr+=z;
}
else if(!zcmp(buf+x,name)) flg=1;
x=y+1;
}
while(c && c!='\n');
if(flg) return addr;
}
return 0;
}
/* Load termcap entry */
CAP *getcap(name,baud,out,outptr)
char *name;
unsigned baud;
void (*out)();
void *outptr;
{
CAP *cap;
FILE *f, *f1;
long idx;
int x,y,c,z,ti;
char *tp, *pp, *qq, *namebuf, **npbuf, *idxname;
int sortsiz;
if(!name && !(name=getenv("TERM"))) return 0;
name=vsncpy(NULL,0,sz(name));
cap=(CAP *)malloc(sizeof(CAP));
cap->tbuf=vsmk(1024);
cap->sort=(struct sortentry *)malloc(sizeof(struct sortentry)*(sortsiz=64));
cap->sortlen=0;
tp=getenv("TERMCAP");
if(tp && tp[0]=='/') namebuf=vsncpy(NULL,0,sz(tp));
else
{
if(tp) cap->tbuf=vsncpy(sv(cap->tbuf),sz(tp));
if((tp=getenv("TERMPATH"))) namebuf=vsncpy(NULL,0,sz(tp));
else if((tp=getenv("HOME")))
namebuf=vsncpy(NULL,0,sz(tp)),
namebuf=vsadd(namebuf,'/'),
namebuf=vsncpy(sv(namebuf),sz(TERMPATH));
else namebuf=vsncpy(NULL,0,sz(TERMPATH));
}
npbuf=vawords(NULL,sv(namebuf),sc("\t :"));
vsrm(namebuf);
y=0; ti=0;
if(match(cap->tbuf,name)) goto checktc;
cap->tbuf=vstrunc(cap->tbuf,0);
nextfile:
if(!npbuf[y])
{
varm(npbuf);
vsrm(name);
vsrm(cap->tbuf);
free(cap->sort);
free(cap);
return 0;
}
idx=0;
idxname=vsncpy(NULL,0,sz(npbuf[y]));
idxname=vsncpy(idxname,sLEN(idxname),sc(".idx"));
f1=fopen(npbuf[y],"r");
++y;
if(!f1) goto nextfile;
f=fopen(idxname,"r");
if(f)
{
struct stat buf, buf1;
fstat(fileno(f),&buf);
fstat(fileno(f1),&buf1);
if(buf.st_mtime>buf1.st_mtime) idx=findidx(f,name);
else fprintf(stderr,"%s is out of date\n",idxname);
fclose(f);
}
vsrm(idxname);
fseek(f1,idx,0);
cap->tbuf=lfind(cap->tbuf,ti,f1,name);
fclose(f1);
if(sLEN(cap->tbuf)==ti) goto nextfile;
checktc:
x=sLEN(cap->tbuf);
do
{
cap->tbuf[x]=0;
while(x && cap->tbuf[--x]!=':');
}
while(x && (!cap->tbuf[x+1] || cap->tbuf[x+1]==':'));
if(cap->tbuf[x+1]=='t' && cap->tbuf[x+2]=='c' && cap->tbuf[x+3]=='=')
{
name=vsncpy(NULL,0,sz(cap->tbuf+x+4));
cap->tbuf[x]=0;
cap->tbuf[x+1]=0;
ti=x+1;
sLen(cap->tbuf)=x+1;
if(y) --y;
goto nextfile;
}
doline:
pp=cap->tbuf+ti;
/* Process line at pp */
loop:
while(*pp && *pp!=':') ++pp;
if(*pp)
{
int q;
*pp++=0;
loop1:
if(pp[0]==' ' || pp[0]=='\t') goto loop;
for(q=0;pp[q] && pp[q]!='#' && pp[q]!='=' && pp[q]!='@' && pp[q]!=':';++q);
qq=pp;
c=pp[q]; pp[q]=0;
if(c) pp+=q+1;
else pp+=q;
x=0; y=cap->sortlen; z= -1;
if(!y) { z=0; goto in; }
while(z!=(x+y)/2)
{
z=(x+y)/2;
switch(zcmp(qq,cap->sort[z].name))
{
case 1: x=z; break;
case -1: y=z; break;
case 0:
if(c=='@')
mfwrd(cap->sort+z,cap->sort+z+1,
(cap->sortlen---(z+1))*sizeof(struct sortentry));
else
if(c && c!=':') cap->sort[z].value=qq+q+1;
else cap->sort[z].value=0;
if(c==':') goto loop1;
else goto loop;
}
}
in:
if(cap->sortlen==sortsiz)
cap->sort=(struct sortentry *)realloc(cap->sort,
(sortsiz+=32)*sizeof(struct sortentry));
mbkwd(cap->sort+y+1,cap->sort+y,
(cap->sortlen++-y)*sizeof(struct sortentry));
cap->sort[y].name=qq;
if(c && c!=':') cap->sort[y].value=qq+q+1;
else cap->sort[y].value=0;
if(c==':') goto loop1;
else goto loop;
}
if(ti)
{
for(--ti;ti;--ti) if(!cap->tbuf[ti-1]) break;
goto doline;
}
varm(npbuf);
vsrm(name);
cap->pad=jgetstr(cap,"pc");
if(dopadding) cap->dopadding=1;
else cap->dopadding=0;
return setcap(cap,baud,out,outptr);
}
struct sortentry *findcap(cap,name)
CAP *cap;
char *name;
{
int x,y,z;
x=0; y=cap->sortlen; z= -1;
while(z!=(x+y)/2)
{
z=(x+y)/2;
switch(zcmp(name,cap->sort[z].name))
{
case 1: x=z; break;
case -1: y=z; break;
case 0: return cap->sort+z;
}
}
return 0;
}
CAP *setcap(cap,baud,out,outptr)
CAP *cap;
unsigned baud;
void (*out)();
void *outptr;
{
cap->baud=baud;
cap->div=100000/baud;
cap->out=out;
cap->outptr=outptr;
return cap;
}
int getflag(cap,name)
CAP *cap;
char *name;
{
return findcap(cap,name)!=0;
}
char *jgetstr(cap,name)
CAP *cap;
char *name;
{
struct sortentry *s=findcap(cap,name);
if(s) return s->value;
else return 0;
}
int getnum(cap,name)
CAP *cap;
char *name;
{
struct sortentry *s=findcap(cap,name);
if(s && s->value) return atoi(s->value);
return -1;
}
void rmcap(cap)
CAP *cap;
{
vsrm(cap->tbuf);
free(cap->sort);
free(cap);
}
static char escape(s)
char **s;
{
char c= *(*s)++;
if(c=='^' && **s)
if(**s!='?') return 037&*(*s)++;
else return (*s)++, 127;
else if(c=='\\' && **s)
switch(c= *((*s)++))
{
case '0': case '1': case '2': case'3': case '4': case '5': case '6': case '7':
c-='0';
if(**s>='0' && **s<='7') c=(c<<3)+*((*s)++)-'0';
if(**s>='0' && **s<='7') c=(c<<3)+*((*s)++)-'0';
return c;
case 'e':
case 'E': return 27;
case 'n':
case 'l': return 10;
case 'r': return 13;
case 't': return 9;
case 'b': return 8;
case 'f': return 12;
case 's': return 32;
default: return c;
}
else return c;
}
void texec(cap,s,l,a0,a1,a2,a3)
CAP *cap;
char *s;
int l,a0,a1,a2,a3;
{
int c, tenth=0, x;
int args[4];
int vars[128];
int *a=args;
/* Copy args into array (yuk) */
args[0]=a0; args[1]=a1; args[2]=a2; args[3]=a3;
/* Do nothing if there is no string */
if(!s) return;
/* Get tenths of MS of padding needed */
while(*s>='0' && *s<='9') tenth=tenth*10+*s++-'0';
tenth*=10;
if(*s=='.') ++s, tenth+= *s++-'0';
/* Check if we have to multiply by number of lines */
if(*s=='*') ++s, tenth*=l;
/* Output string */
while(c= *s++)
if(c=='%' && *s)
switch(x=a[0], c= escape(&s))
{
case 'C': if(x>=96) cap->out(cap->outptr,x/96), x%=96;
case '+': if(*s) x+= escape(&s);
case '.': cap->out(cap->outptr,x); ++a; break;
case 'd': if(x<10) goto one;
case '2': if(x<100) goto two;
case '3': c='0'; while(x>=100) ++c, x-=100; cap->out(cap->outptr,c);
two: c='0'; while(x>=10) ++c, x-=10; cap->out(cap->outptr,c);
one: cap->out(cap->outptr,'0'+x); ++a; break;
case 'r': a[0]=a[1]; a[1]=x; break;
case 'i': ++a[0]; ++a[1]; break;
case 'n': a[0]^=0140; a[1]^=0140; break;
case 'm': a[0]^=0177; a[1]^=0177; break;
case 'f': ++a; break;
case 'b': --a; break;
case 'a': x=s[2];
if(s[1]=='p') x=a[x-0100];
switch(*s)
{
case '+': a[0]+=x; break;
case '-': a[0]-=x; break;
case '*': a[0]*=x; break;
case '/': a[0]/=x; break;
case '%': a[0]%=x; break;
case 'l': a[0]=vars[x]; break;
case 's': vars[x]=a[0]; break;
default: a[0]=x;
}
s+=3;
break;
case 'D': a[0]=a[0]-2*(a[0]&15); break;
case 'B': a[0]=16*(a[0]/10)+a[0]%10; break;
case '>': if(a[0]>escape(&s)) a[0]+=escape(&s); else escape(&s);
default: cap->out(cap->outptr,'%'); cap->out(cap->outptr,c);
}
else --s, cap->out(cap->outptr,escape(&s));
/* Output padding characters */
if(cap->dopadding)
if(cap->pad)
while(tenth>=cap->div)
for(s=cap->pad;*s;++s) cap->out(cap->outptr,*s), tenth-=cap->div;
else
while(tenth>=cap->div) cap->out(cap->outptr,0), tenth-=cap->div;
}
static int total;
static void cst()
{
++total;
}
int tcost(cap,s,l,a0,a1,a2,a3)
CAP *cap;
char *s;
int l,a0,a1,a2,a3;
{
void (*out)()=cap->out;
if(!s) return 10000;
total=0;
cap->out=cst;
texec(cap,s,l,a0,a1,a2,a3);
cap->out=out;
return total;
}
static char *ssp;
static void cpl(ptr,c)
char *ptr;
char c;
{
ssp=vsadd(ssp,c);
}
char *tcompile(cap,s,a0,a1,a2,a3)
CAP *cap;
char *s;
int a0,a1,a2,a3;
{
void (*out)()=cap->out;
int div=cap->div;
if(!s) return 0;
cap->out=cpl; cap->div=10000;
ssp=vsmk(10);
texec(cap,s,0,a0,a1,a2,a3);
cap->out=out; cap->div=div;
return ssp;
}
/* Old termcap compatibility */
#ifdef junk
short ospeed; /* Output speed */
char PC, *UP, *BC; /* Unused */
static CAP *latest; /* CAP entry to use */
static void stupid(ptr,c)
void (*ptr)();
char c;
{
ptr(c);
}
int tgetent(buf,name)
char *buf, *name;
{
latest=getcap(name,9600,stupid,NULL);
if(latest) return 1;
else return -1;
}
int tgetflag(name)
char *name;
{
return getflag(latest,name);
}
int tgetnum(name)
char *name;
{
return getnum(latest,name);
}
char *tgetstr(name)
char *name;
{
return jgetstr(latest,name);
}
static int latestx, latesty;
char *tgoto(str,x,y)
char *str;
int x,y;
{
latestx=x; latesty=y;
return str;
}
void tputs(str,l,out)
char *str;
int l;
void (*out)();
{
latest->outptr=(void *)out;
if(latest->baud!=ospeed) latest->baud=ospeed, latest->div=100000/ospeed;
texec(latest,str,l,latesty,latestx);
}
#endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.