3 # Since the debugger uses Term::ReadLine which uses Term::Cap, we want
4 # to load as few modules as possible. This includes Carp.pm.
19 use vars qw($VERSION $VMS_TERMCAP);
20 use vars qw($termpat $state $first $entry);
25 # support Berkeley DB termcaps
26 # force $FH into callers package?
27 # keep $FH in object at Tgetent time?
31 Term::Cap - Perl termcap interface
36 $terminal = Tgetent Term::Cap { TERM => undef, OSPEED => $ospeed };
37 $terminal->Trequire(qw/ce ku kd/);
38 $terminal->Tgoto('cm', $col, $row, $FH);
39 $terminal->Tputs('dl', $count, $FH);
40 $terminal->Tpad($string, $count, $FH);
44 These are low-level functions to extract and use capabilities from
45 a terminal capability (termcap) database.
47 More information on the terminal capabilities will be found in the
48 termcap manpage on most Unix-like systems.
52 The output strings for B<Tputs> are cached for counts of 1 for performance.
53 B<Tgoto> and B<Tpad> do not cache. C<$self-E<gt>{_xx}> is the raw termcap
54 data and C<$self-E<gt>{xx}> is the cached version.
56 print $terminal->Tpad($self->{_xx}, 1);
58 B<Tgoto>, B<Tputs>, and B<Tpad> return the string and will also
59 output the string to $FH if specified.
64 # Preload the default VMS termcap.
65 # If a different termcap is required then the text of one can be supplied
66 # in $Term::Cap::VMS_TERMCAP before Tgetent is called.
70 chomp( my @entry = <DATA> );
71 $VMS_TERMCAP = join '', @entry;
74 # Returns a list of termcap files to check.
80 # $TERMCAP, if it's a filespec
81 push( @termcap_path, $ENV{TERMCAP} )
83 ( exists $ENV{TERMCAP} )
85 ( $^O eq 'os2' || $^O eq 'MSWin32' || $^O eq 'dos' )
86 ? $ENV{TERMCAP} =~ /^[a-z]:[\\\/]/is
87 : $ENV{TERMCAP} =~ /^\//s
90 if ( ( exists $ENV{TERMPATH} ) && ( $ENV{TERMPATH} ) )
93 # Add the users $TERMPATH
94 push( @termcap_path, split( /(:|\s+)/, $ENV{TERMPATH} ) );
101 exists $ENV{'HOME'} ? $ENV{'HOME'} . '/.termcap' : undef,
102 '/etc/termcap', '/usr/share/misc/termcap', );
105 # return the list of those termcaps that exist
106 return grep { defined $_ && -f $_ } @termcap_path;
113 Returns a blessed object reference which the user can
114 then use to send the control strings to the terminal using B<Tputs>
117 The function extracts the entry of the specified terminal
118 type I<TERM> (defaults to the environment variable I<TERM>) from the
121 It will look in the environment for a I<TERMCAP> variable. If
122 found, and the value does not begin with a slash, and the terminal
123 type name is the same as the environment string I<TERM>, the
124 I<TERMCAP> string is used instead of reading a termcap file. If
125 it does begin with a slash, the string is used as a path name of
126 the termcap file to search. If I<TERMCAP> does not begin with a
127 slash and name is different from I<TERM>, B<Tgetent> searches the
128 files F<$HOME/.termcap>, F</etc/termcap>, and F</usr/share/misc/termcap>,
129 in that order, unless the environment variable I<TERMPATH> exists,
130 in which case it specifies a list of file pathnames (separated by
131 spaces or colons) to be searched B<instead>. Whenever multiple
132 files are searched and a tc field occurs in the requested entry,
133 the entry it names must be found in the same file or one of the
134 succeeding files. If there is a C<:tc=...:> in the I<TERMCAP>
135 environment variable string it will continue the search in the
138 The extracted termcap entry is available in the object
139 as C<$self-E<gt>{TERMCAP}>.
141 It takes a hash reference as an argument with two optional keys:
147 The terminal output bit rate (often mistakenly called the baud rate)
148 for this terminal - if not set a warning will be generated
149 and it will be defaulted to 9600. I<OSPEED> can be specified as
150 either a POSIX termios/SYSV termio speeds (where 9600 equals 9600) or
151 an old DSD-style speed ( where 13 equals 9600).
156 The terminal type whose termcap entry will be used - if not supplied it will
157 default to $ENV{TERM}: if that is not set then B<Tgetent> will croak.
161 It calls C<croak> on failure.
166 { ## public -- static method
170 $self = {} unless defined $self;
173 my ( $term, $cap, $search, $field, $max, $tmp_term, $TERMCAP );
174 local ( $termpat, $state, $first, $entry ); # used inside eval
177 # Compute PADDING factor from OSPEED (to be used by Tpad)
178 if ( !$self->{OSPEED} )
182 carp "OSPEED was not set, defaulting to 9600";
184 $self->{OSPEED} = 9600;
186 if ( $self->{OSPEED} < 16 )
189 # delays for old style speeds
191 0, 200, 133.3, 90.9, 74.3, 66.7, 50, 33.3,
192 16.7, 8.3, 5.5, 4.1, 2, 1, .5, .2
194 $self->{PADDING} = $pad[ $self->{OSPEED} ];
198 $self->{PADDING} = 10000 / $self->{OSPEED};
201 unless ( $self->{TERM} )
205 $self->{TERM} = $ENV{TERM} ;
209 if ( $^O eq 'MSWin32' )
211 $self->{TERM} = 'dumb';
215 croak "TERM not set";
220 $term = $self->{TERM}; # $term is the term type we are looking for
222 # $tmp_term is always the next term (possibly :tc=...:) we are looking for
223 $tmp_term = $self->{TERM};
225 # protect any pattern metacharacters in $tmp_term
226 $termpat = $tmp_term;
227 $termpat =~ s/(\W)/\\$1/g;
229 my $foo = ( exists $ENV{TERMCAP} ? $ENV{TERMCAP} : '' );
231 # $entry is the extracted termcap entry
232 if ( ( $foo !~ m:^/:s ) && ( $foo =~ m/(^|\|)${termpat}[:|]/s ) )
237 my @termcap_path = termcap_path();
239 if ( !@termcap_path && !$entry )
242 # last resort--fake up a termcap from terminfo
243 local $ENV{TERM} = $term;
247 $entry = $VMS_TERMCAP;
251 if ( grep { -x "$_/infocmp" } split /:/, $ENV{PATH} )
254 my $tmp = `infocmp -C 2>/dev/null`;
255 $tmp =~ s/^#.*\n//gm; # remove comments
256 if ( ( $tmp !~ m%^/%s )
257 && ( $tmp =~ /(^|\|)${termpat}[:|]/s ) )
262 warn "Can't run infocmp to get a termcap entry: $@" if $@;
266 # this is getting desperate now
267 if ( $self->{TERM} eq 'dumb' )
269 $entry = 'dumb|80-column dumb tty::am::co#80::bl=^G:cr=^M:do=^J:sf=^J:';
275 croak "Can't find a valid termcap file" unless @termcap_path || $entry;
277 $state = 1; # 0 == finished
281 $first = 0; # first entry (keeps term name)
283 $max = 32; # max :tc=...:'s
288 # ok, we're starting with $TERMCAP
289 $first++; # we're the first entry
290 # do we need to continue?
291 if ( $entry =~ s/:tc=([^:]+):/:/ )
295 # protect any pattern metacharacters in $tmp_term
296 $termpat = $tmp_term;
297 $termpat =~ s/(\W)/\\$1/g;
301 $state = 0; # we're already finished
305 # This is eval'ed inside the while loop for each file
308 next if /^\\t/ || /^#/;
309 if ($_ =~ m/(^|\\|)${termpat}[:|]/o) {
311 s/^[^:]*:// if $first++;
313 while ($_ =~ s/\\\\$//) {
314 defined(my $x = <TERMCAP>) or last;
320 defined $entry or $entry = '';
324 while ( $state != 0 )
329 # get the next TERMCAP
330 $TERMCAP = shift @termcap_path
331 || croak "failed termcap lookup on $tmp_term";
336 # do the same file again
337 # prevent endless recursion
338 $max-- || croak "failed termcap loop at $tmp_term";
339 $state = 1; # ok, maybe do a new file next time
342 open( TERMCAP, "< $TERMCAP\0" ) || croak "open $TERMCAP: $!";
347 # If :tc=...: found then search this file again
348 $entry =~ s/:tc=([^:]+):/:/ && ( $tmp_term = $1, $state = 2 );
350 # protect any pattern metacharacters in $tmp_term
351 $termpat = $tmp_term;
352 $termpat =~ s/(\W)/\\$1/g;
355 croak "Can't find $term" if $entry eq '';
356 $entry =~ s/:+\s*:+/:/g; # cleanup $entry
357 $entry =~ s/:+/:/g; # cleanup $entry
358 $self->{TERMCAP} = $entry; # save it
359 # print STDERR "DEBUG: $entry = ", $entry, "\n";
361 # Precompile $entry into the object
362 $entry =~ s/^[^:]*://;
363 foreach $field ( split( /:[\s:\\]*/, $entry ) )
365 if ( defined $field && $field =~ /^(\w{2,})$/ )
367 $self->{ '_' . $field } = 1 unless defined $self->{ '_' . $1 };
369 # print STDERR "DEBUG: flag $1\n";
371 elsif ( defined $field && $field =~ /^(\w{2,})\@/ )
373 $self->{ '_' . $1 } = "";
375 # print STDERR "DEBUG: unset $1\n";
377 elsif ( defined $field && $field =~ /^(\w{2,})#(.*)/ )
379 $self->{ '_' . $1 } = $2 unless defined $self->{ '_' . $1 };
381 # print STDERR "DEBUG: numeric $1 = $2\n";
383 elsif ( defined $field && $field =~ /^(\w{2,})=(.*)/ )
386 # print STDERR "DEBUG: string $1 = $2\n";
387 next if defined $self->{ '_' . ( $cap = $1 ) };
389 if ( ord('A') == 193 )
392 s/\\(\d\d\d)/pack('c',oct($1) & 0177)/eg;
400 s/\^(.)/pack('c',ord($1) & 31)/eg;
407 s/\\(\d\d\d)/pack('c',oct($1) & 0177)/eg;
415 s/\^(.)/pack('c',ord($1) & 31)/eg;
419 $self->{ '_' . $cap } = $_;
422 # else { carp "junk in $term ignored: $field"; }
424 $self->{'_pc'} = "\0" unless defined $self->{'_pc'};
425 $self->{'_bc'} = "\b" unless defined $self->{'_bc'};
429 # $terminal->Tpad($string, $cnt, $FH);
433 Outputs a literal string with appropriate padding for the current terminal.
435 It takes three arguments:
441 The literal string to be output. If it starts with a number and an optional
442 '*' then the padding will be increased by an amount relative to this number,
443 if the '*' is present then this amount will be multiplied by $cnt. This part
444 of $string is removed before output/
448 Will be used to modify the padding applied to string as described above.
452 An optional filehandle (or IO::Handle ) that output will be printed to.
456 The padded $string is returned.
463 my ( $string, $cnt, $FH ) = @_;
466 if ( defined $string && $string =~ /(^[\d.]+)(\*?)(.*)$/ )
471 $decr = $self->{PADDING};
475 $string .= $self->{'_pc'} x ( $ms / $decr );
478 print $FH $string if $FH;
482 # $terminal->Tputs($cap, $cnt, $FH);
486 Output the string for the given capability padded as appropriate without
487 any parameter substitution.
489 It takes three arguments:
495 The capability whose string is to be output.
499 A count passed to Tpad to modify the padding applied to the output string.
500 If $cnt is zero or one then the resulting string will be cached.
504 An optional filehandle (or IO::Handle ) that output will be printed to.
508 The appropriate string for the capability will be returned.
515 my ( $cap, $cnt, $FH ) = @_;
518 $cnt = 0 unless $cnt;
522 $string = Tpad( $self, $self->{ '_' . $cap }, $cnt );
527 # cache result because Tpad can be slow
528 unless ( exists $self->{$cap} )
531 exists $self->{"_$cap"}
532 ? Tpad( $self, $self->{"_$cap"}, 1 )
535 $string = $self->{$cap};
537 print $FH $string if $FH;
541 # $terminal->Tgoto($cap, $col, $row, $FH);
545 B<Tgoto> decodes a cursor addressing string with the given parameters.
547 There are four arguments:
553 The name of the capability to be output.
557 The first value to be substituted in the output string ( usually the column
558 in a cursor addressing capability )
562 The second value to be substituted in the output string (usually the row
563 in cursor addressing capabilities)
567 An optional filehandle (or IO::Handle ) to which the output string will be
572 Substitutions are made with $col and $row in the output string with the
573 following sprintf() line formats:
576 %d output value as in printf %d
577 %2 output value as in printf %2d
578 %3 output value as in printf %3d
579 %. output value as in printf %c
580 %+x add x to value, then do %.
582 %>xy if value > x then add y, no output
583 %r reverse order of two parameters, no output
584 %i increment by one, no output
585 %B BCD (16*(value/10)) + (value%10), no output
587 %n exclusive-or all parameters with 0140 (Datamedia 2500)
588 %D Reverse coding (value - 2*(value%16)), no output (Delta Data)
590 The output string will be returned.
597 my ( $cap, $code, $tmp, $FH ) = @_;
598 my $string = $self->{ '_' . $cap };
602 my @tmp = ( $tmp, $code );
605 while ( $string =~ /^([^%]*)%(.)(.*)/ )
612 $result .= sprintf( "%d", shift(@tmp) );
614 elsif ( $code eq '.' )
617 if ( $tmp == 0 || $tmp == 4 || $tmp == 10 )
621 ++$tmp, $after .= $self->{'_up'} if $self->{'_up'};
625 ++$tmp, $after .= $self->{'_bc'};
628 $result .= sprintf( "%c", $tmp );
631 elsif ( $code eq '+' )
633 $result .= sprintf( "%c", shift(@tmp) + ord($string) );
634 $string = substr( $string, 1, 99 );
637 elsif ( $code eq 'r' )
639 ( $code, $tmp ) = @tmp;
640 @tmp = ( $tmp, $code );
643 elsif ( $code eq '>' )
645 ( $code, $tmp, $string ) = unpack( "CCa99", $string );
646 if ( $tmp[0] > $code )
651 elsif ( $code eq '2' )
653 $result .= sprintf( "%02d", shift(@tmp) );
656 elsif ( $code eq '3' )
658 $result .= sprintf( "%03d", shift(@tmp) );
661 elsif ( $code eq 'i' )
663 ( $code, $tmp ) = @tmp;
664 @tmp = ( $code + 1, $tmp + 1 );
671 $string = Tpad( $self, $result . $string . $after, $cnt );
672 print $FH $string if $FH;
676 # $terminal->Trequire(qw/ce ku kd/);
680 Takes a list of capabilities as an argument and will croak if one is not
688 my ( $cap, @undefined );
691 push( @undefined, $cap )
692 unless defined $self->{ '_' . $cap } && $self->{ '_' . $cap };
694 croak "Terminal does not support: (@undefined)" if @undefined;
703 # Get terminal output speed
705 my $termios = new POSIX::Termios;
707 my $ospeed = $termios->getospeed;
709 # Old-style ioctl code to get ospeed:
710 # require 'ioctl.pl';
711 # ioctl(TTY,$TIOCGETP,$sgtty);
712 # ($ispeed,$ospeed) = unpack('cc',$sgtty);
714 # allocate and initialize a terminal structure
715 $terminal = Tgetent Term::Cap { TERM => undef, OSPEED => $ospeed };
717 # require certain capabilities to be available
718 $terminal->Trequire(qw/ce ku kd/);
720 # Output Routines, if $FH is undefined these just return the string
722 # Tgoto does the % expansion stuff with the given args
723 $terminal->Tgoto('cm', $col, $row, $FH);
725 # Tputs doesn't do any % expansion.
726 $terminal->Tputs('dl', $count = 1, $FH);
728 =head1 COPYRIGHT AND LICENSE
730 Copyright 1995-2015 (c) perl5 porters.
732 This software is free software and can be modified and distributed under
733 the same terms as Perl itself.
735 Please see the file README in the Perl source distribution for details of
740 This module is part of the core Perl distribution and is also maintained
741 for CPAN by Jonathan Stowe <jns@gellyfish.co.uk>.
743 The code is hosted on Github: https://github.com/jonathanstowe/Term-Cap
744 please feel free to fork, submit patches etc, etc there.
752 # Below is a default entry for systems where there are terminals but no
756 vt220|vt200|DEC VT220 in vt100 emulation mode:
760 ac=kkllmmjjnnwwqquuttvvxx:ae=\E(B:al=\E[L:as=\E(0:
761 bl=^G:cd=\E[J:ce=\E[K:cl=\E[H\E[2J:cm=\E[%i%d;%dH:
762 cr=^M:cs=\E[%i%d;%dr:dc=\E[P:dl=\E[M:do=\E[B:
763 ei=\E[4l:ho=\E[H:im=\E[4h:
766 kd=\E[B::kl=\E[D:kr=\E[C:ku=\E[A:le=^H:
767 mb=\E[5m:md=\E[1m:me=\E[m:mr=\E[7m:
769 r2=\E>\E[24;1H\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h\E=:rc=\E8:
770 sc=\E7:se=\E[27m:sf=\ED:so=\E[7m:sr=\EM:ta=^I:
771 ue=\E[24m:up=\E[A:us=\E[4m:ve=\E[?25h:vi=\E[?25l: