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. */
56 #endif /* not emacs */
59 #define NULL (char *) 0
66 /* BUFSIZE is the initial size allocated for the buffer
67 for reading the termcap file.
69 Make it large normally for speed.
70 Make it variable when debugging, so can exercise
71 increasing the space dynamically. */
75 #define BUFSIZE bufsize
84 #define TERMCAP_FILE "/etc/termcap"
91 write (2, "virtual memory exhausted\n", 25);
99 register char *tem
= malloc (size
);
111 register char *tem
= realloc (ptr
, size
);
117 #endif /* not emacs */
119 /* Looking up capabilities in the entry already found. */
121 /* The pointer to the data made by tgetent is left here
122 for tgetnum, tgetflag and tgetstr to find. */
123 static char *term_entry
;
125 static char *tgetst1 (char *ptr
, char **area
);
127 /* Search entry BP for capability CAP.
128 Return a pointer to the capability (in BP) if found,
132 find_capability (register char *bp
, register char *cap
)
145 register char *ptr
= find_capability (term_entry
, cap
);
146 if (!ptr
|| ptr
[-1] != '#')
154 register char *ptr
= find_capability (term_entry
, cap
);
155 return ptr
&& ptr
[-1] == ':';
158 /* Look up a string-valued capability CAP.
159 If AREA is non-null, it points to a pointer to a block in which
160 to store the string. That pointer is advanced over the space used.
161 If AREA is null, space is allocated with `malloc'. */
164 tgetstr (char *cap
, char **area
)
166 register char *ptr
= find_capability (term_entry
, cap
);
167 if (!ptr
|| (ptr
[-1] != '=' && ptr
[-1] != '~'))
169 return tgetst1 (ptr
, area
);
172 #ifdef IS_EBCDIC_HOST
173 /* Table, indexed by a character in range 0200 to 0300 with 0200 subtracted,
174 gives meaning of character following \, or a space if no special meaning.
175 Sixteen characters per line within the string. */
177 static const char esctab
[]
178 = " \057\026 \047\014 \
183 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
184 gives meaning of character following \, or a space if no special meaning.
185 Eight characters per line within the string. */
187 static const char esctab
[]
188 = " \007\010 \033\014 \
194 /* PTR points to a string value inside a termcap entry.
195 Copy that value, processing \ and ^ abbreviations,
196 into the block that *AREA points to,
197 or to newly allocated storage if AREA is NULL.
198 Return the address to which we copied the value,
199 or NULL if PTR is NULL. */
202 tgetst1 (char *ptr
, char **area
)
204 register char *p
, *r
;
213 /* `ret' gets address of where to store the string. */
216 /* Compute size of block needed (may overestimate). */
218 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
220 ret
= (char *) xmalloc (p
- ptr
+ 1);
225 /* Copy the string value, stopping at null or colon.
226 Also process ^ and \ abbreviations. */
229 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
242 if (c
>= '0' && c
<= '7')
247 while (++size
< 3 && (c1
= *p
) >= '0' && c1
<= '7')
254 #ifdef IS_EBCDIC_HOST
255 else if (c
>= 0200 && c
< 0360)
257 c1
= esctab
[(c
& ~0100) - 0200];
262 else if (c
>= 0100 && c
< 0200)
264 c1
= esctab
[(c
& ~040) - 0100];
273 /* Sometimes entries have "%pN" which means use parameter N in the
274 next %-substitution. If all such N are continuous in the range
275 [1,9] we can remove each "%pN" because they are redundant, thus
276 reducing bandwidth requirements. True, Emacs is well beyond the
277 days of 150baud teletypes, but some of its users aren't much so.
279 This pass could probably be integrated into the one above but
280 abbreviation expansion makes that effort a little more hairy than
281 its worth; this is cleaner. */
283 register int last_p_param
= 0;
284 int remove_p_params
= 1;
285 struct { char *beg
; int len
; } cut
[11];
287 for (cut
[0].beg
= p
= ret
; p
< r
- 3; p
++)
289 if (!remove_p_params
)
291 if (*p
== '%' && *(p
+ 1) == 'p')
293 if (*(p
+ 2) - '0' == 1 + last_p_param
)
295 cut
[last_p_param
].len
= p
- cut
[last_p_param
].beg
;
298 cut
[last_p_param
].beg
= p
;
300 else /* not continuous: bail */
302 if (last_p_param
> 10) /* too many: bail */
306 if (remove_p_params
&& last_p_param
)
311 cut
[last_p_param
].len
= r
- cut
[last_p_param
].beg
;
312 for (i
= 0, wp
= ret
; i
<= last_p_param
; wp
+= cut
[i
++].len
)
313 memcpy (wp
, cut
[i
].beg
, cut
[i
].len
);
325 /* Outputting a string with padding. */
329 /* If OSPEED is 0, we use this as the actual baud rate. */
336 /* Actual baud rate if positive;
337 - baud rate / 100 if negative. */
339 static const int speeds
[] =
341 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
342 -18, -24, -48, -96, -192, -288, -384, -576, -1152
345 #endif /* not emacs */
348 tputs (register char *str
, int nlines
, register int (*outfun
) (/* ??? */))
350 register int padcount
= 0;
354 extern EMACS_INT baud_rate
;
356 /* For quite high speeds, convert to the smaller
357 units to avoid overflow. */
359 speed
= - speed
/ 100;
362 speed
= tputs_baud_rate
;
364 speed
= speeds
[ospeed
];
370 while (*str
>= '0' && *str
<= '9')
372 padcount
+= *str
++ - '0';
378 padcount
+= *str
++ - '0';
388 /* PADCOUNT is now in units of tenths of msec.
389 SPEED is measured in characters per 10 seconds
390 or in characters per .1 seconds (if negative).
391 We use the smaller units for larger speeds to avoid overflow. */
396 padcount
= -padcount
;
403 while (padcount
-- > 0)
407 /* Finding the termcap entry in the termcap data base. */
409 struct termcap_buffer
418 /* Forward declarations of static functions. */
420 static int scan_file (char *str
, int fd
, register struct termcap_buffer
*bufp
);
421 static char *gobble_line (int fd
, register struct termcap_buffer
*bufp
, char *append_end
);
422 static int compare_contin (register char *str1
, register char *str2
);
423 static int name_match (char *line
, char *name
);
425 #ifdef MSDOS /* MW, May 1993 */
427 valid_filename_p (fn
)
430 return *fn
== '/' || fn
[1] == ':';
433 #define valid_filename_p(fn) (*(fn) == '/')
436 /* Find the termcap entry data for terminal type NAME
437 and store it in the block that BP points to.
438 Record its address for future use.
440 If BP is null, space is dynamically allocated.
442 Return -1 if there is some difficulty accessing the data base
444 0 if the data base is accessible but the type NAME is not defined
445 in it, and some other value otherwise. */
448 tgetent (char *bp
, char *name
)
450 register char *termcap_name
;
452 struct termcap_buffer buf
;
454 char *tc_search_point
;
458 char *tcenv
= NULL
; /* TERMCAP value, if it contains :tc=. */
459 char *indirect
= NULL
; /* Terminal type in :tc= in TERMCAP value. */
462 #ifdef INTERNAL_TERMINAL
463 /* For the internal terminal we don't want to read any termcap file,
465 if (!strcmp (name
, "internal"))
467 term
= INTERNAL_TERMINAL
;
470 malloc_size
= 1 + strlen (term
);
471 bp
= (char *) xmalloc (malloc_size
);
476 #endif /* INTERNAL_TERMINAL */
478 /* For compatibility with programs like `less' that want to
479 put data in the termcap buffer themselves as a fallback. */
483 termcap_name
= getenv ("TERMCAP");
484 if (termcap_name
&& *termcap_name
== '\0')
486 #if defined (MSDOS) && !defined (TEST)
487 if (termcap_name
&& (*termcap_name
== '\\'
488 || *termcap_name
== '/'
489 || termcap_name
[1] == ':'))
490 dostounix_filename(termcap_name
);
493 filep
= termcap_name
&& valid_filename_p (termcap_name
);
495 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
496 it is a file name to use instead of /etc/termcap.
497 If it is non-null and does not start with /,
498 it is the entry itself, but only if
499 the name the caller requested matches the TERM variable. */
501 if (termcap_name
&& !filep
&& !strcmp (name
, getenv ("TERM")))
503 indirect
= tgetst1 (find_capability (termcap_name
, "tc"), (char **) 0);
509 strcpy (bp
, termcap_name
);
513 { /* It has tc=. Need to read /etc/termcap. */
514 tcenv
= termcap_name
;
519 if (!termcap_name
|| !filep
)
520 termcap_name
= TERMCAP_FILE
;
522 /* Here we know we must search a file and termcap_name has its name. */
525 fd
= open (termcap_name
, O_RDONLY
|O_TEXT
, 0);
527 fd
= open (termcap_name
, O_RDONLY
, 0);
533 /* Add 1 to size to ensure room for terminating null. */
534 buf
.beg
= (char *) xmalloc (buf
.size
+ 1);
535 term
= indirect
? indirect
: name
;
539 malloc_size
= indirect
? strlen (tcenv
) + 1 : buf
.size
;
540 bp
= (char *) xmalloc (malloc_size
);
542 tc_search_point
= bp1
= bp
;
545 /* Copy the data from the environment variable. */
548 bp1
+= strlen (tcenv
);
553 /* Scan the file, reading it via buf, till find start of main entry. */
554 if (scan_file (term
, fd
, &buf
) == 0)
563 /* Free old `term' if appropriate. */
567 /* If BP is malloc'd by us, make sure it is big enough. */
570 int offset1
= bp1
- bp
, offset2
= tc_search_point
- bp
;
571 malloc_size
= offset1
+ buf
.size
;
572 bp
= termcap_name
= (char *) xrealloc (bp
, malloc_size
);
573 bp1
= termcap_name
+ offset1
;
574 tc_search_point
= termcap_name
+ offset2
;
577 /* Copy the line of the entry from buf into bp. */
578 termcap_name
= buf
.ptr
;
579 while ((*bp1
++ = c
= *termcap_name
++) && c
!= '\n')
580 /* Drop out any \ newline sequence. */
581 if (c
== '\\' && *termcap_name
== '\n')
588 /* Does this entry refer to another terminal type's entry?
589 If something is found, copy it into heap and null-terminate it. */
590 tc_search_point
= find_capability (tc_search_point
, "tc");
591 term
= tgetst1 (tc_search_point
, (char **) 0);
598 bp
= (char *) xrealloc (bp
, bp1
- bp
+ 1);
605 /* Given file open on FD and buffer BUFP,
606 scan the file from the beginning until a line is found
607 that starts the entry for terminal type STR.
608 Return 1 if successful, with that line in BUFP,
609 or 0 if no entry is found in the file. */
612 scan_file (char *str
, int fd
, register struct termcap_buffer
*bufp
)
616 bufp
->ptr
= bufp
->beg
;
625 /* Read a line into the buffer. */
629 /* if it is continued, append another line to it,
630 until a non-continued line ends. */
631 end
= gobble_line (fd
, bufp
, end
);
633 while (!bufp
->ateof
&& end
[-2] == '\\');
635 if (*bufp
->ptr
!= '#'
636 && name_match (bufp
->ptr
, str
))
639 /* Discard the line just processed. */
645 /* Return nonzero if NAME is one of the names specified
646 by termcap entry LINE. */
649 name_match (char *line
, char *name
)
653 if (!compare_contin (line
, name
))
655 /* This line starts an entry. Is it the right one? */
656 for (tem
= line
; *tem
&& *tem
!= '\n' && *tem
!= ':'; tem
++)
657 if (*tem
== '|' && !compare_contin (tem
+ 1, name
))
664 compare_contin (register char *str1
, register char *str2
)
671 while (c1
== '\\' && *str1
== '\n')
674 while ((c1
= *str1
++) == ' ' || c1
== '\t');
678 /* End of type being looked up. */
679 if (c1
== '|' || c1
== ':')
680 /* If end of name in data base, we win. */
690 /* Make sure that the buffer <- BUFP contains a full line
691 of the file open on FD, starting at the place BUFP->ptr
692 points to. Can read more of the file, discard stuff before
693 BUFP->ptr, or make the buffer bigger.
695 Return the pointer to after the newline ending the line,
696 or to the end of the file, if there is no newline to end it.
698 Can also merge on continuation lines. If APPEND_END is
699 non-null, it points past the newline of a line that is
700 continued; we add another line onto it and regard the whole
701 thing as one line. The caller decides when a line is continued. */
704 gobble_line (int fd
, register struct termcap_buffer
*bufp
, char *append_end
)
708 register char *buf
= bufp
->beg
;
712 append_end
= bufp
->ptr
;
717 while (*end
&& *end
!= '\n') end
++;
721 return buf
+ bufp
->full
;
722 if (bufp
->ptr
== buf
)
724 if (bufp
->full
== bufp
->size
)
727 /* Add 1 to size to ensure room for terminating null. */
728 tem
= (char *) xrealloc (buf
, bufp
->size
+ 1);
729 bufp
->ptr
= (bufp
->ptr
- buf
) + tem
;
730 append_end
= (append_end
- buf
) + tem
;
731 bufp
->beg
= buf
= tem
;
736 append_end
-= bufp
->ptr
- buf
;
737 memcpy (buf
, bufp
->ptr
, bufp
->full
-= bufp
->ptr
- buf
);
740 if (!(nread
= read (fd
, buf
+ bufp
->full
, bufp
->size
- bufp
->full
)))
743 buf
[bufp
->full
] = '\0';
764 printf ("TERM: %s\n", term
);
766 buf
= (char *) tgetent (0, term
);
769 printf ("No entry.\n");
773 printf ("Entry: %s\n", buf
);
778 printf ("co: %d\n", tgetnum ("co"));
779 printf ("am: %d\n", tgetflag ("am"));
785 char *x
= tgetstr (cap
, 0);
788 printf ("%s: ", cap
);
792 if (*y
<= ' ' || *y
== 0177)
793 printf ("\\%0o", *y
);
805 /* arch-tag: c2e8d427-2271-4fac-95fe-411857238b80
806 (do not change this comment) */