17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California. 37c478bd9Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 47c478bd9Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 57c478bd9Sstevel@tonic-gate */ 67c478bd9Sstevel@tonic-gate 77c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 87c478bd9Sstevel@tonic-gate 97c478bd9Sstevel@tonic-gate #define BUFSIZ 1024 107c478bd9Sstevel@tonic-gate #define MAXHOP 32 /* max number of tc= indirections */ 117c478bd9Sstevel@tonic-gate 127c478bd9Sstevel@tonic-gate #include <ctype.h> 137c478bd9Sstevel@tonic-gate #include <locale.h> 147c478bd9Sstevel@tonic-gate #include <string.h> 157c478bd9Sstevel@tonic-gate /* 167c478bd9Sstevel@tonic-gate * grindcap - routines for dealing with the language definitions data base 177c478bd9Sstevel@tonic-gate * (code stolen almost totally from termcap) 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * BUG: Should use a "last" pointer in tbuf, so that searching 207c478bd9Sstevel@tonic-gate * for capabilities alphabetically would not be a n**2/2 217c478bd9Sstevel@tonic-gate * process when large numbers of capabilities are given. 227c478bd9Sstevel@tonic-gate * Note: If we add a last pointer now we will screw up the 237c478bd9Sstevel@tonic-gate * tc capability. We really should compile termcap. 247c478bd9Sstevel@tonic-gate * 257c478bd9Sstevel@tonic-gate * Essentially all the work here is scanning and decoding escapes 267c478bd9Sstevel@tonic-gate * in string capabilities. We don't use stdio because the editor 277c478bd9Sstevel@tonic-gate * doesn't, and because living w/o it is not hard. 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate static char *tbuf; 317c478bd9Sstevel@tonic-gate static char *filename; 327c478bd9Sstevel@tonic-gate static int hopcount; /* detect infinite loops in termcap, init 0 */ 337c478bd9Sstevel@tonic-gate char *tgetstr(); 347c478bd9Sstevel@tonic-gate char *getenv(); 357c478bd9Sstevel@tonic-gate 36*e5af7cceScraigm static char *tdecode(char *str, char **area); 37*e5af7cceScraigm static char *tskip(char *bp); 38*e5af7cceScraigm static int tnchktc(void); 39*e5af7cceScraigm static int tnamatch(char *np); 40*e5af7cceScraigm 417c478bd9Sstevel@tonic-gate static char *vgrind_msg; 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate /* 447c478bd9Sstevel@tonic-gate * Get an entry for terminal name in buffer bp, 457c478bd9Sstevel@tonic-gate * from the termcap file. Parse is very rudimentary; 467c478bd9Sstevel@tonic-gate * we just notice escaped newlines. 477c478bd9Sstevel@tonic-gate */ 48*e5af7cceScraigm int 49*e5af7cceScraigm tgetent(char *bp, char *name, char *file) 507c478bd9Sstevel@tonic-gate { 51*e5af7cceScraigm char *cp; 52*e5af7cceScraigm int c; 53*e5af7cceScraigm int i = 0, cnt = 0; 547c478bd9Sstevel@tonic-gate char ibuf[BUFSIZ]; 557c478bd9Sstevel@tonic-gate char *cp2; 567c478bd9Sstevel@tonic-gate int tf; 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate tbuf = bp; 597c478bd9Sstevel@tonic-gate tf = 0; 607c478bd9Sstevel@tonic-gate filename = file; 617c478bd9Sstevel@tonic-gate tf = open(filename, 0); 627c478bd9Sstevel@tonic-gate if (tf < 0) 637c478bd9Sstevel@tonic-gate return (-1); 647c478bd9Sstevel@tonic-gate for (;;) { 657c478bd9Sstevel@tonic-gate cp = bp; 667c478bd9Sstevel@tonic-gate for (;;) { 677c478bd9Sstevel@tonic-gate if (i == cnt) { 687c478bd9Sstevel@tonic-gate cnt = read(tf, ibuf, BUFSIZ); 697c478bd9Sstevel@tonic-gate if (cnt <= 0) { 707c478bd9Sstevel@tonic-gate close(tf); 717c478bd9Sstevel@tonic-gate return (0); 727c478bd9Sstevel@tonic-gate } 737c478bd9Sstevel@tonic-gate i = 0; 747c478bd9Sstevel@tonic-gate } 757c478bd9Sstevel@tonic-gate c = ibuf[i++]; 767c478bd9Sstevel@tonic-gate if (c == '\n') { 777c478bd9Sstevel@tonic-gate if (cp > bp && cp[-1] == '\\'){ 787c478bd9Sstevel@tonic-gate cp--; 797c478bd9Sstevel@tonic-gate continue; 807c478bd9Sstevel@tonic-gate } 817c478bd9Sstevel@tonic-gate break; 827c478bd9Sstevel@tonic-gate } 837c478bd9Sstevel@tonic-gate if (cp >= bp+BUFSIZ) { 847c478bd9Sstevel@tonic-gate vgrind_msg = gettext("Vgrind entry too long\n"); 857c478bd9Sstevel@tonic-gate write(2, vgrind_msg, strlen(vgrind_msg)); 867c478bd9Sstevel@tonic-gate break; 877c478bd9Sstevel@tonic-gate } else 887c478bd9Sstevel@tonic-gate *cp++ = c; 897c478bd9Sstevel@tonic-gate } 907c478bd9Sstevel@tonic-gate *cp = 0; 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate /* 937c478bd9Sstevel@tonic-gate * The real work for the match. 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate if (tnamatch(name)) { 967c478bd9Sstevel@tonic-gate close(tf); 977c478bd9Sstevel@tonic-gate return(tnchktc()); 987c478bd9Sstevel@tonic-gate } 997c478bd9Sstevel@tonic-gate } 1007c478bd9Sstevel@tonic-gate } 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /* 1037c478bd9Sstevel@tonic-gate * tnchktc: check the last entry, see if it's tc=xxx. If so, 1047c478bd9Sstevel@tonic-gate * recursively find xxx and append that entry (minus the names) 1057c478bd9Sstevel@tonic-gate * to take the place of the tc=xxx entry. This allows termcap 1067c478bd9Sstevel@tonic-gate * entries to say "like an HP2621 but doesn't turn on the labels". 1077c478bd9Sstevel@tonic-gate * Note that this works because of the left to right scan. 1087c478bd9Sstevel@tonic-gate */ 109*e5af7cceScraigm static int 110*e5af7cceScraigm tnchktc(void) 1117c478bd9Sstevel@tonic-gate { 112*e5af7cceScraigm char *p, *q; 1137c478bd9Sstevel@tonic-gate char tcname[16]; /* name of similar terminal */ 1147c478bd9Sstevel@tonic-gate char tcbuf[BUFSIZ]; 1157c478bd9Sstevel@tonic-gate char *holdtbuf = tbuf; 1167c478bd9Sstevel@tonic-gate int l; 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate p = tbuf + strlen(tbuf) - 2; /* before the last colon */ 1197c478bd9Sstevel@tonic-gate while (*--p != ':') 1207c478bd9Sstevel@tonic-gate if (p<tbuf) { 1217c478bd9Sstevel@tonic-gate vgrind_msg = gettext("Bad vgrind entry\n"); 1227c478bd9Sstevel@tonic-gate write(2, vgrind_msg, strlen(vgrind_msg)); 1237c478bd9Sstevel@tonic-gate return (0); 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate p++; 1267c478bd9Sstevel@tonic-gate /* p now points to beginning of last field */ 1277c478bd9Sstevel@tonic-gate if (p[0] != 't' || p[1] != 'c') 1287c478bd9Sstevel@tonic-gate return(1); 1297c478bd9Sstevel@tonic-gate strcpy(tcname,p+3); 1307c478bd9Sstevel@tonic-gate q = tcname; 1317c478bd9Sstevel@tonic-gate while (q && *q != ':') 1327c478bd9Sstevel@tonic-gate q++; 1337c478bd9Sstevel@tonic-gate *q = 0; 1347c478bd9Sstevel@tonic-gate if (++hopcount > MAXHOP) { 1357c478bd9Sstevel@tonic-gate vgrind_msg = gettext("Infinite tc= loop\n"); 1367c478bd9Sstevel@tonic-gate write(2, vgrind_msg, strlen(vgrind_msg)); 1377c478bd9Sstevel@tonic-gate return (0); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate if (tgetent(tcbuf, tcname, filename) != 1) 1407c478bd9Sstevel@tonic-gate return(0); 1417c478bd9Sstevel@tonic-gate for (q=tcbuf; *q != ':'; q++) 1427c478bd9Sstevel@tonic-gate ; 1437c478bd9Sstevel@tonic-gate l = p - holdtbuf + strlen(q); 1447c478bd9Sstevel@tonic-gate if (l > BUFSIZ) { 1457c478bd9Sstevel@tonic-gate vgrind_msg = gettext("Vgrind entry too long\n"); 1467c478bd9Sstevel@tonic-gate write(2, vgrind_msg, strlen(vgrind_msg)); 1477c478bd9Sstevel@tonic-gate q[BUFSIZ - (p-tbuf)] = 0; 1487c478bd9Sstevel@tonic-gate } 1497c478bd9Sstevel@tonic-gate strcpy(p, q+1); 1507c478bd9Sstevel@tonic-gate tbuf = holdtbuf; 1517c478bd9Sstevel@tonic-gate return(1); 1527c478bd9Sstevel@tonic-gate } 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* 1557c478bd9Sstevel@tonic-gate * Tnamatch deals with name matching. The first field of the termcap 1567c478bd9Sstevel@tonic-gate * entry is a sequence of names separated by |'s, so we compare 1577c478bd9Sstevel@tonic-gate * against each such name. The normal : terminator after the last 1587c478bd9Sstevel@tonic-gate * name (before the first field) stops us. 1597c478bd9Sstevel@tonic-gate */ 160*e5af7cceScraigm static int 161*e5af7cceScraigm tnamatch(char *np) 1627c478bd9Sstevel@tonic-gate { 163*e5af7cceScraigm char *Np, *Bp; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate Bp = tbuf; 1667c478bd9Sstevel@tonic-gate if (*Bp == '#') 1677c478bd9Sstevel@tonic-gate return(0); 1687c478bd9Sstevel@tonic-gate for (;;) { 1697c478bd9Sstevel@tonic-gate for (Np = np; *Np && *Bp == *Np; Bp++, Np++) 1707c478bd9Sstevel@tonic-gate continue; 1717c478bd9Sstevel@tonic-gate if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) 1727c478bd9Sstevel@tonic-gate return (1); 1737c478bd9Sstevel@tonic-gate while (*Bp && *Bp != ':' && *Bp != '|') 1747c478bd9Sstevel@tonic-gate Bp++; 1757c478bd9Sstevel@tonic-gate if (*Bp == 0 || *Bp == ':') 1767c478bd9Sstevel@tonic-gate return (0); 1777c478bd9Sstevel@tonic-gate Bp++; 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* 1827c478bd9Sstevel@tonic-gate * Skip to the next field. Notice that this is very dumb, not 1837c478bd9Sstevel@tonic-gate * knowing about \: escapes or any such. If necessary, :'s can be put 1847c478bd9Sstevel@tonic-gate * into the termcap file in octal. 1857c478bd9Sstevel@tonic-gate */ 1867c478bd9Sstevel@tonic-gate static char * 187*e5af7cceScraigm tskip(char *bp) 1887c478bd9Sstevel@tonic-gate { 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate while (*bp && *bp != ':') 1917c478bd9Sstevel@tonic-gate bp++; 1927c478bd9Sstevel@tonic-gate if (*bp == ':') 1937c478bd9Sstevel@tonic-gate bp++; 1947c478bd9Sstevel@tonic-gate return (bp); 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate /* 1987c478bd9Sstevel@tonic-gate * Return the (numeric) option id. 1997c478bd9Sstevel@tonic-gate * Numeric options look like 2007c478bd9Sstevel@tonic-gate * li#80 2017c478bd9Sstevel@tonic-gate * i.e. the option string is separated from the numeric value by 2027c478bd9Sstevel@tonic-gate * a # character. If the option is not found we return -1. 2037c478bd9Sstevel@tonic-gate * Note that we handle octal numbers beginning with 0. 2047c478bd9Sstevel@tonic-gate */ 205*e5af7cceScraigm static int 206*e5af7cceScraigm tgetnum(char *id) 2077c478bd9Sstevel@tonic-gate { 208*e5af7cceScraigm int i, base; 209*e5af7cceScraigm char *bp = tbuf; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate for (;;) { 2127c478bd9Sstevel@tonic-gate bp = tskip(bp); 2137c478bd9Sstevel@tonic-gate if (*bp == 0) 2147c478bd9Sstevel@tonic-gate return (-1); 2157c478bd9Sstevel@tonic-gate if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 2167c478bd9Sstevel@tonic-gate continue; 2177c478bd9Sstevel@tonic-gate if (*bp == '@') 2187c478bd9Sstevel@tonic-gate return(-1); 2197c478bd9Sstevel@tonic-gate if (*bp != '#') 2207c478bd9Sstevel@tonic-gate continue; 2217c478bd9Sstevel@tonic-gate bp++; 2227c478bd9Sstevel@tonic-gate base = 10; 2237c478bd9Sstevel@tonic-gate if (*bp == '0') 2247c478bd9Sstevel@tonic-gate base = 8; 2257c478bd9Sstevel@tonic-gate i = 0; 2267c478bd9Sstevel@tonic-gate while (isdigit(*bp)) 2277c478bd9Sstevel@tonic-gate i *= base, i += *bp++ - '0'; 2287c478bd9Sstevel@tonic-gate return (i); 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate } 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate /* 2337c478bd9Sstevel@tonic-gate * Handle a flag option. 2347c478bd9Sstevel@tonic-gate * Flag options are given "naked", i.e. followed by a : or the end 2357c478bd9Sstevel@tonic-gate * of the buffer. Return 1 if we find the option, or 0 if it is 2367c478bd9Sstevel@tonic-gate * not given. 2377c478bd9Sstevel@tonic-gate */ 238*e5af7cceScraigm int 239*e5af7cceScraigm tgetflag(char *id) 2407c478bd9Sstevel@tonic-gate { 241*e5af7cceScraigm char *bp = tbuf; 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate for (;;) { 2447c478bd9Sstevel@tonic-gate bp = tskip(bp); 2457c478bd9Sstevel@tonic-gate if (!*bp) 2467c478bd9Sstevel@tonic-gate return (0); 2477c478bd9Sstevel@tonic-gate if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { 2487c478bd9Sstevel@tonic-gate if (!*bp || *bp == ':') 2497c478bd9Sstevel@tonic-gate return (1); 2507c478bd9Sstevel@tonic-gate else if (*bp == '@') 2517c478bd9Sstevel@tonic-gate return(0); 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate /* 2577c478bd9Sstevel@tonic-gate * Get a string valued option. 2587c478bd9Sstevel@tonic-gate * These are given as 2597c478bd9Sstevel@tonic-gate * cl=^Z 2607c478bd9Sstevel@tonic-gate * Much decoding is done on the strings, and the strings are 2617c478bd9Sstevel@tonic-gate * placed in area, which is a ref parameter which is updated. 2627c478bd9Sstevel@tonic-gate * No checking on area overflow. 2637c478bd9Sstevel@tonic-gate */ 2647c478bd9Sstevel@tonic-gate char * 265*e5af7cceScraigm tgetstr(char *id, char **area) 2667c478bd9Sstevel@tonic-gate { 267*e5af7cceScraigm char *bp = tbuf; 2687c478bd9Sstevel@tonic-gate 2697c478bd9Sstevel@tonic-gate for (;;) { 2707c478bd9Sstevel@tonic-gate bp = tskip(bp); 2717c478bd9Sstevel@tonic-gate if (!*bp) 2727c478bd9Sstevel@tonic-gate return (0); 2737c478bd9Sstevel@tonic-gate if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 2747c478bd9Sstevel@tonic-gate continue; 2757c478bd9Sstevel@tonic-gate if (*bp == '@') 2767c478bd9Sstevel@tonic-gate return(0); 2777c478bd9Sstevel@tonic-gate if (*bp != '=') 2787c478bd9Sstevel@tonic-gate continue; 2797c478bd9Sstevel@tonic-gate bp++; 2807c478bd9Sstevel@tonic-gate return (tdecode(bp, area)); 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* 2857c478bd9Sstevel@tonic-gate * Tdecode does the grung work to decode the 2867c478bd9Sstevel@tonic-gate * string capability escapes. 2877c478bd9Sstevel@tonic-gate */ 2887c478bd9Sstevel@tonic-gate static char * 289*e5af7cceScraigm tdecode(char *str, char **area) 2907c478bd9Sstevel@tonic-gate { 291*e5af7cceScraigm char *cp; 292*e5af7cceScraigm int c; 2937c478bd9Sstevel@tonic-gate int i; 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate cp = *area; 2967c478bd9Sstevel@tonic-gate while (c = *str++) { 2977c478bd9Sstevel@tonic-gate if (c == ':' && *(cp-1) != '\\') 2987c478bd9Sstevel@tonic-gate break; 2997c478bd9Sstevel@tonic-gate *cp++ = c; 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate *cp++ = 0; 3027c478bd9Sstevel@tonic-gate str = *area; 3037c478bd9Sstevel@tonic-gate *area = cp; 3047c478bd9Sstevel@tonic-gate return (str); 3057c478bd9Sstevel@tonic-gate } 306