1 /* Work-alike for termcap, plus extra features.
2 Copyright (C) 1985, 1986, 1993 Free Software Foundation, Inc.
4 This file is part of XEmacs.
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Synched up with: Not synched with FSF. */
23 /* config.h may rename various library functions such as malloc. */
26 #include "lisp.h" /* For encapsulated open, close, read */
27 #include "device.h" /* For DEVICE_BAUD_RATE */
29 #if defined(USG) || defined(STDC_HEADERS)
30 #define memcpy(d, s, n) memcpy ((d), (s), (n))
49 #endif /* not emacs */
51 /* BUFSIZE is the initial size allocated for the buffer
52 for reading the termcap file.
54 Make it large normally for speed.
55 Make it variable when debugging, so can exercise
56 increasing the space dynamically. */
60 #define BUFSIZE bufsize
72 write (2, "virtual memory exhausted\n", 25);
80 char *tem = malloc (size);
92 char *tem = realloc (ptr, size);
98 #endif /* not emacs */
100 /* Looking up capabilities in the entry already found. */
102 /* The pointer to the data made by tgetent is left here
103 for tgetnum, tgetflag and tgetstr to find. */
104 static char *term_entry;
106 static CONST char *tgetst1 (CONST char *ptr, char **area);
108 /* Search entry BP for capability CAP.
109 Return a pointer to the capability (in BP) if found,
113 find_capability (bp, cap)
129 CONST char *ptr = find_capability (term_entry, cap);
130 if (!ptr || ptr[-1] != '#')
139 CONST char *ptr = find_capability (term_entry, cap);
140 return 0 != ptr && ptr[-1] == ':';
143 /* Look up a string-valued capability CAP.
144 If AREA is nonzero, it points to a pointer to a block in which
145 to store the string. That pointer is advanced over the space used.
146 If AREA is zero, space is allocated with `malloc'. */
153 CONST char *ptr = find_capability (term_entry, cap);
154 if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
156 return tgetst1 (ptr, area);
159 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
160 gives meaning of character following \, or a space if no special meaning.
161 Eight characters per line within the string. */
164 = " \007\010 \033\014 "
169 /* PTR points to a string value inside a termcap entry.
170 Copy that value, processing \ and ^ abbreviations,
171 into the block that *AREA points to,
172 or to newly allocated storage if AREA is 0. */
189 /* `ret' gets address of where to store the string. */
192 /* Compute size of block needed (may overestimate). */
194 while ((c = *p++) && c != ':' && c != '\n')
196 ret = (char *) xmalloc (p - ptr + 1);
201 /* Copy the string value, stopping at null or colon.
202 Also process ^ and \ abbreviations. */
205 while ((c = *p++) && c != ':' && c != '\n')
212 if (c >= '0' && c <= '7')
217 while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7')
224 else if (c >= 0100 && c < 0200)
226 c1 = esctab[(c & ~040) - 0100];
240 /* Outputting a string with padding. */
247 /* If `ospeed' is 0, we use `tputs_baud_rate' as the actual baud rate. */
251 /* Actual baud rate if positive;
252 - baud rate / 100 if negative. */
254 static short speeds[] =
256 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
257 -18, -24, -48, -96, -192, -288, -384, -576, -1152
261 tputs (string, nlines, outfun)
264 void (*outfun) (int);
270 speed = DEVICE_BAUD_RATE (XDEVICE (Fselected_device (Qnil)));
273 speed = tputs_baud_rate;
275 speed = speeds[ospeed];
278 if (string == (char *) 0)
281 while (isdigit (* (CONST unsigned char *) string))
283 padcount += *string++ - '0';
289 padcount += *string++ - '0';
297 (*outfun) (*string++);
299 /* padcount is now in units of tenths of msec. */
300 padcount *= speeds[ospeed];
303 if (speeds[ospeed] < 0)
304 padcount = -padcount;
311 while (padcount-- > 0)
315 /* Finding the termcap entry in the termcap data base. */
326 /* Forward declarations of static functions. */
328 static int scan_file ();
329 static char *gobble_line ();
330 static int compare_contin ();
331 static int name_match ();
334 /* Find the termcap entry data for terminal type NAME
335 and store it in the block that BP points to.
336 Record its address for future use.
338 If BP is zero, space is dynamically allocated. */
340 extern char *getenv ();
355 char *tcenv; /* TERMCAP value, if it contais :tc=. */
356 CONST char *indirect = 0; /* Terminal type in :tc= in TERMCAP value. */
358 tem = getenv ("TERMCAP");
359 if (tem && *tem == 0) tem = 0;
362 /* If tem is non-null and starts with / (in the un*x case, that is),
363 it is a file name to use instead of /etc/termcap.
364 If it is non-null and does not start with /,
365 it is the entry itself, but only if
366 the name the caller requested matches the TERM variable. */
368 if (tem && !IS_DIRECTORY_SEP (*tem) && !strcmp (name, (char *) getenv ("TERM")))
370 indirect = tgetst1 (find_capability (tem, "tc"), 0);
380 { /* We will need to read /etc/termcap. */
386 indirect = (char *) 0;
389 tem = "/etc/termcap";
391 /* Here we know we must search a file and tem has its name. */
393 fd = open (tem, 0, 0);
398 /* Add 1 to size to ensure room for terminating null. */
399 buf.beg = (char *) xmalloc (buf.size + 1);
400 term = indirect ? indirect : name;
404 malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
405 bp = (char *) xmalloc (malloc_size);
410 /* Copy the data from the environment variable. */
413 bp1 += strlen (tcenv);
418 /* Scan the file, reading it via buf, till find start of main entry. */
419 if (scan_file (term, fd, &buf) == 0)
422 /* Free old `term' if appropriate. */
426 /* If BP is malloc'd by us, make sure it is big enough. */
429 malloc_size = bp1 - bp + buf.size;
430 tem = (char *) xrealloc (bp, malloc_size);
437 /* Copy the line of the entry from buf into bp. */
439 while ((*bp1++ = c = *tem++) && c != '\n')
440 /* Drop out any \ newline sequence. */
441 if (c == '\\' && *tem == '\n')
448 /* Does this entry refer to another terminal type's entry?
449 If something is found, copy it into heap and null-terminate it. */
450 term = tgetst1 (find_capability (bp2, "tc"), 0);
458 bp = (char *) xrealloc (bp, bp1 - bp + 1);
464 /* #### yuck, why the hell are we casting a pointer to an int? */
465 return (int) (long) bp;
469 /* Given file open on FD and buffer BUFP,
470 scan the file from the beginning until a line is found
471 that starts the entry for terminal type STRING.
472 Returns 1 if successful, with that line in BUFP,
473 or returns 0 if no entry found in the file. */
476 scan_file (string, fd, bufp)
483 bufp->ptr = bufp->beg;
492 /* Read a line into the buffer. */
496 /* if it is continued, append another line to it,
497 until a non-continued line ends. */
498 end = gobble_line (fd, bufp, end);
500 while (!bufp->ateof && end[-2] == '\\');
502 if (*bufp->ptr != '#'
503 && name_match (bufp->ptr, string))
506 /* Discard the line just processed. */
512 /* Return nonzero if NAME is one of the names specified
513 by termcap entry LINE. */
516 name_match (line, name)
521 if (!compare_contin (line, name))
523 /* This line starts an entry. Is it the right one? */
524 for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
525 if (*tem == '|' && !compare_contin (tem + 1, name))
532 compare_contin (str1, str2)
540 while (c1 == '\\' && *str1 == '\n')
543 while ((c1 = *str1++) == ' ' || c1 == '\t');
547 /* End of type being looked up. */
548 if (c1 == '|' || c1 == ':')
549 /* If end of name in data base, we win. */
559 /* Make sure that the buffer <- BUFP contains a full line
560 of the file open on FD, starting at the place BUFP->ptr
561 points to. Can read more of the file, discard stuff before
562 BUFP->ptr, or make the buffer bigger.
564 Returns the pointer to after the newline ending the line,
565 or to the end of the file, if there is no newline to end it.
567 Can also merge on continuation lines. If APPEND_END is
568 nonzero, it points past the newline of a line that is
569 continued; we add another line onto it and regard the whole
570 thing as one line. The caller decides when a line is continued. */
573 gobble_line (fd, bufp, append_end)
580 char *buf = bufp->beg;
584 append_end = bufp->ptr;
589 while (*end && *end != '\n') end++;
593 return buf + bufp->full;
594 if (bufp->ptr == buf)
596 if (bufp->full == bufp->size)
599 /* Add 1 to size to ensure room for terminating null. */
600 tem = (char *) xrealloc (buf, bufp->size + 1);
601 bufp->ptr = (bufp->ptr - buf) + tem;
602 append_end = (append_end - buf) + tem;
603 bufp->beg = buf = tem;
608 append_end -= bufp->ptr - buf;
609 memcpy (buf, bufp->ptr, bufp->full -= bufp->ptr - buf);
612 if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
632 printf ("TERM: %s\n", term);
634 buf = (char *) tgetent (0, term);
637 printf ("No entry.\n");
641 printf ("Entry: %s\n", buf);
646 printf ("co: %d\n", tgetnum ("co"));
647 printf ("am: %d\n", tgetflag ("am"));
653 char *x = tgetstr (cap, 0);
656 printf ("%s: ", cap);
660 if (*y <= ' ' || *y == 0177)
661 printf ("\\%0o", *y);