1 /* Work-alike for termcap, plus extra features.
2 Copyright (C) 1985, 1986, 1993, 1994 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. */
23 /* Get the O_* definitions for open et al. */
29 #else /* not HAVE_CONFIG_H */
31 #if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
32 #define bcopy(s, d, n) memcpy ((d), (s), (n))
51 #endif /* not HAVE_CONFIG_H */
54 #define NULL (char *) 0
61 /* BUFSIZE is the initial size allocated for the buffer
62 for reading the termcap file.
64 Make it large normally for speed.
65 Make it variable when debugging, so can exercise
66 increasing the space dynamically. */
70 #define BUFSIZE bufsize
79 #define TERMCAP_NAME "/etc/termcap"
86 write (2, "virtual memory exhausted\n", 25);
94 register char *tem
= malloc (size
);
106 register char *tem
= realloc (ptr
, size
);
112 #endif /* not emacs */
114 /* Looking up capabilities in the entry already found. */
116 /* The pointer to the data made by tgetent is left here
117 for tgetnum, tgetflag and tgetstr to find. */
118 static char *term_entry
;
120 static char *tgetst1 ();
122 /* Search entry BP for capability CAP.
123 Return a pointer to the capability (in BP) if found,
127 find_capability (bp
, cap
)
128 register char *bp
, *cap
;
142 register char *ptr
= find_capability (term_entry
, cap
);
143 if (!ptr
|| ptr
[-1] != '#')
152 register char *ptr
= find_capability (term_entry
, cap
);
153 return ptr
&& ptr
[-1] == ':';
156 /* Look up a string-valued capability CAP.
157 If AREA is non-null, it points to a pointer to a block in which
158 to store the string. That pointer is advanced over the space used.
159 If AREA is null, space is allocated with `malloc'. */
166 register char *ptr
= find_capability (term_entry
, cap
);
167 if (!ptr
|| (ptr
[-1] != '=' && ptr
[-1] != '~'))
169 return tgetst1 (ptr
, area
);
172 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
173 gives meaning of character following \, or a space if no special meaning.
174 Eight characters per line within the string. */
177 = " \007\010 \033\014 \
182 /* PTR points to a string value inside a termcap entry.
183 Copy that value, processing \ and ^ abbreviations,
184 into the block that *AREA points to,
185 or to newly allocated storage if AREA is NULL.
186 Return the address to which we copied the value,
187 or NULL if PTR is NULL. */
194 register char *p
, *r
;
203 /* `ret' gets address of where to store the string. */
206 /* Compute size of block needed (may overestimate). */
208 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
210 ret
= (char *) xmalloc (p
- ptr
+ 1);
215 /* Copy the string value, stopping at null or colon.
216 Also process ^ and \ abbreviations. */
219 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
232 if (c
>= '0' && c
<= '7')
237 while (++size
< 3 && (c1
= *p
) >= '0' && c1
<= '7')
244 else if (c
>= 0100 && c
< 0200)
246 c1
= esctab
[(c
& ~040) - 0100];
260 /* Outputting a string with padding. */
263 /* If OSPEED is 0, we use this as the actual baud rate. */
267 /* Actual baud rate if positive;
268 - baud rate / 100 if negative. */
270 static int speeds
[] =
273 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
274 -20, -24, -36, -48, -72, -96, -192
276 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
277 -18, -24, -48, -96, -192, -288, -384, -576, -1152
282 tputs (str
, nlines
, outfun
)
285 register int (*outfun
) ();
287 register int padcount
= 0;
293 /* For quite high speeds, convert to the smaller
294 units to avoid overflow. */
296 speed
= - speed
/ 100;
299 speed
= tputs_baud_rate
;
301 speed
= speeds
[ospeed
];
307 while (*str
>= '0' && *str
<= '9')
309 padcount
+= *str
++ - '0';
315 padcount
+= *str
++ - '0';
325 /* PADCOUNT is now in units of tenths of msec.
326 SPEED is measured in characters per 10 seconds
327 or in characters per .1 seconds (if negative).
328 We use the smaller units for larger speeds to avoid overflow. */
333 padcount
= -padcount
;
340 while (padcount
-- > 0)
344 /* Finding the termcap entry in the termcap data base. */
355 /* Forward declarations of static functions. */
357 static int scan_file ();
358 static char *gobble_line ();
359 static int compare_contin ();
360 static int name_match ();
369 valid_filename_p (fn
)
372 struct FAB fab
= cc$rms_fab
;
373 struct NAM nam
= cc$rms_nam
;
374 char esa
[NAM$C_MAXRSS
];
377 fab
.fab$b_fns
= strlen(fn
);
378 fab
.fab$l_nam
= &nam
;
379 fab
.fab$l_fop
= FAB$M_NAM
;
382 nam
.nam$b_ess
= sizeof esa
;
384 return SYS$
PARSE(&fab
, 0, 0) == RMS$_NORMAL
;
389 #ifdef MSDOS /* MW, May 1993 */
391 valid_filename_p (fn
)
394 return *fn
== '/' || fn
[1] == ':';
397 #define valid_filename_p(fn) (*(fn) == '/')
402 /* Find the termcap entry data for terminal type NAME
403 and store it in the block that BP points to.
404 Record its address for future use.
406 If BP is null, space is dynamically allocated.
408 Return -1 if there is some difficulty accessing the data base
410 0 if the data base is accessible but the type NAME is not defined
411 in it, and some other value otherwise. */
417 register char *termcap_name
;
425 char *tcenv
; /* TERMCAP value, if it contains :tc=. */
426 char *indirect
= NULL
; /* Terminal type in :tc= in TERMCAP value. */
429 #ifdef INTERNAL_TERMINAL
430 /* For the internal terminal we don't want to read any termcap file,
432 if (!strcmp (name
, "internal"))
434 term
= INTERNAL_TERMINAL
;
437 malloc_size
= 1 + strlen (term
);
438 bp
= (char *) xmalloc (malloc_size
);
443 #endif /* INTERNAL_TERMINAL */
445 termcap_name
= getenv ("TERMCAP");
446 if (termcap_name
&& *termcap_name
== '\0')
448 #if defined (MSDOS) && !defined (TEST)
449 if (termcap_name
&& (*termcap_name
== '\\'
450 || *termcap_name
== '/'
451 || termcap_name
[1] == ':'))
452 dostounix_filename(termcap_name
);
455 filep
= termcap_name
&& valid_filename_p (termcap_name
);
457 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
458 it is a file name to use instead of /etc/termcap.
459 If it is non-null and does not start with /,
460 it is the entry itself, but only if
461 the name the caller requested matches the TERM variable. */
463 if (termcap_name
&& !filep
&& !strcmp (name
, getenv ("TERM")))
465 indirect
= tgetst1 (find_capability (termcap_name
, "tc"), (char **) 0);
471 strcpy (bp
, termcap_name
);
475 { /* It has tc=. Need to read /etc/termcap. */
476 tcenv
= termcap_name
;
481 if (!termcap_name
|| !filep
)
482 termcap_name
= TERMCAP_NAME
;
484 /* Here we know we must search a file and termcap_name has its name. */
487 fd
= open (termcap_name
, O_RDONLY
|O_TEXT
, 0);
489 fd
= open (termcap_name
, O_RDONLY
, 0);
495 /* Add 1 to size to ensure room for terminating null. */
496 buf
.beg
= (char *) xmalloc (buf
.size
+ 1);
497 term
= indirect
? indirect
: name
;
501 malloc_size
= indirect
? strlen (tcenv
) + 1 : buf
.size
;
502 bp
= (char *) xmalloc (malloc_size
);
507 /* Copy the data from the environment variable. */
510 bp1
+= strlen (tcenv
);
515 /* Scan the file, reading it via buf, till find start of main entry. */
516 if (scan_file (term
, fd
, &buf
) == 0)
525 /* Free old `term' if appropriate. */
529 /* If BP is malloc'd by us, make sure it is big enough. */
532 malloc_size
= bp1
- bp
+ buf
.size
;
533 termcap_name
= (char *) xrealloc (bp
, malloc_size
);
534 bp1
+= termcap_name
- bp
;
540 /* Copy the line of the entry from buf into bp. */
541 termcap_name
= buf
.ptr
;
542 while ((*bp1
++ = c
= *termcap_name
++) && c
!= '\n')
543 /* Drop out any \ newline sequence. */
544 if (c
== '\\' && *termcap_name
== '\n')
551 /* Does this entry refer to another terminal type's entry?
552 If something is found, copy it into heap and null-terminate it. */
553 term
= tgetst1 (find_capability (bp2
, "tc"), (char **) 0);
560 bp
= (char *) xrealloc (bp
, bp1
- bp
+ 1);
567 /* Given file open on FD and buffer BUFP,
568 scan the file from the beginning until a line is found
569 that starts the entry for terminal type STR.
570 Return 1 if successful, with that line in BUFP,
571 or 0 if no entry is found in the file. */
574 scan_file (str
, fd
, bufp
)
577 register struct buffer
*bufp
;
581 bufp
->ptr
= bufp
->beg
;
590 /* Read a line into the buffer. */
594 /* if it is continued, append another line to it,
595 until a non-continued line ends. */
596 end
= gobble_line (fd
, bufp
, end
);
598 while (!bufp
->ateof
&& end
[-2] == '\\');
600 if (*bufp
->ptr
!= '#'
601 && name_match (bufp
->ptr
, str
))
604 /* Discard the line just processed. */
610 /* Return nonzero if NAME is one of the names specified
611 by termcap entry LINE. */
614 name_match (line
, name
)
619 if (!compare_contin (line
, name
))
621 /* This line starts an entry. Is it the right one? */
622 for (tem
= line
; *tem
&& *tem
!= '\n' && *tem
!= ':'; tem
++)
623 if (*tem
== '|' && !compare_contin (tem
+ 1, name
))
630 compare_contin (str1
, str2
)
631 register char *str1
, *str2
;
638 while (c1
== '\\' && *str1
== '\n')
641 while ((c1
= *str1
++) == ' ' || c1
== '\t');
645 /* End of type being looked up. */
646 if (c1
== '|' || c1
== ':')
647 /* If end of name in data base, we win. */
657 /* Make sure that the buffer <- BUFP contains a full line
658 of the file open on FD, starting at the place BUFP->ptr
659 points to. Can read more of the file, discard stuff before
660 BUFP->ptr, or make the buffer bigger.
662 Return the pointer to after the newline ending the line,
663 or to the end of the file, if there is no newline to end it.
665 Can also merge on continuation lines. If APPEND_END is
666 non-null, it points past the newline of a line that is
667 continued; we add another line onto it and regard the whole
668 thing as one line. The caller decides when a line is continued. */
671 gobble_line (fd
, bufp
, append_end
)
673 register struct buffer
*bufp
;
678 register char *buf
= bufp
->beg
;
682 append_end
= bufp
->ptr
;
687 while (*end
&& *end
!= '\n') end
++;
691 return buf
+ bufp
->full
;
692 if (bufp
->ptr
== buf
)
694 if (bufp
->full
== bufp
->size
)
697 /* Add 1 to size to ensure room for terminating null. */
698 tem
= (char *) xrealloc (buf
, bufp
->size
+ 1);
699 bufp
->ptr
= (bufp
->ptr
- buf
) + tem
;
700 append_end
= (append_end
- buf
) + tem
;
701 bufp
->beg
= buf
= tem
;
706 append_end
-= bufp
->ptr
- buf
;
707 bcopy (bufp
->ptr
, buf
, bufp
->full
-= bufp
->ptr
- buf
);
710 if (!(nread
= read (fd
, buf
+ bufp
->full
, bufp
->size
- bufp
->full
)))
713 buf
[bufp
->full
] = '\0';
734 printf ("TERM: %s\n", term
);
736 buf
= (char *) tgetent (0, term
);
739 printf ("No entry.\n");
743 printf ("Entry: %s\n", buf
);
748 printf ("co: %d\n", tgetnum ("co"));
749 printf ("am: %d\n", tgetflag ("am"));
755 char *x
= tgetstr (cap
, 0);
758 printf ("%s: ", cap
);
762 if (*y
<= ' ' || *y
== 0177)
763 printf ("\\%0o", *y
);