|
|
1.1 root 1: /* Work-alike for termcap, plus extra features.
2: Copyright (C) 1985, 1986 Free Software Foundation, Inc.
3:
4: This program is free software; you can redistribute it and/or modify
5: it under the terms of the GNU General Public License as published by
6: the Free Software Foundation; either version 1, or (at your option)
7: any later version.
8:
9: This program is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
14: You should have received a copy of the GNU General Public License
15: along with this program; if not, write to the Free Software
16: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17:
18: In other words, you are welcome to use, share and improve this program.
19: You are forbidden to forbid anyone else to use, share and improve
20: what you give them. Help stamp out software-hoarding! */
21:
22:
23:
24: /* BUFSIZE is the initial size allocated for the buffer
25: for reading the termcap file.
26: It is not a limit.
27: Make it large normally for speed.
28: Make it variable when debugging, so can exercise
29: increasing the space dynamically. */
30:
31: #ifdef emacs
32: #include "config.h"
33: #endif
34:
35: #ifndef BUFSIZE
36: #ifdef DEBUG
37: #define BUFSIZE bufsize
38:
39: int bufsize = 128;
40: #else
41: #define BUFSIZE 2048
42: #endif
43: #endif
44:
45: #ifndef emacs
46: static
47: memory_out ()
48: {
49: write (2, "Virtual memory exhausted\n", 25);
50: exit (1);
51: }
52:
53: static int
54: xmalloc (size)
55: int size;
56: {
57: register tem = malloc (size);
58: if (!tem)
59: memory_out ();
60: return tem;
61: }
62:
63: static int
64: xrealloc (ptr, size)
65: int ptr;
66: int size;
67: {
68: register tem = realloc (ptr, size);
69: if (!tem)
70: memory_out ();
71: return tem;
72: }
73: #endif /* not emacs */
74:
75: /* Looking up capabilities in the entry already found */
76:
77: /* The pointer to the data made by tgetent is left here
78: for tgetnum, tgetflag and tgetstr to find. */
79:
80: static char *term_entry;
81:
82: static char *tgetst1 ();
83:
84: /* This is the main subroutine that is used to search
85: an entry for a particular capability */
86:
87: static char *
88: find_capability (bp, cap)
89: register char *bp, *cap;
90: {
91: for (; *bp; bp++)
92: if (bp[0] == ':'
93: && bp[1] == cap[0]
94: && bp[2] == cap[1])
95: return &bp[4];
96: return 0;
97: }
98:
99: int
100: tgetnum (cap)
101: char *cap;
102: {
103: register char *ptr = find_capability (term_entry, cap);
104: if (!ptr || ptr[-1] != '#')
105: return -1;
106: return atoi (ptr);
107: }
108:
109: int
110: tgetflag (cap)
111: char *cap;
112: {
113: register char *ptr = find_capability (term_entry, cap);
114: return 0 != ptr && ptr[-1] == ':';
115: }
116:
117: /* Look up a string-valued capability `cap'.
118: If `area' is nonzero, it points to a pointer to a block in which
119: to store the string. That pointer is advanced over the space used.
120: If `area' is zero, space is allocated with `malloc'. */
121:
122: char *
123: tgetstr (cap, area)
124: char *cap;
125: char **area;
126: {
127: register char *ptr = find_capability (term_entry, cap);
128: if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
129: return 0;
130: return tgetst1 (ptr, area);
131: }
132:
133: /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
134: gives meaning of character following \, or a space if no special meaning.
135: Eight characters per line within the string. */
136:
137: static char esctab[]
138: = " \007\010 \033\014 \
139: \012 \
140: \015 \011 \013 \
141: ";
142:
143: /* Given a pointer to a string value inside a termcap entry (`ptr'),
144: copy the value and process \ and ^ abbreviations.
145: Copy into block that *area points to,
146: or to newly allocated storage if area is 0. */
147:
148: static char *
149: tgetst1 (ptr, area)
150: char *ptr;
151: char **area;
152: {
153: register char *p, *r;
154: register int c;
155: register int size;
156: char *ret;
157: register int c1;
158:
159: if (!ptr)
160: return 0;
161:
162: /* `ret' gets address of where to store the string */
163: if (!area)
164: {
165: /* Compute size of block needed (may overestimate) */
166: p = ptr;
167: while ((c = *p++) && c != ':' && c != '\n');
168: ret = (char *) xmalloc (p - ptr + 1);
169: }
170: else
171: ret = *area;
172:
173: /* Copy the string value, stopping at null or colon. */
174: /* Also process ^ and \ abbreviations. */
175: p = ptr;
176: r = ret;
177: while ((c = *p++) && c != ':' && c != '\n')
178: {
179: if (c == '^')
180: c = *p++ & 037;
181: else if (c == '\\')
182: {
183: c = *p++;
184: if (c >= '0' && c <= '7')
185: {
186: c -= '0';
187: size = 0;
188:
189: while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7')
190: {
191: c *= 8;
192: c += c1 - '0';
193: p++;
194: }
195: }
196: else if (c >= 0100 && c < 0200)
197: {
198: c1 = esctab[(c & ~040) - 0100];
199: if (c1 != ' ')
200: c = c1;
201: }
202: }
203: *r++ = c;
204: }
205: *r = 0;
206: /* Update *area */
207: if (area)
208: *area = r + 1;
209: return ret;
210: }
211:
212: /* Outputting a string with padding */
213:
214: short ospeed;
215: char PC;
216:
217: /* Actual baud rate if positive;
218: - baud rate / 100 if negative. */
219:
220: static short speeds[] =
221: {
222: #ifdef VMS
223: 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
224: -20, -24, -36, -48, -72, -96, -192
225: #else /* not VMS */
226: 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
227: -18, -24, -48, -96, -192, -384
228: #endif /* not VMS */
229: };
230:
231: tputs (string, nlines, outfun)
232: register char *string;
233: int nlines;
234: register int (*outfun) ();
235: {
236: register int padcount = 0;
237:
238: if (string == (char *) 0)
239: return;
240: while (*string >= '0' && *string <= '9')
241: {
242: padcount += *string++ - '0';
243: padcount *= 10;
244: }
245: if (*string == '.')
246: {
247: string++;
248: padcount += *string++ - '0';
249: }
250: if (*string == '*')
251: {
252: string++;
253: padcount *= nlines;
254: }
255: while (*string)
256: (*outfun) (*string++);
257:
258: /* padcount is now in units of tenths of msec. */
259: padcount *= speeds[ospeed];
260: padcount += 500;
261: padcount /= 1000;
262: if (speeds[ospeed] < 0)
263: padcount = -padcount;
264: else
265: {
266: padcount += 50;
267: padcount /= 100;
268: }
269:
270: while (padcount-- > 0)
271: (*outfun) (PC);
272: }
273:
274: /* Finding the termcap entry in the termcap data base */
275:
276: struct buffer
277: {
278: char *beg;
279: int size;
280: char *ptr;
281: int ateof;
282: int full;
283: };
284:
285: /* Forward declarations of static functions */
286:
287: static int scan_file ();
288: static char *gobble_line ();
289: static int compare_contin ();
290: static int name_match ();
291:
292: #ifdef VMS
293:
294: #include <rmsdef.h>
295: #include <fab.h>
296: #include <nam.h>
297:
298: static int
299: legal_filename_p (fn)
300: char *fn;
301: {
302: struct FAB fab = cc$rms_fab;
303: struct NAM nam = cc$rms_nam;
304: char esa[NAM$C_MAXRSS];
305:
306: fab.fab$l_fna = fn;
307: fab.fab$b_fns = strlen(fn);
308: fab.fab$l_nam = &nam;
309: fab.fab$l_fop = FAB$M_NAM;
310:
311: nam.nam$l_esa = esa;
312: nam.nam$b_ess = sizeof esa;
313:
314: return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL;
315: }
316:
317: #endif /* VMS */
318:
319: /* Find the termcap entry data for terminal type `name'
320: and store it in the block that `bp' points to.
321: Record its address for future use.
322:
323: If `bp' is zero, space is dynamically allocated. */
324:
325: int
326: tgetent (bp, name)
327: char *bp, *name;
328: {
329: register char *tem;
330: register int fd;
331: struct buffer buf;
332: register char *bp1;
333: char *bp2;
334: char *term;
335: int malloc_size = 0;
336: register int c;
337: char *tcenv; /* TERMCAP value, if it contais :tc=. */
338: char *indirect = 0; /* Terminal type in :tc= in TERMCAP value. */
339: int filep;
340:
341: tem = (char *) getenv ("TERMCAP");
342: if (tem && *tem == 0) tem = 0;
343:
344: #ifdef VMS
345: filep = tem && legal_filename_p (tem);
346: #else
347: filep = tem && (*tem == '/');
348: #endif /* VMS */
349:
350: /* If tem is non-null and starts with / (in the un*x case, that is),
351: it is a file name to use instead of /etc/termcap.
352: If it is non-null and does not start with /,
353: it is the entry itself, but only if
354: the name the caller requested matches the TERM variable. */
355:
356: if (tem && !filep && !strcmp (name, getenv ("TERM")))
357: {
358: indirect = tgetst1 (find_capability (tem, "tc"), 0);
359: if (!indirect)
360: {
361: if (!bp)
362: bp = tem;
363: else
364: strcpy (bp, tem);
365: goto ret;
366: }
367: else
368: { /* we will need to read /etc/termcap */
369: tcenv = tem;
370: tem = 0;
371: }
372: }
373: else
374: indirect = (char *) 0;
375:
376: if (!tem)
377: #ifdef VMS
378: tem = "emacs_library:[etc]termcap.dat";
379: #else
380: tem = "/etc/termcap";
381: #endif
382:
383: /* Here we know we must search a file and tem has its name. */
384:
385: fd = open (tem, 0, 0);
386: if (fd < 0)
387: return -1;
388:
389: buf.size = BUFSIZE;
390: /* Add 1 to size to ensure room for terminating null. */
391: buf.beg = (char *) xmalloc (buf.size + 1);
392: term = indirect ? indirect : name;
393:
394: if (!bp)
395: {
396: malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
397: bp = (char *) xmalloc (malloc_size);
398: }
399: bp1 = bp;
400:
401: if (indirect) /* copy the data from the environment variable */
402: {
403: strcpy (bp, tcenv);
404: bp1 += strlen (tcenv);
405: }
406:
407: while (term)
408: {
409: /* Scan file, reading it via buf, till find start of main entry */
410: if (scan_file (term, fd, &buf) == 0)
411: return 0;
412:
413: /* Free old `term' if appropriate. */
414: if (term != name)
415: free (term);
416:
417: /* If `bp' is malloc'd by us, make sure it is big enough. */
418: if (malloc_size)
419: {
420: malloc_size = bp1 - bp + buf.size;
421: tem = (char *) xrealloc (bp, malloc_size);
422: bp1 += tem - bp;
423: bp = tem;
424: }
425:
426: bp2 = bp1;
427:
428: /* Copy the line of the entry from buf into bp. */
429: tem = buf.ptr;
430: while ((*bp1++ = c = *tem++) && c != '\n')
431: /* Drop out any \ newline sequence. */
432: if (c == '\\' && *tem == '\n')
433: {
434: bp1--;
435: tem++;
436: }
437: *bp1 = 0;
438:
439: /* Does this entry refer to another terminal type's entry? */
440: /* If something is found, copy it into heap and null-terminate it */
441: term = tgetst1 (find_capability (bp2, "tc"), 0);
442: }
443:
444: close (fd);
445: free (buf.beg);
446:
447: if (malloc_size)
448: {
449: bp = (char *) xrealloc (bp, bp1 - bp + 1);
450: }
451:
452: ret:
453: term_entry = bp;
454: if (malloc_size)
455: return (int) bp;
456: return 1;
457: }
458:
459: /* Given file open on `fd' and buffer `bufp',
460: scan the file from the beginning until a line is found
461: that starts the entry for terminal type `string'.
462: Returns 1 if successful, with that line in `bufp',
463: or returns 0 if no entry found in the file. */
464:
465: static int
466: scan_file (string, fd, bufp)
467: char *string;
468: int fd;
469: register struct buffer *bufp;
470: {
471: register char *tem;
472: register char *end;
473:
474: bufp->ptr = bufp->beg;
475: bufp->full = 0;
476: bufp->ateof = 0;
477: *bufp->ptr = 0;
478:
479: lseek (fd, 0L, 0);
480:
481: while (!bufp->ateof)
482: {
483: /* Read a line into the buffer */
484: end = 0;
485: do
486: {
487: /* if it is continued, append another line to it,
488: until a non-continued line ends */
489: end = gobble_line (fd, bufp, end);
490: }
491: while (!bufp->ateof && end[-2] == '\\');
492:
493: if (*bufp->ptr != '#'
494: && name_match (bufp->ptr, string))
495: return 1;
496:
497: /* Discard the line just processed */
498: bufp->ptr = end;
499: }
500: return 0;
501: }
502:
503: /* Return nonzero if NAME is one of the names specified
504: by termcap entry LINE. */
505:
506: static int
507: name_match (line, name)
508: char *line, *name;
509: {
510: register char *tem;
511:
512: if (!compare_contin (line, name))
513: return 1;
514: /* This line starts an entry. Is it the right one? */
515: for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
516: if (*tem == '|' && !compare_contin (tem + 1, name))
517: return 1;
518:
519: return 0;
520: }
521:
522: static int
523: compare_contin (str1, str2)
524: register char *str1, *str2;
525: {
526: register int c1, c2;
527: while (1)
528: {
529: c1 = *str1++;
530: c2 = *str2++;
531: while (c1 == '\\' && *str1 == '\n')
532: {
533: str1++;
534: while ((c1 = *str1++) == ' ' || c1 == '\t');
535: }
536: if (c2 == '\0') /* end of type being looked up */
537: {
538: if (c1 == '|' || c1 == ':') /* If end of name in data base, */
539: return 0; /* we win. */
540: else
541: return 1;
542: }
543: else if (c1 != c2)
544: return 1;
545: }
546: }
547:
548: /* Make sure that the buffer <- `bufp' contains a full line
549: of the file open on `fd', starting at the place `bufp->ptr'
550: points to. Can read more of the file, discard stuff before
551: `bufp->ptr', or make the buffer bigger.
552:
553: Returns the pointer to after the newline ending the line,
554: or to the end of the file, if there is no newline to end it.
555:
556: Can also merge on continuation lines. If `append_end' is
557: nonzero, it points past the newline of a line that is
558: continued; we add another line onto it and regard the whole
559: thing as one line. The caller decides when a line is continued. */
560:
561: static char *
562: gobble_line (fd, bufp, append_end)
563: int fd;
564: register struct buffer *bufp;
565: char *append_end;
566: {
567: register char *end;
568: register int nread;
569: register char *buf = bufp->beg;
570: register char *tem;
571:
572: if (append_end == 0)
573: append_end = bufp->ptr;
574:
575: while (1)
576: {
577: end = append_end;
578: while (*end && *end != '\n') end++;
579: if (*end)
580: break;
581: if (bufp->ateof)
582: return buf + bufp->full;
583: if (bufp->ptr == buf)
584: {
585: if (bufp->full == bufp->size)
586: {
587: bufp->size *= 2;
588: /* Add 1 to size to ensure room for terminating null. */
589: tem = (char *) xrealloc (buf, bufp->size + 1);
590: bufp->ptr = (bufp->ptr - buf) + tem;
591: append_end = (append_end - buf) + tem;
592: bufp->beg = buf = tem;
593: }
594: }
595: else
596: {
597: append_end -= bufp->ptr - buf;
598: bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf);
599: bufp->ptr = buf;
600: }
601: if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
602: bufp->ateof = 1;
603: bufp->full += nread;
604: buf[bufp->full] = 0;
605: }
606: return end + 1;
607: }
608:
609: #ifdef TEST
610:
611: #include <stdio.h>
612:
613: main (argc, argv)
614: int argc;
615: char **argv;
616: {
617: char *term;
618: char *buf;
619:
620: term = argv[1];
621: printf ("TERM: %s\n", term);
622:
623: buf = (char *) tgetent (0, term);
624: if ((int) buf <= 0)
625: {
626: printf ("No entry.\n");
627: return 0;
628: }
629:
630: printf ("Entry: %s\n", buf);
631:
632: tprint ("cm");
633: tprint ("AL");
634:
635: printf ("co: %d\n", tgetnum ("co"));
636: printf ("am: %d\n", tgetflag ("am"));
637: }
638:
639: tprint (cap)
640: char *cap;
641: {
642: char *x = tgetstr (cap, 0);
643: register char *y;
644:
645: printf ("%s: ", cap);
646: if (x)
647: {
648: for (y = x; *y; y++)
649: if (*y <= ' ' || *y == 0177)
650: printf ("\\%0o", *y);
651: else
652: putchar (*y);
653: free (x);
654: }
655: else
656: printf ("none");
657: putchar ('\n');
658: }
659:
660: #endif /* TEST */
661:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.