1 /* Work-alike for termcap, plus extra features.
2 Copyright (C) 1985, 1986, 1993, 1994, 1995, 2000, 2001, 2002, 2003,
3 2004, 2005 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
;
147 /* These are already defined in the System framework in Mac OS X and
148 cause prebinding to fail. */
154 register char *ptr
= find_capability (term_entry
, cap
);
155 if (!ptr
|| ptr
[-1] != '#')
164 register char *ptr
= find_capability (term_entry
, cap
);
165 return ptr
&& ptr
[-1] == ':';
168 /* Look up a string-valued capability CAP.
169 If AREA is non-null, it points to a pointer to a block in which
170 to store the string. That pointer is advanced over the space used.
171 If AREA is null, space is allocated with `malloc'. */
178 register char *ptr
= find_capability (term_entry
, cap
);
179 if (!ptr
|| (ptr
[-1] != '=' && ptr
[-1] != '~'))
181 return tgetst1 (ptr
, area
);
185 #ifdef IS_EBCDIC_HOST
186 /* Table, indexed by a character in range 0200 to 0300 with 0200 subtracted,
187 gives meaning of character following \, or a space if no special meaning.
188 Sixteen characters per line within the string. */
191 = " \057\026 \047\014 \
196 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
197 gives meaning of character following \, or a space if no special meaning.
198 Eight characters per line within the string. */
201 = " \007\010 \033\014 \
207 /* PTR points to a string value inside a termcap entry.
208 Copy that value, processing \ and ^ abbreviations,
209 into the block that *AREA points to,
210 or to newly allocated storage if AREA is NULL.
211 Return the address to which we copied the value,
212 or NULL if PTR is NULL. */
219 register char *p
, *r
;
228 /* `ret' gets address of where to store the string. */
231 /* Compute size of block needed (may overestimate). */
233 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
235 ret
= (char *) xmalloc (p
- ptr
+ 1);
240 /* Copy the string value, stopping at null or colon.
241 Also process ^ and \ abbreviations. */
244 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
257 if (c
>= '0' && c
<= '7')
262 while (++size
< 3 && (c1
= *p
) >= '0' && c1
<= '7')
269 #ifdef IS_EBCDIC_HOST
270 else if (c
>= 0200 && c
< 0360)
272 c1
= esctab
[(c
& ~0100) - 0200];
277 else if (c
>= 0100 && c
< 0200)
279 c1
= esctab
[(c
& ~040) - 0100];
288 /* Sometimes entries have "%pN" which means use parameter N in the
289 next %-substitution. If all such N are continuous in the range
290 [1,9] we can remove each "%pN" because they are redundant, thus
291 reducing bandwidth requirements. True, Emacs is well beyond the
292 days of 150baud teletypes, but some of its users aren't much so.
294 This pass could probably be integrated into the one above but
295 abbreviation expansion makes that effort a little more hairy than
296 its worth; this is cleaner. */
298 register int last_p_param
= 0;
299 int remove_p_params
= 1;
300 struct { char *beg
; int len
; } cut
[11];
302 for (cut
[0].beg
= p
= ret
; p
< r
- 3; p
++)
304 if (!remove_p_params
)
306 if (*p
== '%' && *(p
+ 1) == 'p')
308 if (*(p
+ 2) - '0' == 1 + last_p_param
)
310 cut
[last_p_param
].len
= p
- cut
[last_p_param
].beg
;
313 cut
[last_p_param
].beg
= p
;
315 else /* not continuous: bail */
317 if (last_p_param
> 10) /* too many: bail */
321 if (remove_p_params
&& last_p_param
)
326 cut
[last_p_param
].len
= r
- cut
[last_p_param
].beg
;
327 for (i
= 0, wp
= ret
; i
<= last_p_param
; wp
+= cut
[i
++].len
)
328 bcopy (cut
[i
].beg
, wp
, cut
[i
].len
);
340 /* Outputting a string with padding. */
344 /* If OSPEED is 0, we use this as the actual baud rate. */
348 /* Already defined in the System framework in Mac OS X and causes
349 prebinding to fail. */
355 /* Actual baud rate if positive;
356 - baud rate / 100 if negative. */
358 static int speeds
[] =
361 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
362 -20, -24, -36, -48, -72, -96, -192
364 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
365 -18, -24, -48, -96, -192, -288, -384, -576, -1152
369 #endif /* not emacs */
371 /* Already defined in the System framework in Mac OS X and causes
372 prebinding to fail. */
375 tputs (str
, nlines
, outfun
)
378 register int (*outfun
) ();
380 register int padcount
= 0;
384 extern EMACS_INT baud_rate
;
386 /* For quite high speeds, convert to the smaller
387 units to avoid overflow. */
389 speed
= - speed
/ 100;
392 speed
= tputs_baud_rate
;
394 speed
= speeds
[ospeed
];
400 while (*str
>= '0' && *str
<= '9')
402 padcount
+= *str
++ - '0';
408 padcount
+= *str
++ - '0';
418 /* PADCOUNT is now in units of tenths of msec.
419 SPEED is measured in characters per 10 seconds
420 or in characters per .1 seconds (if negative).
421 We use the smaller units for larger speeds to avoid overflow. */
426 padcount
= -padcount
;
433 while (padcount
-- > 0)
438 /* Finding the termcap entry in the termcap data base. */
440 struct termcap_buffer
449 /* Forward declarations of static functions. */
451 static int scan_file ();
452 static char *gobble_line ();
453 static int compare_contin ();
454 static int name_match ();
464 valid_filename_p (fn
)
467 struct FAB fab
= cc$rms_fab
;
468 struct NAM nam
= cc$rms_nam
;
469 char esa
[NAM$C_MAXRSS
];
472 fab
.fab$b_fns
= strlen(fn
);
473 fab
.fab$l_nam
= &nam
;
474 fab
.fab$l_fop
= FAB$M_NAM
;
477 nam
.nam$b_ess
= sizeof esa
;
479 return SYS$
PARSE(&fab
, 0, 0) == RMS$_NORMAL
;
484 #ifdef MSDOS /* MW, May 1993 */
486 valid_filename_p (fn
)
489 return *fn
== '/' || fn
[1] == ':';
492 #define valid_filename_p(fn) (*(fn) == '/')
497 /* Find the termcap entry data for terminal type NAME
498 and store it in the block that BP points to.
499 Record its address for future use.
501 If BP is null, space is dynamically allocated.
503 Return -1 if there is some difficulty accessing the data base
505 0 if the data base is accessible but the type NAME is not defined
506 in it, and some other value otherwise. */
508 /* Already defined in the System framework in Mac OS X and causes
509 prebinding to fail. */
515 register char *termcap_name
;
517 struct termcap_buffer buf
;
519 char *tc_search_point
;
523 char *tcenv
= NULL
; /* TERMCAP value, if it contains :tc=. */
524 char *indirect
= NULL
; /* Terminal type in :tc= in TERMCAP value. */
527 #ifdef INTERNAL_TERMINAL
528 /* For the internal terminal we don't want to read any termcap file,
530 if (!strcmp (name
, "internal"))
532 term
= INTERNAL_TERMINAL
;
535 malloc_size
= 1 + strlen (term
);
536 bp
= (char *) xmalloc (malloc_size
);
541 #endif /* INTERNAL_TERMINAL */
543 /* For compatibility with programs like `less' that want to
544 put data in the termcap buffer themselves as a fallback. */
548 termcap_name
= getenv ("TERMCAP");
549 if (termcap_name
&& *termcap_name
== '\0')
551 #if defined (MSDOS) && !defined (TEST)
552 if (termcap_name
&& (*termcap_name
== '\\'
553 || *termcap_name
== '/'
554 || termcap_name
[1] == ':'))
555 dostounix_filename(termcap_name
);
558 filep
= termcap_name
&& valid_filename_p (termcap_name
);
560 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
561 it is a file name to use instead of /etc/termcap.
562 If it is non-null and does not start with /,
563 it is the entry itself, but only if
564 the name the caller requested matches the TERM variable. */
566 if (termcap_name
&& !filep
&& !strcmp (name
, getenv ("TERM")))
568 indirect
= tgetst1 (find_capability (termcap_name
, "tc"), (char **) 0);
574 strcpy (bp
, termcap_name
);
578 { /* It has tc=. Need to read /etc/termcap. */
579 tcenv
= termcap_name
;
584 if (!termcap_name
|| !filep
)
585 termcap_name
= TERMCAP_FILE
;
587 /* Here we know we must search a file and termcap_name has its name. */
590 fd
= open (termcap_name
, O_RDONLY
|O_TEXT
, 0);
592 fd
= open (termcap_name
, O_RDONLY
, 0);
598 /* Add 1 to size to ensure room for terminating null. */
599 buf
.beg
= (char *) xmalloc (buf
.size
+ 1);
600 term
= indirect
? indirect
: name
;
604 malloc_size
= indirect
? strlen (tcenv
) + 1 : buf
.size
;
605 bp
= (char *) xmalloc (malloc_size
);
607 tc_search_point
= bp1
= bp
;
610 /* Copy the data from the environment variable. */
613 bp1
+= strlen (tcenv
);
618 /* Scan the file, reading it via buf, till find start of main entry. */
619 if (scan_file (term
, fd
, &buf
) == 0)
628 /* Free old `term' if appropriate. */
632 /* If BP is malloc'd by us, make sure it is big enough. */
635 int offset1
= bp1
- bp
, offset2
= tc_search_point
- bp
;
636 malloc_size
= offset1
+ buf
.size
;
637 bp
= termcap_name
= (char *) xrealloc (bp
, malloc_size
);
638 bp1
= termcap_name
+ offset1
;
639 tc_search_point
= termcap_name
+ offset2
;
642 /* Copy the line of the entry from buf into bp. */
643 termcap_name
= buf
.ptr
;
644 while ((*bp1
++ = c
= *termcap_name
++) && c
!= '\n')
645 /* Drop out any \ newline sequence. */
646 if (c
== '\\' && *termcap_name
== '\n')
653 /* Does this entry refer to another terminal type's entry?
654 If something is found, copy it into heap and null-terminate it. */
655 tc_search_point
= find_capability (tc_search_point
, "tc");
656 term
= tgetst1 (tc_search_point
, (char **) 0);
663 bp
= (char *) xrealloc (bp
, bp1
- bp
+ 1);
671 /* Given file open on FD and buffer BUFP,
672 scan the file from the beginning until a line is found
673 that starts the entry for terminal type STR.
674 Return 1 if successful, with that line in BUFP,
675 or 0 if no entry is found in the file. */
678 scan_file (str
, fd
, bufp
)
681 register struct termcap_buffer
*bufp
;
685 bufp
->ptr
= bufp
->beg
;
694 /* Read a line into the buffer. */
698 /* if it is continued, append another line to it,
699 until a non-continued line ends. */
700 end
= gobble_line (fd
, bufp
, end
);
702 while (!bufp
->ateof
&& end
[-2] == '\\');
704 if (*bufp
->ptr
!= '#'
705 && name_match (bufp
->ptr
, str
))
708 /* Discard the line just processed. */
714 /* Return nonzero if NAME is one of the names specified
715 by termcap entry LINE. */
718 name_match (line
, name
)
723 if (!compare_contin (line
, name
))
725 /* This line starts an entry. Is it the right one? */
726 for (tem
= line
; *tem
&& *tem
!= '\n' && *tem
!= ':'; tem
++)
727 if (*tem
== '|' && !compare_contin (tem
+ 1, name
))
734 compare_contin (str1
, str2
)
735 register char *str1
, *str2
;
742 while (c1
== '\\' && *str1
== '\n')
745 while ((c1
= *str1
++) == ' ' || c1
== '\t');
749 /* End of type being looked up. */
750 if (c1
== '|' || c1
== ':')
751 /* If end of name in data base, we win. */
761 /* Make sure that the buffer <- BUFP contains a full line
762 of the file open on FD, starting at the place BUFP->ptr
763 points to. Can read more of the file, discard stuff before
764 BUFP->ptr, or make the buffer bigger.
766 Return the pointer to after the newline ending the line,
767 or to the end of the file, if there is no newline to end it.
769 Can also merge on continuation lines. If APPEND_END is
770 non-null, it points past the newline of a line that is
771 continued; we add another line onto it and regard the whole
772 thing as one line. The caller decides when a line is continued. */
775 gobble_line (fd
, bufp
, append_end
)
777 register struct termcap_buffer
*bufp
;
782 register char *buf
= bufp
->beg
;
786 append_end
= bufp
->ptr
;
791 while (*end
&& *end
!= '\n') end
++;
795 return buf
+ bufp
->full
;
796 if (bufp
->ptr
== buf
)
798 if (bufp
->full
== bufp
->size
)
801 /* Add 1 to size to ensure room for terminating null. */
802 tem
= (char *) xrealloc (buf
, bufp
->size
+ 1);
803 bufp
->ptr
= (bufp
->ptr
- buf
) + tem
;
804 append_end
= (append_end
- buf
) + tem
;
805 bufp
->beg
= buf
= tem
;
810 append_end
-= bufp
->ptr
- buf
;
811 bcopy (bufp
->ptr
, buf
, bufp
->full
-= bufp
->ptr
- buf
);
814 if (!(nread
= read (fd
, buf
+ bufp
->full
, bufp
->size
- bufp
->full
)))
817 buf
[bufp
->full
] = '\0';
838 printf ("TERM: %s\n", term
);
840 buf
= (char *) tgetent (0, term
);
843 printf ("No entry.\n");
847 printf ("Entry: %s\n", buf
);
852 printf ("co: %d\n", tgetnum ("co"));
853 printf ("am: %d\n", tgetflag ("am"));
859 char *x
= tgetstr (cap
, 0);
862 printf ("%s: ", cap
);
866 if (*y
<= ' ' || *y
== 0177)
867 printf ("\\%0o", *y
);
879 /* arch-tag: c2e8d427-2271-4fac-95fe-411857238b80
880 (do not change this comment) */