1 /* termcap.c - Work-alike for termcap, plus extra features. */
3 /* Copyright (C) 1985, 1986, 1993,1994, 1995, 1998, 2001,2003,2005,2006,2008,2009 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
7 Bash is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 Bash is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Bash. If not, see <http://www.gnu.org/licenses/>.
21 /* Emacs config.h may rename various library functions such as malloc. */
26 /* Get the O_* definitions for open et al. */
27 #if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
28 # include <sys/file.h>
40 extern char *getenv ();
41 extern char *malloc ();
42 extern char *realloc ();
45 #if defined (HAVE_STRING_H)
49 #if !defined (HAVE_BCOPY) && (defined (HAVE_STRING_H) || defined (STDC_HEADERS))
50 # define bcopy(s, d, n) memcpy ((d), (s), (n))
53 #else /* not HAVE_CONFIG_H */
64 /* Do this after the include, in case string.h prototypes bcopy. */
65 #if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy)
66 #define bcopy(s, d, n) memcpy ((d), (s), (n))
76 #endif /* not HAVE_CONFIG_H */
79 #define NULL (char *) 0
86 /* BUFSIZE is the initial size allocated for the buffer
87 for reading the termcap file.
89 Make it large normally for speed.
90 Make it variable when debugging, so can exercise
91 increasing the space dynamically. */
95 #define BUFSIZE bufsize
106 #define TERMCAP_FILE "/etc/termcap"
113 write (2, "virtual memory exhausted\n", 25);
121 register char *tem = malloc (size);
133 register char *tem = realloc (ptr, size);
139 #endif /* not emacs */
141 /* Looking up capabilities in the entry already found. */
143 /* The pointer to the data made by tgetent is left here
144 for tgetnum, tgetflag and tgetstr to find. */
145 static char *term_entry;
147 static char *tgetst1 ();
149 /* Search entry BP for capability CAP.
150 Return a pointer to the capability (in BP) if found,
154 find_capability (bp, cap)
155 register char *bp, *cap;
170 register char *ptr = find_capability (term_entry, cap);
171 if (!ptr || ptr[-1] != '#')
181 register char *ptr = find_capability (term_entry, cap);
182 return ptr && ptr[-1] == ':';
185 /* Look up a string-valued capability CAP.
186 If AREA is non-null, it points to a pointer to a block in which
187 to store the string. That pointer is advanced over the space used.
188 If AREA is null, space is allocated with `malloc'. */
196 register char *ptr = find_capability (term_entry, cap);
197 if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
199 return tgetst1 (ptr, area);
202 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
203 gives meaning of character following \, or a space if no special meaning.
204 Eight characters per line within the string. */
207 = " \007\010 \033\014 \
212 /* PTR points to a string value inside a termcap entry.
213 Copy that value, processing \ and ^ abbreviations,
214 into the block that *AREA points to,
215 or to newly allocated storage if AREA is NULL.
216 Return the address to which we copied the value,
217 or NULL if PTR is NULL. */
224 register char *p, *r;
233 /* `ret' gets address of where to store the string. */
236 /* Compute size of block needed (may overestimate). */
238 while ((c = *p++) && c != ':' && c != '\n')
240 ret = (char *) xmalloc (p - ptr + 1);
245 /* Copy the string value, stopping at null or colon.
246 Also process ^ and \ abbreviations. */
249 while ((c = *p++) && c != ':' && c != '\n')
262 if (c >= '0' && c <= '7')
267 while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7')
274 else if (c >= 0100 && c < 0200)
276 c1 = esctab[(c & ~040) - 0100];
290 /* Outputting a string with padding. */
293 /* If OSPEED is 0, we use this as the actual baud rate. */
295 __private_extern__ char PC = '\0';
297 /* Actual baud rate if positive;
298 - baud rate / 100 if negative. */
300 static int speeds[] =
303 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
304 -20, -24, -36, -48, -72, -96, -192
306 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
307 -18, -24, -48, -96, -192, -288, -384, -576, -1152
313 tputs (str, nlines, outfun)
316 register int (*outfun) ();
318 register int padcount = 0;
324 /* For quite high speeds, convert to the smaller
325 units to avoid overflow. */
327 speed = - speed / 100;
330 speed = tputs_baud_rate;
331 else if (ospeed > 0 && ospeed < (sizeof speeds / sizeof speeds[0]))
332 speed = speeds[ospeed];
340 while (*str >= '0' && *str <= '9')
342 padcount += *str++ - '0';
348 padcount += *str++ - '0';
358 /* PADCOUNT is now in units of tenths of msec.
359 SPEED is measured in characters per 10 seconds
360 or in characters per .1 seconds (if negative).
361 We use the smaller units for larger speeds to avoid overflow. */
366 padcount = -padcount;
373 while (padcount-- > 0)
377 /* Finding the termcap entry in the termcap data base. */
388 /* Forward declarations of static functions. */
390 static int scan_file ();
391 static char *gobble_line ();
392 static int compare_contin ();
393 static int name_match ();
402 valid_filename_p (fn)
405 struct FAB fab = cc$rms_fab;
406 struct NAM nam = cc$rms_nam;
407 char esa[NAM$C_MAXRSS];
410 fab.fab$b_fns = strlen(fn);
411 fab.fab$l_nam = &nam;
412 fab.fab$l_fop = FAB$M_NAM;
415 nam.nam$b_ess = sizeof esa;
417 return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL;
422 #ifdef MSDOS /* MW, May 1993 */
424 valid_filename_p (fn)
427 return *fn == '\\' || *fn == '/' ||
428 (*fn >= 'A' && *fn <= 'z' && fn[1] == ':');
431 #define valid_filename_p(fn) (*(fn) == '/')
436 /* Find the termcap entry data for terminal type NAME
437 and store it in the block that BP points to.
438 Record its address for future use.
440 If BP is null, space is dynamically allocated.
442 Return -1 if there is some difficulty accessing the data base
444 0 if the data base is accessible but the type NAME is not defined
445 in it, and some other value otherwise. */
452 register char *termcap_name;
460 char *tcenv; /* TERMCAP value, if it contains :tc=. */
461 char *indirect = NULL; /* Terminal type in :tc= in TERMCAP value. */
464 #ifdef INTERNAL_TERMINAL
465 /* For the internal terminal we don't want to read any termcap file,
467 if (!strcmp (name, "internal"))
469 term = INTERNAL_TERMINAL;
472 malloc_size = 1 + strlen (term);
473 bp = (char *) xmalloc (malloc_size);
478 #endif /* INTERNAL_TERMINAL */
480 /* For compatibility with programs like `less' that want to
481 put data in the termcap buffer themselves as a fallback. */
485 termcap_name = getenv ("TERMCAP");
486 if (termcap_name && *termcap_name == '\0')
489 #if defined (MSDOS) && !defined (TEST)
490 if (termcap_name && (*termcap_name == '\\'
491 || *termcap_name == '/'
492 || termcap_name[1] == ':'))
493 dostounix_filename(termcap_name);
497 filep = termcap_name && valid_filename_p (termcap_name);
499 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
500 it is a file name to use instead of /etc/termcap.
501 If it is non-null and does not start with /,
502 it is the entry itself, but only if
503 the name the caller requested matches the TERM variable. */
505 if (termcap_name && !filep && !strcmp (name, getenv ("TERM")))
507 indirect = tgetst1 (find_capability (termcap_name, "tc"), (char **) 0);
513 strcpy (bp, termcap_name);
517 { /* It has tc=. Need to read /etc/termcap. */
518 tcenv = termcap_name;
523 if (!termcap_name || !filep)
524 termcap_name = TERMCAP_FILE;
526 /* Here we know we must search a file and termcap_name has its name. */
529 fd = open (termcap_name, O_RDONLY|O_TEXT, 0);
531 fd = open (termcap_name, O_RDONLY, 0);
537 /* Add 1 to size to ensure room for terminating null. */
538 buf.beg = (char *) xmalloc (buf.size + 1);
539 term = indirect ? indirect : name;
543 malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
544 bp = (char *) xmalloc (malloc_size);
549 /* Copy the data from the environment variable. */
552 bp1 += strlen (tcenv);
557 /* Scan the file, reading it via buf, till find start of main entry. */
558 if (scan_file (term, fd, &buf) == 0)
567 /* Free old `term' if appropriate. */
571 /* If BP is malloc'd by us, make sure it is big enough. */
574 malloc_size = bp1 - bp + buf.size;
575 termcap_name = (char *) xrealloc (bp, malloc_size);
576 bp1 += termcap_name - bp;
582 /* Copy the line of the entry from buf into bp. */
583 termcap_name = buf.ptr;
584 while ((*bp1++ = c = *termcap_name++) && c != '\n')
585 /* Drop out any \ newline sequence. */
586 if (c == '\\' && *termcap_name == '\n')
593 /* Does this entry refer to another terminal type's entry?
594 If something is found, copy it into heap and null-terminate it. */
595 term = tgetst1 (find_capability (bp2, "tc"), (char **) 0);
602 bp = (char *) xrealloc (bp, bp1 - bp + 1);
609 /* Given file open on FD and buffer BUFP,
610 scan the file from the beginning until a line is found
611 that starts the entry for terminal type STR.
612 Return 1 if successful, with that line in BUFP,
613 or 0 if no entry is found in the file. */
616 scan_file (str, fd, bufp)
619 register struct buffer *bufp;
623 bufp->ptr = bufp->beg;
632 /* Read a line into the buffer. */
636 /* if it is continued, append another line to it,
637 until a non-continued line ends. */
638 end = gobble_line (fd, bufp, end);
640 while (!bufp->ateof && end[-2] == '\\');
642 if (*bufp->ptr != '#'
643 && name_match (bufp->ptr, str))
646 /* Discard the line just processed. */
652 /* Return nonzero if NAME is one of the names specified
653 by termcap entry LINE. */
656 name_match (line, name)
661 if (!compare_contin (line, name))
663 /* This line starts an entry. Is it the right one? */
664 for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
665 if (*tem == '|' && !compare_contin (tem + 1, name))
672 compare_contin (str1, str2)
673 register char *str1, *str2;
680 while (c1 == '\\' && *str1 == '\n')
683 while ((c1 = *str1++) == ' ' || c1 == '\t');
687 /* End of type being looked up. */
688 if (c1 == '|' || c1 == ':')
689 /* If end of name in data base, we win. */
699 /* Make sure that the buffer <- BUFP contains a full line
700 of the file open on FD, starting at the place BUFP->ptr
701 points to. Can read more of the file, discard stuff before
702 BUFP->ptr, or make the buffer bigger.
704 Return the pointer to after the newline ending the line,
705 or to the end of the file, if there is no newline to end it.
707 Can also merge on continuation lines. If APPEND_END is
708 non-null, it points past the newline of a line that is
709 continued; we add another line onto it and regard the whole
710 thing as one line. The caller decides when a line is continued. */
713 gobble_line (fd, bufp, append_end)
715 register struct buffer *bufp;
720 register char *buf = bufp->beg;
724 append_end = bufp->ptr;
729 while (*end && *end != '\n') end++;
733 return buf + bufp->full;
734 if (bufp->ptr == buf)
736 if (bufp->full == bufp->size)
739 /* Add 1 to size to ensure room for terminating null. */
740 tem = (char *) xrealloc (buf, bufp->size + 1);
741 bufp->ptr = (bufp->ptr - buf) + tem;
742 append_end = (append_end - buf) + tem;
743 bufp->beg = buf = tem;
748 append_end -= bufp->ptr - buf;
749 bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf);
752 if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
755 buf[bufp->full] = '\0';
776 printf ("TERM: %s\n", term);
778 buf = (char *) tgetent (0, term);
781 printf ("No entry.\n");
785 printf ("Entry: %s\n", buf);
790 printf ("co: %d\n", tgetnum ("co"));
791 printf ("am: %d\n", tgetflag ("am"));
797 char *x = tgetstr (cap, 0);
800 printf ("%s: ", cap);
804 if (*y <= ' ' || *y == 0177)
805 printf ("\\%0o", *y);