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
16 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
18 /* Emacs config.h may rename various library functions such as malloc. */
25 /* Get the O_* definitions for open et al. */
42 /* Do this after the include, in case string.h prototypes bcopy. */
43 #if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy)
44 #define bcopy(s, d, n) memcpy ((d), (s), (n))
54 #endif /* not emacs */
57 #define NULL (char *) 0
64 /* BUFSIZE is the initial size allocated for the buffer
65 for reading the termcap file.
67 Make it large normally for speed.
68 Make it variable when debugging, so can exercise
69 increasing the space dynamically. */
73 #define BUFSIZE bufsize
82 #define TERMCAP_FILE "/etc/termcap"
89 write (2, "virtual memory exhausted\n", 25);
97 register char *tem
= malloc (size
);
109 register char *tem
= realloc (ptr
, size
);
115 #endif /* not emacs */
117 /* Looking up capabilities in the entry already found. */
119 /* The pointer to the data made by tgetent is left here
120 for tgetnum, tgetflag and tgetstr to find. */
121 static char *term_entry
;
123 static char *tgetst1 ();
125 /* Search entry BP for capability CAP.
126 Return a pointer to the capability (in BP) if found,
130 find_capability (bp
, cap
)
131 register char *bp
, *cap
;
145 register char *ptr
= find_capability (term_entry
, cap
);
146 if (!ptr
|| ptr
[-1] != '#')
155 register char *ptr
= find_capability (term_entry
, cap
);
156 return ptr
&& ptr
[-1] == ':';
159 /* Look up a string-valued capability CAP.
160 If AREA is non-null, it points to a pointer to a block in which
161 to store the string. That pointer is advanced over the space used.
162 If AREA is null, space is allocated with `malloc'. */
169 register char *ptr
= find_capability (term_entry
, cap
);
170 if (!ptr
|| (ptr
[-1] != '=' && ptr
[-1] != '~'))
172 return tgetst1 (ptr
, area
);
175 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
176 gives meaning of character following \, or a space if no special meaning.
177 Eight characters per line within the string. */
180 = " \007\010 \033\014 \
185 /* PTR points to a string value inside a termcap entry.
186 Copy that value, processing \ and ^ abbreviations,
187 into the block that *AREA points to,
188 or to newly allocated storage if AREA is NULL.
189 Return the address to which we copied the value,
190 or NULL if PTR is NULL. */
197 register char *p
, *r
;
206 /* `ret' gets address of where to store the string. */
209 /* Compute size of block needed (may overestimate). */
211 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
213 ret
= (char *) xmalloc (p
- ptr
+ 1);
218 /* Copy the string value, stopping at null or colon.
219 Also process ^ and \ abbreviations. */
222 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
235 if (c
>= '0' && c
<= '7')
240 while (++size
< 3 && (c1
= *p
) >= '0' && c1
<= '7')
247 else if (c
>= 0100 && c
< 0200)
249 c1
= esctab
[(c
& ~040) - 0100];
263 /* Outputting a string with padding. */
266 /* If OSPEED is 0, we use this as the actual baud rate. */
270 /* Actual baud rate if positive;
271 - baud rate / 100 if negative. */
273 static int speeds
[] =
276 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
277 -20, -24, -36, -48, -72, -96, -192
279 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
280 -18, -24, -48, -96, -192, -288, -384, -576, -1152
285 tputs (str
, nlines
, outfun
)
288 register int (*outfun
) ();
290 register int padcount
= 0;
296 /* For quite high speeds, convert to the smaller
297 units to avoid overflow. */
299 speed
= - speed
/ 100;
302 speed
= tputs_baud_rate
;
303 else if (ospeed
> 0 && ospeed
< (sizeof speeds
/ sizeof speeds
[0]))
304 speed
= speeds
[ospeed
];
312 while (*str
>= '0' && *str
<= '9')
314 padcount
+= *str
++ - '0';
320 padcount
+= *str
++ - '0';
330 /* PADCOUNT is now in units of tenths of msec.
331 SPEED is measured in characters per 10 seconds
332 or in characters per .1 seconds (if negative).
333 We use the smaller units for larger speeds to avoid overflow. */
338 padcount
= -padcount
;
345 while (padcount
-- > 0)
349 /* Finding the termcap entry in the termcap data base. */
360 /* Forward declarations of static functions. */
362 static int scan_file ();
363 static char *gobble_line ();
364 static int compare_contin ();
365 static int name_match ();
374 valid_filename_p (fn
)
377 struct FAB fab
= cc$rms_fab
;
378 struct NAM nam
= cc$rms_nam
;
379 char esa
[NAM$C_MAXRSS
];
382 fab
.fab$b_fns
= strlen(fn
);
383 fab
.fab$l_nam
= &nam
;
384 fab
.fab$l_fop
= FAB$M_NAM
;
387 nam
.nam$b_ess
= sizeof esa
;
389 return SYS$
PARSE(&fab
, 0, 0) == RMS$_NORMAL
;
394 #ifdef MSDOS /* MW, May 1993 */
396 valid_filename_p (fn
)
399 return *fn
== '/' || fn
[1] == ':';
402 #define valid_filename_p(fn) (*(fn) == '/')
407 /* Find the termcap entry data for terminal type NAME
408 and store it in the block that BP points to.
409 Record its address for future use.
411 If BP is null, space is dynamically allocated.
413 Return -1 if there is some difficulty accessing the data base
415 0 if the data base is accessible but the type NAME is not defined
416 in it, and some other value otherwise. */
422 register char *termcap_name
;
426 char *tc_search_point
;
430 char *tcenv
; /* TERMCAP value, if it contains :tc=. */
431 char *indirect
= NULL
; /* Terminal type in :tc= in TERMCAP value. */
434 #ifdef INTERNAL_TERMINAL
435 /* For the internal terminal we don't want to read any termcap file,
437 if (!strcmp (name
, "internal"))
439 term
= INTERNAL_TERMINAL
;
442 malloc_size
= 1 + strlen (term
);
443 bp
= (char *) xmalloc (malloc_size
);
448 #endif /* INTERNAL_TERMINAL */
450 /* For compatibility with programs like `less' that want to
451 put data in the termcap buffer themselves as a fallback. */
455 termcap_name
= getenv ("TERMCAP");
456 if (termcap_name
&& *termcap_name
== '\0')
458 #if defined (MSDOS) && !defined (TEST)
459 if (termcap_name
&& (*termcap_name
== '\\'
460 || *termcap_name
== '/'
461 || termcap_name
[1] == ':'))
462 dostounix_filename(termcap_name
);
465 filep
= termcap_name
&& valid_filename_p (termcap_name
);
467 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
468 it is a file name to use instead of /etc/termcap.
469 If it is non-null and does not start with /,
470 it is the entry itself, but only if
471 the name the caller requested matches the TERM variable. */
473 if (termcap_name
&& !filep
&& !strcmp (name
, getenv ("TERM")))
475 indirect
= tgetst1 (find_capability (termcap_name
, "tc"), (char **) 0);
481 strcpy (bp
, termcap_name
);
485 { /* It has tc=. Need to read /etc/termcap. */
486 tcenv
= termcap_name
;
491 if (!termcap_name
|| !filep
)
492 termcap_name
= TERMCAP_FILE
;
494 /* Here we know we must search a file and termcap_name has its name. */
497 fd
= open (termcap_name
, O_RDONLY
|O_TEXT
, 0);
499 fd
= open (termcap_name
, O_RDONLY
, 0);
505 /* Add 1 to size to ensure room for terminating null. */
506 buf
.beg
= (char *) xmalloc (buf
.size
+ 1);
507 term
= indirect
? indirect
: name
;
511 malloc_size
= indirect
? strlen (tcenv
) + 1 : buf
.size
;
512 bp
= (char *) xmalloc (malloc_size
);
514 tc_search_point
= bp1
= bp
;
517 /* Copy the data from the environment variable. */
520 bp1
+= strlen (tcenv
);
525 /* Scan the file, reading it via buf, till find start of main entry. */
526 if (scan_file (term
, fd
, &buf
) == 0)
535 /* Free old `term' if appropriate. */
539 /* If BP is malloc'd by us, make sure it is big enough. */
542 malloc_size
= bp1
- bp
+ buf
.size
;
543 termcap_name
= (char *) xrealloc (bp
, malloc_size
);
544 bp1
+= termcap_name
- bp
;
545 tc_search_point
+= termcap_name
- bp
;
549 /* Copy the line of the entry from buf into bp. */
550 termcap_name
= buf
.ptr
;
551 while ((*bp1
++ = c
= *termcap_name
++) && c
!= '\n')
552 /* Drop out any \ newline sequence. */
553 if (c
== '\\' && *termcap_name
== '\n')
560 /* Does this entry refer to another terminal type's entry?
561 If something is found, copy it into heap and null-terminate it. */
562 tc_search_point
= find_capability (tc_search_point
, "tc");
563 term
= tgetst1 (tc_search_point
, (char **) 0);
570 bp
= (char *) xrealloc (bp
, bp1
- bp
+ 1);
577 /* Given file open on FD and buffer BUFP,
578 scan the file from the beginning until a line is found
579 that starts the entry for terminal type STR.
580 Return 1 if successful, with that line in BUFP,
581 or 0 if no entry is found in the file. */
584 scan_file (str
, fd
, bufp
)
587 register struct buffer
*bufp
;
591 bufp
->ptr
= bufp
->beg
;
600 /* Read a line into the buffer. */
604 /* if it is continued, append another line to it,
605 until a non-continued line ends. */
606 end
= gobble_line (fd
, bufp
, end
);
608 while (!bufp
->ateof
&& end
[-2] == '\\');
610 if (*bufp
->ptr
!= '#'
611 && name_match (bufp
->ptr
, str
))
614 /* Discard the line just processed. */
620 /* Return nonzero if NAME is one of the names specified
621 by termcap entry LINE. */
624 name_match (line
, name
)
629 if (!compare_contin (line
, name
))
631 /* This line starts an entry. Is it the right one? */
632 for (tem
= line
; *tem
&& *tem
!= '\n' && *tem
!= ':'; tem
++)
633 if (*tem
== '|' && !compare_contin (tem
+ 1, name
))
640 compare_contin (str1
, str2
)
641 register char *str1
, *str2
;
648 while (c1
== '\\' && *str1
== '\n')
651 while ((c1
= *str1
++) == ' ' || c1
== '\t');
655 /* End of type being looked up. */
656 if (c1
== '|' || c1
== ':')
657 /* If end of name in data base, we win. */
667 /* Make sure that the buffer <- BUFP contains a full line
668 of the file open on FD, starting at the place BUFP->ptr
669 points to. Can read more of the file, discard stuff before
670 BUFP->ptr, or make the buffer bigger.
672 Return the pointer to after the newline ending the line,
673 or to the end of the file, if there is no newline to end it.
675 Can also merge on continuation lines. If APPEND_END is
676 non-null, it points past the newline of a line that is
677 continued; we add another line onto it and regard the whole
678 thing as one line. The caller decides when a line is continued. */
681 gobble_line (fd
, bufp
, append_end
)
683 register struct buffer
*bufp
;
688 register char *buf
= bufp
->beg
;
692 append_end
= bufp
->ptr
;
697 while (*end
&& *end
!= '\n') end
++;
701 return buf
+ bufp
->full
;
702 if (bufp
->ptr
== buf
)
704 if (bufp
->full
== bufp
->size
)
707 /* Add 1 to size to ensure room for terminating null. */
708 tem
= (char *) xrealloc (buf
, bufp
->size
+ 1);
709 bufp
->ptr
= (bufp
->ptr
- buf
) + tem
;
710 append_end
= (append_end
- buf
) + tem
;
711 bufp
->beg
= buf
= tem
;
716 append_end
-= bufp
->ptr
- buf
;
717 bcopy (bufp
->ptr
, buf
, bufp
->full
-= bufp
->ptr
- buf
);
720 if (!(nread
= read (fd
, buf
+ bufp
->full
, bufp
->size
- bufp
->full
)))
723 buf
[bufp
->full
] = '\0';
744 printf ("TERM: %s\n", term
);
746 buf
= (char *) tgetent (0, term
);
749 printf ("No entry.\n");
753 printf ("Entry: %s\n", buf
);
758 printf ("co: %d\n", tgetnum ("co"));
759 printf ("am: %d\n", tgetflag ("am"));
765 char *x
= tgetstr (cap
, 0);
768 printf ("%s: ", cap
);
772 if (*y
<= ' ' || *y
== 0177)
773 printf ("\\%0o", *y
);