1 /* Work-alike for termcap, plus extra features.
2 Copyright (C) 1985, 1986, 1993 Free Software Foundation, Inc.
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 2, or (at your option)
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.
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
18 /* Emacs config.h may rename various library functions such as malloc. */
21 #else /* not HAVE_CONFIG_H */
23 #if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
24 #define bcopy(s, d, n) memcpy ((d), (s), (n))
43 #endif /* not HAVE_CONFIG_H */
46 #define NULL (char *) 0
49 /* BUFSIZE is the initial size allocated for the buffer
50 for reading the termcap file.
52 Make it large normally for speed.
53 Make it variable when debugging, so can exercise
54 increasing the space dynamically. */
58 #define BUFSIZE bufsize
70 write (2, "virtual memory exhausted\n", 25);
78 register char *tem = malloc (size);
90 register char *tem = realloc (ptr, size);
96 #endif /* not emacs */
98 /* Looking up capabilities in the entry already found. */
100 /* The pointer to the data made by tgetent is left here
101 for tgetnum, tgetflag and tgetstr to find. */
102 static char *term_entry;
104 static char *tgetst1 ();
106 /* Search entry BP for capability CAP.
107 Return a pointer to the capability (in BP) if found,
111 find_capability (bp, cap)
112 register char *bp, *cap;
126 register char *ptr = find_capability (term_entry, cap);
127 if (!ptr || ptr[-1] != '#')
136 register char *ptr = find_capability (term_entry, cap);
137 return ptr && ptr[-1] == ':';
140 /* Look up a string-valued capability CAP.
141 If AREA is non-null, it points to a pointer to a block in which
142 to store the string. That pointer is advanced over the space used.
143 If AREA is null, space is allocated with `malloc'. */
150 register char *ptr = find_capability (term_entry, cap);
151 if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
153 return tgetst1 (ptr, area);
156 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
157 gives meaning of character following \, or a space if no special meaning.
158 Eight characters per line within the string. */
161 = " \007\010 \033\014 \
166 /* PTR points to a string value inside a termcap entry.
167 Copy that value, processing \ and ^ abbreviations,
168 into the block that *AREA points to,
169 or to newly allocated storage if AREA is NULL.
170 Return the address to which we copied the value,
171 or NULL if PTR is NULL. */
178 register char *p, *r;
187 /* `ret' gets address of where to store the string. */
190 /* Compute size of block needed (may overestimate). */
192 while ((c = *p++) && c != ':' && c != '\n')
194 ret = (char *) xmalloc (p - ptr + 1);
199 /* Copy the string value, stopping at null or colon.
200 Also process ^ and \ abbreviations. */
203 while ((c = *p++) && c != ':' && c != '\n')
210 if (c >= '0' && c <= '7')
215 while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7')
222 else if (c >= 0100 && c < 0200)
224 c1 = esctab[(c & ~040) - 0100];
238 /* Outputting a string with padding. */
241 /* If OSPEED is 0, we use this as the actual baud rate. */
245 /* Actual baud rate if positive;
246 - baud rate / 100 if negative. */
248 static short speeds[] =
251 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
252 -20, -24, -36, -48, -72, -96, -192
254 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
255 -18, -24, -48, -96, -192, -384
260 tputs (str, nlines, outfun)
263 register int (*outfun) ();
265 register int padcount = 0;
273 speed = tputs_baud_rate;
275 speed = speeds[ospeed];
281 while (*str >= '0' && *str <= '9')
283 padcount += *str++ - '0';
289 padcount += *str++ - '0';
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 ();
340 valid_filename_p (fn)
343 struct FAB fab = cc$rms_fab;
344 struct NAM nam = cc$rms_nam;
345 char esa[NAM$C_MAXRSS];
348 fab.fab$b_fns = strlen(fn);
349 fab.fab$l_nam = &nam;
350 fab.fab$l_fop = FAB$M_NAM;
353 nam.nam$b_ess = sizeof esa;
355 return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL;
360 #define valid_filename_p(fn) (*(fn) == '/')
364 /* Find the termcap entry data for terminal type NAME
365 and store it in the block that BP points to.
366 Record its address for future use.
368 If BP is null, space is dynamically allocated.
370 Return -1 if there is some difficulty accessing the data base
372 0 if the data base is accessible but the type NAME is not defined
373 in it, and some other value otherwise. */
379 register char *termcap_name;
387 char *tcenv; /* TERMCAP value, if it contains :tc=. */
388 char *indirect = NULL; /* Terminal type in :tc= in TERMCAP value. */
391 termcap_name = getenv ("TERMCAP");
392 if (termcap_name && *termcap_name == '\0')
395 filep = termcap_name && valid_filename_p (termcap_name);
397 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
398 it is a file name to use instead of /etc/termcap.
399 If it is non-null and does not start with /,
400 it is the entry itself, but only if
401 the name the caller requested matches the TERM variable. */
403 if (termcap_name && !filep && !strcmp (name, getenv ("TERM")))
405 indirect = tgetst1 (find_capability (termcap_name, "tc"), (char **) 0);
411 strcpy (bp, termcap_name);
415 { /* It has tc=. Need to read /etc/termcap. */
416 tcenv = termcap_name;
421 if (!termcap_name || !filep)
423 termcap_name = "emacs_library:[etc]termcap.dat";
425 termcap_name = "/etc/termcap";
428 /* Here we know we must search a file and termcap_name has its name. */
430 fd = open (termcap_name, 0, 0);
435 /* Add 1 to size to ensure room for terminating null. */
436 buf.beg = (char *) xmalloc (buf.size + 1);
437 term = indirect ? indirect : name;
441 malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
442 bp = (char *) xmalloc (malloc_size);
447 /* Copy the data from the environment variable. */
450 bp1 += strlen (tcenv);
455 /* Scan the file, reading it via buf, till find start of main entry. */
456 if (scan_file (term, fd, &buf) == 0)
465 /* Free old `term' if appropriate. */
469 /* If BP is malloc'd by us, make sure it is big enough. */
472 malloc_size = bp1 - bp + buf.size;
473 termcap_name = (char *) xrealloc (bp, malloc_size);
474 bp1 += termcap_name - bp;
480 /* Copy the line of the entry from buf into bp. */
481 termcap_name = buf.ptr;
482 while ((*bp1++ = c = *termcap_name++) && c != '\n')
483 /* Drop out any \ newline sequence. */
484 if (c == '\\' && *termcap_name == '\n')
491 /* Does this entry refer to another terminal type's entry?
492 If something is found, copy it into heap and null-terminate it. */
493 term = tgetst1 (find_capability (bp2, "tc"), (char **) 0);
500 bp = (char *) xrealloc (bp, bp1 - bp + 1);
509 /* Given file open on FD and buffer BUFP,
510 scan the file from the beginning until a line is found
511 that starts the entry for terminal type STR.
512 Return 1 if successful, with that line in BUFP,
513 or 0 if no entry is found in the file. */
516 scan_file (str, fd, bufp)
519 register struct buffer *bufp;
523 bufp->ptr = bufp->beg;
532 /* Read a line into the buffer. */
536 /* if it is continued, append another line to it,
537 until a non-continued line ends. */
538 end = gobble_line (fd, bufp, end);
540 while (!bufp->ateof && end[-2] == '\\');
542 if (*bufp->ptr != '#'
543 && name_match (bufp->ptr, str))
546 /* Discard the line just processed. */
552 /* Return nonzero if NAME is one of the names specified
553 by termcap entry LINE. */
556 name_match (line, name)
561 if (!compare_contin (line, name))
563 /* This line starts an entry. Is it the right one? */
564 for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
565 if (*tem == '|' && !compare_contin (tem + 1, name))
572 compare_contin (str1, str2)
573 register char *str1, *str2;
580 while (c1 == '\\' && *str1 == '\n')
583 while ((c1 = *str1++) == ' ' || c1 == '\t');
587 /* End of type being looked up. */
588 if (c1 == '|' || c1 == ':')
589 /* If end of name in data base, we win. */
599 /* Make sure that the buffer <- BUFP contains a full line
600 of the file open on FD, starting at the place BUFP->ptr
601 points to. Can read more of the file, discard stuff before
602 BUFP->ptr, or make the buffer bigger.
604 Return the pointer to after the newline ending the line,
605 or to the end of the file, if there is no newline to end it.
607 Can also merge on continuation lines. If APPEND_END is
608 non-null, it points past the newline of a line that is
609 continued; we add another line onto it and regard the whole
610 thing as one line. The caller decides when a line is continued. */
613 gobble_line (fd, bufp, append_end)
615 register struct buffer *bufp;
620 register char *buf = bufp->beg;
624 append_end = bufp->ptr;
629 while (*end && *end != '\n') end++;
633 return buf + bufp->full;
634 if (bufp->ptr == buf)
636 if (bufp->full == bufp->size)
639 /* Add 1 to size to ensure room for terminating null. */
640 tem = (char *) xrealloc (buf, bufp->size + 1);
641 bufp->ptr = (bufp->ptr - buf) + tem;
642 append_end = (append_end - buf) + tem;
643 bufp->beg = buf = tem;
648 append_end -= bufp->ptr - buf;
649 bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf);
652 if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
655 buf[bufp->full] = '\0';
676 printf ("TERM: %s\n", term);
678 buf = (char *) tgetent (0, term);
681 printf ("No entry.\n");
685 printf ("Entry: %s\n", buf);
690 printf ("co: %d\n", tgetnum ("co"));
691 printf ("am: %d\n", tgetflag ("am"));
697 char *x = tgetstr (cap, 0);
700 printf ("%s: ", cap);
704 if (*y <= ' ' || *y == 0177)
705 printf ("\\%0o", *y);