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, Inc., 59 Temple Place - Suite 330,
17 Boston, MA 02111-1307, USA. */
19 /* Emacs config.h may rename various library functions such as malloc. */
26 /* Get the O_* definitions for open et al. */
43 /* Do this after the include, in case string.h prototypes bcopy. */
44 #if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy)
45 #define bcopy(s, d, n) memcpy ((d), (s), (n))
55 #endif /* not emacs */
58 #define NULL (char *) 0
65 /* BUFSIZE is the initial size allocated for the buffer
66 for reading the termcap file.
68 Make it large normally for speed.
69 Make it variable when debugging, so can exercise
70 increasing the space dynamically. */
74 #define BUFSIZE bufsize
83 #define TERMCAP_FILE "/etc/termcap"
90 write (2, "virtual memory exhausted\n", 25);
98 register char *tem
= malloc (size
);
110 register char *tem
= realloc (ptr
, size
);
116 #endif /* not emacs */
118 /* Looking up capabilities in the entry already found. */
120 /* The pointer to the data made by tgetent is left here
121 for tgetnum, tgetflag and tgetstr to find. */
122 static char *term_entry
;
124 static char *tgetst1 ();
126 /* Search entry BP for capability CAP.
127 Return a pointer to the capability (in BP) if found,
131 find_capability (bp
, cap
)
132 register char *bp
, *cap
;
146 register char *ptr
= find_capability (term_entry
, cap
);
147 if (!ptr
|| ptr
[-1] != '#')
156 register char *ptr
= find_capability (term_entry
, cap
);
157 return ptr
&& ptr
[-1] == ':';
160 /* Look up a string-valued capability CAP.
161 If AREA is non-null, it points to a pointer to a block in which
162 to store the string. That pointer is advanced over the space used.
163 If AREA is null, space is allocated with `malloc'. */
170 register char *ptr
= find_capability (term_entry
, cap
);
171 if (!ptr
|| (ptr
[-1] != '=' && ptr
[-1] != '~'))
173 return tgetst1 (ptr
, area
);
176 #ifdef IS_EBCDIC_HOST
177 /* Table, indexed by a character in range 0200 to 0300 with 0200 subtracted,
178 gives meaning of character following \, or a space if no special meaning.
179 Sixteen characters per line within the string. */
182 = " \057\026 \047\014 \
187 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
188 gives meaning of character following \, or a space if no special meaning.
189 Eight characters per line within the string. */
192 = " \007\010 \033\014 \
198 /* PTR points to a string value inside a termcap entry.
199 Copy that value, processing \ and ^ abbreviations,
200 into the block that *AREA points to,
201 or to newly allocated storage if AREA is NULL.
202 Return the address to which we copied the value,
203 or NULL if PTR is NULL. */
210 register char *p
, *r
;
219 /* `ret' gets address of where to store the string. */
222 /* Compute size of block needed (may overestimate). */
224 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
226 ret
= (char *) xmalloc (p
- ptr
+ 1);
231 /* Copy the string value, stopping at null or colon.
232 Also process ^ and \ abbreviations. */
235 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
248 if (c
>= '0' && c
<= '7')
253 while (++size
< 3 && (c1
= *p
) >= '0' && c1
<= '7')
260 #ifdef IS_EBCDIC_HOST
261 else if (c
>= 0200 && c
< 0360)
263 c1
= esctab
[(c
& ~0100) - 0200];
268 else if (c
>= 0100 && c
< 0200)
270 c1
= esctab
[(c
& ~040) - 0100];
285 /* Outputting a string with padding. */
288 /* If OSPEED is 0, we use this as the actual baud rate. */
292 /* Actual baud rate if positive;
293 - baud rate / 100 if negative. */
295 static int speeds
[] =
298 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
299 -20, -24, -36, -48, -72, -96, -192
301 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
302 -18, -24, -48, -96, -192, -288, -384, -576, -1152
307 tputs (str
, nlines
, outfun
)
310 register int (*outfun
) ();
312 register int padcount
= 0;
318 /* For quite high speeds, convert to the smaller
319 units to avoid overflow. */
321 speed
= - speed
/ 100;
324 speed
= tputs_baud_rate
;
325 else if (ospeed
> 0 && ospeed
< (sizeof speeds
/ sizeof speeds
[0]))
326 speed
= speeds
[ospeed
];
334 while (*str
>= '0' && *str
<= '9')
336 padcount
+= *str
++ - '0';
342 padcount
+= *str
++ - '0';
352 /* PADCOUNT is now in units of tenths of msec.
353 SPEED is measured in characters per 10 seconds
354 or in characters per .1 seconds (if negative).
355 We use the smaller units for larger speeds to avoid overflow. */
360 padcount
= -padcount
;
367 while (padcount
-- > 0)
371 /* Finding the termcap entry in the termcap data base. */
373 struct termcap_buffer
382 /* Forward declarations of static functions. */
384 static int scan_file ();
385 static char *gobble_line ();
386 static int compare_contin ();
387 static int name_match ();
396 valid_filename_p (fn
)
399 struct FAB fab
= cc$rms_fab
;
400 struct NAM nam
= cc$rms_nam
;
401 char esa
[NAM$C_MAXRSS
];
404 fab
.fab$b_fns
= strlen(fn
);
405 fab
.fab$l_nam
= &nam
;
406 fab
.fab$l_fop
= FAB$M_NAM
;
409 nam
.nam$b_ess
= sizeof esa
;
411 return SYS$
PARSE(&fab
, 0, 0) == RMS$_NORMAL
;
416 #ifdef MSDOS /* MW, May 1993 */
418 valid_filename_p (fn
)
421 return *fn
== '/' || fn
[1] == ':';
424 #define valid_filename_p(fn) (*(fn) == '/')
429 /* Find the termcap entry data for terminal type NAME
430 and store it in the block that BP points to.
431 Record its address for future use.
433 If BP is null, space is dynamically allocated.
435 Return -1 if there is some difficulty accessing the data base
437 0 if the data base is accessible but the type NAME is not defined
438 in it, and some other value otherwise. */
444 register char *termcap_name
;
446 struct termcap_buffer buf
;
448 char *tc_search_point
;
452 char *tcenv
; /* TERMCAP value, if it contains :tc=. */
453 char *indirect
= NULL
; /* Terminal type in :tc= in TERMCAP value. */
456 #ifdef INTERNAL_TERMINAL
457 /* For the internal terminal we don't want to read any termcap file,
459 if (!strcmp (name
, "internal"))
461 term
= INTERNAL_TERMINAL
;
464 malloc_size
= 1 + strlen (term
);
465 bp
= (char *) xmalloc (malloc_size
);
470 #endif /* INTERNAL_TERMINAL */
472 /* For compatibility with programs like `less' that want to
473 put data in the termcap buffer themselves as a fallback. */
477 termcap_name
= getenv ("TERMCAP");
478 if (termcap_name
&& *termcap_name
== '\0')
480 #if defined (MSDOS) && !defined (TEST)
481 if (termcap_name
&& (*termcap_name
== '\\'
482 || *termcap_name
== '/'
483 || termcap_name
[1] == ':'))
484 dostounix_filename(termcap_name
);
487 filep
= termcap_name
&& valid_filename_p (termcap_name
);
489 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
490 it is a file name to use instead of /etc/termcap.
491 If it is non-null and does not start with /,
492 it is the entry itself, but only if
493 the name the caller requested matches the TERM variable. */
495 if (termcap_name
&& !filep
&& !strcmp (name
, getenv ("TERM")))
497 indirect
= tgetst1 (find_capability (termcap_name
, "tc"), (char **) 0);
503 strcpy (bp
, termcap_name
);
507 { /* It has tc=. Need to read /etc/termcap. */
508 tcenv
= termcap_name
;
513 if (!termcap_name
|| !filep
)
514 termcap_name
= TERMCAP_FILE
;
516 /* Here we know we must search a file and termcap_name has its name. */
519 fd
= open (termcap_name
, O_RDONLY
|O_TEXT
, 0);
521 fd
= open (termcap_name
, O_RDONLY
, 0);
527 /* Add 1 to size to ensure room for terminating null. */
528 buf
.beg
= (char *) xmalloc (buf
.size
+ 1);
529 term
= indirect
? indirect
: name
;
533 malloc_size
= indirect
? strlen (tcenv
) + 1 : buf
.size
;
534 bp
= (char *) xmalloc (malloc_size
);
536 tc_search_point
= bp1
= bp
;
539 /* Copy the data from the environment variable. */
542 bp1
+= strlen (tcenv
);
547 /* Scan the file, reading it via buf, till find start of main entry. */
548 if (scan_file (term
, fd
, &buf
) == 0)
557 /* Free old `term' if appropriate. */
561 /* If BP is malloc'd by us, make sure it is big enough. */
564 malloc_size
= bp1
- bp
+ buf
.size
;
565 termcap_name
= (char *) xrealloc (bp
, malloc_size
);
566 bp1
+= termcap_name
- bp
;
567 tc_search_point
+= termcap_name
- bp
;
571 /* Copy the line of the entry from buf into bp. */
572 termcap_name
= buf
.ptr
;
573 while ((*bp1
++ = c
= *termcap_name
++) && c
!= '\n')
574 /* Drop out any \ newline sequence. */
575 if (c
== '\\' && *termcap_name
== '\n')
582 /* Does this entry refer to another terminal type's entry?
583 If something is found, copy it into heap and null-terminate it. */
584 tc_search_point
= find_capability (tc_search_point
, "tc");
585 term
= tgetst1 (tc_search_point
, (char **) 0);
592 bp
= (char *) xrealloc (bp
, bp1
- bp
+ 1);
599 /* Given file open on FD and buffer BUFP,
600 scan the file from the beginning until a line is found
601 that starts the entry for terminal type STR.
602 Return 1 if successful, with that line in BUFP,
603 or 0 if no entry is found in the file. */
606 scan_file (str
, fd
, bufp
)
609 register struct termcap_buffer
*bufp
;
613 bufp
->ptr
= bufp
->beg
;
622 /* Read a line into the buffer. */
626 /* if it is continued, append another line to it,
627 until a non-continued line ends. */
628 end
= gobble_line (fd
, bufp
, end
);
630 while (!bufp
->ateof
&& end
[-2] == '\\');
632 if (*bufp
->ptr
!= '#'
633 && name_match (bufp
->ptr
, str
))
636 /* Discard the line just processed. */
642 /* Return nonzero if NAME is one of the names specified
643 by termcap entry LINE. */
646 name_match (line
, name
)
651 if (!compare_contin (line
, name
))
653 /* This line starts an entry. Is it the right one? */
654 for (tem
= line
; *tem
&& *tem
!= '\n' && *tem
!= ':'; tem
++)
655 if (*tem
== '|' && !compare_contin (tem
+ 1, name
))
662 compare_contin (str1
, str2
)
663 register char *str1
, *str2
;
670 while (c1
== '\\' && *str1
== '\n')
673 while ((c1
= *str1
++) == ' ' || c1
== '\t');
677 /* End of type being looked up. */
678 if (c1
== '|' || c1
== ':')
679 /* If end of name in data base, we win. */
689 /* Make sure that the buffer <- BUFP contains a full line
690 of the file open on FD, starting at the place BUFP->ptr
691 points to. Can read more of the file, discard stuff before
692 BUFP->ptr, or make the buffer bigger.
694 Return the pointer to after the newline ending the line,
695 or to the end of the file, if there is no newline to end it.
697 Can also merge on continuation lines. If APPEND_END is
698 non-null, it points past the newline of a line that is
699 continued; we add another line onto it and regard the whole
700 thing as one line. The caller decides when a line is continued. */
703 gobble_line (fd
, bufp
, append_end
)
705 register struct termcap_buffer
*bufp
;
710 register char *buf
= bufp
->beg
;
714 append_end
= bufp
->ptr
;
719 while (*end
&& *end
!= '\n') end
++;
723 return buf
+ bufp
->full
;
724 if (bufp
->ptr
== buf
)
726 if (bufp
->full
== bufp
->size
)
729 /* Add 1 to size to ensure room for terminating null. */
730 tem
= (char *) xrealloc (buf
, bufp
->size
+ 1);
731 bufp
->ptr
= (bufp
->ptr
- buf
) + tem
;
732 append_end
= (append_end
- buf
) + tem
;
733 bufp
->beg
= buf
= tem
;
738 append_end
-= bufp
->ptr
- buf
;
739 bcopy (bufp
->ptr
, buf
, bufp
->full
-= bufp
->ptr
- buf
);
742 if (!(nread
= read (fd
, buf
+ bufp
->full
, bufp
->size
- bufp
->full
)))
745 buf
[bufp
->full
] = '\0';
766 printf ("TERM: %s\n", term
);
768 buf
= (char *) tgetent (0, term
);
771 printf ("No entry.\n");
775 printf ("Entry: %s\n", buf
);
780 printf ("co: %d\n", tgetnum ("co"));
781 printf ("am: %d\n", tgetflag ("am"));
787 char *x
= tgetstr (cap
, 0);
790 printf ("%s: ", cap
);
794 if (*y
<= ' ' || *y
== 0177)
795 printf ("\\%0o", *y
);