]>
git.ipfire.org Git - thirdparty/bash.git/blob - lib/termcap/termcap.c
1 /* Work-alike for termcap, plus extra features.
2 Copyright (C) 1985, 86, 93, 94, 95 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. If not, write to the
16 Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
18 /* Emacs config.h may rename various library functions such as malloc. */
23 /* Get the O_* definitions for open et al. */
33 extern char *getenv ();
34 extern char *malloc ();
35 extern char *realloc ();
38 #else /* not HAVE_CONFIG_H */
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 HAVE_CONFIG_H */
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
91 #define TERMCAP_FILE "/etc/termcap"
98 write (2, "virtual memory exhausted\n", 25);
106 register char *tem
= malloc (size
);
118 register char *tem
= realloc (ptr
, size
);
124 #endif /* not emacs */
126 /* Looking up capabilities in the entry already found. */
128 /* The pointer to the data made by tgetent is left here
129 for tgetnum, tgetflag and tgetstr to find. */
130 static char *term_entry
;
132 static char *tgetst1 ();
134 /* Search entry BP for capability CAP.
135 Return a pointer to the capability (in BP) if found,
139 find_capability (bp
, cap
)
140 register char *bp
, *cap
;
155 register char *ptr
= find_capability (term_entry
, cap
);
156 if (!ptr
|| ptr
[-1] != '#')
166 register char *ptr
= find_capability (term_entry
, cap
);
167 return ptr
&& ptr
[-1] == ':';
170 /* Look up a string-valued capability CAP.
171 If AREA is non-null, it points to a pointer to a block in which
172 to store the string. That pointer is advanced over the space used.
173 If AREA is null, space is allocated with `malloc'. */
181 register char *ptr
= find_capability (term_entry
, cap
);
182 if (!ptr
|| (ptr
[-1] != '=' && ptr
[-1] != '~'))
184 return tgetst1 (ptr
, area
);
187 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
188 gives meaning of character following \, or a space if no special meaning.
189 Eight characters per line within the string. */
192 = " \007\010 \033\014 \
197 /* PTR points to a string value inside a termcap entry.
198 Copy that value, processing \ and ^ abbreviations,
199 into the block that *AREA points to,
200 or to newly allocated storage if AREA is NULL.
201 Return the address to which we copied the value,
202 or NULL if PTR is NULL. */
209 register char *p
, *r
;
218 /* `ret' gets address of where to store the string. */
221 /* Compute size of block needed (may overestimate). */
223 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
225 ret
= (char *) xmalloc (p
- ptr
+ 1);
230 /* Copy the string value, stopping at null or colon.
231 Also process ^ and \ abbreviations. */
234 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
247 if (c
>= '0' && c
<= '7')
252 while (++size
< 3 && (c1
= *p
) >= '0' && c1
<= '7')
259 else if (c
>= 0100 && c
< 0200)
261 c1
= esctab
[(c
& ~040) - 0100];
275 /* Outputting a string with padding. */
278 /* If OSPEED is 0, we use this as the actual baud rate. */
280 __private_extern__
char PC
= '\0';
282 /* Actual baud rate if positive;
283 - baud rate / 100 if negative. */
285 static int speeds
[] =
288 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
289 -20, -24, -36, -48, -72, -96, -192
291 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
292 -18, -24, -48, -96, -192, -288, -384, -576, -1152
298 tputs (str
, nlines
, outfun
)
301 register int (*outfun
) ();
303 register int padcount
= 0;
309 /* For quite high speeds, convert to the smaller
310 units to avoid overflow. */
312 speed
= - speed
/ 100;
315 speed
= tputs_baud_rate
;
316 else if (ospeed
> 0 && ospeed
< (sizeof speeds
/ sizeof speeds
[0]))
317 speed
= speeds
[ospeed
];
325 while (*str
>= '0' && *str
<= '9')
327 padcount
+= *str
++ - '0';
333 padcount
+= *str
++ - '0';
343 /* PADCOUNT is now in units of tenths of msec.
344 SPEED is measured in characters per 10 seconds
345 or in characters per .1 seconds (if negative).
346 We use the smaller units for larger speeds to avoid overflow. */
351 padcount
= -padcount
;
358 while (padcount
-- > 0)
362 /* Finding the termcap entry in the termcap data base. */
373 /* Forward declarations of static functions. */
375 static int scan_file ();
376 static char *gobble_line ();
377 static int compare_contin ();
378 static int name_match ();
387 valid_filename_p (fn
)
390 struct FAB fab
= cc$rms_fab
;
391 struct NAM nam
= cc$rms_nam
;
392 char esa
[NAM$C_MAXRSS
];
395 fab
.fab$b_fns
= strlen(fn
);
396 fab
.fab$l_nam
= &nam
;
397 fab
.fab$l_fop
= FAB$M_NAM
;
400 nam
.nam$b_ess
= sizeof esa
;
402 return SYS$
PARSE(&fab
, 0, 0) == RMS$_NORMAL
;
407 #ifdef MSDOS /* MW, May 1993 */
409 valid_filename_p (fn
)
412 return *fn
== '\\' || *fn
== '/' ||
413 (*fn
>= 'A' && *fn
<= 'z' && fn
[1] == ':');
416 #define valid_filename_p(fn) (*(fn) == '/')
421 /* Find the termcap entry data for terminal type NAME
422 and store it in the block that BP points to.
423 Record its address for future use.
425 If BP is null, space is dynamically allocated.
427 Return -1 if there is some difficulty accessing the data base
429 0 if the data base is accessible but the type NAME is not defined
430 in it, and some other value otherwise. */
437 register char *termcap_name
;
445 char *tcenv
; /* TERMCAP value, if it contains :tc=. */
446 char *indirect
= NULL
; /* Terminal type in :tc= in TERMCAP value. */
449 #ifdef INTERNAL_TERMINAL
450 /* For the internal terminal we don't want to read any termcap file,
452 if (!strcmp (name
, "internal"))
454 term
= INTERNAL_TERMINAL
;
457 malloc_size
= 1 + strlen (term
);
458 bp
= (char *) xmalloc (malloc_size
);
463 #endif /* INTERNAL_TERMINAL */
465 /* For compatibility with programs like `less' that want to
466 put data in the termcap buffer themselves as a fallback. */
470 termcap_name
= getenv ("TERMCAP");
471 if (termcap_name
&& *termcap_name
== '\0')
474 #if defined (MSDOS) && !defined (TEST)
475 if (termcap_name
&& (*termcap_name
== '\\'
476 || *termcap_name
== '/'
477 || termcap_name
[1] == ':'))
478 dostounix_filename(termcap_name
);
482 filep
= termcap_name
&& valid_filename_p (termcap_name
);
484 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
485 it is a file name to use instead of /etc/termcap.
486 If it is non-null and does not start with /,
487 it is the entry itself, but only if
488 the name the caller requested matches the TERM variable. */
490 if (termcap_name
&& !filep
&& !strcmp (name
, getenv ("TERM")))
492 indirect
= tgetst1 (find_capability (termcap_name
, "tc"), (char **) 0);
498 strcpy (bp
, termcap_name
);
502 { /* It has tc=. Need to read /etc/termcap. */
503 tcenv
= termcap_name
;
508 if (!termcap_name
|| !filep
)
509 termcap_name
= TERMCAP_FILE
;
511 /* Here we know we must search a file and termcap_name has its name. */
514 fd
= open (termcap_name
, O_RDONLY
|O_TEXT
, 0);
516 fd
= open (termcap_name
, O_RDONLY
, 0);
522 /* Add 1 to size to ensure room for terminating null. */
523 buf
.beg
= (char *) xmalloc (buf
.size
+ 1);
524 term
= indirect
? indirect
: name
;
528 malloc_size
= indirect
? strlen (tcenv
) + 1 : buf
.size
;
529 bp
= (char *) xmalloc (malloc_size
);
534 /* Copy the data from the environment variable. */
537 bp1
+= strlen (tcenv
);
542 /* Scan the file, reading it via buf, till find start of main entry. */
543 if (scan_file (term
, fd
, &buf
) == 0)
552 /* Free old `term' if appropriate. */
556 /* If BP is malloc'd by us, make sure it is big enough. */
559 malloc_size
= bp1
- bp
+ buf
.size
;
560 termcap_name
= (char *) xrealloc (bp
, malloc_size
);
561 bp1
+= termcap_name
- bp
;
567 /* Copy the line of the entry from buf into bp. */
568 termcap_name
= buf
.ptr
;
569 while ((*bp1
++ = c
= *termcap_name
++) && c
!= '\n')
570 /* Drop out any \ newline sequence. */
571 if (c
== '\\' && *termcap_name
== '\n')
578 /* Does this entry refer to another terminal type's entry?
579 If something is found, copy it into heap and null-terminate it. */
580 term
= tgetst1 (find_capability (bp2
, "tc"), (char **) 0);
587 bp
= (char *) xrealloc (bp
, bp1
- bp
+ 1);
594 /* Given file open on FD and buffer BUFP,
595 scan the file from the beginning until a line is found
596 that starts the entry for terminal type STR.
597 Return 1 if successful, with that line in BUFP,
598 or 0 if no entry is found in the file. */
601 scan_file (str
, fd
, bufp
)
604 register struct buffer
*bufp
;
608 bufp
->ptr
= bufp
->beg
;
617 /* Read a line into the buffer. */
621 /* if it is continued, append another line to it,
622 until a non-continued line ends. */
623 end
= gobble_line (fd
, bufp
, end
);
625 while (!bufp
->ateof
&& end
[-2] == '\\');
627 if (*bufp
->ptr
!= '#'
628 && name_match (bufp
->ptr
, str
))
631 /* Discard the line just processed. */
637 /* Return nonzero if NAME is one of the names specified
638 by termcap entry LINE. */
641 name_match (line
, name
)
646 if (!compare_contin (line
, name
))
648 /* This line starts an entry. Is it the right one? */
649 for (tem
= line
; *tem
&& *tem
!= '\n' && *tem
!= ':'; tem
++)
650 if (*tem
== '|' && !compare_contin (tem
+ 1, name
))
657 compare_contin (str1
, str2
)
658 register char *str1
, *str2
;
665 while (c1
== '\\' && *str1
== '\n')
668 while ((c1
= *str1
++) == ' ' || c1
== '\t');
672 /* End of type being looked up. */
673 if (c1
== '|' || c1
== ':')
674 /* If end of name in data base, we win. */
684 /* Make sure that the buffer <- BUFP contains a full line
685 of the file open on FD, starting at the place BUFP->ptr
686 points to. Can read more of the file, discard stuff before
687 BUFP->ptr, or make the buffer bigger.
689 Return the pointer to after the newline ending the line,
690 or to the end of the file, if there is no newline to end it.
692 Can also merge on continuation lines. If APPEND_END is
693 non-null, it points past the newline of a line that is
694 continued; we add another line onto it and regard the whole
695 thing as one line. The caller decides when a line is continued. */
698 gobble_line (fd
, bufp
, append_end
)
700 register struct buffer
*bufp
;
705 register char *buf
= bufp
->beg
;
709 append_end
= bufp
->ptr
;
714 while (*end
&& *end
!= '\n') end
++;
718 return buf
+ bufp
->full
;
719 if (bufp
->ptr
== buf
)
721 if (bufp
->full
== bufp
->size
)
724 /* Add 1 to size to ensure room for terminating null. */
725 tem
= (char *) xrealloc (buf
, bufp
->size
+ 1);
726 bufp
->ptr
= (bufp
->ptr
- buf
) + tem
;
727 append_end
= (append_end
- buf
) + tem
;
728 bufp
->beg
= buf
= tem
;
733 append_end
-= bufp
->ptr
- buf
;
734 bcopy (bufp
->ptr
, buf
, bufp
->full
-= bufp
->ptr
- buf
);
737 if (!(nread
= read (fd
, buf
+ bufp
->full
, bufp
->size
- bufp
->full
)))
740 buf
[bufp
->full
] = '\0';
761 printf ("TERM: %s\n", term
);
763 buf
= (char *) tgetent (0, term
);
766 printf ("No entry.\n");
770 printf ("Entry: %s\n", buf
);
775 printf ("co: %d\n", tgetnum ("co"));
776 printf ("am: %d\n", tgetflag ("am"));
782 char *x
= tgetstr (cap
, 0);
785 printf ("%s: ", cap
);
789 if (*y
<= ' ' || *y
== 0177)
790 printf ("\\%0o", *y
);