1 | /*
|
---|
2 | * termcap.c 1.1 20/7/87 agc Joypace Ltd
|
---|
3 | *
|
---|
4 | * Copyright Joypace Ltd, London, UK, 1987. All rights reserved.
|
---|
5 | * This file may be freely distributed provided that this notice
|
---|
6 | * remains attached.
|
---|
7 | *
|
---|
8 | * A public domain implementation of the termcap(3) routines.
|
---|
9 | *
|
---|
10 | * Made fully functional by Ceriel J.H. Jacobs.
|
---|
11 | *
|
---|
12 | * BUGS:
|
---|
13 | * - does not check termcap entry sizes
|
---|
14 | * - not fully tested
|
---|
15 | */
|
---|
16 |
|
---|
17 | #define CAPABLEN 2
|
---|
18 |
|
---|
19 | #define ISSPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == '\n')
|
---|
20 | #define ISDIGIT(x) ((x) >= '0' && (x) <= '9')
|
---|
21 |
|
---|
22 | short ospeed = 0; /* output speed */
|
---|
23 | char PC = 0; /* padding character */
|
---|
24 | char *BC = 0; /* back cursor movement */
|
---|
25 | char *UP = 0; /* up cursor movement */
|
---|
26 |
|
---|
27 | static char *capab = 0; /* the capability itself */
|
---|
28 | static int check_for_tc();
|
---|
29 | static int match_name();
|
---|
30 |
|
---|
31 | #define NULL 0
|
---|
32 |
|
---|
33 | /* Some things from C-library, needed here because the C-library is not
|
---|
34 | loaded with Modula-2 programs
|
---|
35 | */
|
---|
36 |
|
---|
37 | static char *
|
---|
38 | strcat(s1, s2)
|
---|
39 | register char *s1, *s2;
|
---|
40 | {
|
---|
41 | /* Append s2 to the end of s1. */
|
---|
42 |
|
---|
43 | char *original = s1;
|
---|
44 |
|
---|
45 | /* Find the end of s1. */
|
---|
46 | while (*s1 != 0) s1++;
|
---|
47 |
|
---|
48 | /* Now copy s2 to the end of s1. */
|
---|
49 | while (*s1++ = *s2++) /* nothing */ ;
|
---|
50 | return(original);
|
---|
51 | }
|
---|
52 |
|
---|
53 | static char *
|
---|
54 | strcpy(s1, s2)
|
---|
55 | register char *s1, *s2;
|
---|
56 | {
|
---|
57 | /* Copy s2 to s1. */
|
---|
58 | char *original = s1;
|
---|
59 |
|
---|
60 | while (*s1++ = *s2++) /* nothing */;
|
---|
61 | return(original);
|
---|
62 | }
|
---|
63 |
|
---|
64 | static int
|
---|
65 | strlen(s)
|
---|
66 | char *s;
|
---|
67 | {
|
---|
68 | /* Return length of s. */
|
---|
69 |
|
---|
70 | char *original = s;
|
---|
71 |
|
---|
72 | while (*s != 0) s++;
|
---|
73 | return(s - original);
|
---|
74 | }
|
---|
75 |
|
---|
76 | static int
|
---|
77 | strcmp(s1, s2)
|
---|
78 | register char *s1, *s2;
|
---|
79 | {
|
---|
80 | /* Compare 2 strings. */
|
---|
81 |
|
---|
82 | for(;;) {
|
---|
83 | if (*s1 != *s2) {
|
---|
84 | if (!*s1) return -1;
|
---|
85 | if (!*s2) return 1;
|
---|
86 | return(*s1 - *s2);
|
---|
87 | }
|
---|
88 | if (*s1++ == 0) return(0);
|
---|
89 | s2++;
|
---|
90 | }
|
---|
91 | }
|
---|
92 |
|
---|
93 | static int
|
---|
94 | strncmp(s1, s2, n)
|
---|
95 | register char *s1, *s2;
|
---|
96 | int n;
|
---|
97 | {
|
---|
98 | /* Compare two strings, but at most n characters. */
|
---|
99 |
|
---|
100 | while (n-- > 0) {
|
---|
101 | if (*s1 != *s2) {
|
---|
102 | if (!*s1) return -1;
|
---|
103 | if (!*s2) return 1;
|
---|
104 | return(*s1 - *s2);
|
---|
105 | }
|
---|
106 | if (*s1++ == 0) break;
|
---|
107 | s2++;
|
---|
108 | }
|
---|
109 | return 0;
|
---|
110 | }
|
---|
111 |
|
---|
112 | static char *
|
---|
113 | getenv(name)
|
---|
114 | register char *name;
|
---|
115 | {
|
---|
116 | extern char ***_penviron;
|
---|
117 | register char **v = *_penviron, *p, *q;
|
---|
118 |
|
---|
119 | if (v == 0 || name == 0) return 0;
|
---|
120 | while ((p = *v++) != 0) {
|
---|
121 | q = name;
|
---|
122 | while (*q && *q++ == *p++) /* nothing */ ;
|
---|
123 | if (*q || *p != '=') continue;
|
---|
124 | return(p+1);
|
---|
125 | }
|
---|
126 | return(0);
|
---|
127 | }
|
---|
128 |
|
---|
129 | static char *
|
---|
130 | fgets(buf, count, fd)
|
---|
131 | char *buf;
|
---|
132 | {
|
---|
133 | static char bf[1024];
|
---|
134 | static int cnt = 0;
|
---|
135 | static char *pbf = &bf[0];
|
---|
136 | register char *c = buf;
|
---|
137 |
|
---|
138 |
|
---|
139 | while (--count) {
|
---|
140 | if (pbf >= &bf[cnt]) {
|
---|
141 | if ((cnt = read(fd, bf, 1024)) <= 0) {
|
---|
142 | if (c == buf) return (char *) NULL;
|
---|
143 | *c = 0;
|
---|
144 | return buf;
|
---|
145 | }
|
---|
146 | pbf = &bf[0];
|
---|
147 | }
|
---|
148 | *c = *pbf++;
|
---|
149 | if (*c++ == '\n') {
|
---|
150 | *c = 0;
|
---|
151 | return buf;
|
---|
152 | }
|
---|
153 | }
|
---|
154 | *c = 0;
|
---|
155 | return buf;
|
---|
156 | }
|
---|
157 |
|
---|
158 | /*
|
---|
159 | * tgetent - get the termcap entry for terminal name, and put it
|
---|
160 | * in bp (which must be an array of 1024 chars). Returns 1 if
|
---|
161 | * termcap entry found, 0 if not found, and -1 if file not found.
|
---|
162 | */
|
---|
163 | int
|
---|
164 | tgetent(bp, name)
|
---|
165 | char *bp;
|
---|
166 | char *name;
|
---|
167 | {
|
---|
168 | int fp;
|
---|
169 | char *file;
|
---|
170 | char *cp;
|
---|
171 | short len = strlen(name);
|
---|
172 | char buf[1024];
|
---|
173 |
|
---|
174 | capab = bp;
|
---|
175 | if ((file = getenv("TERMCAP")) != (char *) NULL) {
|
---|
176 | if (*file != '/' &&
|
---|
177 | (cp = getenv("TERM")) != NULL && strcmp(name, cp) == 0) {
|
---|
178 | (void) strcpy(bp, file);
|
---|
179 | return(1);
|
---|
180 | }
|
---|
181 | else file = "/etc/termcap";
|
---|
182 | } else
|
---|
183 | file = "/etc/termcap";
|
---|
184 | if ((fp = open(file, 0)) < 0) {
|
---|
185 | capab = 0;
|
---|
186 | return(-1);
|
---|
187 | }
|
---|
188 | while (fgets(buf, 1024, fp) != NULL) {
|
---|
189 | if (buf[0] == '#') continue;
|
---|
190 | while (*(cp = &buf[strlen(buf) - 2]) == '\\')
|
---|
191 | if (fgets(cp, 1024, fp) == NULL)
|
---|
192 | return (0);
|
---|
193 | if (match_name(buf, name)) {
|
---|
194 | strcpy(bp, buf);
|
---|
195 | close(fp);
|
---|
196 | if(check_for_tc() == 0) {
|
---|
197 | capab = 0;
|
---|
198 | return 0;
|
---|
199 | }
|
---|
200 | return 1;
|
---|
201 | }
|
---|
202 | }
|
---|
203 | capab = 0;
|
---|
204 | close(fp);
|
---|
205 | return(0);
|
---|
206 | }
|
---|
207 |
|
---|
208 | /*
|
---|
209 | * Compare the terminal name with each termcap entry name; Return 1 if a
|
---|
210 | * match is found.
|
---|
211 | */
|
---|
212 | static int
|
---|
213 | match_name(buf, name)
|
---|
214 | char *buf;
|
---|
215 | char *name;
|
---|
216 | {
|
---|
217 | register char *tp = buf;
|
---|
218 | register char *np;
|
---|
219 |
|
---|
220 | for (;;) {
|
---|
221 | for (np = name; *np && *tp == *np; np++, tp++) { }
|
---|
222 | if (*np == 0 && (*tp == '|' || *tp == ':' || *tp == 0))
|
---|
223 | return(1);
|
---|
224 | while (*tp != 0 && *tp != '|' && *tp != ':') tp++;
|
---|
225 | if (*tp++ != '|') return (0);
|
---|
226 | }
|
---|
227 | }
|
---|
228 |
|
---|
229 | /*
|
---|
230 | * Handle tc= definitions recursively.
|
---|
231 | */
|
---|
232 | static int
|
---|
233 | check_for_tc()
|
---|
234 | {
|
---|
235 | static int count = 0;
|
---|
236 | char *savcapab = capab;
|
---|
237 | char buf[1024];
|
---|
238 | char terminalname[128];
|
---|
239 | register char *p = capab + strlen(capab) - 2, *q;
|
---|
240 |
|
---|
241 | while (*p != ':')
|
---|
242 | if (--p < capab)
|
---|
243 | return(0); /* no : in termcap entry */
|
---|
244 | if (p[1] != 't' || p[2] != 'c')
|
---|
245 | return(1);
|
---|
246 | if (count > 16) {
|
---|
247 | return(0); /* recursion in tc= definitions */
|
---|
248 | }
|
---|
249 | count++;
|
---|
250 | strcpy(terminalname, &p[4]);
|
---|
251 | q = terminalname;
|
---|
252 | while (*q && *q != ':') q++;
|
---|
253 | *q = 0;
|
---|
254 | if (tgetent(buf, terminalname) != 1) {
|
---|
255 | --count;
|
---|
256 | return(0);
|
---|
257 | }
|
---|
258 | --count;
|
---|
259 | for (q = buf; *q && *q != ':'; q++) { }
|
---|
260 | strcpy(p, q);
|
---|
261 | capab = savcapab;
|
---|
262 | return(1);
|
---|
263 | }
|
---|
264 |
|
---|
265 | /*
|
---|
266 | * tgetnum - get the numeric terminal capability corresponding
|
---|
267 | * to id. Returns the value, -1 if invalid.
|
---|
268 | */
|
---|
269 | int
|
---|
270 | tgetnum(id)
|
---|
271 | char *id;
|
---|
272 | {
|
---|
273 | char *cp;
|
---|
274 | int ret;
|
---|
275 |
|
---|
276 | if ((cp = capab) == NULL || id == NULL || *cp == 0)
|
---|
277 | return(-1);
|
---|
278 | while (*++cp && *cp != ':')
|
---|
279 | ;
|
---|
280 | while (*cp) {
|
---|
281 | cp++;
|
---|
282 | while (ISSPACE(*cp))
|
---|
283 | cp++;
|
---|
284 | if (strncmp(cp, id, CAPABLEN) == 0) {
|
---|
285 | while (*cp && *cp != ':' && *cp != '#')
|
---|
286 | cp++;
|
---|
287 | if (*cp != '#')
|
---|
288 | return(-1);
|
---|
289 | for (ret = 0, cp++ ; *cp && ISDIGIT(*cp) ; cp++)
|
---|
290 | ret = ret * 10 + *cp - '0';
|
---|
291 | return(ret);
|
---|
292 | }
|
---|
293 | while (*cp && *cp != ':')
|
---|
294 | cp++;
|
---|
295 | }
|
---|
296 | return(-1);
|
---|
297 | }
|
---|
298 |
|
---|
299 | /*
|
---|
300 | * tgetflag - get the boolean flag corresponding to id. Returns -1
|
---|
301 | * if invalid, 0 if the flag is not in termcap entry, or 1 if it is
|
---|
302 | * present.
|
---|
303 | */
|
---|
304 | int
|
---|
305 | tgetflag(id)
|
---|
306 | char *id;
|
---|
307 | {
|
---|
308 | char *cp;
|
---|
309 |
|
---|
310 | if ((cp = capab) == NULL || id == NULL || *cp == 0)
|
---|
311 | return(-1);
|
---|
312 | while (*++cp && *cp != ':')
|
---|
313 | ;
|
---|
314 | while (*cp) {
|
---|
315 | cp++;
|
---|
316 | while (ISSPACE(*cp))
|
---|
317 | cp++;
|
---|
318 | if (strncmp(cp, id, CAPABLEN) == 0)
|
---|
319 | return(1);
|
---|
320 | while (*cp && *cp != ':')
|
---|
321 | cp++;
|
---|
322 | }
|
---|
323 | return(0);
|
---|
324 | }
|
---|
325 |
|
---|
326 | /*
|
---|
327 | * tgetstr - get the string capability corresponding to id and place
|
---|
328 | * it in area (advancing area at same time). Expand escape sequences
|
---|
329 | * etc. Returns the string, or NULL if it can't do it.
|
---|
330 | */
|
---|
331 | char *
|
---|
332 | tgetstr(id, area)
|
---|
333 | char *id;
|
---|
334 | char **area;
|
---|
335 | {
|
---|
336 | char *cp;
|
---|
337 | char *ret;
|
---|
338 | int i;
|
---|
339 |
|
---|
340 | if ((cp = capab) == NULL || id == NULL || *cp == 0)
|
---|
341 | return(NULL);
|
---|
342 | while (*++cp != ':')
|
---|
343 | ;
|
---|
344 | while (*cp) {
|
---|
345 | cp++;
|
---|
346 | while (ISSPACE(*cp))
|
---|
347 | cp++;
|
---|
348 | if (strncmp(cp, id, CAPABLEN) == 0) {
|
---|
349 | while (*cp && *cp != ':' && *cp != '=')
|
---|
350 | cp++;
|
---|
351 | if (*cp != '=')
|
---|
352 | return(NULL);
|
---|
353 | for (ret = *area, cp++; *cp && *cp != ':' ; (*area)++, cp++)
|
---|
354 | switch(*cp) {
|
---|
355 | case '^' :
|
---|
356 | **area = *++cp - 'A' + 1;
|
---|
357 | break;
|
---|
358 | case '\\' :
|
---|
359 | switch(*++cp) {
|
---|
360 | case 'E' :
|
---|
361 | **area = '\033';
|
---|
362 | break;
|
---|
363 | case 'n' :
|
---|
364 | **area = '\n';
|
---|
365 | break;
|
---|
366 | case 'r' :
|
---|
367 | **area = '\r';
|
---|
368 | break;
|
---|
369 | case 't' :
|
---|
370 | **area = '\t';
|
---|
371 | break;
|
---|
372 | case 'b' :
|
---|
373 | **area = '\b';
|
---|
374 | break;
|
---|
375 | case 'f' :
|
---|
376 | **area = '\f';
|
---|
377 | break;
|
---|
378 | case '0' :
|
---|
379 | case '1' :
|
---|
380 | case '2' :
|
---|
381 | case '3' :
|
---|
382 | for (i=0 ; *cp && ISDIGIT(*cp) ; cp++)
|
---|
383 | i = i * 8 + *cp - '0';
|
---|
384 | **area = i;
|
---|
385 | cp--;
|
---|
386 | break;
|
---|
387 | case '^' :
|
---|
388 | case '\\' :
|
---|
389 | **area = *cp;
|
---|
390 | break;
|
---|
391 | }
|
---|
392 | break;
|
---|
393 | default :
|
---|
394 | **area = *cp;
|
---|
395 | }
|
---|
396 | *(*area)++ = '\0';
|
---|
397 | return(ret);
|
---|
398 | }
|
---|
399 | while (*cp && *cp != ':')
|
---|
400 | cp++;
|
---|
401 | }
|
---|
402 | return(NULL);
|
---|
403 | }
|
---|
404 |
|
---|
405 | /*
|
---|
406 | * tgoto - given the cursor motion string cm, make up the string
|
---|
407 | * for the cursor to go to (destcol, destline), and return the string.
|
---|
408 | * Returns "OOPS" if something's gone wrong, or the string otherwise.
|
---|
409 | */
|
---|
410 | char *
|
---|
411 | tgoto(cm, destcol, destline)
|
---|
412 | char *cm;
|
---|
413 | int destcol;
|
---|
414 | int destline;
|
---|
415 | {
|
---|
416 | register char *rp;
|
---|
417 | static char ret[32];
|
---|
418 | char added[16];
|
---|
419 | int *dp = &destline;
|
---|
420 | int numval;
|
---|
421 | int swapped = 0;
|
---|
422 |
|
---|
423 | added[0] = 0;
|
---|
424 | for (rp = ret ; *cm ; cm++) {
|
---|
425 | if (*cm == '%') {
|
---|
426 | switch(*++cm) {
|
---|
427 | case '>' :
|
---|
428 | if (dp == NULL)
|
---|
429 | return("OOPS");
|
---|
430 | cm++;
|
---|
431 | if (*dp > *cm++) {
|
---|
432 | *dp += *cm;
|
---|
433 | }
|
---|
434 | break;
|
---|
435 | case '+' :
|
---|
436 | case '.' :
|
---|
437 | if (dp == NULL)
|
---|
438 | return("OOPS");
|
---|
439 | if (*cm == '+') *dp = *dp + *++cm;
|
---|
440 | for (;;) {
|
---|
441 | switch(*dp) {
|
---|
442 | case 0:
|
---|
443 | case 04:
|
---|
444 | case '\t':
|
---|
445 | case '\n':
|
---|
446 | /* filter these out */
|
---|
447 | if (dp == &destcol || swapped || UP) {
|
---|
448 | strcat(added, dp == &destcol || swapped ?
|
---|
449 | (BC ? BC : "\b") :
|
---|
450 | UP);
|
---|
451 | (*dp)++;
|
---|
452 | continue;
|
---|
453 | }
|
---|
454 | }
|
---|
455 | break;
|
---|
456 | }
|
---|
457 | *rp++ = *dp;
|
---|
458 | dp = (dp == &destline) ? &destcol : NULL;
|
---|
459 | break;
|
---|
460 |
|
---|
461 | case 'r' : {
|
---|
462 | int tmp = destline;
|
---|
463 |
|
---|
464 | destline = destcol;
|
---|
465 | destcol = tmp;
|
---|
466 | swapped = 1 - swapped;
|
---|
467 | break;
|
---|
468 | }
|
---|
469 | case 'n' :
|
---|
470 | destcol ^= 0140;
|
---|
471 | destline ^= 0140;
|
---|
472 | break;
|
---|
473 |
|
---|
474 | case '%' :
|
---|
475 | *rp++ = '%';
|
---|
476 | break;
|
---|
477 |
|
---|
478 | case 'i' :
|
---|
479 | destcol++;
|
---|
480 | destline++;
|
---|
481 | break;
|
---|
482 |
|
---|
483 | case 'B' :
|
---|
484 | if (dp == NULL)
|
---|
485 | return("OOPS");
|
---|
486 | *dp = 16 * (*dp / 10) + *dp % 10;
|
---|
487 | break;
|
---|
488 |
|
---|
489 | case 'D' :
|
---|
490 | if (dp == NULL)
|
---|
491 | return("OOPS");
|
---|
492 | *dp = *dp - 2 * (*dp % 16);
|
---|
493 | break;
|
---|
494 |
|
---|
495 | case 'd' :
|
---|
496 | case '2' :
|
---|
497 | case '3' :
|
---|
498 | if (dp == NULL)
|
---|
499 | return("OOPS");
|
---|
500 | numval = *dp;
|
---|
501 | dp = (dp == &destline) ? &destcol : NULL;
|
---|
502 | if (numval >= 100) {
|
---|
503 | *rp++ = '0' + numval / 100;
|
---|
504 | }
|
---|
505 | else if (*cm == '3') {
|
---|
506 | *rp++ = ' ';
|
---|
507 | }
|
---|
508 | if (numval >= 10) {
|
---|
509 | *rp++ = '0' + ((numval%100)/10);
|
---|
510 | }
|
---|
511 | else if (*cm == '3' || *cm == '2') {
|
---|
512 | *rp++ = ' ';
|
---|
513 | }
|
---|
514 | *rp++ = '0' + (numval%10);
|
---|
515 | break;
|
---|
516 | default :
|
---|
517 | return("OOPS");
|
---|
518 | }
|
---|
519 | }
|
---|
520 | else *rp++ = *cm;
|
---|
521 | }
|
---|
522 | *rp = '\0';
|
---|
523 | strcpy(rp, added);
|
---|
524 | return(ret);
|
---|
525 | }
|
---|
526 |
|
---|
527 | static int tens_of_ms_p_char[] = { /* index as returned by gtty */
|
---|
528 | /* assume 10 bits per char */
|
---|
529 | 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 2
|
---|
530 | };
|
---|
531 | /*
|
---|
532 | * tputs - put the string cp out onto the terminal, using the function
|
---|
533 | * outc. Also handle padding.
|
---|
534 | */
|
---|
535 | int
|
---|
536 | tputs(cp, affcnt, outc)
|
---|
537 | register char *cp;
|
---|
538 | int affcnt;
|
---|
539 | int (*outc)();
|
---|
540 | {
|
---|
541 | int delay = 0;
|
---|
542 | if (cp == NULL)
|
---|
543 | return(1);
|
---|
544 | while (ISDIGIT(*cp)) {
|
---|
545 | delay = delay * 10 + (*cp++ - '0');
|
---|
546 | }
|
---|
547 | delay *= 10;
|
---|
548 | if (*cp == '.') {
|
---|
549 | cp++;
|
---|
550 | if (ISDIGIT(*cp)) {
|
---|
551 | delay += *cp++ - '0';
|
---|
552 | }
|
---|
553 | while (ISDIGIT(*cp)) cp++;
|
---|
554 | }
|
---|
555 | if (*cp == '*') {
|
---|
556 | delay *= affcnt;
|
---|
557 | cp++;
|
---|
558 | }
|
---|
559 | while (*cp)
|
---|
560 | (*outc)(*cp++);
|
---|
561 | if (delay != 0 &&
|
---|
562 | ospeed > 0 &&
|
---|
563 | ospeed < (sizeof tens_of_ms_p_char / sizeof tens_of_ms_p_char[0])) {
|
---|
564 | delay = (delay + tens_of_ms_p_char[ospeed] - 1) /
|
---|
565 | tens_of_ms_p_char[ospeed];
|
---|
566 | while (delay--) (*outc)(PC);
|
---|
567 | }
|
---|
568 | return(1);
|
---|
569 | }
|
---|
570 |
|
---|
571 | /*
|
---|
572 | * That's all, folks...
|
---|
573 | */
|
---|