1 /*
2 * Copyright (c) 1983 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 static char sccsid[] = "@(#)gettytab.c 5.5 (Berkeley) 2/25/91";
36 #endif /* not lint */
37
38 #include <fcntl.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include "pathnames.h"
43
44 #define TABBUFSIZ 512
45
46 static char *tbuf;
47 int hopcount; /* detect infinite loops in termcap, init 0 */
48 char *skip();
49 char *getstr();
50 char *decode();
51
52 /*
53 * Get an entry for terminal name in buffer bp,
54 * from the termcap file. Parse is very rudimentary;
55 * we just notice escaped newlines.
56 */
getent(bp,name)57 getent(bp, name)
58 char *bp, *name;
59 {
60 register char *cp;
61 register int c;
62 register int i = 0, cnt = 0;
63 char ibuf[TABBUFSIZ];
64 char *cp2;
65 int tf;
66
67 tbuf = bp;
68 tf = open(_PATH_GETTYTAB, O_RDONLY, 0);
69 if (tf < 0)
70 return (-1);
71 for (;;) {
72 cp = bp;
73 for (;;) {
74 if (i == cnt) {
75 cnt = read(tf, ibuf, TABBUFSIZ);
76 if (cnt <= 0) {
77 close(tf);
78 return (0);
79 }
80 i = 0;
81 }
82 c = ibuf[i++];
83 if (c == '\n') {
84 if (cp > bp && cp[-1] == '\\'){
85 cp--;
86 continue;
87 }
88 break;
89 }
90 if (cp >= bp+TABBUFSIZ) {
91 write(2,"Gettytab entry too long\n", 24);
92 break;
93 } else
94 *cp++ = c;
95 }
96 *cp = 0;
97
98 /*
99 * The real work for the match.
100 */
101 if (namatch(name)) {
102 close(tf);
103 return(nchktc());
104 }
105 }
106 }
107
108 /*
109 * tnchktc: check the last entry, see if it's tc=xxx. If so,
110 * recursively find xxx and append that entry (minus the names)
111 * to take the place of the tc=xxx entry. This allows termcap
112 * entries to say "like an HP2621 but doesn't turn on the labels".
113 * Note that this works because of the left to right scan.
114 */
115 #define MAXHOP 32
nchktc()116 nchktc()
117 {
118 register char *p, *q;
119 char tcname[16]; /* name of similar terminal */
120 char tcbuf[TABBUFSIZ];
121 char *holdtbuf = tbuf;
122 int l;
123
124 p = tbuf + strlen(tbuf) - 2; /* before the last colon */
125 while (*--p != ':')
126 if (p<tbuf) {
127 write(2, "Bad gettytab entry\n", 19);
128 return (0);
129 }
130 p++;
131 /* p now points to beginning of last field */
132 if (p[0] != 't' || p[1] != 'c')
133 return(1);
134 strcpy(tcname,p+3);
135 q = tcname;
136 while (q && *q != ':')
137 q++;
138 *q = 0;
139 if (++hopcount > MAXHOP) {
140 write(2, "Getty: infinite tc= loop\n", 25);
141 return (0);
142 }
143 if (getent(tcbuf, tcname) != 1)
144 return(0);
145 for (q=tcbuf; *q != ':'; q++)
146 ;
147 l = p - holdtbuf + strlen(q);
148 if (l > TABBUFSIZ) {
149 write(2, "Gettytab entry too long\n", 24);
150 q[TABBUFSIZ - (p-tbuf)] = 0;
151 }
152 strcpy(p, q+1);
153 tbuf = holdtbuf;
154 return(1);
155 }
156
157 /*
158 * Tnamatch deals with name matching. The first field of the termcap
159 * entry is a sequence of names separated by |'s, so we compare
160 * against each such name. The normal : terminator after the last
161 * name (before the first field) stops us.
162 */
namatch(np)163 namatch(np)
164 char *np;
165 {
166 register char *Np, *Bp;
167
168 Bp = tbuf;
169 if (*Bp == '#')
170 return(0);
171 for (;;) {
172 for (Np = np; *Np && *Bp == *Np; Bp++, Np++)
173 continue;
174 if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0))
175 return (1);
176 while (*Bp && *Bp != ':' && *Bp != '|')
177 Bp++;
178 if (*Bp == 0 || *Bp == ':')
179 return (0);
180 Bp++;
181 }
182 }
183
184 /*
185 * Skip to the next field. Notice that this is very dumb, not
186 * knowing about \: escapes or any such. If necessary, :'s can be put
187 * into the termcap file in octal.
188 */
189 static char *
skip(bp)190 skip(bp)
191 register char *bp;
192 {
193
194 while (*bp && *bp != ':')
195 bp++;
196 if (*bp == ':')
197 bp++;
198 return (bp);
199 }
200
201 /*
202 * Return the (numeric) option id.
203 * Numeric options look like
204 * li#80
205 * i.e. the option string is separated from the numeric value by
206 * a # character. If the option is not found we return -1.
207 * Note that we handle octal numbers beginning with 0.
208 */
209 long
getnum(id)210 getnum(id)
211 char *id;
212 {
213 register long i, base;
214 register char *bp = tbuf;
215
216 for (;;) {
217 bp = skip(bp);
218 if (*bp == 0)
219 return (-1);
220 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
221 continue;
222 if (*bp == '@')
223 return(-1);
224 if (*bp != '#')
225 continue;
226 bp++;
227 base = 10;
228 if (*bp == '0')
229 base = 8;
230 i = 0;
231 while (isdigit(*bp))
232 i *= base, i += *bp++ - '0';
233 return (i);
234 }
235 }
236
237 /*
238 * Handle a flag option.
239 * Flag options are given "naked", i.e. followed by a : or the end
240 * of the buffer. Return 1 if we find the option, or 0 if it is
241 * not given.
242 */
getflag(id)243 getflag(id)
244 char *id;
245 {
246 register char *bp = tbuf;
247
248 for (;;) {
249 bp = skip(bp);
250 if (!*bp)
251 return (-1);
252 if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
253 if (!*bp || *bp == ':')
254 return (1);
255 else if (*bp == '!')
256 return (0);
257 else if (*bp == '@')
258 return(-1);
259 }
260 }
261 }
262
263 /*
264 * Get a string valued option.
265 * These are given as
266 * cl=^Z
267 * Much decoding is done on the strings, and the strings are
268 * placed in area, which is a ref parameter which is updated.
269 * No checking on area overflow.
270 */
271 char *
getstr(id,area)272 getstr(id, area)
273 char *id, **area;
274 {
275 register char *bp = tbuf;
276
277 for (;;) {
278 bp = skip(bp);
279 if (!*bp)
280 return (0);
281 if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1])
282 continue;
283 if (*bp == '@')
284 return(0);
285 if (*bp != '=')
286 continue;
287 bp++;
288 return (decode(bp, area));
289 }
290 }
291
292 /*
293 * Tdecode does the grung work to decode the
294 * string capability escapes.
295 */
296 static char *
decode(str,area)297 decode(str, area)
298 register char *str;
299 char **area;
300 {
301 register char *cp;
302 register int c;
303 register char *dp;
304 int i;
305
306 cp = *area;
307 while ((c = *str++) && c != ':') {
308 switch (c) {
309
310 case '^':
311 c = *str++ & 037;
312 break;
313
314 case '\\':
315 dp = "E\033^^\\\\::n\nr\rt\tb\bf\f";
316 c = *str++;
317 nextc:
318 if (*dp++ == c) {
319 c = *dp++;
320 break;
321 }
322 dp++;
323 if (*dp)
324 goto nextc;
325 if (isdigit(c)) {
326 c -= '0', i = 2;
327 do
328 c <<= 3, c |= *str++ - '0';
329 while (--i && isdigit(*str));
330 }
331 break;
332 }
333 *cp++ = c;
334 }
335 *cp++ = 0;
336 str = *area;
337 *area = cp;
338 return (str);
339 }
340