/* * TERMCAP/TERMINFO database interface * Copyright * (C) 1992 Joseph H. Allen * * This file is part of JOE (Joe's Own Editor) */ #include "types.h" #ifdef TERMINFO #ifdef HAVE_CURSES_H #include #endif /* curses has to come before term.h on SGI */ #ifdef HAVE_TERM_H /* term.h is a disaster: it #defines 'tab' */ #include #endif #endif int dopadding = 0; unsigned char *joeterm = NULL; /* Default termcap entry */ unsigned char defentry[] = "\ :co#80:li#25:am:\ :ho=\\E[H:cm=\\E[%i%d;%dH:cV=\\E[%i%dH:\ :up=\\E[A:UP=\\E[%dA:DO=\\E[%dB:nd=\\E[C:RI=\\E[%dC:LE=\\E[%dD:\ :cd=\\E[J:ce=\\E[K:cl=\\E[H\\E[J:\ :so=\\E[7m:se=\\E[m:us=\\E[4m:ue=\\E[m:\ :mb=\\E[5m:md=\\E[1m:mh=\\E[2m:me=\\E[m:\ :ku=\\E[A:kd=\\E[B:kl=\\E[D:kr=\\E[C:\ :al=\\E[L:AL=\\E[%dL:dl=\\E[M:DL=\\E[%dM:\ :ic=\\E[@:IC=\\E[%d@:dc=\\E[P:DC=\\E[%dP:\ "; /* Return true if termcap line matches name */ static int match(unsigned char *s, unsigned char *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 unsigned char *lfind(unsigned char *s, int pos, FILE *fd, unsigned char *name) { 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') /* do nothing */; 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') /* do nothing */; else { s = vsset(s, x, c); ++x; } s = vstrunc(s, x); return s; } /* Lookup termcap entry in index */ static long findidx(FILE *file, unsigned char *name) { unsigned char buf[80]; long addr = 0; while (fgets((char *)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((char *)(buf + x), "%x", (unsigned *)&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 *my_getcap(unsigned char *name, unsigned int baud, void (*out) (unsigned char *, unsigned char), void *outptr) { CAP *cap; FILE *f, *f1; long idx; int x, y, c, z, ti; unsigned char *tp, *pp, *qq, *namebuf, **npbuf, *idxname; int sortsiz; if (!name && !(name = joeterm) && !(name = (unsigned char *)getenv("TERM"))) return NULL; cap = (CAP *) joe_malloc(sizeof(CAP)); cap->tbuf = vsmk(4096); cap->abuf = NULL; cap->sort = NULL; #ifdef TERMINFO cap->abuf = (unsigned char *) joe_malloc(4096); cap->abufp = cap->abuf; if (tgetent((char *)cap->tbuf, (char *)name) == 1) return setcap(cap, baud, out, outptr); else { joe_free(cap->abuf); cap->abuf = NULL; } #endif name = vsncpy(NULL, 0, sz(name)); cap->sort = (struct sortentry *) joe_malloc(sizeof(struct sortentry) * (sortsiz = 64)); cap->sortlen = 0; tp = (unsigned char *)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 = (unsigned char *)getenv("TERMPATH"))) namebuf = vsncpy(NULL, 0, sz(tp)); else { if ((tp = (unsigned char *)getenv("HOME"))) { namebuf = vsncpy(NULL, 0, sz(tp)); namebuf = vsadd(namebuf, '/'); } else namebuf = NULL; namebuf = vsncpy(sv(namebuf), sc(".termcap ")); namebuf = vsncpy(sv(namebuf), sc(JOERC)); namebuf = vsncpy(sv(namebuf), sc("termcap /etc/termcap")); } } 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); joe_free(cap->sort); joe_free(cap); return 0; */ fprintf(stderr, (char *)joe_gettext(_("Couldn't load termcap entry. Using ansi default\n"))); ti = 0; cap->tbuf = vsncpy(cap->tbuf, 0, sc(defentry)); goto checktc; } idx = 0; idxname = vsncpy(NULL, 0, sz(npbuf[y])); idxname = vsncpy(idxname, sLEN(idxname), sc(".idx")); f1 = fopen((char *)(npbuf[y]), "r"); ++y; if (!f1) goto nextfile; f = fopen((char *)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, (char *)joe_gettext(_("%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] != ':') /* do nothing */; } 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) { int found; z = (x + y) / 2; found = zcmp(qq, cap->sort[z].name); if(found > 0) { x = z; } else if(found < 0) { y = z; } else { if (c == '@') mmove(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 = NULL; if (c == ':') goto loop1; else goto loop; } } in: if (cap->sortlen == sortsiz) cap->sort = (struct sortentry *) joe_realloc(cap->sort, (sortsiz += 32) * sizeof(struct sortentry)); mmove(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 = NULL; 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, USTR "pc"); if (dopadding) cap->dopadding = 1; else cap->dopadding = 0; /* show sorted entries for(x=0;x!=cap->sortlen;++x) printf("%s = %s\n",cap->sort[x].name,cap->sort[x].value); */ return setcap(cap, baud, out, outptr); } static struct sortentry *findcap(CAP *cap, unsigned char *name) { int x, y, z; int found; x = 0; y = cap->sortlen; z = -1; while (z != (x + y) / 2) { z = (x + y) / 2; found = zcmp(name, cap->sort[z].name); if (found > 0) x = z; else if (found < 0) y = z; else return cap->sort + z; } return NULL; } CAP *setcap(CAP *cap, unsigned int baud, void (*out) (unsigned char *, unsigned char), void *outptr) { cap->baud = baud; cap->div = 100000 / baud; cap->out = out; cap->outptr = outptr; return cap; } int getflag(CAP *cap, unsigned char *name) { #ifdef TERMINFO if (cap->abuf) return tgetflag((char *)name); #endif return findcap(cap, name) != NULL; } unsigned char *jgetstr(CAP *cap, unsigned char *name) { struct sortentry *s; #ifdef TERMINFO if (cap->abuf) { char *new_ptr = (char *)cap->abufp; char *rtn; rtn = tgetstr((char *)name, &new_ptr); cap->abufp = (unsigned char *)new_ptr; return (unsigned char *)rtn; } #endif s = findcap(cap, name); if (s) return s->value; else return NULL; } int getnum(CAP *cap, unsigned char *name) { struct sortentry *s; #ifdef TERMINFO if (cap->abuf) return tgetnum((char *)name); #endif s = findcap(cap, name); if (s && s->value) return atoi((char *)(s->value)); return -1; } void rmcap(CAP *cap) { vsrm(cap->tbuf); if (cap->abuf) joe_free(cap->abuf); if (cap->sort) joe_free(cap->sort); joe_free(cap); } static unsigned char escape1(unsigned char **s) { unsigned char c = *(*s)++; if (c == '^' && **s) if (**s != '?') return 037 & *(*s)++; else { (*s)++; return 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; } static CAP *outcap; static int outout(int c) { outcap->out(outcap->outptr, c); return(c); /* act like putchar() - return written char */ } void texec(CAP *cap, unsigned char *s, int l, int a0, int a1, int a2, int a3) { int c, tenth = 0, x; int args[4]; int vars[128]; int *a = args; /* Do nothing if there is no string */ if (!s) return; #ifdef TERMINFO if (cap->abuf) { unsigned char *a; outcap = cap; a = (unsigned char *)tgoto((char *)s, a1, a0); tputs((char *)a, l, outout); return; } #endif /* Copy args into array (yuk) */ args[0] = a0; args[1] = a1; args[2] = a2; args[3] = a3; /* 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++) != '\0') if (c == '%' && *s) { switch (x = a[0], c = escape1(&s)) { case 'C': if (x >= 96) { cap->out(cap->outptr, x / 96); x %= 96; } case '+': if (*s) x += escape1(&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] > escape1(&s)) a[0] += escape1(&s); else escape1(&s); default: cap->out(cap->outptr, '%'); cap->out(cap->outptr, c); } } else { --s; cap->out(cap->outptr, escape1(&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(unsigned char *ptr, unsigned char c) { ++total; } int tcost(CAP *cap, unsigned char *s, int l, int a0, int a1, int a2, int a3) { void (*out) (unsigned char *, unsigned char) = 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 unsigned char *ssp; static void cpl(unsigned char *ptr, unsigned char c) { ssp = vsadd(ssp, c); } unsigned char *tcompile(CAP *cap, unsigned char *s, int a0, int a1, int a2, int a3) { void (*out) (unsigned char *, unsigned char) = cap->out; int div = cap->div; if (!s) return NULL; 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 (not to be used when TERMINFO is set) */ #ifdef junk short ospeed; /* Output speed */ unsigned char PC, *UP, *BC; /* Unused */ static CAP *latest; /* CAP entry to use */ static void stupid(ptr, c) void (*ptr) (); unsigned char c; { ptr(c); } int tgetent(buf, name) unsigned char *buf, *name; { latest = my_getcap(name, 9600, stupid, NULL); if (latest) return 1; else return -1; } int tgetflag(name) unsigned char *name; { return getflag(latest, name); } int tgetnum(name) unsigned char *name; { return getnum(latest, name); } unsigned char *tgetstr(name) unsigned char *name; { return jgetstr(latest, name); } static int latestx, latesty; unsigned char *tgoto(str, x, y) unsigned char *str; int x, y; { latestx = x; latesty = y; return str; } void tputs(str, l, out) unsigned 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