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 */
40 #endif /* not emacs */
42 /* BUFSIZE is the initial size allocated for the buffer
43 for reading the termcap file.
45 Make it large normally for speed.
46 Make it variable when debugging, so can exercise
47 increasing the space dynamically. */
51 #define BUFSIZE bufsize
63 write (2, "virtual memory exhausted\n", 25);
71 char *tem = malloc (size);
83 char *tem = realloc (ptr, size);
89 #endif /* not emacs */
91 /* Looking up capabilities in the entry already found. */
93 /* The pointer to the data made by tgetent is left here
94 for tgetnum, tgetflag and tgetstr to find. */
95 static char *term_entry;
97 static const char *tgetst1 (const char *ptr, char **area);
99 /* Search entry BP for capability CAP.
100 Return a pointer to the capability (in BP) if found,
104 find_capability (bp, cap)
120 const char *ptr = find_capability (term_entry, cap);
121 if (!ptr || ptr[-1] != '#')
130 const char *ptr = find_capability (term_entry, cap);
131 return 0 != ptr && ptr[-1] == ':';
134 /* Look up a string-valued capability CAP.
135 If AREA is nonzero, it points to a pointer to a block in which
136 to store the string. That pointer is advanced over the space used.
137 If AREA is zero, space is allocated with `malloc'. */
144 const char *ptr = find_capability (term_entry, cap);
145 if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
147 return tgetst1 (ptr, area);
150 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
151 gives meaning of character following \, or a space if no special meaning.
152 Eight characters per line within the string. */
155 = " \007\010 \033\014 "
160 /* PTR points to a string value inside a termcap entry.
161 Copy that value, processing \ and ^ abbreviations,
162 into the block that *AREA points to,
163 or to newly allocated storage if AREA is 0. */
180 /* `ret' gets address of where to store the string. */
183 /* Compute size of block needed (may overestimate). */
185 while ((c = *p++) && c != ':' && c != '\n')
187 ret = (char *) xmalloc (p - ptr + 1);
192 /* Copy the string value, stopping at null or colon.
193 Also process ^ and \ abbreviations. */
196 while ((c = *p++) && c != ':' && c != '\n')
203 if (c >= '0' && c <= '7')
208 while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7')
215 else if (c >= 0100 && c < 0200)
217 c1 = esctab[(c & ~040) - 0100];
231 /* Outputting a string with padding. */
238 /* If `ospeed' is 0, we use `tputs_baud_rate' as the actual baud rate. */
242 /* Actual baud rate if positive;
243 - baud rate / 100 if negative. */
245 static short speeds[] =
247 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
248 -18, -24, -48, -96, -192, -288, -384, -576, -1152
252 tputs (string, nlines, outfun)
255 void (*outfun) (int);
261 speed = DEVICE_BAUD_RATE (XDEVICE (Fselected_device (Qnil)));
264 speed = tputs_baud_rate;
266 speed = speeds[ospeed];
269 if (string == (char *) 0)
272 while (isdigit (* (const unsigned char *) string))
274 padcount += *string++ - '0';
280 padcount += *string++ - '0';
288 (*outfun) (*string++);
290 /* padcount is now in units of tenths of msec. */
291 padcount *= speeds[ospeed];
294 if (speeds[ospeed] < 0)
295 padcount = -padcount;
302 while (padcount-- > 0)
306 /* Finding the termcap entry in the termcap data base. */
317 /* Forward declarations of static functions. */
319 static int scan_file ();
320 static char *gobble_line ();
321 static int compare_contin ();
322 static int name_match ();
325 /* Find the termcap entry data for terminal type NAME
326 and store it in the block that BP points to.
327 Record its address for future use.
329 If BP is zero, space is dynamically allocated. */
344 char *tcenv; /* TERMCAP value, if it contains :tc=. */
345 const char *indirect = 0; /* Terminal type in :tc= in TERMCAP value. */
347 tem = getenv ("TERMCAP");
348 if (tem && *tem == 0) tem = 0;
351 /* If tem is non-null and starts with / (in the un*x case, that is),
352 it is a file name to use instead of /etc/termcap.
353 If it is non-null and does not start with /,
354 it is the entry itself, but only if
355 the name the caller requested matches the TERM variable. */
357 if (tem && !IS_DIRECTORY_SEP (*tem) && !strcmp (name, getenv ("TERM")))
359 indirect = tgetst1 (find_capability (tem, "tc"), 0);
369 { /* We will need to read /etc/termcap. */
375 indirect = (char *) 0;
378 tem = "/etc/termcap";
380 /* Here we know we must search a file and tem has its name. */
382 fd = open (tem, 0, 0);
387 /* Add 1 to size to ensure room for terminating null. */
388 buf.beg = (char *) xmalloc (buf.size + 1);
389 term = indirect ? indirect : name;
393 malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
394 bp = (char *) xmalloc (malloc_size);
399 /* Copy the data from the environment variable. */
402 bp1 += strlen (tcenv);
407 /* Scan the file, reading it via buf, till find start of main entry. */
408 if (scan_file (term, fd, &buf) == 0)
411 /* Free old `term' if appropriate. */
415 /* If BP is malloc'd by us, make sure it is big enough. */
418 malloc_size = bp1 - bp + buf.size;
419 tem = (char *) xrealloc (bp, malloc_size);
426 /* Copy the line of the entry from buf into bp. */
428 while ((*bp1++ = c = *tem++) && c != '\n')
429 /* Drop out any \ newline sequence. */
430 if (c == '\\' && *tem == '\n')
437 /* Does this entry refer to another terminal type's entry?
438 If something is found, copy it into heap and null-terminate it. */
439 term = tgetst1 (find_capability (bp2, "tc"), 0);
447 bp = (char *) xrealloc (bp, bp1 - bp + 1);
453 /* #### yuck, why the hell are we casting a pointer to an int? */
454 return (int) (long) bp;
458 /* Given file open on FD and buffer BUFP,
459 scan the file from the beginning until a line is found
460 that starts the entry for terminal type STRING.
461 Returns 1 if successful, with that line in BUFP,
462 or returns 0 if no entry found in the file. */
465 scan_file (string, fd, bufp)
472 bufp->ptr = bufp->beg;
481 /* Read a line into the buffer. */
485 /* if it is continued, append another line to it,
486 until a non-continued line ends. */
487 end = gobble_line (fd, bufp, end);
489 while (!bufp->ateof && end[-2] == '\\');
491 if (*bufp->ptr != '#'
492 && name_match (bufp->ptr, string))
495 /* Discard the line just processed. */
501 /* Return nonzero if NAME is one of the names specified
502 by termcap entry LINE. */
505 name_match (line, name)
510 if (!compare_contin (line, name))
512 /* This line starts an entry. Is it the right one? */
513 for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
514 if (*tem == '|' && !compare_contin (tem + 1, name))
521 compare_contin (str1, str2)
529 while (c1 == '\\' && *str1 == '\n')
532 while ((c1 = *str1++) == ' ' || c1 == '\t');
536 /* End of type being looked up. */
537 if (c1 == '|' || c1 == ':')
538 /* If end of name in data base, we win. */
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.
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.
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. */
562 gobble_line (fd, bufp, append_end)
569 char *buf = bufp->beg;
573 append_end = bufp->ptr;
578 while (*end && *end != '\n') end++;
582 return buf + bufp->full;
583 if (bufp->ptr == buf)
585 if (bufp->full == bufp->size)
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;
597 append_end -= bufp->ptr - buf;
598 memcpy (buf, bufp->ptr, bufp->full -= bufp->ptr - buf);
601 if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
621 printf ("TERM: %s\n", term);
623 buf = (char *) tgetent (0, term);
626 printf ("No entry.\n");
630 printf ("Entry: %s\n", buf);
635 printf ("co: %d\n", tgetnum ("co"));
636 printf ("am: %d\n", tgetflag ("am"));
642 char *x = tgetstr (cap, 0);
645 printf ("%s: ", cap);
649 if (*y <= ' ' || *y == 0177)
650 printf ("\\%0o", *y);