1 /* Work-alike for termcap, plus extra features.
2 Copyright (C) 1985, 1986, 1993, 1994, 1995, 2000, 2001, 2002, 2003,
3 2004, 2005, 2006, 2007, 2008 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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA. */
20 /* Emacs config.h may rename various library functions such as malloc. */
28 #include <lisp.h> /* xmalloc is here */
29 /* Get the O_* definitions for open et al. */
49 /* Do this after the include, in case string.h prototypes bcopy. */
50 #if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy)
51 #define bcopy(s, d, n) memcpy ((d), (s), (n))
61 #endif /* not emacs */
64 #define NULL (char *) 0
71 /* BUFSIZE is the initial size allocated for the buffer
72 for reading the termcap file.
74 Make it large normally for speed.
75 Make it variable when debugging, so can exercise
76 increasing the space dynamically. */
80 #define BUFSIZE bufsize
89 #define TERMCAP_FILE "/etc/termcap"
96 write (2, "virtual memory exhausted\n", 25);
104 register char *tem
= malloc (size
);
116 register char *tem
= realloc (ptr
, size
);
122 #endif /* not emacs */
124 /* Looking up capabilities in the entry already found. */
126 /* The pointer to the data made by tgetent is left here
127 for tgetnum, tgetflag and tgetstr to find. */
128 static char *term_entry
;
130 static char *tgetst1 (char *ptr
, char **area
);
132 /* Search entry BP for capability CAP.
133 Return a pointer to the capability (in BP) if found,
137 find_capability (register char *bp
, register char *cap
)
150 register char *ptr
= find_capability (term_entry
, cap
);
151 if (!ptr
|| ptr
[-1] != '#')
159 register char *ptr
= find_capability (term_entry
, cap
);
160 return ptr
&& ptr
[-1] == ':';
163 /* Look up a string-valued capability CAP.
164 If AREA is non-null, it points to a pointer to a block in which
165 to store the string. That pointer is advanced over the space used.
166 If AREA is null, space is allocated with `malloc'. */
169 tgetstr (char *cap
, char **area
)
171 register char *ptr
= find_capability (term_entry
, cap
);
172 if (!ptr
|| (ptr
[-1] != '=' && ptr
[-1] != '~'))
174 return tgetst1 (ptr
, area
);
177 #ifdef IS_EBCDIC_HOST
178 /* Table, indexed by a character in range 0200 to 0300 with 0200 subtracted,
179 gives meaning of character following \, or a space if no special meaning.
180 Sixteen characters per line within the string. */
182 static const char esctab
[]
183 = " \057\026 \047\014 \
188 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
189 gives meaning of character following \, or a space if no special meaning.
190 Eight characters per line within the string. */
192 static const char esctab
[]
193 = " \007\010 \033\014 \
199 /* PTR points to a string value inside a termcap entry.
200 Copy that value, processing \ and ^ abbreviations,
201 into the block that *AREA points to,
202 or to newly allocated storage if AREA is NULL.
203 Return the address to which we copied the value,
204 or NULL if PTR is NULL. */
207 tgetst1 (char *ptr
, char **area
)
209 register char *p
, *r
;
218 /* `ret' gets address of where to store the string. */
221 /* Compute size of block needed (may overestimate). */
223 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
225 ret
= (char *) xmalloc (p
- ptr
+ 1);
230 /* Copy the string value, stopping at null or colon.
231 Also process ^ and \ abbreviations. */
234 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
247 if (c
>= '0' && c
<= '7')
252 while (++size
< 3 && (c1
= *p
) >= '0' && c1
<= '7')
259 #ifdef IS_EBCDIC_HOST
260 else if (c
>= 0200 && c
< 0360)
262 c1
= esctab
[(c
& ~0100) - 0200];
267 else if (c
>= 0100 && c
< 0200)
269 c1
= esctab
[(c
& ~040) - 0100];
278 /* Sometimes entries have "%pN" which means use parameter N in the
279 next %-substitution. If all such N are continuous in the range
280 [1,9] we can remove each "%pN" because they are redundant, thus
281 reducing bandwidth requirements. True, Emacs is well beyond the
282 days of 150baud teletypes, but some of its users aren't much so.
284 This pass could probably be integrated into the one above but
285 abbreviation expansion makes that effort a little more hairy than
286 its worth; this is cleaner. */
288 register int last_p_param
= 0;
289 int remove_p_params
= 1;
290 struct { char *beg
; int len
; } cut
[11];
292 for (cut
[0].beg
= p
= ret
; p
< r
- 3; p
++)
294 if (!remove_p_params
)
296 if (*p
== '%' && *(p
+ 1) == 'p')
298 if (*(p
+ 2) - '0' == 1 + last_p_param
)
300 cut
[last_p_param
].len
= p
- cut
[last_p_param
].beg
;
303 cut
[last_p_param
].beg
= p
;
305 else /* not continuous: bail */
307 if (last_p_param
> 10) /* too many: bail */
311 if (remove_p_params
&& last_p_param
)
316 cut
[last_p_param
].len
= r
- cut
[last_p_param
].beg
;
317 for (i
= 0, wp
= ret
; i
<= last_p_param
; wp
+= cut
[i
++].len
)
318 bcopy (cut
[i
].beg
, wp
, cut
[i
].len
);
330 /* Outputting a string with padding. */
334 /* If OSPEED is 0, we use this as the actual baud rate. */
341 /* Actual baud rate if positive;
342 - baud rate / 100 if negative. */
344 static const int speeds
[] =
346 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
347 -18, -24, -48, -96, -192, -288, -384, -576, -1152
350 #endif /* not emacs */
353 tputs (register char *str
, int nlines
, register int (*outfun
) (/* ??? */))
355 register int padcount
= 0;
359 extern EMACS_INT baud_rate
;
361 /* For quite high speeds, convert to the smaller
362 units to avoid overflow. */
364 speed
= - speed
/ 100;
367 speed
= tputs_baud_rate
;
369 speed
= speeds
[ospeed
];
375 while (*str
>= '0' && *str
<= '9')
377 padcount
+= *str
++ - '0';
383 padcount
+= *str
++ - '0';
393 /* PADCOUNT is now in units of tenths of msec.
394 SPEED is measured in characters per 10 seconds
395 or in characters per .1 seconds (if negative).
396 We use the smaller units for larger speeds to avoid overflow. */
401 padcount
= -padcount
;
408 while (padcount
-- > 0)
412 /* Finding the termcap entry in the termcap data base. */
414 struct termcap_buffer
423 /* Forward declarations of static functions. */
425 static int scan_file (char *str
, int fd
, register struct termcap_buffer
*bufp
);
426 static char *gobble_line (int fd
, register struct termcap_buffer
*bufp
, char *append_end
);
427 static int compare_contin (register char *str1
, register char *str2
);
428 static int name_match (char *line
, char *name
);
430 #ifdef MSDOS /* MW, May 1993 */
432 valid_filename_p (fn
)
435 return *fn
== '/' || fn
[1] == ':';
438 #define valid_filename_p(fn) (*(fn) == '/')
441 /* Find the termcap entry data for terminal type NAME
442 and store it in the block that BP points to.
443 Record its address for future use.
445 If BP is null, space is dynamically allocated.
447 Return -1 if there is some difficulty accessing the data base
449 0 if the data base is accessible but the type NAME is not defined
450 in it, and some other value otherwise. */
453 tgetent (char *bp
, char *name
)
455 register char *termcap_name
;
457 struct termcap_buffer buf
;
459 char *tc_search_point
;
463 char *tcenv
= NULL
; /* TERMCAP value, if it contains :tc=. */
464 char *indirect
= NULL
; /* Terminal type in :tc= in TERMCAP value. */
467 #ifdef INTERNAL_TERMINAL
468 /* For the internal terminal we don't want to read any termcap file,
470 if (!strcmp (name
, "internal"))
472 term
= INTERNAL_TERMINAL
;
475 malloc_size
= 1 + strlen (term
);
476 bp
= (char *) xmalloc (malloc_size
);
481 #endif /* INTERNAL_TERMINAL */
483 /* For compatibility with programs like `less' that want to
484 put data in the termcap buffer themselves as a fallback. */
488 termcap_name
= getenv ("TERMCAP");
489 if (termcap_name
&& *termcap_name
== '\0')
491 #if defined (MSDOS) && !defined (TEST)
492 if (termcap_name
&& (*termcap_name
== '\\'
493 || *termcap_name
== '/'
494 || termcap_name
[1] == ':'))
495 dostounix_filename(termcap_name
);
498 filep
= termcap_name
&& valid_filename_p (termcap_name
);
500 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
501 it is a file name to use instead of /etc/termcap.
502 If it is non-null and does not start with /,
503 it is the entry itself, but only if
504 the name the caller requested matches the TERM variable. */
506 if (termcap_name
&& !filep
&& !strcmp (name
, getenv ("TERM")))
508 indirect
= tgetst1 (find_capability (termcap_name
, "tc"), (char **) 0);
514 strcpy (bp
, termcap_name
);
518 { /* It has tc=. Need to read /etc/termcap. */
519 tcenv
= termcap_name
;
524 if (!termcap_name
|| !filep
)
525 termcap_name
= TERMCAP_FILE
;
527 /* Here we know we must search a file and termcap_name has its name. */
530 fd
= open (termcap_name
, O_RDONLY
|O_TEXT
, 0);
532 fd
= open (termcap_name
, O_RDONLY
, 0);
538 /* Add 1 to size to ensure room for terminating null. */
539 buf
.beg
= (char *) xmalloc (buf
.size
+ 1);
540 term
= indirect
? indirect
: name
;
544 malloc_size
= indirect
? strlen (tcenv
) + 1 : buf
.size
;
545 bp
= (char *) xmalloc (malloc_size
);
547 tc_search_point
= bp1
= bp
;
550 /* Copy the data from the environment variable. */
553 bp1
+= strlen (tcenv
);
558 /* Scan the file, reading it via buf, till find start of main entry. */
559 if (scan_file (term
, fd
, &buf
) == 0)
568 /* Free old `term' if appropriate. */
572 /* If BP is malloc'd by us, make sure it is big enough. */
575 int offset1
= bp1
- bp
, offset2
= tc_search_point
- bp
;
576 malloc_size
= offset1
+ buf
.size
;
577 bp
= termcap_name
= (char *) xrealloc (bp
, malloc_size
);
578 bp1
= termcap_name
+ offset1
;
579 tc_search_point
= termcap_name
+ offset2
;
582 /* Copy the line of the entry from buf into bp. */
583 termcap_name
= buf
.ptr
;
584 while ((*bp1
++ = c
= *termcap_name
++) && c
!= '\n')
585 /* Drop out any \ newline sequence. */
586 if (c
== '\\' && *termcap_name
== '\n')
593 /* Does this entry refer to another terminal type's entry?
594 If something is found, copy it into heap and null-terminate it. */
595 tc_search_point
= find_capability (tc_search_point
, "tc");
596 term
= tgetst1 (tc_search_point
, (char **) 0);
603 bp
= (char *) xrealloc (bp
, bp1
- bp
+ 1);
610 /* Given file open on FD and buffer BUFP,
611 scan the file from the beginning until a line is found
612 that starts the entry for terminal type STR.
613 Return 1 if successful, with that line in BUFP,
614 or 0 if no entry is found in the file. */
617 scan_file (char *str
, int fd
, register struct termcap_buffer
*bufp
)
621 bufp
->ptr
= bufp
->beg
;
630 /* Read a line into the buffer. */
634 /* if it is continued, append another line to it,
635 until a non-continued line ends. */
636 end
= gobble_line (fd
, bufp
, end
);
638 while (!bufp
->ateof
&& end
[-2] == '\\');
640 if (*bufp
->ptr
!= '#'
641 && name_match (bufp
->ptr
, str
))
644 /* Discard the line just processed. */
650 /* Return nonzero if NAME is one of the names specified
651 by termcap entry LINE. */
654 name_match (char *line
, char *name
)
658 if (!compare_contin (line
, name
))
660 /* This line starts an entry. Is it the right one? */
661 for (tem
= line
; *tem
&& *tem
!= '\n' && *tem
!= ':'; tem
++)
662 if (*tem
== '|' && !compare_contin (tem
+ 1, name
))
669 compare_contin (register char *str1
, register char *str2
)
676 while (c1
== '\\' && *str1
== '\n')
679 while ((c1
= *str1
++) == ' ' || c1
== '\t');
683 /* End of type being looked up. */
684 if (c1
== '|' || c1
== ':')
685 /* If end of name in data base, we win. */
695 /* Make sure that the buffer <- BUFP contains a full line
696 of the file open on FD, starting at the place BUFP->ptr
697 points to. Can read more of the file, discard stuff before
698 BUFP->ptr, or make the buffer bigger.
700 Return the pointer to after the newline ending the line,
701 or to the end of the file, if there is no newline to end it.
703 Can also merge on continuation lines. If APPEND_END is
704 non-null, it points past the newline of a line that is
705 continued; we add another line onto it and regard the whole
706 thing as one line. The caller decides when a line is continued. */
709 gobble_line (int fd
, register struct termcap_buffer
*bufp
, char *append_end
)
713 register char *buf
= bufp
->beg
;
717 append_end
= bufp
->ptr
;
722 while (*end
&& *end
!= '\n') end
++;
726 return buf
+ bufp
->full
;
727 if (bufp
->ptr
== buf
)
729 if (bufp
->full
== bufp
->size
)
732 /* Add 1 to size to ensure room for terminating null. */
733 tem
= (char *) xrealloc (buf
, bufp
->size
+ 1);
734 bufp
->ptr
= (bufp
->ptr
- buf
) + tem
;
735 append_end
= (append_end
- buf
) + tem
;
736 bufp
->beg
= buf
= tem
;
741 append_end
-= bufp
->ptr
- buf
;
742 bcopy (bufp
->ptr
, buf
, bufp
->full
-= bufp
->ptr
- buf
);
745 if (!(nread
= read (fd
, buf
+ bufp
->full
, bufp
->size
- bufp
->full
)))
748 buf
[bufp
->full
] = '\0';
769 printf ("TERM: %s\n", term
);
771 buf
= (char *) tgetent (0, term
);
774 printf ("No entry.\n");
778 printf ("Entry: %s\n", buf
);
783 printf ("co: %d\n", tgetnum ("co"));
784 printf ("am: %d\n", tgetflag ("am"));
790 char *x
= tgetstr (cap
, 0);
793 printf ("%s: ", cap
);
797 if (*y
<= ' ' || *y
== 0177)
798 printf ("\\%0o", *y
);
810 /* arch-tag: c2e8d427-2271-4fac-95fe-411857238b80
811 (do not change this comment) */