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 ();
132 /* Search entry BP for capability CAP.
133 Return a pointer to the capability (in BP) if found,
137 find_capability (bp
, cap
)
138 register char *bp
, *cap
;
152 register char *ptr
= find_capability (term_entry
, cap
);
153 if (!ptr
|| ptr
[-1] != '#')
162 register char *ptr
= find_capability (term_entry
, cap
);
163 return ptr
&& ptr
[-1] == ':';
166 /* Look up a string-valued capability CAP.
167 If AREA is non-null, it points to a pointer to a block in which
168 to store the string. That pointer is advanced over the space used.
169 If AREA is null, space is allocated with `malloc'. */
176 register char *ptr
= find_capability (term_entry
, cap
);
177 if (!ptr
|| (ptr
[-1] != '=' && ptr
[-1] != '~'))
179 return tgetst1 (ptr
, area
);
182 #ifdef IS_EBCDIC_HOST
183 /* Table, indexed by a character in range 0200 to 0300 with 0200 subtracted,
184 gives meaning of character following \, or a space if no special meaning.
185 Sixteen characters per line within the string. */
187 static const char esctab
[]
188 = " \057\026 \047\014 \
193 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
194 gives meaning of character following \, or a space if no special meaning.
195 Eight characters per line within the string. */
197 static const char esctab
[]
198 = " \007\010 \033\014 \
204 /* PTR points to a string value inside a termcap entry.
205 Copy that value, processing \ and ^ abbreviations,
206 into the block that *AREA points to,
207 or to newly allocated storage if AREA is NULL.
208 Return the address to which we copied the value,
209 or NULL if PTR is NULL. */
216 register char *p
, *r
;
225 /* `ret' gets address of where to store the string. */
228 /* Compute size of block needed (may overestimate). */
230 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
232 ret
= (char *) xmalloc (p
- ptr
+ 1);
237 /* Copy the string value, stopping at null or colon.
238 Also process ^ and \ abbreviations. */
241 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
254 if (c
>= '0' && c
<= '7')
259 while (++size
< 3 && (c1
= *p
) >= '0' && c1
<= '7')
266 #ifdef IS_EBCDIC_HOST
267 else if (c
>= 0200 && c
< 0360)
269 c1
= esctab
[(c
& ~0100) - 0200];
274 else if (c
>= 0100 && c
< 0200)
276 c1
= esctab
[(c
& ~040) - 0100];
285 /* Sometimes entries have "%pN" which means use parameter N in the
286 next %-substitution. If all such N are continuous in the range
287 [1,9] we can remove each "%pN" because they are redundant, thus
288 reducing bandwidth requirements. True, Emacs is well beyond the
289 days of 150baud teletypes, but some of its users aren't much so.
291 This pass could probably be integrated into the one above but
292 abbreviation expansion makes that effort a little more hairy than
293 its worth; this is cleaner. */
295 register int last_p_param
= 0;
296 int remove_p_params
= 1;
297 struct { char *beg
; int len
; } cut
[11];
299 for (cut
[0].beg
= p
= ret
; p
< r
- 3; p
++)
301 if (!remove_p_params
)
303 if (*p
== '%' && *(p
+ 1) == 'p')
305 if (*(p
+ 2) - '0' == 1 + last_p_param
)
307 cut
[last_p_param
].len
= p
- cut
[last_p_param
].beg
;
310 cut
[last_p_param
].beg
= p
;
312 else /* not continuous: bail */
314 if (last_p_param
> 10) /* too many: bail */
318 if (remove_p_params
&& last_p_param
)
323 cut
[last_p_param
].len
= r
- cut
[last_p_param
].beg
;
324 for (i
= 0, wp
= ret
; i
<= last_p_param
; wp
+= cut
[i
++].len
)
325 bcopy (cut
[i
].beg
, wp
, cut
[i
].len
);
337 /* Outputting a string with padding. */
341 /* If OSPEED is 0, we use this as the actual baud rate. */
348 /* Actual baud rate if positive;
349 - baud rate / 100 if negative. */
351 static const int speeds
[] =
353 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
354 -18, -24, -48, -96, -192, -288, -384, -576, -1152
357 #endif /* not emacs */
360 tputs (str
, nlines
, outfun
)
363 register int (*outfun
) ();
365 register int padcount
= 0;
369 extern EMACS_INT baud_rate
;
371 /* For quite high speeds, convert to the smaller
372 units to avoid overflow. */
374 speed
= - speed
/ 100;
377 speed
= tputs_baud_rate
;
379 speed
= speeds
[ospeed
];
385 while (*str
>= '0' && *str
<= '9')
387 padcount
+= *str
++ - '0';
393 padcount
+= *str
++ - '0';
403 /* PADCOUNT is now in units of tenths of msec.
404 SPEED is measured in characters per 10 seconds
405 or in characters per .1 seconds (if negative).
406 We use the smaller units for larger speeds to avoid overflow. */
411 padcount
= -padcount
;
418 while (padcount
-- > 0)
422 /* Finding the termcap entry in the termcap data base. */
424 struct termcap_buffer
433 /* Forward declarations of static functions. */
435 static int scan_file ();
436 static char *gobble_line ();
437 static int compare_contin ();
438 static int name_match ();
440 #ifdef MSDOS /* MW, May 1993 */
442 valid_filename_p (fn
)
445 return *fn
== '/' || fn
[1] == ':';
448 #define valid_filename_p(fn) (*(fn) == '/')
451 /* Find the termcap entry data for terminal type NAME
452 and store it in the block that BP points to.
453 Record its address for future use.
455 If BP is null, space is dynamically allocated.
457 Return -1 if there is some difficulty accessing the data base
459 0 if the data base is accessible but the type NAME is not defined
460 in it, and some other value otherwise. */
466 register char *termcap_name
;
468 struct termcap_buffer buf
;
470 char *tc_search_point
;
474 char *tcenv
= NULL
; /* TERMCAP value, if it contains :tc=. */
475 char *indirect
= NULL
; /* Terminal type in :tc= in TERMCAP value. */
478 #ifdef INTERNAL_TERMINAL
479 /* For the internal terminal we don't want to read any termcap file,
481 if (!strcmp (name
, "internal"))
483 term
= INTERNAL_TERMINAL
;
486 malloc_size
= 1 + strlen (term
);
487 bp
= (char *) xmalloc (malloc_size
);
492 #endif /* INTERNAL_TERMINAL */
494 /* For compatibility with programs like `less' that want to
495 put data in the termcap buffer themselves as a fallback. */
499 termcap_name
= getenv ("TERMCAP");
500 if (termcap_name
&& *termcap_name
== '\0')
502 #if defined (MSDOS) && !defined (TEST)
503 if (termcap_name
&& (*termcap_name
== '\\'
504 || *termcap_name
== '/'
505 || termcap_name
[1] == ':'))
506 dostounix_filename(termcap_name
);
509 filep
= termcap_name
&& valid_filename_p (termcap_name
);
511 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
512 it is a file name to use instead of /etc/termcap.
513 If it is non-null and does not start with /,
514 it is the entry itself, but only if
515 the name the caller requested matches the TERM variable. */
517 if (termcap_name
&& !filep
&& !strcmp (name
, getenv ("TERM")))
519 indirect
= tgetst1 (find_capability (termcap_name
, "tc"), (char **) 0);
525 strcpy (bp
, termcap_name
);
529 { /* It has tc=. Need to read /etc/termcap. */
530 tcenv
= termcap_name
;
535 if (!termcap_name
|| !filep
)
536 termcap_name
= TERMCAP_FILE
;
538 /* Here we know we must search a file and termcap_name has its name. */
541 fd
= open (termcap_name
, O_RDONLY
|O_TEXT
, 0);
543 fd
= open (termcap_name
, O_RDONLY
, 0);
549 /* Add 1 to size to ensure room for terminating null. */
550 buf
.beg
= (char *) xmalloc (buf
.size
+ 1);
551 term
= indirect
? indirect
: name
;
555 malloc_size
= indirect
? strlen (tcenv
) + 1 : buf
.size
;
556 bp
= (char *) xmalloc (malloc_size
);
558 tc_search_point
= bp1
= bp
;
561 /* Copy the data from the environment variable. */
564 bp1
+= strlen (tcenv
);
569 /* Scan the file, reading it via buf, till find start of main entry. */
570 if (scan_file (term
, fd
, &buf
) == 0)
579 /* Free old `term' if appropriate. */
583 /* If BP is malloc'd by us, make sure it is big enough. */
586 int offset1
= bp1
- bp
, offset2
= tc_search_point
- bp
;
587 malloc_size
= offset1
+ buf
.size
;
588 bp
= termcap_name
= (char *) xrealloc (bp
, malloc_size
);
589 bp1
= termcap_name
+ offset1
;
590 tc_search_point
= termcap_name
+ offset2
;
593 /* Copy the line of the entry from buf into bp. */
594 termcap_name
= buf
.ptr
;
595 while ((*bp1
++ = c
= *termcap_name
++) && c
!= '\n')
596 /* Drop out any \ newline sequence. */
597 if (c
== '\\' && *termcap_name
== '\n')
604 /* Does this entry refer to another terminal type's entry?
605 If something is found, copy it into heap and null-terminate it. */
606 tc_search_point
= find_capability (tc_search_point
, "tc");
607 term
= tgetst1 (tc_search_point
, (char **) 0);
614 bp
= (char *) xrealloc (bp
, bp1
- bp
+ 1);
621 /* Given file open on FD and buffer BUFP,
622 scan the file from the beginning until a line is found
623 that starts the entry for terminal type STR.
624 Return 1 if successful, with that line in BUFP,
625 or 0 if no entry is found in the file. */
628 scan_file (str
, fd
, bufp
)
631 register struct termcap_buffer
*bufp
;
635 bufp
->ptr
= bufp
->beg
;
644 /* Read a line into the buffer. */
648 /* if it is continued, append another line to it,
649 until a non-continued line ends. */
650 end
= gobble_line (fd
, bufp
, end
);
652 while (!bufp
->ateof
&& end
[-2] == '\\');
654 if (*bufp
->ptr
!= '#'
655 && name_match (bufp
->ptr
, str
))
658 /* Discard the line just processed. */
664 /* Return nonzero if NAME is one of the names specified
665 by termcap entry LINE. */
668 name_match (line
, name
)
673 if (!compare_contin (line
, name
))
675 /* This line starts an entry. Is it the right one? */
676 for (tem
= line
; *tem
&& *tem
!= '\n' && *tem
!= ':'; tem
++)
677 if (*tem
== '|' && !compare_contin (tem
+ 1, name
))
684 compare_contin (str1
, str2
)
685 register char *str1
, *str2
;
692 while (c1
== '\\' && *str1
== '\n')
695 while ((c1
= *str1
++) == ' ' || c1
== '\t');
699 /* End of type being looked up. */
700 if (c1
== '|' || c1
== ':')
701 /* If end of name in data base, we win. */
711 /* Make sure that the buffer <- BUFP contains a full line
712 of the file open on FD, starting at the place BUFP->ptr
713 points to. Can read more of the file, discard stuff before
714 BUFP->ptr, or make the buffer bigger.
716 Return the pointer to after the newline ending the line,
717 or to the end of the file, if there is no newline to end it.
719 Can also merge on continuation lines. If APPEND_END is
720 non-null, it points past the newline of a line that is
721 continued; we add another line onto it and regard the whole
722 thing as one line. The caller decides when a line is continued. */
725 gobble_line (fd
, bufp
, append_end
)
727 register struct termcap_buffer
*bufp
;
732 register char *buf
= bufp
->beg
;
736 append_end
= bufp
->ptr
;
741 while (*end
&& *end
!= '\n') end
++;
745 return buf
+ bufp
->full
;
746 if (bufp
->ptr
== buf
)
748 if (bufp
->full
== bufp
->size
)
751 /* Add 1 to size to ensure room for terminating null. */
752 tem
= (char *) xrealloc (buf
, bufp
->size
+ 1);
753 bufp
->ptr
= (bufp
->ptr
- buf
) + tem
;
754 append_end
= (append_end
- buf
) + tem
;
755 bufp
->beg
= buf
= tem
;
760 append_end
-= bufp
->ptr
- buf
;
761 bcopy (bufp
->ptr
, buf
, bufp
->full
-= bufp
->ptr
- buf
);
764 if (!(nread
= read (fd
, buf
+ bufp
->full
, bufp
->size
- bufp
->full
)))
767 buf
[bufp
->full
] = '\0';
788 printf ("TERM: %s\n", term
);
790 buf
= (char *) tgetent (0, term
);
793 printf ("No entry.\n");
797 printf ("Entry: %s\n", buf
);
802 printf ("co: %d\n", tgetnum ("co"));
803 printf ("am: %d\n", tgetflag ("am"));
809 char *x
= tgetstr (cap
, 0);
812 printf ("%s: ", cap
);
816 if (*y
<= ' ' || *y
== 0177)
817 printf ("\\%0o", *y
);
829 /* arch-tag: c2e8d427-2271-4fac-95fe-411857238b80
830 (do not change this comment) */