1 /* Work-alike for termcap, plus extra features.
2 Copyright (C) 1985, 86, 93, 94, 95 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 the
16 Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
18 /* Emacs config.h may rename various library functions such as malloc. */
23 /* Get the O_* definitions for open et al. */
24 #if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
25 # include <sys/file.h>
37 extern char *getenv ();
38 extern char *malloc ();
39 extern char *realloc ();
42 #if defined (HAVE_STRING_H)
46 #if !defined (HAVE_BCOPY) && (defined (HAVE_STRING_H) || defined (STDC_HEADERS))
47 # define bcopy(s, d, n) memcpy ((d), (s), (n))
50 #else /* not HAVE_CONFIG_H */
61 /* Do this after the include, in case string.h prototypes bcopy. */
62 #if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy)
63 #define bcopy(s, d, n) memcpy ((d), (s), (n))
73 #endif /* not HAVE_CONFIG_H */
76 #define NULL (char *) 0
83 /* BUFSIZE is the initial size allocated for the buffer
84 for reading the termcap file.
86 Make it large normally for speed.
87 Make it variable when debugging, so can exercise
88 increasing the space dynamically. */
92 #define BUFSIZE bufsize
103 #define TERMCAP_FILE "/etc/termcap"
110 write (2, "virtual memory exhausted\n", 25);
118 register char *tem = malloc (size);
130 register char *tem = realloc (ptr, size);
136 #endif /* not emacs */
138 /* Looking up capabilities in the entry already found. */
140 /* The pointer to the data made by tgetent is left here
141 for tgetnum, tgetflag and tgetstr to find. */
142 static char *term_entry;
144 static char *tgetst1 ();
146 /* Search entry BP for capability CAP.
147 Return a pointer to the capability (in BP) if found,
151 find_capability (bp, cap)
152 register char *bp, *cap;
167 register char *ptr = find_capability (term_entry, cap);
168 if (!ptr || ptr[-1] != '#')
178 register char *ptr = find_capability (term_entry, cap);
179 return ptr && ptr[-1] == ':';
182 /* Look up a string-valued capability CAP.
183 If AREA is non-null, it points to a pointer to a block in which
184 to store the string. That pointer is advanced over the space used.
185 If AREA is null, space is allocated with `malloc'. */
193 register char *ptr = find_capability (term_entry, cap);
194 if (!ptr || (ptr[-1] != '=' && ptr[-1] != '~'))
196 return tgetst1 (ptr, area);
199 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
200 gives meaning of character following \, or a space if no special meaning.
201 Eight characters per line within the string. */
204 = " \007\010 \033\014 \
209 /* PTR points to a string value inside a termcap entry.
210 Copy that value, processing \ and ^ abbreviations,
211 into the block that *AREA points to,
212 or to newly allocated storage if AREA is NULL.
213 Return the address to which we copied the value,
214 or NULL if PTR is NULL. */
221 register char *p, *r;
230 /* `ret' gets address of where to store the string. */
233 /* Compute size of block needed (may overestimate). */
235 while ((c = *p++) && c != ':' && c != '\n')
237 ret = (char *) xmalloc (p - ptr + 1);
242 /* Copy the string value, stopping at null or colon.
243 Also process ^ and \ abbreviations. */
246 while ((c = *p++) && c != ':' && c != '\n')
259 if (c >= '0' && c <= '7')
264 while (++size < 3 && (c1 = *p) >= '0' && c1 <= '7')
271 else if (c >= 0100 && c < 0200)
273 c1 = esctab[(c & ~040) - 0100];
287 /* Outputting a string with padding. */
290 /* If OSPEED is 0, we use this as the actual baud rate. */
292 __private_extern__ char PC = '\0';
294 /* Actual baud rate if positive;
295 - baud rate / 100 if negative. */
297 static int speeds[] =
300 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
301 -20, -24, -36, -48, -72, -96, -192
303 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
304 -18, -24, -48, -96, -192, -288, -384, -576, -1152
310 tputs (str, nlines, outfun)
313 register int (*outfun) ();
315 register int padcount = 0;
321 /* For quite high speeds, convert to the smaller
322 units to avoid overflow. */
324 speed = - speed / 100;
327 speed = tputs_baud_rate;
328 else if (ospeed > 0 && ospeed < (sizeof speeds / sizeof speeds[0]))
329 speed = speeds[ospeed];
337 while (*str >= '0' && *str <= '9')
339 padcount += *str++ - '0';
345 padcount += *str++ - '0';
355 /* PADCOUNT is now in units of tenths of msec.
356 SPEED is measured in characters per 10 seconds
357 or in characters per .1 seconds (if negative).
358 We use the smaller units for larger speeds to avoid overflow. */
363 padcount = -padcount;
370 while (padcount-- > 0)
374 /* Finding the termcap entry in the termcap data base. */
385 /* Forward declarations of static functions. */
387 static int scan_file ();
388 static char *gobble_line ();
389 static int compare_contin ();
390 static int name_match ();
399 valid_filename_p (fn)
402 struct FAB fab = cc$rms_fab;
403 struct NAM nam = cc$rms_nam;
404 char esa[NAM$C_MAXRSS];
407 fab.fab$b_fns = strlen(fn);
408 fab.fab$l_nam = &nam;
409 fab.fab$l_fop = FAB$M_NAM;
412 nam.nam$b_ess = sizeof esa;
414 return SYS$PARSE(&fab, 0, 0) == RMS$_NORMAL;
419 #ifdef MSDOS /* MW, May 1993 */
421 valid_filename_p (fn)
424 return *fn == '\\' || *fn == '/' ||
425 (*fn >= 'A' && *fn <= 'z' && fn[1] == ':');
428 #define valid_filename_p(fn) (*(fn) == '/')
433 /* Find the termcap entry data for terminal type NAME
434 and store it in the block that BP points to.
435 Record its address for future use.
437 If BP is null, space is dynamically allocated.
439 Return -1 if there is some difficulty accessing the data base
441 0 if the data base is accessible but the type NAME is not defined
442 in it, and some other value otherwise. */
449 register char *termcap_name;
457 char *tcenv; /* TERMCAP value, if it contains :tc=. */
458 char *indirect = NULL; /* Terminal type in :tc= in TERMCAP value. */
461 #ifdef INTERNAL_TERMINAL
462 /* For the internal terminal we don't want to read any termcap file,
464 if (!strcmp (name, "internal"))
466 term = INTERNAL_TERMINAL;
469 malloc_size = 1 + strlen (term);
470 bp = (char *) xmalloc (malloc_size);
475 #endif /* INTERNAL_TERMINAL */
477 /* For compatibility with programs like `less' that want to
478 put data in the termcap buffer themselves as a fallback. */
482 termcap_name = getenv ("TERMCAP");
483 if (termcap_name && *termcap_name == '\0')
486 #if defined (MSDOS) && !defined (TEST)
487 if (termcap_name && (*termcap_name == '\\'
488 || *termcap_name == '/'
489 || termcap_name[1] == ':'))
490 dostounix_filename(termcap_name);
494 filep = termcap_name && valid_filename_p (termcap_name);
496 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
497 it is a file name to use instead of /etc/termcap.
498 If it is non-null and does not start with /,
499 it is the entry itself, but only if
500 the name the caller requested matches the TERM variable. */
502 if (termcap_name && !filep && !strcmp (name, getenv ("TERM")))
504 indirect = tgetst1 (find_capability (termcap_name, "tc"), (char **) 0);
510 strcpy (bp, termcap_name);
514 { /* It has tc=. Need to read /etc/termcap. */
515 tcenv = termcap_name;
520 if (!termcap_name || !filep)
521 termcap_name = TERMCAP_FILE;
523 /* Here we know we must search a file and termcap_name has its name. */
526 fd = open (termcap_name, O_RDONLY|O_TEXT, 0);
528 fd = open (termcap_name, O_RDONLY, 0);
534 /* Add 1 to size to ensure room for terminating null. */
535 buf.beg = (char *) xmalloc (buf.size + 1);
536 term = indirect ? indirect : name;
540 malloc_size = indirect ? strlen (tcenv) + 1 : buf.size;
541 bp = (char *) xmalloc (malloc_size);
546 /* Copy the data from the environment variable. */
549 bp1 += strlen (tcenv);
554 /* Scan the file, reading it via buf, till find start of main entry. */
555 if (scan_file (term, fd, &buf) == 0)
564 /* Free old `term' if appropriate. */
568 /* If BP is malloc'd by us, make sure it is big enough. */
571 malloc_size = bp1 - bp + buf.size;
572 termcap_name = (char *) xrealloc (bp, malloc_size);
573 bp1 += termcap_name - bp;
579 /* Copy the line of the entry from buf into bp. */
580 termcap_name = buf.ptr;
581 while ((*bp1++ = c = *termcap_name++) && c != '\n')
582 /* Drop out any \ newline sequence. */
583 if (c == '\\' && *termcap_name == '\n')
590 /* Does this entry refer to another terminal type's entry?
591 If something is found, copy it into heap and null-terminate it. */
592 term = tgetst1 (find_capability (bp2, "tc"), (char **) 0);
599 bp = (char *) xrealloc (bp, bp1 - bp + 1);
606 /* Given file open on FD and buffer BUFP,
607 scan the file from the beginning until a line is found
608 that starts the entry for terminal type STR.
609 Return 1 if successful, with that line in BUFP,
610 or 0 if no entry is found in the file. */
613 scan_file (str, fd, bufp)
616 register struct buffer *bufp;
620 bufp->ptr = bufp->beg;
629 /* Read a line into the buffer. */
633 /* if it is continued, append another line to it,
634 until a non-continued line ends. */
635 end = gobble_line (fd, bufp, end);
637 while (!bufp->ateof && end[-2] == '\\');
639 if (*bufp->ptr != '#'
640 && name_match (bufp->ptr, str))
643 /* Discard the line just processed. */
649 /* Return nonzero if NAME is one of the names specified
650 by termcap entry LINE. */
653 name_match (line, name)
658 if (!compare_contin (line, name))
660 /* This line starts an entry. Is it the right one? */
661 for (tem = line; *tem && *tem != '\n' && *tem != ':'; tem++)
662 if (*tem == '|' && !compare_contin (tem + 1, name))
669 compare_contin (str1, str2)
670 register char *str1, *str2;
677 while (c1 == '\\' && *str1 == '\n')
680 while ((c1 = *str1++) == ' ' || c1 == '\t');
684 /* End of type being looked up. */
685 if (c1 == '|' || c1 == ':')
686 /* If end of name in data base, we win. */
696 /* Make sure that the buffer <- BUFP contains a full line
697 of the file open on FD, starting at the place BUFP->ptr
698 points to. Can read more of the file, discard stuff before
699 BUFP->ptr, or make the buffer bigger.
701 Return the pointer to after the newline ending the line,
702 or to the end of the file, if there is no newline to end it.
704 Can also merge on continuation lines. If APPEND_END is
705 non-null, it points past the newline of a line that is
706 continued; we add another line onto it and regard the whole
707 thing as one line. The caller decides when a line is continued. */
710 gobble_line (fd, bufp, append_end)
712 register struct buffer *bufp;
717 register char *buf = bufp->beg;
721 append_end = bufp->ptr;
726 while (*end && *end != '\n') end++;
730 return buf + bufp->full;
731 if (bufp->ptr == buf)
733 if (bufp->full == bufp->size)
736 /* Add 1 to size to ensure room for terminating null. */
737 tem = (char *) xrealloc (buf, bufp->size + 1);
738 bufp->ptr = (bufp->ptr - buf) + tem;
739 append_end = (append_end - buf) + tem;
740 bufp->beg = buf = tem;
745 append_end -= bufp->ptr - buf;
746 bcopy (bufp->ptr, buf, bufp->full -= bufp->ptr - buf);
749 if (!(nread = read (fd, buf + bufp->full, bufp->size - bufp->full)))
752 buf[bufp->full] = '\0';
773 printf ("TERM: %s\n", term);
775 buf = (char *) tgetent (0, term);
778 printf ("No entry.\n");
782 printf ("Entry: %s\n", buf);
787 printf ("co: %d\n", tgetnum ("co"));
788 printf ("am: %d\n", tgetflag ("am"));
794 char *x = tgetstr (cap, 0);
797 printf ("%s: ", cap);
801 if (*y <= ' ' || *y == 0177)
802 printf ("\\%0o", *y);