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 #include <lisp.h> /* xmalloc is here */
27 /* Get the O_* definitions for open et al. */
47 /* Do this after the include, in case string.h prototypes bcopy. */
48 #if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy)
49 #define bcopy(s, d, n) memcpy ((d), (s), (n))
59 #endif /* not emacs */
62 #define NULL (char *) 0
69 /* BUFSIZE is the initial size allocated for the buffer
70 for reading the termcap file.
72 Make it large normally for speed.
73 Make it variable when debugging, so can exercise
74 increasing the space dynamically. */
78 #define BUFSIZE bufsize
87 #define TERMCAP_FILE "/etc/termcap"
94 write (2, "virtual memory exhausted\n", 25);
102 register char *tem
= malloc (size
);
114 register char *tem
= realloc (ptr
, size
);
120 #endif /* not emacs */
122 /* Looking up capabilities in the entry already found. */
124 /* The pointer to the data made by tgetent is left here
125 for tgetnum, tgetflag and tgetstr to find. */
126 static char *term_entry
;
128 static char *tgetst1 ();
130 /* Search entry BP for capability CAP.
131 Return a pointer to the capability (in BP) if found,
135 find_capability (bp
, cap
)
136 register char *bp
, *cap
;
150 register char *ptr
= find_capability (term_entry
, cap
);
151 if (!ptr
|| ptr
[-1] != '#')
160 register char *ptr
= find_capability (term_entry
, cap
);
161 return ptr
&& ptr
[-1] == ':';
164 /* Look up a string-valued capability CAP.
165 If AREA is non-null, it points to a pointer to a block in which
166 to store the string. That pointer is advanced over the space used.
167 If AREA is null, space is allocated with `malloc'. */
174 register char *ptr
= find_capability (term_entry
, cap
);
175 if (!ptr
|| (ptr
[-1] != '=' && ptr
[-1] != '~'))
177 return tgetst1 (ptr
, area
);
180 #ifdef IS_EBCDIC_HOST
181 /* Table, indexed by a character in range 0200 to 0300 with 0200 subtracted,
182 gives meaning of character following \, or a space if no special meaning.
183 Sixteen characters per line within the string. */
186 = " \057\026 \047\014 \
191 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
192 gives meaning of character following \, or a space if no special meaning.
193 Eight characters per line within the string. */
196 = " \007\010 \033\014 \
202 /* PTR points to a string value inside a termcap entry.
203 Copy that value, processing \ and ^ abbreviations,
204 into the block that *AREA points to,
205 or to newly allocated storage if AREA is NULL.
206 Return the address to which we copied the value,
207 or NULL if PTR is NULL. */
214 register char *p
, *r
;
223 /* `ret' gets address of where to store the string. */
226 /* Compute size of block needed (may overestimate). */
228 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
230 ret
= (char *) xmalloc (p
- ptr
+ 1);
235 /* Copy the string value, stopping at null or colon.
236 Also process ^ and \ abbreviations. */
239 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
252 if (c
>= '0' && c
<= '7')
257 while (++size
< 3 && (c1
= *p
) >= '0' && c1
<= '7')
264 #ifdef IS_EBCDIC_HOST
265 else if (c
>= 0200 && c
< 0360)
267 c1
= esctab
[(c
& ~0100) - 0200];
272 else if (c
>= 0100 && c
< 0200)
274 c1
= esctab
[(c
& ~040) - 0100];
289 /* Outputting a string with padding. */
292 /* If OSPEED is 0, we use this as the actual baud rate. */
296 /* Actual baud rate if positive;
297 - baud rate / 100 if negative. */
299 static int speeds
[] =
302 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
303 -20, -24, -36, -48, -72, -96, -192
305 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
306 -18, -24, -48, -96, -192, -288, -384, -576, -1152
311 tputs (str
, nlines
, outfun
)
314 register int (*outfun
) ();
316 register int padcount
= 0;
320 extern int baud_rate
;
322 /* For quite high speeds, convert to the smaller
323 units to avoid overflow. */
325 speed
= - speed
/ 100;
328 speed
= tputs_baud_rate
;
329 else if (ospeed
> 0 && ospeed
< (sizeof speeds
/ sizeof speeds
[0]))
330 speed
= speeds
[ospeed
];
338 while (*str
>= '0' && *str
<= '9')
340 padcount
+= *str
++ - '0';
346 padcount
+= *str
++ - '0';
356 /* PADCOUNT is now in units of tenths of msec.
357 SPEED is measured in characters per 10 seconds
358 or in characters per .1 seconds (if negative).
359 We use the smaller units for larger speeds to avoid overflow. */
364 padcount
= -padcount
;
371 while (padcount
-- > 0)
375 /* Finding the termcap entry in the termcap data base. */
377 struct termcap_buffer
386 /* Forward declarations of static functions. */
388 static int scan_file ();
389 static char *gobble_line ();
390 static int compare_contin ();
391 static int name_match ();
400 valid_filename_p (fn
)
403 struct FAB fab
= cc$rms_fab
;
404 struct NAM nam
= cc$rms_nam
;
405 char esa
[NAM$C_MAXRSS
];
408 fab
.fab$b_fns
= strlen(fn
);
409 fab
.fab$l_nam
= &nam
;
410 fab
.fab$l_fop
= FAB$M_NAM
;
413 nam
.nam$b_ess
= sizeof esa
;
415 return SYS$
PARSE(&fab
, 0, 0) == RMS$_NORMAL
;
420 #ifdef MSDOS /* MW, May 1993 */
422 valid_filename_p (fn
)
425 return *fn
== '/' || 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. */
448 register char *termcap_name
;
450 struct termcap_buffer buf
;
452 char *tc_search_point
;
456 char *tcenv
; /* TERMCAP value, if it contains :tc=. */
457 char *indirect
= NULL
; /* Terminal type in :tc= in TERMCAP value. */
460 #ifdef INTERNAL_TERMINAL
461 /* For the internal terminal we don't want to read any termcap file,
463 if (!strcmp (name
, "internal"))
465 term
= INTERNAL_TERMINAL
;
468 malloc_size
= 1 + strlen (term
);
469 bp
= (char *) xmalloc (malloc_size
);
474 #endif /* INTERNAL_TERMINAL */
476 /* For compatibility with programs like `less' that want to
477 put data in the termcap buffer themselves as a fallback. */
481 termcap_name
= getenv ("TERMCAP");
482 if (termcap_name
&& *termcap_name
== '\0')
484 #if defined (MSDOS) && !defined (TEST)
485 if (termcap_name
&& (*termcap_name
== '\\'
486 || *termcap_name
== '/'
487 || termcap_name
[1] == ':'))
488 dostounix_filename(termcap_name
);
491 filep
= termcap_name
&& valid_filename_p (termcap_name
);
493 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
494 it is a file name to use instead of /etc/termcap.
495 If it is non-null and does not start with /,
496 it is the entry itself, but only if
497 the name the caller requested matches the TERM variable. */
499 if (termcap_name
&& !filep
&& !strcmp (name
, getenv ("TERM")))
501 indirect
= tgetst1 (find_capability (termcap_name
, "tc"), (char **) 0);
507 strcpy (bp
, termcap_name
);
511 { /* It has tc=. Need to read /etc/termcap. */
512 tcenv
= termcap_name
;
517 if (!termcap_name
|| !filep
)
518 termcap_name
= TERMCAP_FILE
;
520 /* Here we know we must search a file and termcap_name has its name. */
523 fd
= open (termcap_name
, O_RDONLY
|O_TEXT
, 0);
525 fd
= open (termcap_name
, O_RDONLY
, 0);
531 /* Add 1 to size to ensure room for terminating null. */
532 buf
.beg
= (char *) xmalloc (buf
.size
+ 1);
533 term
= indirect
? indirect
: name
;
537 malloc_size
= indirect
? strlen (tcenv
) + 1 : buf
.size
;
538 bp
= (char *) xmalloc (malloc_size
);
540 tc_search_point
= bp1
= bp
;
543 /* Copy the data from the environment variable. */
546 bp1
+= strlen (tcenv
);
551 /* Scan the file, reading it via buf, till find start of main entry. */
552 if (scan_file (term
, fd
, &buf
) == 0)
561 /* Free old `term' if appropriate. */
565 /* If BP is malloc'd by us, make sure it is big enough. */
568 malloc_size
= bp1
- bp
+ buf
.size
;
569 termcap_name
= (char *) xrealloc (bp
, malloc_size
);
570 bp1
+= termcap_name
- bp
;
571 tc_search_point
+= termcap_name
- bp
;
575 /* Copy the line of the entry from buf into bp. */
576 termcap_name
= buf
.ptr
;
577 while ((*bp1
++ = c
= *termcap_name
++) && c
!= '\n')
578 /* Drop out any \ newline sequence. */
579 if (c
== '\\' && *termcap_name
== '\n')
586 /* Does this entry refer to another terminal type's entry?
587 If something is found, copy it into heap and null-terminate it. */
588 tc_search_point
= find_capability (tc_search_point
, "tc");
589 term
= tgetst1 (tc_search_point
, (char **) 0);
596 bp
= (char *) xrealloc (bp
, bp1
- bp
+ 1);
603 /* Given file open on FD and buffer BUFP,
604 scan the file from the beginning until a line is found
605 that starts the entry for terminal type STR.
606 Return 1 if successful, with that line in BUFP,
607 or 0 if no entry is found in the file. */
610 scan_file (str
, fd
, bufp
)
613 register struct termcap_buffer
*bufp
;
617 bufp
->ptr
= bufp
->beg
;
626 /* Read a line into the buffer. */
630 /* if it is continued, append another line to it,
631 until a non-continued line ends. */
632 end
= gobble_line (fd
, bufp
, end
);
634 while (!bufp
->ateof
&& end
[-2] == '\\');
636 if (*bufp
->ptr
!= '#'
637 && name_match (bufp
->ptr
, str
))
640 /* Discard the line just processed. */
646 /* Return nonzero if NAME is one of the names specified
647 by termcap entry LINE. */
650 name_match (line
, name
)
655 if (!compare_contin (line
, name
))
657 /* This line starts an entry. Is it the right one? */
658 for (tem
= line
; *tem
&& *tem
!= '\n' && *tem
!= ':'; tem
++)
659 if (*tem
== '|' && !compare_contin (tem
+ 1, name
))
666 compare_contin (str1
, str2
)
667 register char *str1
, *str2
;
674 while (c1
== '\\' && *str1
== '\n')
677 while ((c1
= *str1
++) == ' ' || c1
== '\t');
681 /* End of type being looked up. */
682 if (c1
== '|' || c1
== ':')
683 /* If end of name in data base, we win. */
693 /* Make sure that the buffer <- BUFP contains a full line
694 of the file open on FD, starting at the place BUFP->ptr
695 points to. Can read more of the file, discard stuff before
696 BUFP->ptr, or make the buffer bigger.
698 Return the pointer to after the newline ending the line,
699 or to the end of the file, if there is no newline to end it.
701 Can also merge on continuation lines. If APPEND_END is
702 non-null, it points past the newline of a line that is
703 continued; we add another line onto it and regard the whole
704 thing as one line. The caller decides when a line is continued. */
707 gobble_line (fd
, bufp
, append_end
)
709 register struct termcap_buffer
*bufp
;
714 register char *buf
= bufp
->beg
;
718 append_end
= bufp
->ptr
;
723 while (*end
&& *end
!= '\n') end
++;
727 return buf
+ bufp
->full
;
728 if (bufp
->ptr
== buf
)
730 if (bufp
->full
== bufp
->size
)
733 /* Add 1 to size to ensure room for terminating null. */
734 tem
= (char *) xrealloc (buf
, bufp
->size
+ 1);
735 bufp
->ptr
= (bufp
->ptr
- buf
) + tem
;
736 append_end
= (append_end
- buf
) + tem
;
737 bufp
->beg
= buf
= tem
;
742 append_end
-= bufp
->ptr
- buf
;
743 bcopy (bufp
->ptr
, buf
, bufp
->full
-= bufp
->ptr
- buf
);
746 if (!(nread
= read (fd
, buf
+ bufp
->full
, bufp
->size
- bufp
->full
)))
749 buf
[bufp
->full
] = '\0';
770 printf ("TERM: %s\n", term
);
772 buf
= (char *) tgetent (0, term
);
775 printf ("No entry.\n");
779 printf ("Entry: %s\n", buf
);
784 printf ("co: %d\n", tgetnum ("co"));
785 printf ("am: %d\n", tgetflag ("am"));
791 char *x
= tgetstr (cap
, 0);
794 printf ("%s: ", cap
);
798 if (*y
<= ' ' || *y
== 0177)
799 printf ("\\%0o", *y
);