]>
git.ipfire.org Git - thirdparty/bash.git/blob - lib/termcap/termcap.c
2a270c454eb66da96633feac6083a0c5f87bde1e
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
16 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
18 /* Emacs config.h may rename various library functions such as malloc. */
23 /* Get the O_* definitions for open et al. */
29 #else /* not HAVE_CONFIG_H */
40 /* Do this after the include, in case string.h prototypes bcopy. */
41 #if (defined(HAVE_STRING_H) || defined(STDC_HEADERS)) && !defined(bcopy)
42 #define bcopy(s, d, n) memcpy ((d), (s), (n))
52 #endif /* not HAVE_CONFIG_H */
55 #define NULL (char *) 0
62 /* BUFSIZE is the initial size allocated for the buffer
63 for reading the termcap file.
65 Make it large normally for speed.
66 Make it variable when debugging, so can exercise
67 increasing the space dynamically. */
71 #define BUFSIZE bufsize
80 #define TERMCAP_FILE "/etc/termcap"
87 write (2, "virtual memory exhausted\n", 25);
95 register char *tem
= malloc (size
);
107 register char *tem
= realloc (ptr
, size
);
113 #endif /* not emacs */
115 /* Looking up capabilities in the entry already found. */
117 /* The pointer to the data made by tgetent is left here
118 for tgetnum, tgetflag and tgetstr to find. */
119 static char *term_entry
;
121 static char *tgetst1 ();
123 /* Search entry BP for capability CAP.
124 Return a pointer to the capability (in BP) if found,
128 find_capability (bp
, cap
)
129 register char *bp
, *cap
;
143 register char *ptr
= find_capability (term_entry
, cap
);
144 if (!ptr
|| ptr
[-1] != '#')
153 register char *ptr
= find_capability (term_entry
, cap
);
154 return ptr
&& ptr
[-1] == ':';
157 /* Look up a string-valued capability CAP.
158 If AREA is non-null, it points to a pointer to a block in which
159 to store the string. That pointer is advanced over the space used.
160 If AREA is null, space is allocated with `malloc'. */
167 register char *ptr
= find_capability (term_entry
, cap
);
168 if (!ptr
|| (ptr
[-1] != '=' && ptr
[-1] != '~'))
170 return tgetst1 (ptr
, area
);
173 /* Table, indexed by a character in range 0100 to 0140 with 0100 subtracted,
174 gives meaning of character following \, or a space if no special meaning.
175 Eight characters per line within the string. */
178 = " \007\010 \033\014 \
183 /* PTR points to a string value inside a termcap entry.
184 Copy that value, processing \ and ^ abbreviations,
185 into the block that *AREA points to,
186 or to newly allocated storage if AREA is NULL.
187 Return the address to which we copied the value,
188 or NULL if PTR is NULL. */
195 register char *p
, *r
;
204 /* `ret' gets address of where to store the string. */
207 /* Compute size of block needed (may overestimate). */
209 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
211 ret
= (char *) xmalloc (p
- ptr
+ 1);
216 /* Copy the string value, stopping at null or colon.
217 Also process ^ and \ abbreviations. */
220 while ((c
= *p
++) && c
!= ':' && c
!= '\n')
233 if (c
>= '0' && c
<= '7')
238 while (++size
< 3 && (c1
= *p
) >= '0' && c1
<= '7')
245 else if (c
>= 0100 && c
< 0200)
247 c1
= esctab
[(c
& ~040) - 0100];
261 /* Outputting a string with padding. */
264 /* If OSPEED is 0, we use this as the actual baud rate. */
268 /* Actual baud rate if positive;
269 - baud rate / 100 if negative. */
271 static int speeds
[] =
274 0, 50, 75, 110, 134, 150, -3, -6, -12, -18,
275 -20, -24, -36, -48, -72, -96, -192
277 0, 50, 75, 110, 135, 150, -2, -3, -6, -12,
278 -18, -24, -48, -96, -192, -288, -384, -576, -1152
283 tputs (str
, nlines
, outfun
)
286 register int (*outfun
) ();
288 register int padcount
= 0;
294 /* For quite high speeds, convert to the smaller
295 units to avoid overflow. */
297 speed
= - speed
/ 100;
300 speed
= tputs_baud_rate
;
302 speed
= speeds
[ospeed
];
308 while (*str
>= '0' && *str
<= '9')
310 padcount
+= *str
++ - '0';
316 padcount
+= *str
++ - '0';
326 /* PADCOUNT is now in units of tenths of msec.
327 SPEED is measured in characters per 10 seconds
328 or in characters per .1 seconds (if negative).
329 We use the smaller units for larger speeds to avoid overflow. */
334 padcount
= -padcount
;
341 while (padcount
-- > 0)
345 /* Finding the termcap entry in the termcap data base. */
356 /* Forward declarations of static functions. */
358 static int scan_file ();
359 static char *gobble_line ();
360 static int compare_contin ();
361 static int name_match ();
370 valid_filename_p (fn
)
373 struct FAB fab
= cc$rms_fab
;
374 struct NAM nam
= cc$rms_nam
;
375 char esa
[NAM$C_MAXRSS
];
378 fab
.fab$b_fns
= strlen(fn
);
379 fab
.fab$l_nam
= &nam
;
380 fab
.fab$l_fop
= FAB$M_NAM
;
383 nam
.nam$b_ess
= sizeof esa
;
385 return SYS$
PARSE(&fab
, 0, 0) == RMS$_NORMAL
;
390 #ifdef MSDOS /* MW, May 1993 */
392 valid_filename_p (fn
)
395 return *fn
== '/' || fn
[1] == ':';
398 #define valid_filename_p(fn) (*(fn) == '/')
403 /* Find the termcap entry data for terminal type NAME
404 and store it in the block that BP points to.
405 Record its address for future use.
407 If BP is null, space is dynamically allocated.
409 Return -1 if there is some difficulty accessing the data base
411 0 if the data base is accessible but the type NAME is not defined
412 in it, and some other value otherwise. */
418 register char *termcap_name
;
426 char *tcenv
; /* TERMCAP value, if it contains :tc=. */
427 char *indirect
= NULL
; /* Terminal type in :tc= in TERMCAP value. */
430 #ifdef INTERNAL_TERMINAL
431 /* For the internal terminal we don't want to read any termcap file,
433 if (!strcmp (name
, "internal"))
435 term
= INTERNAL_TERMINAL
;
438 malloc_size
= 1 + strlen (term
);
439 bp
= (char *) xmalloc (malloc_size
);
444 #endif /* INTERNAL_TERMINAL */
446 /* For compatibility with programs like `less' that want to
447 put data in the termcap buffer themselves as a fallback. */
451 termcap_name
= getenv ("TERMCAP");
452 if (termcap_name
&& *termcap_name
== '\0')
454 #if defined (MSDOS) && !defined (TEST)
455 if (termcap_name
&& (*termcap_name
== '\\'
456 || *termcap_name
== '/'
457 || termcap_name
[1] == ':'))
458 dostounix_filename(termcap_name
);
461 filep
= termcap_name
&& valid_filename_p (termcap_name
);
463 /* If termcap_name is non-null and starts with / (in the un*x case, that is),
464 it is a file name to use instead of /etc/termcap.
465 If it is non-null and does not start with /,
466 it is the entry itself, but only if
467 the name the caller requested matches the TERM variable. */
469 if (termcap_name
&& !filep
&& !strcmp (name
, getenv ("TERM")))
471 indirect
= tgetst1 (find_capability (termcap_name
, "tc"), (char **) 0);
477 strcpy (bp
, termcap_name
);
481 { /* It has tc=. Need to read /etc/termcap. */
482 tcenv
= termcap_name
;
487 if (!termcap_name
|| !filep
)
488 termcap_name
= TERMCAP_FILE
;
490 /* Here we know we must search a file and termcap_name has its name. */
493 fd
= open (termcap_name
, O_RDONLY
|O_TEXT
, 0);
495 fd
= open (termcap_name
, O_RDONLY
, 0);
501 /* Add 1 to size to ensure room for terminating null. */
502 buf
.beg
= (char *) xmalloc (buf
.size
+ 1);
503 term
= indirect
? indirect
: name
;
507 malloc_size
= indirect
? strlen (tcenv
) + 1 : buf
.size
;
508 bp
= (char *) xmalloc (malloc_size
);
513 /* Copy the data from the environment variable. */
516 bp1
+= strlen (tcenv
);
521 /* Scan the file, reading it via buf, till find start of main entry. */
522 if (scan_file (term
, fd
, &buf
) == 0)
531 /* Free old `term' if appropriate. */
535 /* If BP is malloc'd by us, make sure it is big enough. */
538 malloc_size
= bp1
- bp
+ buf
.size
;
539 termcap_name
= (char *) xrealloc (bp
, malloc_size
);
540 bp1
+= termcap_name
- bp
;
546 /* Copy the line of the entry from buf into bp. */
547 termcap_name
= buf
.ptr
;
548 while ((*bp1
++ = c
= *termcap_name
++) && c
!= '\n')
549 /* Drop out any \ newline sequence. */
550 if (c
== '\\' && *termcap_name
== '\n')
557 /* Does this entry refer to another terminal type's entry?
558 If something is found, copy it into heap and null-terminate it. */
559 term
= tgetst1 (find_capability (bp2
, "tc"), (char **) 0);
566 bp
= (char *) xrealloc (bp
, bp1
- bp
+ 1);
573 /* Given file open on FD and buffer BUFP,
574 scan the file from the beginning until a line is found
575 that starts the entry for terminal type STR.
576 Return 1 if successful, with that line in BUFP,
577 or 0 if no entry is found in the file. */
580 scan_file (str
, fd
, bufp
)
583 register struct buffer
*bufp
;
587 bufp
->ptr
= bufp
->beg
;
596 /* Read a line into the buffer. */
600 /* if it is continued, append another line to it,
601 until a non-continued line ends. */
602 end
= gobble_line (fd
, bufp
, end
);
604 while (!bufp
->ateof
&& end
[-2] == '\\');
606 if (*bufp
->ptr
!= '#'
607 && name_match (bufp
->ptr
, str
))
610 /* Discard the line just processed. */
616 /* Return nonzero if NAME is one of the names specified
617 by termcap entry LINE. */
620 name_match (line
, name
)
625 if (!compare_contin (line
, name
))
627 /* This line starts an entry. Is it the right one? */
628 for (tem
= line
; *tem
&& *tem
!= '\n' && *tem
!= ':'; tem
++)
629 if (*tem
== '|' && !compare_contin (tem
+ 1, name
))
636 compare_contin (str1
, str2
)
637 register char *str1
, *str2
;
644 while (c1
== '\\' && *str1
== '\n')
647 while ((c1
= *str1
++) == ' ' || c1
== '\t');
651 /* End of type being looked up. */
652 if (c1
== '|' || c1
== ':')
653 /* If end of name in data base, we win. */
663 /* Make sure that the buffer <- BUFP contains a full line
664 of the file open on FD, starting at the place BUFP->ptr
665 points to. Can read more of the file, discard stuff before
666 BUFP->ptr, or make the buffer bigger.
668 Return the pointer to after the newline ending the line,
669 or to the end of the file, if there is no newline to end it.
671 Can also merge on continuation lines. If APPEND_END is
672 non-null, it points past the newline of a line that is
673 continued; we add another line onto it and regard the whole
674 thing as one line. The caller decides when a line is continued. */
677 gobble_line (fd
, bufp
, append_end
)
679 register struct buffer
*bufp
;
684 register char *buf
= bufp
->beg
;
688 append_end
= bufp
->ptr
;
693 while (*end
&& *end
!= '\n') end
++;
697 return buf
+ bufp
->full
;
698 if (bufp
->ptr
== buf
)
700 if (bufp
->full
== bufp
->size
)
703 /* Add 1 to size to ensure room for terminating null. */
704 tem
= (char *) xrealloc (buf
, bufp
->size
+ 1);
705 bufp
->ptr
= (bufp
->ptr
- buf
) + tem
;
706 append_end
= (append_end
- buf
) + tem
;
707 bufp
->beg
= buf
= tem
;
712 append_end
-= bufp
->ptr
- buf
;
713 bcopy (bufp
->ptr
, buf
, bufp
->full
-= bufp
->ptr
- buf
);
716 if (!(nread
= read (fd
, buf
+ bufp
->full
, bufp
->size
- bufp
->full
)))
719 buf
[bufp
->full
] = '\0';
740 printf ("TERM: %s\n", term
);
742 buf
= (char *) tgetent (0, term
);
745 printf ("No entry.\n");
749 printf ("Entry: %s\n", buf
);
754 printf ("co: %d\n", tgetnum ("co"));
755 printf ("am: %d\n", tgetflag ("am"));
761 char *x
= tgetstr (cap
, 0);
764 printf ("%s: ", cap
);
768 if (*y
<= ' ' || *y
== 0177)
769 printf ("\\%0o", *y
);