1 /* Work-alike for termcap, plus extra features.
2 Copyright (C) 1985, 86, 93, 94, 95, 2000, 2001
3 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; see the file COPYING. If not, write to
17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
20 /* Emacs config.h may rename various library functions such as malloc. */
27 #include <lisp.h> /* xmalloc is here */
28 /* Get the O_* definitions for open et al. */
48 /* Do this after the include, in case string.h prototypes bcopy. */
49 #if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy)
50 #define bcopy(s, d, n) memcpy ((d), (s), (n))
60 #endif /* not emacs */
63 #define NULL (char *) 0
70 /* BUFSIZE is the initial size allocated for the buffer
71 for reading the termcap file.
73 Make it large normally for speed.
74 Make it variable when debugging, so can exercise
75 increasing the space dynamically. */
79 #define BUFSIZE bufsize
88 #define TERMCAP_FILE "/etc/termcap"
95 write (2, "virtual memory exhausted\n", 25);
103 register char *tem
= malloc (size
);
115 register char *tem
= realloc (ptr
, size
);
121 #endif /* not emacs */
123 /* Looking up capabilities in the entry already found. */
125 /* The pointer to the data made by tgetent is left here
126 for tgetnum, tgetflag and tgetstr to find. */
127 static char *term_entry
;
129 static char *tgetst1 ();
131 /* Search entry BP for capability CAP.
132 Return a pointer to the capability (in BP) if found,
136 find_capability (bp
, cap
)
137 register char *bp
, *cap
;
151 register char *ptr
= find_capability (term_entry
, cap
);
152 if (!ptr
|| ptr
[-1] != '#')
161 register char *ptr
= find_capability (term_entry
, cap
);
162 return ptr
&& ptr
[-1] == ':';
165 /* Look up a string-valued capability CAP.
166 If AREA is non-null, it points to a pointer to a block in which
167 to store the string. That pointer is advanced over the space used.
168 If AREA is null, space is allocated with `malloc'. */
175 register char *ptr
= find_capability (term_entry
, cap
);
176 if (!ptr
|| (ptr
[-1] != '=' && ptr
[-1] != '~'))
178 return tgetst1 (ptr
, area
);
181 #ifdef IS_EBCDIC_HOST
182 /* Table, indexed by a character in range 0200 to 0300 with 0200 subtracted,
183 gives meaning of character following \, or a space if no special meaning.
184 Sixteen characters per line within the string. */
187 = " \057\026 \047\014 \
192 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
193 gives meaning of character following \, or a space if no special meaning.
194 Eight characters per line within the string. */
197 = " \007\010 \033\014 \
203 /* PTR points to a string value inside a termcap entry.
204 Copy that value, processing \ and ^ abbreviations,
205 into the block that *AREA points to,
206 or to newly allocated storage if AREA is NULL.
207 Return the address to which we copied the value,
208 or NULL if PTR is NULL. */
215 register char *p
, *r
;
224 /* `ret' gets address of where to store the string. */
227 /* Compute size of block needed (may overestimate). */
229 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
231 ret
= (char *) xmalloc (p
- ptr
+ 1);
236 /* Copy the string value, stopping at null or colon.
237 Also process ^ and \ abbreviations. */
240 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
253 if (c
>= '0' && c
<= '7')
258 while (++size
< 3 && (c1
= *p
) >= '0' && c1
<= '7')
265 #ifdef IS_EBCDIC_HOST
266 else if (c
>= 0200 && c
< 0360)
268 c1
= esctab
[(c
& ~0100) - 0200];
273 else if (c
>= 0100 && c
< 0200)
275 c1
= esctab
[(c
& ~040) - 0100];
290 /* Outputting a string with padding. */
292 /* If OSPEED is 0, we use this as the actual baud rate. */
296 #if 0 /* Doesn't seem to be used anymore. */
298 /* Actual baud rate if positive;
299 - baud rate / 100 if negative. */
301 static int speeds
[] =
304 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
305 -20, -24, -36, -48, -72, -96, -192
307 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
308 -18, -24, -48, -96, -192, -288, -384, -576, -1152
315 tputs (str
, nlines
, outfun
)
318 register int (*outfun
) ();
320 register int padcount
= 0;
323 extern int baud_rate
;
325 /* For quite high speeds, convert to the smaller
326 units to avoid overflow. */
328 speed
= - speed
/ 100;
333 while (*str
>= '0' && *str
<= '9')
335 padcount
+= *str
++ - '0';
341 padcount
+= *str
++ - '0';
351 /* PADCOUNT is now in units of tenths of msec.
352 SPEED is measured in characters per 10 seconds
353 or in characters per .1 seconds (if negative).
354 We use the smaller units for larger speeds to avoid overflow. */
359 padcount
= -padcount
;
366 while (padcount
-- > 0)
370 /* Finding the termcap entry in the termcap data base. */
372 struct termcap_buffer
381 /* Forward declarations of static functions. */
383 static int scan_file ();
384 static char *gobble_line ();
385 static int compare_contin ();
386 static int name_match ();
395 valid_filename_p (fn
)
398 struct FAB fab
= cc$rms_fab
;
399 struct NAM nam
= cc$rms_nam
;
400 char esa
[NAM$C_MAXRSS
];
403 fab
.fab$b_fns
= strlen(fn
);
404 fab
.fab$l_nam
= &nam
;
405 fab
.fab$l_fop
= FAB$M_NAM
;
408 nam
.nam$b_ess
= sizeof esa
;
410 return SYS$
PARSE(&fab
, 0, 0) == RMS$_NORMAL
;
415 #ifdef MSDOS /* MW, May 1993 */
417 valid_filename_p (fn
)
420 return *fn
== '/' || fn
[1] == ':';
423 #define valid_filename_p(fn) (*(fn) == '/')
428 /* Find the termcap entry data for terminal type NAME
429 and store it in the block that BP points to.
430 Record its address for future use.
432 If BP is null, space is dynamically allocated.
434 Return -1 if there is some difficulty accessing the data base
436 0 if the data base is accessible but the type NAME is not defined
437 in it, and some other value otherwise. */
443 register char *termcap_name
;
445 struct termcap_buffer buf
;
447 char *tc_search_point
;
451 char *tcenv
= NULL
; /* TERMCAP value, if it contains :tc=. */
452 char *indirect
= NULL
; /* Terminal type in :tc= in TERMCAP value. */
455 #ifdef INTERNAL_TERMINAL
456 /* For the internal terminal we don't want to read any termcap file,
458 if (!strcmp (name
, "internal"))
460 term
= INTERNAL_TERMINAL
;
463 malloc_size
= 1 + strlen (term
);
464 bp
= (char *) xmalloc (malloc_size
);
469 #endif /* INTERNAL_TERMINAL */
471 /* For compatibility with programs like `less' that want to
472 put data in the termcap buffer themselves as a fallback. */
476 termcap_name
= getenv ("TERMCAP");
477 if (termcap_name
&& *termcap_name
== '\0')
479 #if defined (MSDOS) && !defined (TEST)
480 if (termcap_name
&& (*termcap_name
== '\\'
481 || *termcap_name
== '/'
482 || termcap_name
[1] == ':'))
483 dostounix_filename(termcap_name
);
486 filep
= termcap_name
&& valid_filename_p (termcap_name
);
488 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
489 it is a file name to use instead of /etc/termcap.
490 If it is non-null and does not start with /,
491 it is the entry itself, but only if
492 the name the caller requested matches the TERM variable. */
494 if (termcap_name
&& !filep
&& !strcmp (name
, getenv ("TERM")))
496 indirect
= tgetst1 (find_capability (termcap_name
, "tc"), (char **) 0);
502 strcpy (bp
, termcap_name
);
506 { /* It has tc=. Need to read /etc/termcap. */
507 tcenv
= termcap_name
;
512 if (!termcap_name
|| !filep
)
513 termcap_name
= TERMCAP_FILE
;
515 /* Here we know we must search a file and termcap_name has its name. */
518 fd
= open (termcap_name
, O_RDONLY
|O_TEXT
, 0);
520 fd
= open (termcap_name
, O_RDONLY
, 0);
526 /* Add 1 to size to ensure room for terminating null. */
527 buf
.beg
= (char *) xmalloc (buf
.size
+ 1);
528 term
= indirect
? indirect
: name
;
532 malloc_size
= indirect
? strlen (tcenv
) + 1 : buf
.size
;
533 bp
= (char *) xmalloc (malloc_size
);
535 tc_search_point
= bp1
= bp
;
538 /* Copy the data from the environment variable. */
541 bp1
+= strlen (tcenv
);
546 /* Scan the file, reading it via buf, till find start of main entry. */
547 if (scan_file (term
, fd
, &buf
) == 0)
556 /* Free old `term' if appropriate. */
560 /* If BP is malloc'd by us, make sure it is big enough. */
563 int offset1
= bp1
- bp
, offset2
= tc_search_point
- bp
;
564 malloc_size
= offset1
+ buf
.size
;
565 bp
= termcap_name
= (char *) xrealloc (bp
, malloc_size
);
566 bp1
= termcap_name
+ offset1
;
567 tc_search_point
= termcap_name
+ offset2
;
570 /* Copy the line of the entry from buf into bp. */
571 termcap_name
= buf
.ptr
;
572 while ((*bp1
++ = c
= *termcap_name
++) && c
!= '\n')
573 /* Drop out any \ newline sequence. */
574 if (c
== '\\' && *termcap_name
== '\n')
581 /* Does this entry refer to another terminal type's entry?
582 If something is found, copy it into heap and null-terminate it. */
583 tc_search_point
= find_capability (tc_search_point
, "tc");
584 term
= tgetst1 (tc_search_point
, (char **) 0);
591 bp
= (char *) xrealloc (bp
, bp1
- bp
+ 1);
598 /* Given file open on FD and buffer BUFP,
599 scan the file from the beginning until a line is found
600 that starts the entry for terminal type STR.
601 Return 1 if successful, with that line in BUFP,
602 or 0 if no entry is found in the file. */
605 scan_file (str
, fd
, bufp
)
608 register struct termcap_buffer
*bufp
;
612 bufp
->ptr
= bufp
->beg
;
621 /* Read a line into the buffer. */
625 /* if it is continued, append another line to it,
626 until a non-continued line ends. */
627 end
= gobble_line (fd
, bufp
, end
);
629 while (!bufp
->ateof
&& end
[-2] == '\\');
631 if (*bufp
->ptr
!= '#'
632 && name_match (bufp
->ptr
, str
))
635 /* Discard the line just processed. */
641 /* Return nonzero if NAME is one of the names specified
642 by termcap entry LINE. */
645 name_match (line
, name
)
650 if (!compare_contin (line
, name
))
652 /* This line starts an entry. Is it the right one? */
653 for (tem
= line
; *tem
&& *tem
!= '\n' && *tem
!= ':'; tem
++)
654 if (*tem
== '|' && !compare_contin (tem
+ 1, name
))
661 compare_contin (str1
, str2
)
662 register char *str1
, *str2
;
669 while (c1
== '\\' && *str1
== '\n')
672 while ((c1
= *str1
++) == ' ' || c1
== '\t');
676 /* End of type being looked up. */
677 if (c1
== '|' || c1
== ':')
678 /* If end of name in data base, we win. */
688 /* Make sure that the buffer <- BUFP contains a full line
689 of the file open on FD, starting at the place BUFP->ptr
690 points to. Can read more of the file, discard stuff before
691 BUFP->ptr, or make the buffer bigger.
693 Return the pointer to after the newline ending the line,
694 or to the end of the file, if there is no newline to end it.
696 Can also merge on continuation lines. If APPEND_END is
697 non-null, it points past the newline of a line that is
698 continued; we add another line onto it and regard the whole
699 thing as one line. The caller decides when a line is continued. */
702 gobble_line (fd
, bufp
, append_end
)
704 register struct termcap_buffer
*bufp
;
709 register char *buf
= bufp
->beg
;
713 append_end
= bufp
->ptr
;
718 while (*end
&& *end
!= '\n') end
++;
722 return buf
+ bufp
->full
;
723 if (bufp
->ptr
== buf
)
725 if (bufp
->full
== bufp
->size
)
728 /* Add 1 to size to ensure room for terminating null. */
729 tem
= (char *) xrealloc (buf
, bufp
->size
+ 1);
730 bufp
->ptr
= (bufp
->ptr
- buf
) + tem
;
731 append_end
= (append_end
- buf
) + tem
;
732 bufp
->beg
= buf
= tem
;
737 append_end
-= bufp
->ptr
- buf
;
738 bcopy (bufp
->ptr
, buf
, bufp
->full
-= bufp
->ptr
- buf
);
741 if (!(nread
= read (fd
, buf
+ bufp
->full
, bufp
->size
- bufp
->full
)))
744 buf
[bufp
->full
] = '\0';
765 printf ("TERM: %s\n", term
);
767 buf
= (char *) tgetent (0, term
);
770 printf ("No entry.\n");
774 printf ("Entry: %s\n", buf
);
779 printf ("co: %d\n", tgetnum ("co"));
780 printf ("am: %d\n", tgetflag ("am"));
786 char *x
= tgetstr (cap
, 0);
789 printf ("%s: ", cap
);
793 if (*y
<= ' ' || *y
== 0177)
794 printf ("\\%0o", *y
);