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. */
34 #define NULL (char *) 0
37 /* BUFSIZE is the initial size allocated for the buffer
38 for reading the termcap file.
40 Make it large normally for speed.
41 Make it variable when debugging, so can exercise
42 increasing the space dynamically. */
46 #define BUFSIZE bufsize
55 #define TERMCAP_FILE "/etc/termcap"
59 /* Looking up capabilities in the entry already found. */
61 /* The pointer to the data made by tgetent is left here
62 for tgetnum, tgetflag and tgetstr to find. */
63 static char *term_entry
;
65 static char *tgetst1 (char *ptr
, char **area
);
67 /* Search entry BP for capability CAP.
68 Return a pointer to the capability (in BP) if found,
72 find_capability (register char *bp
, register const char *cap
)
83 tgetnum (const char *cap
)
85 register char *ptr
= find_capability (term_entry
, cap
);
86 if (!ptr
|| ptr
[-1] != '#')
92 tgetflag (const char *cap
)
94 register char *ptr
= find_capability (term_entry
, cap
);
95 return ptr
&& ptr
[-1] == ':';
98 /* Look up a string-valued capability CAP.
99 If AREA is non-null, it points to a pointer to a block in which
100 to store the string. That pointer is advanced over the space used.
101 If AREA is null, space is allocated with `malloc'. */
104 tgetstr (const char *cap
, char **area
)
106 register char *ptr
= find_capability (term_entry
, cap
);
107 if (!ptr
|| (ptr
[-1] != '=' && ptr
[-1] != '~'))
109 return tgetst1 (ptr
, area
);
112 #ifdef IS_EBCDIC_HOST
113 /* Table, indexed by a character in range 0200 to 0300 with 0200 subtracted,
114 gives meaning of character following \, or a space if no special meaning.
115 Sixteen characters per line within the string. */
117 static const char esctab
[]
118 = " \057\026 \047\014 \
123 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
124 gives meaning of character following \, or a space if no special meaning.
125 Eight characters per line within the string. */
127 static const char esctab
[]
128 = " \007\010 \033\014 \
134 /* PTR points to a string value inside a termcap entry.
135 Copy that value, processing \ and ^ abbreviations,
136 into the block that *AREA points to,
137 or to newly allocated storage if AREA is NULL.
138 Return the address to which we copied the value,
139 or NULL if PTR is NULL. */
142 tgetst1 (char *ptr
, char **area
)
144 register char *p
, *r
;
153 /* `ret' gets address of where to store the string. */
156 /* Compute size of block needed (may overestimate). */
158 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
160 ret
= (char *) xmalloc (p
- ptr
+ 1);
165 /* Copy the string value, stopping at null or colon.
166 Also process ^ and \ abbreviations. */
169 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
182 if (c
>= '0' && c
<= '7')
187 while (++size
< 3 && (c1
= *p
) >= '0' && c1
<= '7')
194 #ifdef IS_EBCDIC_HOST
195 else if (c
>= 0200 && c
< 0360)
197 c1
= esctab
[(c
& ~0100) - 0200];
202 else if (c
>= 0100 && c
< 0200)
204 c1
= esctab
[(c
& ~040) - 0100];
213 /* Sometimes entries have "%pN" which means use parameter N in the
214 next %-substitution. If all such N are continuous in the range
215 [1,9] we can remove each "%pN" because they are redundant, thus
216 reducing bandwidth requirements. True, Emacs is well beyond the
217 days of 150baud teletypes, but some of its users aren't much so.
219 This pass could probably be integrated into the one above but
220 abbreviation expansion makes that effort a little more hairy than
221 its worth; this is cleaner. */
223 register int last_p_param
= 0;
224 int remove_p_params
= 1;
225 struct { char *beg
; int len
; } cut
[11];
227 for (cut
[0].beg
= p
= ret
; p
< r
- 3; p
++)
229 if (!remove_p_params
)
231 if (*p
== '%' && *(p
+ 1) == 'p')
233 if (*(p
+ 2) - '0' == 1 + last_p_param
)
235 cut
[last_p_param
].len
= p
- cut
[last_p_param
].beg
;
238 cut
[last_p_param
].beg
= p
;
240 else /* not continuous: bail */
242 if (last_p_param
> 10) /* too many: bail */
246 if (remove_p_params
&& last_p_param
)
251 cut
[last_p_param
].len
= r
- cut
[last_p_param
].beg
;
252 for (i
= 0, wp
= ret
; i
<= last_p_param
; wp
+= cut
[i
++].len
)
253 memcpy (wp
, cut
[i
].beg
, cut
[i
].len
);
265 /* Outputting a string with padding. */
270 tputs (register const char *str
, int nlines
, int (*outfun
) (int))
272 register int padcount
= 0;
276 /* For quite high speeds, convert to the smaller
277 units to avoid overflow. */
279 speed
= - speed
/ 100;
284 while (*str
>= '0' && *str
<= '9')
286 padcount
+= *str
++ - '0';
292 padcount
+= *str
++ - '0';
302 /* PADCOUNT is now in units of tenths of msec.
303 SPEED is measured in characters per 10 seconds
304 or in characters per .1 seconds (if negative).
305 We use the smaller units for larger speeds to avoid overflow. */
310 padcount
= -padcount
;
317 while (padcount
-- > 0)
321 /* Finding the termcap entry in the termcap data base. */
323 struct termcap_buffer
332 /* Forward declarations of static functions. */
334 static int scan_file (char *str
, int fd
, register struct termcap_buffer
*bufp
);
335 static char *gobble_line (int fd
, register struct termcap_buffer
*bufp
, char *append_end
);
336 static int compare_contin (register char *str1
, register char *str2
);
337 static int name_match (char *line
, char *name
);
339 #ifdef MSDOS /* MW, May 1993 */
341 valid_filename_p (fn
)
344 return *fn
== '/' || fn
[1] == ':';
347 #define valid_filename_p(fn) (*(fn) == '/')
350 /* Find the termcap entry data for terminal type NAME
351 and store it in the block that BP points to.
352 Record its address for future use.
354 If BP is null, space is dynamically allocated.
356 Return -1 if there is some difficulty accessing the data base
358 0 if the data base is accessible but the type NAME is not defined
359 in it, and some other value otherwise. */
362 tgetent (char *bp
, const char *name
)
364 register char *termcap_name
;
366 struct termcap_buffer buf
;
368 char *tc_search_point
;
372 char *tcenv
= NULL
; /* TERMCAP value, if it contains :tc=. */
373 char *indirect
= NULL
; /* Terminal type in :tc= in TERMCAP value. */
376 #ifdef INTERNAL_TERMINAL
377 /* For the internal terminal we don't want to read any termcap file,
379 if (!strcmp (name
, "internal"))
381 term
= INTERNAL_TERMINAL
;
384 malloc_size
= 1 + strlen (term
);
385 bp
= (char *) xmalloc (malloc_size
);
390 #endif /* INTERNAL_TERMINAL */
392 /* For compatibility with programs like `less' that want to
393 put data in the termcap buffer themselves as a fallback. */
397 termcap_name
= getenv ("TERMCAP");
398 if (termcap_name
&& *termcap_name
== '\0')
400 #if defined (MSDOS) && !defined (TEST)
401 if (termcap_name
&& (*termcap_name
== '\\'
402 || *termcap_name
== '/'
403 || termcap_name
[1] == ':'))
404 dostounix_filename(termcap_name
);
407 filep
= termcap_name
&& valid_filename_p (termcap_name
);
409 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
410 it is a file name to use instead of /etc/termcap.
411 If it is non-null and does not start with /,
412 it is the entry itself, but only if
413 the name the caller requested matches the TERM variable. */
415 if (termcap_name
&& !filep
&& !strcmp (name
, getenv ("TERM")))
417 indirect
= tgetst1 (find_capability (termcap_name
, "tc"), (char **) 0);
423 strcpy (bp
, termcap_name
);
427 { /* It has tc=. Need to read /etc/termcap. */
428 tcenv
= termcap_name
;
433 if (!termcap_name
|| !filep
)
434 termcap_name
= TERMCAP_FILE
;
436 /* Here we know we must search a file and termcap_name has its name. */
439 fd
= open (termcap_name
, O_RDONLY
|O_TEXT
, 0);
441 fd
= open (termcap_name
, O_RDONLY
, 0);
447 /* Add 1 to size to ensure room for terminating null. */
448 buf
.beg
= (char *) xmalloc (buf
.size
+ 1);
449 term
= indirect
? indirect
: (char *)name
;
453 malloc_size
= indirect
? strlen (tcenv
) + 1 : buf
.size
;
454 bp
= (char *) xmalloc (malloc_size
);
456 tc_search_point
= bp1
= bp
;
459 /* Copy the data from the environment variable. */
462 bp1
+= strlen (tcenv
);
467 /* Scan the file, reading it via buf, till find start of main entry. */
468 if (scan_file (term
, fd
, &buf
) == 0)
477 /* Free old `term' if appropriate. */
481 /* If BP is malloc'd by us, make sure it is big enough. */
484 int offset1
= bp1
- bp
, offset2
= tc_search_point
- bp
;
485 malloc_size
= offset1
+ buf
.size
;
486 bp
= termcap_name
= (char *) xrealloc (bp
, malloc_size
);
487 bp1
= termcap_name
+ offset1
;
488 tc_search_point
= termcap_name
+ offset2
;
491 /* Copy the line of the entry from buf into bp. */
492 termcap_name
= buf
.ptr
;
493 while ((*bp1
++ = c
= *termcap_name
++) && c
!= '\n')
494 /* Drop out any \ newline sequence. */
495 if (c
== '\\' && *termcap_name
== '\n')
502 /* Does this entry refer to another terminal type's entry?
503 If something is found, copy it into heap and null-terminate it. */
504 tc_search_point
= find_capability (tc_search_point
, "tc");
505 term
= tgetst1 (tc_search_point
, (char **) 0);
512 bp
= (char *) xrealloc (bp
, bp1
- bp
+ 1);
519 /* Given file open on FD and buffer BUFP,
520 scan the file from the beginning until a line is found
521 that starts the entry for terminal type STR.
522 Return 1 if successful, with that line in BUFP,
523 or 0 if no entry is found in the file. */
526 scan_file (char *str
, int fd
, register struct termcap_buffer
*bufp
)
530 bufp
->ptr
= bufp
->beg
;
539 /* Read a line into the buffer. */
543 /* if it is continued, append another line to it,
544 until a non-continued line ends. */
545 end
= gobble_line (fd
, bufp
, end
);
547 while (!bufp
->ateof
&& end
[-2] == '\\');
549 if (*bufp
->ptr
!= '#'
550 && name_match (bufp
->ptr
, str
))
553 /* Discard the line just processed. */
559 /* Return nonzero if NAME is one of the names specified
560 by termcap entry LINE. */
563 name_match (char *line
, char *name
)
567 if (!compare_contin (line
, name
))
569 /* This line starts an entry. Is it the right one? */
570 for (tem
= line
; *tem
&& *tem
!= '\n' && *tem
!= ':'; tem
++)
571 if (*tem
== '|' && !compare_contin (tem
+ 1, name
))
578 compare_contin (register char *str1
, register char *str2
)
585 while (c1
== '\\' && *str1
== '\n')
588 while ((c1
= *str1
++) == ' ' || c1
== '\t');
592 /* End of type being looked up. */
593 if (c1
== '|' || c1
== ':')
594 /* If end of name in data base, we win. */
604 /* Make sure that the buffer <- BUFP contains a full line
605 of the file open on FD, starting at the place BUFP->ptr
606 points to. Can read more of the file, discard stuff before
607 BUFP->ptr, or make the buffer bigger.
609 Return the pointer to after the newline ending the line,
610 or to the end of the file, if there is no newline to end it.
612 Can also merge on continuation lines. If APPEND_END is
613 non-null, it points past the newline of a line that is
614 continued; we add another line onto it and regard the whole
615 thing as one line. The caller decides when a line is continued. */
618 gobble_line (int fd
, register struct termcap_buffer
*bufp
, char *append_end
)
622 register char *buf
= bufp
->beg
;
626 append_end
= bufp
->ptr
;
631 while (*end
&& *end
!= '\n') end
++;
635 return buf
+ bufp
->full
;
636 if (bufp
->ptr
== buf
)
638 if (bufp
->full
== bufp
->size
)
641 /* Add 1 to size to ensure room for terminating null. */
642 tem
= (char *) xrealloc (buf
, bufp
->size
+ 1);
643 bufp
->ptr
= (bufp
->ptr
- buf
) + tem
;
644 append_end
= (append_end
- buf
) + tem
;
645 bufp
->beg
= buf
= tem
;
650 append_end
-= bufp
->ptr
- buf
;
651 memcpy (buf
, bufp
->ptr
, bufp
->full
-= bufp
->ptr
- buf
);
654 if (!(nread
= read (fd
, buf
+ bufp
->full
, bufp
->size
- bufp
->full
)))
657 buf
[bufp
->full
] = '\0';
678 printf ("TERM: %s\n", term
);
680 buf
= (char *) tgetent (0, term
);
683 printf ("No entry.\n");
687 printf ("Entry: %s\n", buf
);
692 printf ("co: %d\n", tgetnum ("co"));
693 printf ("am: %d\n", tgetflag ("am"));
699 char *x
= tgetstr (cap
, 0);
702 printf ("%s: ", cap
);
706 if (*y
<= ' ' || *y
== 0177)
707 printf ("\\%0o", *y
);