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. */
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];
284 /* Sometimes entries have "%pN" which means use parameter N in the
285 next %-substitution. If all such N are continuous in the range
286 [1,9] we can remove each "%pN" because they are redundant, thus
287 reducing bandwidth requirements. True, Emacs is well beyond the
288 days of 150baud teletypes, but some of its users aren't much so.
290 This pass could probably be integrated into the one above but
291 abbreviation expansion makes that effort a little more hairy than
292 its worth; this is cleaner. */
294 register int last_p_param
= 0;
295 int remove_p_params
= 1;
296 struct { char *beg
; int len
; } cut
[11];
298 for (cut
[0].beg
= p
= ret
; p
< r
- 3; p
++)
300 if (!remove_p_params
)
302 if (*p
== '%' && *(p
+ 1) == 'p')
304 if (*(p
+ 2) - '0' == 1 + last_p_param
)
306 cut
[last_p_param
].len
= p
- cut
[last_p_param
].beg
;
309 cut
[last_p_param
].beg
= p
;
311 else /* not continuous: bail */
313 if (last_p_param
> 10) /* too many: bail */
317 if (remove_p_params
&& last_p_param
)
322 cut
[last_p_param
].len
= r
- cut
[last_p_param
].beg
;
323 for (i
= 0, wp
= ret
; i
<= last_p_param
; wp
+= cut
[i
++].len
)
324 bcopy (cut
[i
].beg
, wp
, cut
[i
].len
);
336 /* Outputting a string with padding. */
340 /* If OSPEED is 0, we use this as the actual baud rate. */
347 /* Actual baud rate if positive;
348 - baud rate / 100 if negative. */
350 static int speeds
[] =
353 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
354 -20, -24, -36, -48, -72, -96, -192
356 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
357 -18, -24, -48, -96, -192, -288, -384, -576, -1152
361 #endif /* not emacs */
364 tputs (str
, nlines
, outfun
)
367 register int (*outfun
) ();
369 register int padcount
= 0;
373 extern EMACS_INT baud_rate
;
375 /* For quite high speeds, convert to the smaller
376 units to avoid overflow. */
378 speed
= - speed
/ 100;
381 speed
= tputs_baud_rate
;
383 speed
= speeds
[ospeed
];
389 while (*str
>= '0' && *str
<= '9')
391 padcount
+= *str
++ - '0';
397 padcount
+= *str
++ - '0';
407 /* PADCOUNT is now in units of tenths of msec.
408 SPEED is measured in characters per 10 seconds
409 or in characters per .1 seconds (if negative).
410 We use the smaller units for larger speeds to avoid overflow. */
415 padcount
= -padcount
;
422 while (padcount
-- > 0)
426 /* Finding the termcap entry in the termcap data base. */
428 struct termcap_buffer
437 /* Forward declarations of static functions. */
439 static int scan_file ();
440 static char *gobble_line ();
441 static int compare_contin ();
442 static int name_match ();
452 valid_filename_p (fn
)
455 struct FAB fab
= cc$rms_fab
;
456 struct NAM nam
= cc$rms_nam
;
457 char esa
[NAM$C_MAXRSS
];
460 fab
.fab$b_fns
= strlen(fn
);
461 fab
.fab$l_nam
= &nam
;
462 fab
.fab$l_fop
= FAB$M_NAM
;
465 nam
.nam$b_ess
= sizeof esa
;
467 return SYS$
PARSE(&fab
, 0, 0) == RMS$_NORMAL
;
472 #ifdef MSDOS /* MW, May 1993 */
474 valid_filename_p (fn
)
477 return *fn
== '/' || fn
[1] == ':';
480 #define valid_filename_p(fn) (*(fn) == '/')
485 /* Find the termcap entry data for terminal type NAME
486 and store it in the block that BP points to.
487 Record its address for future use.
489 If BP is null, space is dynamically allocated.
491 Return -1 if there is some difficulty accessing the data base
493 0 if the data base is accessible but the type NAME is not defined
494 in it, and some other value otherwise. */
500 register char *termcap_name
;
502 struct termcap_buffer buf
;
504 char *tc_search_point
;
508 char *tcenv
= NULL
; /* TERMCAP value, if it contains :tc=. */
509 char *indirect
= NULL
; /* Terminal type in :tc= in TERMCAP value. */
512 #ifdef INTERNAL_TERMINAL
513 /* For the internal terminal we don't want to read any termcap file,
515 if (!strcmp (name
, "internal"))
517 term
= INTERNAL_TERMINAL
;
520 malloc_size
= 1 + strlen (term
);
521 bp
= (char *) xmalloc (malloc_size
);
526 #endif /* INTERNAL_TERMINAL */
528 /* For compatibility with programs like `less' that want to
529 put data in the termcap buffer themselves as a fallback. */
533 termcap_name
= getenv ("TERMCAP");
534 if (termcap_name
&& *termcap_name
== '\0')
536 #if defined (MSDOS) && !defined (TEST)
537 if (termcap_name
&& (*termcap_name
== '\\'
538 || *termcap_name
== '/'
539 || termcap_name
[1] == ':'))
540 dostounix_filename(termcap_name
);
543 filep
= termcap_name
&& valid_filename_p (termcap_name
);
545 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
546 it is a file name to use instead of /etc/termcap.
547 If it is non-null and does not start with /,
548 it is the entry itself, but only if
549 the name the caller requested matches the TERM variable. */
551 if (termcap_name
&& !filep
&& !strcmp (name
, getenv ("TERM")))
553 indirect
= tgetst1 (find_capability (termcap_name
, "tc"), (char **) 0);
559 strcpy (bp
, termcap_name
);
563 { /* It has tc=. Need to read /etc/termcap. */
564 tcenv
= termcap_name
;
569 if (!termcap_name
|| !filep
)
570 termcap_name
= TERMCAP_FILE
;
572 /* Here we know we must search a file and termcap_name has its name. */
575 fd
= open (termcap_name
, O_RDONLY
|O_TEXT
, 0);
577 fd
= open (termcap_name
, O_RDONLY
, 0);
583 /* Add 1 to size to ensure room for terminating null. */
584 buf
.beg
= (char *) xmalloc (buf
.size
+ 1);
585 term
= indirect
? indirect
: name
;
589 malloc_size
= indirect
? strlen (tcenv
) + 1 : buf
.size
;
590 bp
= (char *) xmalloc (malloc_size
);
592 tc_search_point
= bp1
= bp
;
595 /* Copy the data from the environment variable. */
598 bp1
+= strlen (tcenv
);
603 /* Scan the file, reading it via buf, till find start of main entry. */
604 if (scan_file (term
, fd
, &buf
) == 0)
613 /* Free old `term' if appropriate. */
617 /* If BP is malloc'd by us, make sure it is big enough. */
620 int offset1
= bp1
- bp
, offset2
= tc_search_point
- bp
;
621 malloc_size
= offset1
+ buf
.size
;
622 bp
= termcap_name
= (char *) xrealloc (bp
, malloc_size
);
623 bp1
= termcap_name
+ offset1
;
624 tc_search_point
= termcap_name
+ offset2
;
627 /* Copy the line of the entry from buf into bp. */
628 termcap_name
= buf
.ptr
;
629 while ((*bp1
++ = c
= *termcap_name
++) && c
!= '\n')
630 /* Drop out any \ newline sequence. */
631 if (c
== '\\' && *termcap_name
== '\n')
638 /* Does this entry refer to another terminal type's entry?
639 If something is found, copy it into heap and null-terminate it. */
640 tc_search_point
= find_capability (tc_search_point
, "tc");
641 term
= tgetst1 (tc_search_point
, (char **) 0);
648 bp
= (char *) xrealloc (bp
, bp1
- bp
+ 1);
655 /* Given file open on FD and buffer BUFP,
656 scan the file from the beginning until a line is found
657 that starts the entry for terminal type STR.
658 Return 1 if successful, with that line in BUFP,
659 or 0 if no entry is found in the file. */
662 scan_file (str
, fd
, bufp
)
665 register struct termcap_buffer
*bufp
;
669 bufp
->ptr
= bufp
->beg
;
678 /* Read a line into the buffer. */
682 /* if it is continued, append another line to it,
683 until a non-continued line ends. */
684 end
= gobble_line (fd
, bufp
, end
);
686 while (!bufp
->ateof
&& end
[-2] == '\\');
688 if (*bufp
->ptr
!= '#'
689 && name_match (bufp
->ptr
, str
))
692 /* Discard the line just processed. */
698 /* Return nonzero if NAME is one of the names specified
699 by termcap entry LINE. */
702 name_match (line
, name
)
707 if (!compare_contin (line
, name
))
709 /* This line starts an entry. Is it the right one? */
710 for (tem
= line
; *tem
&& *tem
!= '\n' && *tem
!= ':'; tem
++)
711 if (*tem
== '|' && !compare_contin (tem
+ 1, name
))
718 compare_contin (str1
, str2
)
719 register char *str1
, *str2
;
726 while (c1
== '\\' && *str1
== '\n')
729 while ((c1
= *str1
++) == ' ' || c1
== '\t');
733 /* End of type being looked up. */
734 if (c1
== '|' || c1
== ':')
735 /* If end of name in data base, we win. */
745 /* Make sure that the buffer <- BUFP contains a full line
746 of the file open on FD, starting at the place BUFP->ptr
747 points to. Can read more of the file, discard stuff before
748 BUFP->ptr, or make the buffer bigger.
750 Return the pointer to after the newline ending the line,
751 or to the end of the file, if there is no newline to end it.
753 Can also merge on continuation lines. If APPEND_END is
754 non-null, it points past the newline of a line that is
755 continued; we add another line onto it and regard the whole
756 thing as one line. The caller decides when a line is continued. */
759 gobble_line (fd
, bufp
, append_end
)
761 register struct termcap_buffer
*bufp
;
766 register char *buf
= bufp
->beg
;
770 append_end
= bufp
->ptr
;
775 while (*end
&& *end
!= '\n') end
++;
779 return buf
+ bufp
->full
;
780 if (bufp
->ptr
== buf
)
782 if (bufp
->full
== bufp
->size
)
785 /* Add 1 to size to ensure room for terminating null. */
786 tem
= (char *) xrealloc (buf
, bufp
->size
+ 1);
787 bufp
->ptr
= (bufp
->ptr
- buf
) + tem
;
788 append_end
= (append_end
- buf
) + tem
;
789 bufp
->beg
= buf
= tem
;
794 append_end
-= bufp
->ptr
- buf
;
795 bcopy (bufp
->ptr
, buf
, bufp
->full
-= bufp
->ptr
- buf
);
798 if (!(nread
= read (fd
, buf
+ bufp
->full
, bufp
->size
- bufp
->full
)))
801 buf
[bufp
->full
] = '\0';
822 printf ("TERM: %s\n", term
);
824 buf
= (char *) tgetent (0, term
);
827 printf ("No entry.\n");
831 printf ("Entry: %s\n", buf
);
836 printf ("co: %d\n", tgetnum ("co"));
837 printf ("am: %d\n", tgetflag ("am"));
843 char *x
= tgetstr (cap
, 0);
846 printf ("%s: ", cap
);
850 if (*y
<= ' ' || *y
== 0177)
851 printf ("\\%0o", *y
);
863 /* arch-tag: c2e8d427-2271-4fac-95fe-411857238b80
864 (do not change this comment) */