Allow parity to be set from within .tiprc file
[unix-history] / usr / src / usr.bin / tip / remcap.c
CommitLineData
051b1e55 1/*
c9686c12
KB
2 * Copyright (c) 1983 The Regents of the University of California.
3 * All rights reserved.
4 *
cb956e54 5 * %sccs.include.redist.c%
051b1e55
DF
6 */
7
05862919 8#ifndef lint
cb956e54 9static char sccsid[] = "@(#)remcap.c 5.4 (Berkeley) %G%";
c9686c12 10#endif /* not lint */
ff9b62f7 11
ff9b62f7 12/*
3095e901
SL
13 * remcap - routines for dealing with the remote host data base
14 *
05862919 15 * derived from termcap
3095e901 16 */
05862919
SL
17#include <sys/file.h>
18#include <ctype.h>
435e8dff 19#include "pathnames.h"
05862919
SL
20
21#ifndef BUFSIZ
22#define BUFSIZ 1024
23#endif
24#define MAXHOP 32 /* max number of tc= indirections */
3095e901 25
3095e901
SL
26#define tgetent rgetent
27#define tnchktc rnchktc
28#define tnamatch rnamatch
29#define tgetnum rgetnum
30#define tgetflag rgetflag
31#define tgetstr rgetstr
435e8dff 32#define E_TERMCAP RM = _PATH_REMOTE
fa7b15dc
SL
33#define V_TERMCAP "REMOTE"
34#define V_TERM "HOST"
35
3095e901 36char *RM;
3095e901
SL
37
38/*
39 * termcap - routines for dealing with the terminal capability data base
ff9b62f7
BJ
40 *
41 * BUG: Should use a "last" pointer in tbuf, so that searching
42 * for capabilities alphabetically would not be a n**2/2
43 * process when large numbers of capabilities are given.
3095e901
SL
44 * Note: If we add a last pointer now we will screw up the
45 * tc capability. We really should compile termcap.
ff9b62f7
BJ
46 *
47 * Essentially all the work here is scanning and decoding escapes
3095e901
SL
48 * in string capabilities. We don't use stdio because the editor
49 * doesn't, and because living w/o it is not hard.
50 */
ff9b62f7 51
3095e901
SL
52static char *tbuf;
53static int hopcount; /* detect infinite loops in termcap, init 0 */
54char *tskip();
55char *tgetstr();
56char *tdecode();
ff9b62f7 57char *getenv();
05862919 58static char *remotefile;
ff9b62f7
BJ
59
60/*
3095e901
SL
61 * Get an entry for terminal name in buffer bp,
62 * from the termcap file. Parse is very rudimentary;
ff9b62f7
BJ
63 * we just notice escaped newlines.
64 */
3095e901 65tgetent(bp, name)
ff9b62f7
BJ
66 char *bp, *name;
67{
05862919
SL
68 char lbuf[BUFSIZ], *cp, *p;
69 int rc1, rc2;
6b46907f
RC
70
71 remotefile = cp = getenv(V_TERMCAP);
435e8dff
KB
72 if (cp == (char *)0 || strcmp(cp, _PATH_REMOTE) == 0) {
73 remotefile = cp = _PATH_REMOTE;
05862919 74 return (getent(bp, name, cp));
6b46907f
RC
75 } else {
76 if ((rc1 = getent(bp, name, cp)) != 1)
77 *bp = '\0';
435e8dff 78 remotefile = cp = _PATH_REMOTE;
6b46907f
RC
79 rc2 = getent(lbuf, name, cp);
80 if (rc1 != 1 && rc2 != 1)
05862919 81 return (rc2);
6b46907f
RC
82 if (rc2 == 1) {
83 p = lbuf;
84 if (rc1 == 1)
85 while (*p++ != ':')
86 ;
87 if (strlen(bp) + strlen(p) > BUFSIZ) {
88 write(2, "Remcap entry too long\n", 23);
05862919 89 return (-1);
6b46907f
RC
90 }
91 strcat(bp, p);
92 }
93 tbuf = bp;
05862919 94 return (1);
6b46907f
RC
95 }
96}
97
98getent(bp, name, cp)
99 char *bp, *name, *cp;
100{
ff9b62f7
BJ
101 register int c;
102 register int i = 0, cnt = 0;
05862919 103 char ibuf[BUFSIZ], *cp2;
ff9b62f7
BJ
104 int tf;
105
3095e901
SL
106 tbuf = bp;
107 tf = 0;
3095e901
SL
108 /*
109 * TERMCAP can have one of two things in it. It can be the
110 * name of a file to use instead of /etc/termcap. In this
111 * case it better start with a "/". Or it can be an entry to
112 * use so we don't have to read the file. In this case it
113 * has to already have the newlines crunched out.
114 */
115 if (cp && *cp) {
116 if (*cp!='/') {
fa7b15dc 117 cp2 = getenv(V_TERM);
05862919 118 if (cp2 == (char *)0 || strcmp(name,cp2) == 0) {
3095e901 119 strcpy(bp,cp);
05862919
SL
120 return (tnchktc());
121 } else
122 tf = open(E_TERMCAP, O_RDONLY);
3095e901 123 } else
05862919 124 tf = open(RM = cp, O_RDONLY);
3095e901 125 }
05862919
SL
126 if (tf == 0)
127 tf = open(E_TERMCAP, O_RDONLY);
3095e901 128 if (tf < 0)
ff9b62f7
BJ
129 return (-1);
130 for (;;) {
131 cp = bp;
132 for (;;) {
133 if (i == cnt) {
134 cnt = read(tf, ibuf, BUFSIZ);
135 if (cnt <= 0) {
136 close(tf);
137 return (0);
138 }
139 i = 0;
140 }
141 c = ibuf[i++];
142 if (c == '\n') {
6b46907f 143 if (cp > bp && cp[-1] == '\\') {
ff9b62f7
BJ
144 cp--;
145 continue;
146 }
147 break;
148 }
3095e901 149 if (cp >= bp+BUFSIZ) {
6b46907f 150 write(2,"Remcap entry too long\n", 23);
3095e901
SL
151 break;
152 } else
153 *cp++ = c;
ff9b62f7
BJ
154 }
155 *cp = 0;
156
157 /*
158 * The real work for the match.
159 */
3095e901 160 if (tnamatch(name)) {
ff9b62f7 161 close(tf);
05862919 162 return (tnchktc());
3095e901
SL
163 }
164 }
165}
166
167/*
168 * tnchktc: check the last entry, see if it's tc=xxx. If so,
169 * recursively find xxx and append that entry (minus the names)
170 * to take the place of the tc=xxx entry. This allows termcap
171 * entries to say "like an HP2621 but doesn't turn on the labels".
172 * Note that this works because of the left to right scan.
173 */
174tnchktc()
175{
176 register char *p, *q;
177 char tcname[16]; /* name of similar terminal */
178 char tcbuf[BUFSIZ];
179 char *holdtbuf = tbuf;
180 int l;
6b46907f 181 char *cp;
3095e901
SL
182
183 p = tbuf + strlen(tbuf) - 2; /* before the last colon */
184 while (*--p != ':')
185 if (p<tbuf) {
6b46907f 186 write(2, "Bad remcap entry\n", 18);
3095e901 187 return (0);
ff9b62f7 188 }
3095e901
SL
189 p++;
190 /* p now points to beginning of last field */
191 if (p[0] != 't' || p[1] != 'c')
05862919 192 return (1);
6b46907f 193 strcpy(tcname, p+3);
3095e901 194 q = tcname;
6b46907f 195 while (*q && *q != ':')
3095e901
SL
196 q++;
197 *q = 0;
198 if (++hopcount > MAXHOP) {
199 write(2, "Infinite tc= loop\n", 18);
200 return (0);
201 }
6b46907f 202 if (getent(tcbuf, tcname, remotefile) != 1) {
435e8dff 203 if (strcmp(remotefile, _PATH_REMOTE) == 0)
05862919 204 return (0);
435e8dff 205 else if (getent(tcbuf, tcname, _PATH_REMOTE) != 1)
05862919 206 return (0);
6b46907f
RC
207 }
208 for (q = tcbuf; *q++ != ':'; )
3095e901
SL
209 ;
210 l = p - holdtbuf + strlen(q);
211 if (l > BUFSIZ) {
6b46907f
RC
212 write(2, "Remcap entry too long\n", 23);
213 q[BUFSIZ - (p-holdtbuf)] = 0;
ff9b62f7 214 }
6b46907f 215 strcpy(p, q);
3095e901 216 tbuf = holdtbuf;
05862919 217 return (1);
ff9b62f7
BJ
218}
219
220/*
3095e901 221 * Tnamatch deals with name matching. The first field of the termcap
ff9b62f7
BJ
222 * entry is a sequence of names separated by |'s, so we compare
223 * against each such name. The normal : terminator after the last
224 * name (before the first field) stops us.
225 */
3095e901 226tnamatch(np)
ff9b62f7
BJ
227 char *np;
228{
229 register char *Np, *Bp;
230
3095e901
SL
231 Bp = tbuf;
232 if (*Bp == '#')
05862919 233 return (0);
ff9b62f7
BJ
234 for (;;) {
235 for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
236 continue;
237 if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
238 return (1);
239 while (*Bp && *Bp != ':' && *Bp != '|')
240 Bp++;
241 if (*Bp == 0 || *Bp == ':')
242 return (0);
243 Bp++;
244 }
245}
246
247/*
248 * Skip to the next field. Notice that this is very dumb, not
249 * knowing about \: escapes or any such. If necessary, :'s can be put
3095e901 250 * into the termcap file in octal.
ff9b62f7
BJ
251 */
252static char *
3095e901 253tskip(bp)
ff9b62f7
BJ
254 register char *bp;
255{
256
257 while (*bp && *bp != ':')
258 bp++;
259 if (*bp == ':')
260 bp++;
261 return (bp);
262}
263
264/*
265 * Return the (numeric) option id.
266 * Numeric options look like
267 * li#80
268 * i.e. the option string is separated from the numeric value by
269 * a # character. If the option is not found we return -1.
270 * Note that we handle octal numbers beginning with 0.
271 */
3095e901 272tgetnum(id)
ff9b62f7
BJ
273 char *id;
274{
275 register int i, base;
3095e901 276 register char *bp = tbuf;
ff9b62f7
BJ
277
278 for (;;) {
3095e901 279 bp = tskip(bp);
ff9b62f7
BJ
280 if (*bp == 0)
281 return (-1);
282 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
283 continue;
3095e901 284 if (*bp == '@')
05862919 285 return (-1);
ff9b62f7
BJ
286 if (*bp != '#')
287 continue;
288 bp++;
289 base = 10;
290 if (*bp == '0')
291 base = 8;
292 i = 0;
293 while (isdigit(*bp))
294 i *= base, i += *bp++ - '0';
295 return (i);
296 }
297}
298
299/*
300 * Handle a flag option.
301 * Flag options are given "naked", i.e. followed by a : or the end
302 * of the buffer. Return 1 if we find the option, or 0 if it is
303 * not given.
304 */
3095e901 305tgetflag(id)
ff9b62f7
BJ
306 char *id;
307{
3095e901 308 register char *bp = tbuf;
ff9b62f7
BJ
309
310 for (;;) {
3095e901 311 bp = tskip(bp);
ff9b62f7
BJ
312 if (!*bp)
313 return (0);
3095e901
SL
314 if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
315 if (!*bp || *bp == ':')
316 return (1);
317 else if (*bp == '@')
05862919 318 return (0);
3095e901 319 }
ff9b62f7
BJ
320 }
321}
322
323/*
324 * Get a string valued option.
325 * These are given as
326 * cl=^Z
327 * Much decoding is done on the strings, and the strings are
328 * placed in area, which is a ref parameter which is updated.
329 * No checking on area overflow.
330 */
331char *
3095e901 332tgetstr(id, area)
ff9b62f7
BJ
333 char *id, **area;
334{
3095e901 335 register char *bp = tbuf;
ff9b62f7
BJ
336
337 for (;;) {
3095e901 338 bp = tskip(bp);
ff9b62f7
BJ
339 if (!*bp)
340 return (0);
341 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
342 continue;
3095e901 343 if (*bp == '@')
05862919 344 return (0);
ff9b62f7
BJ
345 if (*bp != '=')
346 continue;
347 bp++;
3095e901 348 return (tdecode(bp, area));
ff9b62f7
BJ
349 }
350}
351
352/*
353 * Tdecode does the grung work to decode the
354 * string capability escapes.
355 */
3095e901
SL
356static char *
357tdecode(str, area)
ff9b62f7
BJ
358 register char *str;
359 char **area;
360{
361 register char *cp;
362 register int c;
363 register char *dp;
364 int i;
365
366 cp = *area;
367 while ((c = *str++) && c != ':') {
368 switch (c) {
369
370 case '^':
371 c = *str++ & 037;
372 break;
373
374 case '\\':
375 dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
376 c = *str++;
377nextc:
378 if (*dp++ == c) {
379 c = *dp++;
380 break;
381 }
382 dp++;
383 if (*dp)
384 goto nextc;
385 if (isdigit(c)) {
386 c -= '0', i = 2;
387 do
388 c <<= 3, c |= *str++ - '0';
389 while (--i && isdigit(*str));
390 }
391 break;
392 }
393 *cp++ = c;
394 }
395 *cp++ = 0;
396 str = *area;
397 *area = cp;
398 return (str);
399}