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 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
177 gives meaning of character following \, or a space if no special meaning.
178 Eight characters per line within the string. */
181 = " \007\010 \033\014 \
186 /* PTR points to a string value inside a termcap entry.
187 Copy that value, processing \ and ^ abbreviations,
188 into the block that *AREA points to,
189 or to newly allocated storage if AREA is NULL.
190 Return the address to which we copied the value,
191 or NULL if PTR is NULL. */
198 register char *p
, *r
;
207 /* `ret' gets address of where to store the string. */
210 /* Compute size of block needed (may overestimate). */
212 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
214 ret
= (char *) xmalloc (p
- ptr
+ 1);
219 /* Copy the string value, stopping at null or colon.
220 Also process ^ and \ abbreviations. */
223 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
236 if (c
>= '0' && c
<= '7')
241 while (++size
< 3 && (c1
= *p
) >= '0' && c1
<= '7')
248 else if (c
>= 0100 && c
< 0200)
250 c1
= esctab
[(c
& ~040) - 0100];
264 /* Outputting a string with padding. */
267 /* If OSPEED is 0, we use this as the actual baud rate. */
271 /* Actual baud rate if positive;
272 - baud rate / 100 if negative. */
274 static int speeds
[] =
277 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
278 -20, -24, -36, -48, -72, -96, -192
280 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
281 -18, -24, -48, -96, -192, -288, -384, -576, -1152
286 tputs (str
, nlines
, outfun
)
289 register int (*outfun
) ();
291 register int padcount
= 0;
297 /* For quite high speeds, convert to the smaller
298 units to avoid overflow. */
300 speed
= - speed
/ 100;
303 speed
= tputs_baud_rate
;
304 else if (ospeed
> 0 && ospeed
< (sizeof speeds
/ sizeof speeds
[0]))
305 speed
= speeds
[ospeed
];
313 while (*str
>= '0' && *str
<= '9')
315 padcount
+= *str
++ - '0';
321 padcount
+= *str
++ - '0';
331 /* PADCOUNT is now in units of tenths of msec.
332 SPEED is measured in characters per 10 seconds
333 or in characters per .1 seconds (if negative).
334 We use the smaller units for larger speeds to avoid overflow. */
339 padcount
= -padcount
;
346 while (padcount
-- > 0)
350 /* Finding the termcap entry in the termcap data base. */
361 /* Forward declarations of static functions. */
363 static int scan_file ();
364 static char *gobble_line ();
365 static int compare_contin ();
366 static int name_match ();
375 valid_filename_p (fn
)
378 struct FAB fab
= cc$rms_fab
;
379 struct NAM nam
= cc$rms_nam
;
380 char esa
[NAM$C_MAXRSS
];
383 fab
.fab$b_fns
= strlen(fn
);
384 fab
.fab$l_nam
= &nam
;
385 fab
.fab$l_fop
= FAB$M_NAM
;
388 nam
.nam$b_ess
= sizeof esa
;
390 return SYS$
PARSE(&fab
, 0, 0) == RMS$_NORMAL
;
395 #ifdef MSDOS /* MW, May 1993 */
397 valid_filename_p (fn
)
400 return *fn
== '/' || fn
[1] == ':';
403 #define valid_filename_p(fn) (*(fn) == '/')
408 /* Find the termcap entry data for terminal type NAME
409 and store it in the block that BP points to.
410 Record its address for future use.
412 If BP is null, space is dynamically allocated.
414 Return -1 if there is some difficulty accessing the data base
416 0 if the data base is accessible but the type NAME is not defined
417 in it, and some other value otherwise. */
423 register char *termcap_name
;
427 char *tc_search_point
;
431 char *tcenv
; /* TERMCAP value, if it contains :tc=. */
432 char *indirect
= NULL
; /* Terminal type in :tc= in TERMCAP value. */
435 #ifdef INTERNAL_TERMINAL
436 /* For the internal terminal we don't want to read any termcap file,
438 if (!strcmp (name
, "internal"))
440 term
= INTERNAL_TERMINAL
;
443 malloc_size
= 1 + strlen (term
);
444 bp
= (char *) xmalloc (malloc_size
);
449 #endif /* INTERNAL_TERMINAL */
451 /* For compatibility with programs like `less' that want to
452 put data in the termcap buffer themselves as a fallback. */
456 termcap_name
= getenv ("TERMCAP");
457 if (termcap_name
&& *termcap_name
== '\0')
459 #if defined (MSDOS) && !defined (TEST)
460 if (termcap_name
&& (*termcap_name
== '\\'
461 || *termcap_name
== '/'
462 || termcap_name
[1] == ':'))
463 dostounix_filename(termcap_name
);
466 filep
= termcap_name
&& valid_filename_p (termcap_name
);
468 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
469 it is a file name to use instead of /etc/termcap.
470 If it is non-null and does not start with /,
471 it is the entry itself, but only if
472 the name the caller requested matches the TERM variable. */
474 if (termcap_name
&& !filep
&& !strcmp (name
, getenv ("TERM")))
476 indirect
= tgetst1 (find_capability (termcap_name
, "tc"), (char **) 0);
482 strcpy (bp
, termcap_name
);
486 { /* It has tc=. Need to read /etc/termcap. */
487 tcenv
= termcap_name
;
492 if (!termcap_name
|| !filep
)
493 termcap_name
= TERMCAP_FILE
;
495 /* Here we know we must search a file and termcap_name has its name. */
498 fd
= open (termcap_name
, O_RDONLY
|O_TEXT
, 0);
500 fd
= open (termcap_name
, O_RDONLY
, 0);
506 /* Add 1 to size to ensure room for terminating null. */
507 buf
.beg
= (char *) xmalloc (buf
.size
+ 1);
508 term
= indirect
? indirect
: name
;
512 malloc_size
= indirect
? strlen (tcenv
) + 1 : buf
.size
;
513 bp
= (char *) xmalloc (malloc_size
);
515 tc_search_point
= bp1
= bp
;
518 /* Copy the data from the environment variable. */
521 bp1
+= strlen (tcenv
);
526 /* Scan the file, reading it via buf, till find start of main entry. */
527 if (scan_file (term
, fd
, &buf
) == 0)
536 /* Free old `term' if appropriate. */
540 /* If BP is malloc'd by us, make sure it is big enough. */
543 malloc_size
= bp1
- bp
+ buf
.size
;
544 termcap_name
= (char *) xrealloc (bp
, malloc_size
);
545 bp1
+= termcap_name
- bp
;
546 tc_search_point
+= termcap_name
- bp
;
550 /* Copy the line of the entry from buf into bp. */
551 termcap_name
= buf
.ptr
;
552 while ((*bp1
++ = c
= *termcap_name
++) && c
!= '\n')
553 /* Drop out any \ newline sequence. */
554 if (c
== '\\' && *termcap_name
== '\n')
561 /* Does this entry refer to another terminal type's entry?
562 If something is found, copy it into heap and null-terminate it. */
563 tc_search_point
= find_capability (tc_search_point
, "tc");
564 term
= tgetst1 (tc_search_point
, (char **) 0);
571 bp
= (char *) xrealloc (bp
, bp1
- bp
+ 1);
578 /* Given file open on FD and buffer BUFP,
579 scan the file from the beginning until a line is found
580 that starts the entry for terminal type STR.
581 Return 1 if successful, with that line in BUFP,
582 or 0 if no entry is found in the file. */
585 scan_file (str
, fd
, bufp
)
588 register struct buffer
*bufp
;
592 bufp
->ptr
= bufp
->beg
;
601 /* Read a line into the buffer. */
605 /* if it is continued, append another line to it,
606 until a non-continued line ends. */
607 end
= gobble_line (fd
, bufp
, end
);
609 while (!bufp
->ateof
&& end
[-2] == '\\');
611 if (*bufp
->ptr
!= '#'
612 && name_match (bufp
->ptr
, str
))
615 /* Discard the line just processed. */
621 /* Return nonzero if NAME is one of the names specified
622 by termcap entry LINE. */
625 name_match (line
, name
)
630 if (!compare_contin (line
, name
))
632 /* This line starts an entry. Is it the right one? */
633 for (tem
= line
; *tem
&& *tem
!= '\n' && *tem
!= ':'; tem
++)
634 if (*tem
== '|' && !compare_contin (tem
+ 1, name
))
641 compare_contin (str1
, str2
)
642 register char *str1
, *str2
;
649 while (c1
== '\\' && *str1
== '\n')
652 while ((c1
= *str1
++) == ' ' || c1
== '\t');
656 /* End of type being looked up. */
657 if (c1
== '|' || c1
== ':')
658 /* If end of name in data base, we win. */
668 /* Make sure that the buffer <- BUFP contains a full line
669 of the file open on FD, starting at the place BUFP->ptr
670 points to. Can read more of the file, discard stuff before
671 BUFP->ptr, or make the buffer bigger.
673 Return the pointer to after the newline ending the line,
674 or to the end of the file, if there is no newline to end it.
676 Can also merge on continuation lines. If APPEND_END is
677 non-null, it points past the newline of a line that is
678 continued; we add another line onto it and regard the whole
679 thing as one line. The caller decides when a line is continued. */
682 gobble_line (fd
, bufp
, append_end
)
684 register struct buffer
*bufp
;
689 register char *buf
= bufp
->beg
;
693 append_end
= bufp
->ptr
;
698 while (*end
&& *end
!= '\n') end
++;
702 return buf
+ bufp
->full
;
703 if (bufp
->ptr
== buf
)
705 if (bufp
->full
== bufp
->size
)
708 /* Add 1 to size to ensure room for terminating null. */
709 tem
= (char *) xrealloc (buf
, bufp
->size
+ 1);
710 bufp
->ptr
= (bufp
->ptr
- buf
) + tem
;
711 append_end
= (append_end
- buf
) + tem
;
712 bufp
->beg
= buf
= tem
;
717 append_end
-= bufp
->ptr
- buf
;
718 bcopy (bufp
->ptr
, buf
, bufp
->full
-= bufp
->ptr
- buf
);
721 if (!(nread
= read (fd
, buf
+ bufp
->full
, bufp
->size
- bufp
->full
)))
724 buf
[bufp
->full
] = '\0';
745 printf ("TERM: %s\n", term
);
747 buf
= (char *) tgetent (0, term
);
750 printf ("No entry.\n");
754 printf ("Entry: %s\n", buf
);
759 printf ("co: %d\n", tgetnum ("co"));
760 printf ("am: %d\n", tgetflag ("am"));
766 char *x
= tgetstr (cap
, 0);
769 printf ("%s: ", cap
);
773 if (*y
<= ' ' || *y
== 0177)
774 printf ("\\%0o", *y
);