xref: /openbsd/gnu/usr.bin/perl/cpan/Term-Cap/Cap.pm (revision 6835ac24)
1b39c5158Smillertpackage Term::Cap;
2b39c5158Smillert
3b39c5158Smillert# Since the debugger uses Term::ReadLine which uses Term::Cap, we want
4b39c5158Smillert# to load as few modules as possible.  This includes Carp.pm.
5b39c5158Smillertsub carp
6b39c5158Smillert{
7b39c5158Smillert    require Carp;
8b39c5158Smillert    goto &Carp::carp;
9b39c5158Smillert}
10b39c5158Smillert
11b39c5158Smillertsub croak
12b39c5158Smillert{
13b39c5158Smillert    require Carp;
14b39c5158Smillert    goto &Carp::croak;
15b39c5158Smillert}
16b39c5158Smillert
17b39c5158Smillertuse strict;
18b39c5158Smillert
19b39c5158Smillertuse vars qw($VERSION $VMS_TERMCAP);
20b39c5158Smillert
21ab0ef1e6Sespie$VERSION = '1.18';
22b39c5158Smillert
23b39c5158Smillert# TODO:
24b39c5158Smillert# support Berkeley DB termcaps
25b39c5158Smillert# force $FH into callers package?
26b39c5158Smillert# keep $FH in object at Tgetent time?
27b39c5158Smillert
28b39c5158Smillert=head1 NAME
29b39c5158Smillert
30b39c5158SmillertTerm::Cap - Perl termcap interface
31b39c5158Smillert
32b39c5158Smillert=head1 SYNOPSIS
33b39c5158Smillert
34b39c5158Smillert    require Term::Cap;
35ab0ef1e6Sespie    $terminal = Term::Cap->Tgetent({ TERM => undef, OSPEED => $ospeed });
36b39c5158Smillert    $terminal->Trequire(qw/ce ku kd/);
37b39c5158Smillert    $terminal->Tgoto('cm', $col, $row, $FH);
38b39c5158Smillert    $terminal->Tputs('dl', $count, $FH);
39b39c5158Smillert    $terminal->Tpad($string, $count, $FH);
40b39c5158Smillert
41b39c5158Smillert=head1 DESCRIPTION
42b39c5158Smillert
43b39c5158SmillertThese are low-level functions to extract and use capabilities from
44b39c5158Smillerta terminal capability (termcap) database.
45b39c5158Smillert
46b39c5158SmillertMore information on the terminal capabilities will be found in the
47b39c5158Smillerttermcap manpage on most Unix-like systems.
48b39c5158Smillert
49b39c5158Smillert=head2 METHODS
50b39c5158Smillert
51b39c5158SmillertThe output strings for B<Tputs> are cached for counts of 1 for performance.
52b39c5158SmillertB<Tgoto> and B<Tpad> do not cache.  C<$self-E<gt>{_xx}> is the raw termcap
53b39c5158Smillertdata and C<$self-E<gt>{xx}> is the cached version.
54b39c5158Smillert
55b39c5158Smillert    print $terminal->Tpad($self->{_xx}, 1);
56b39c5158Smillert
57b39c5158SmillertB<Tgoto>, B<Tputs>, and B<Tpad> return the string and will also
58b39c5158Smillertoutput the string to $FH if specified.
59b39c5158Smillert
60b39c5158Smillert
61b39c5158Smillert=cut
62b39c5158Smillert
63b39c5158Smillert# Preload the default VMS termcap.
64b39c5158Smillert# If a different termcap is required then the text of one can be supplied
65b39c5158Smillert# in $Term::Cap::VMS_TERMCAP before Tgetent is called.
66b39c5158Smillert
67b39c5158Smillertif ( $^O eq 'VMS' )
68b39c5158Smillert{
69b39c5158Smillert    chomp( my @entry = <DATA> );
70b39c5158Smillert    $VMS_TERMCAP = join '', @entry;
71b39c5158Smillert}
72b39c5158Smillert
73b39c5158Smillert# Returns a list of termcap files to check.
74b39c5158Smillert
75b39c5158Smillertsub termcap_path
76b39c5158Smillert{    ## private
77b39c5158Smillert    my @termcap_path;
78b39c5158Smillert
79b39c5158Smillert    # $TERMCAP, if it's a filespec
80b39c5158Smillert    push( @termcap_path, $ENV{TERMCAP} )
81b39c5158Smillert      if (
82b39c5158Smillert        ( exists $ENV{TERMCAP} )
83b39c5158Smillert        && (
84b39c5158Smillert            ( $^O eq 'os2' || $^O eq 'MSWin32' || $^O eq 'dos' )
85b39c5158Smillert            ? $ENV{TERMCAP} =~ /^[a-z]:[\\\/]/is
86b39c5158Smillert            : $ENV{TERMCAP} =~ /^\//s
87b39c5158Smillert        )
88b39c5158Smillert      );
89b39c5158Smillert    if ( ( exists $ENV{TERMPATH} ) && ( $ENV{TERMPATH} ) )
90b39c5158Smillert    {
91b39c5158Smillert
92b39c5158Smillert        # Add the users $TERMPATH
93ab0ef1e6Sespie        push( @termcap_path, split( /:|\s+/, $ENV{TERMPATH} ) );
94b39c5158Smillert    }
95b39c5158Smillert    else
96b39c5158Smillert    {
97b39c5158Smillert
98b39c5158Smillert        # Defaults
99b39c5158Smillert        push( @termcap_path,
100b39c5158Smillert            exists $ENV{'HOME'} ? $ENV{'HOME'} . '/.termcap' : undef,
101b39c5158Smillert            '/etc/termcap', '/usr/share/misc/termcap', );
102b39c5158Smillert    }
103b39c5158Smillert
104b39c5158Smillert    # return the list of those termcaps that exist
105b39c5158Smillert    return grep { defined $_ && -f $_ } @termcap_path;
106b39c5158Smillert}
107b39c5158Smillert
108898184e3Ssthen=over 4
109898184e3Ssthen
110b39c5158Smillert=item B<Tgetent>
111b39c5158Smillert
112b39c5158SmillertReturns a blessed object reference which the user can
113b39c5158Smillertthen use to send the control strings to the terminal using B<Tputs>
114b39c5158Smillertand B<Tgoto>.
115b39c5158Smillert
116b39c5158SmillertThe function extracts the entry of the specified terminal
117b39c5158Smillerttype I<TERM> (defaults to the environment variable I<TERM>) from the
118b39c5158Smillertdatabase.
119b39c5158Smillert
120b39c5158SmillertIt will look in the environment for a I<TERMCAP> variable.  If
121b39c5158Smillertfound, and the value does not begin with a slash, and the terminal
122b39c5158Smillerttype name is the same as the environment string I<TERM>, the
123b39c5158SmillertI<TERMCAP> string is used instead of reading a termcap file.  If
124b39c5158Smillertit does begin with a slash, the string is used as a path name of
125b39c5158Smillertthe termcap file to search.  If I<TERMCAP> does not begin with a
126b39c5158Smillertslash and name is different from I<TERM>, B<Tgetent> searches the
127b39c5158Smillertfiles F<$HOME/.termcap>, F</etc/termcap>, and F</usr/share/misc/termcap>,
128b39c5158Smillertin that order, unless the environment variable I<TERMPATH> exists,
129b39c5158Smillertin which case it specifies a list of file pathnames (separated by
130b39c5158Smillertspaces or colons) to be searched B<instead>.  Whenever multiple
131b39c5158Smillertfiles are searched and a tc field occurs in the requested entry,
132b39c5158Smillertthe entry it names must be found in the same file or one of the
133b39c5158Smillertsucceeding files.  If there is a C<:tc=...:> in the I<TERMCAP>
134b39c5158Smillertenvironment variable string it will continue the search in the
135b39c5158Smillertfiles as above.
136b39c5158Smillert
137b39c5158SmillertThe extracted termcap entry is available in the object
138b39c5158Smillertas C<$self-E<gt>{TERMCAP}>.
139b39c5158Smillert
140b39c5158SmillertIt takes a hash reference as an argument with two optional keys:
141b39c5158Smillert
142b39c5158Smillert=over 2
143b39c5158Smillert
144b39c5158Smillert=item OSPEED
145b39c5158Smillert
146b39c5158SmillertThe terminal output bit rate (often mistakenly called the baud rate)
147b39c5158Smillertfor this terminal - if not set a warning will be generated
1486fb12b70Safresh1and it will be defaulted to 9600.  I<OSPEED> can be specified as
149b39c5158Smillerteither a POSIX termios/SYSV termio speeds (where 9600 equals 9600) or
150b39c5158Smillertan old DSD-style speed ( where 13 equals 9600).
151b39c5158Smillert
152b39c5158Smillert
153b39c5158Smillert=item TERM
154b39c5158Smillert
155b39c5158SmillertThe terminal type whose termcap entry will be used - if not supplied it will
156b39c5158Smillertdefault to $ENV{TERM}: if that is not set then B<Tgetent> will croak.
157b39c5158Smillert
158b39c5158Smillert=back
159b39c5158Smillert
160b39c5158SmillertIt calls C<croak> on failure.
161b39c5158Smillert
162b39c5158Smillert=cut
163b39c5158Smillert
164b39c5158Smillertsub Tgetent
165b39c5158Smillert{    ## public -- static method
166b39c5158Smillert    my $class = shift;
167b39c5158Smillert    my ($self) = @_;
168b39c5158Smillert
169b39c5158Smillert    $self = {} unless defined $self;
170b39c5158Smillert    bless $self, $class;
171b39c5158Smillert
17223376045Sespie    my ( $term, $cap, $search, $field, $tmp_term, $TERMCAP );
173fa4ae7feSespie    my ( $state, $first, $entry );
174b39c5158Smillert    local $_;
175b39c5158Smillert
176b39c5158Smillert    # Compute PADDING factor from OSPEED (to be used by Tpad)
177b39c5158Smillert    if ( !$self->{OSPEED} )
178b39c5158Smillert    {
179b39c5158Smillert        if ($^W)
180b39c5158Smillert        {
181b39c5158Smillert            carp "OSPEED was not set, defaulting to 9600";
182b39c5158Smillert        }
183b39c5158Smillert        $self->{OSPEED} = 9600;
184b39c5158Smillert    }
185b39c5158Smillert    if ( $self->{OSPEED} < 16 )
186b39c5158Smillert    {
187b39c5158Smillert
188b39c5158Smillert        # delays for old style speeds
189b39c5158Smillert        my @pad = (
190b39c5158Smillert            0,    200, 133.3, 90.9, 74.3, 66.7, 50, 33.3,
191b39c5158Smillert            16.7, 8.3, 5.5,   4.1,  2,    1,    .5, .2
192b39c5158Smillert        );
193b39c5158Smillert        $self->{PADDING} = $pad[ $self->{OSPEED} ];
194b39c5158Smillert    }
195b39c5158Smillert    else
196b39c5158Smillert    {
197b39c5158Smillert        $self->{PADDING} = 10000 / $self->{OSPEED};
198b39c5158Smillert    }
199b39c5158Smillert
200b39c5158Smillert    unless ( $self->{TERM} )
201b39c5158Smillert    {
202b39c5158Smillert       if ( $ENV{TERM} )
203b39c5158Smillert       {
204b39c5158Smillert         $self->{TERM} =  $ENV{TERM} ;
205b39c5158Smillert       }
206b39c5158Smillert       else
207b39c5158Smillert       {
2086fb12b70Safresh1          if ( $^O eq 'MSWin32' )
209b39c5158Smillert          {
210b39c5158Smillert             $self->{TERM} =  'dumb';
211b39c5158Smillert          }
212b39c5158Smillert          else
213b39c5158Smillert          {
214b39c5158Smillert             croak "TERM not set";
215b39c5158Smillert          }
216b39c5158Smillert       }
217b39c5158Smillert    }
218b39c5158Smillert
219b39c5158Smillert    $term = $self->{TERM};    # $term is the term type we are looking for
220b39c5158Smillert
221b39c5158Smillert    # $tmp_term is always the next term (possibly :tc=...:) we are looking for
222b39c5158Smillert    $tmp_term = $self->{TERM};
22323376045Sespie    my $seen = {};
224b39c5158Smillert
225962e816aSespie    if (exists $ENV{TERMCAP}) {
226962e816aSespie    	local $_ = $ENV{TERMCAP};
227962e816aSespie	if ( !m:^/:s && m/(^|\|)\Q$tmp_term\E[:|]/s ) {
228962e816aSespie	    $entry = $_;
22923376045Sespie	    $seen->{$tmp_term} = 1;
230b39c5158Smillert	}
231962e816aSespie    }
232b39c5158Smillert
233b39c5158Smillert    my @termcap_path = termcap_path();
234b39c5158Smillert
235b39c5158Smillert    $state = 1;    # 0 == finished
236b39c5158Smillert                   # 1 == next file
237b39c5158Smillert                   # 2 == search again
238000d6ed8Sespie		   # 3 == try infocmp
239b39c5158Smillert
240b39c5158Smillert    $first = 0;    # first entry (keeps term name)
241b39c5158Smillert
242b39c5158Smillert    if ($entry)
243b39c5158Smillert    {
244b39c5158Smillert
245b39c5158Smillert        # ok, we're starting with $TERMCAP
246b39c5158Smillert        $first++;    # we're the first entry
247b39c5158Smillert                     # do we need to continue?
248b39c5158Smillert        if ( $entry =~ s/:tc=([^:]+):/:/ )
249b39c5158Smillert        {
250b39c5158Smillert            $tmp_term = $1;
251b39c5158Smillert        }
252b39c5158Smillert        else
253b39c5158Smillert        {
254b39c5158Smillert            $state = 0;    # we're already finished
255b39c5158Smillert        }
256b39c5158Smillert    }
257b39c5158Smillert
258b39c5158Smillert
259b39c5158Smillert    while ( $state != 0 )
260b39c5158Smillert    {
261000d6ed8Sespie        if ( $state == 1 ) {
262b39c5158Smillert            # get the next TERMCAP
263000d6ed8Sespie            $TERMCAP = shift @termcap_path or $state = 3;
264000d6ed8Sespie	} elsif ($state == 3) {
265000d6ed8Sespie	    croak "failed termcap lookup on $tmp_term";
266000d6ed8Sespie        } else {
267b39c5158Smillert            # do the same file again
268b39c5158Smillert            $state = 1;    # ok, maybe do a new file next time
269b39c5158Smillert        }
270b39c5158Smillert
271000d6ed8Sespie	my ($fh, $child);
272000d6ed8Sespie	if ($state == 3) {
273000d6ed8Sespie	    # need to do a proper fork, so that we can pass tmp_term
274000d6ed8Sespie	    # without having to quote it.
275000d6ed8Sespie	    $child = open($fh, "-|");
276000d6ed8Sespie	    warn "cannot run infocmp: $!" if !defined $child;
277000d6ed8Sespie	    if (!$child) {
278000d6ed8Sespie	    	open(STDERR, ">", "/dev/null");
279*6835ac24Sespie		exec('infocmp', '-CTrx', '--', $tmp_term);
280fea8967dSespie		exit(1);
281000d6ed8Sespie	    }
282000d6ed8Sespie	} else {
283000d6ed8Sespie	    open($fh, '<', $TERMCAP) || croak "open $TERMCAP: $!";
284000d6ed8Sespie	}
2852da37aacSespie	while (<$fh>) {
286fa4ae7feSespie	    next if /^\t/ || /^#/;
287fa4ae7feSespie	    if (m/(^|\|)\Q$tmp_term\E[:|]/) {
288fa4ae7feSespie		chomp;
289fa4ae7feSespie		s/^[^:]*:// if $first++;
290fa4ae7feSespie		$state = 0;
29123376045Sespie		$seen->{$tmp_term} = 1;
292fa4ae7feSespie		while (s/\\$//) {
2932da37aacSespie		    defined(my $x = <$fh>) or last;
294fa4ae7feSespie		    $_ .= $x; chomp;
295fa4ae7feSespie		}
296460dc485Sespie		if (defined $entry) {
297460dc485Sespie		    $entry .= $_;
298460dc485Sespie		} else {
299460dc485Sespie		    $entry = $_;
300460dc485Sespie		}
301fa4ae7feSespie		last;
302fa4ae7feSespie	    }
303fa4ae7feSespie	}
3042da37aacSespie        close $fh;
305000d6ed8Sespie	waitpid($child, 0) if defined $child;
306b39c5158Smillert
307035d1660Sespie	next if $state != 0;
308035d1660Sespie
309b39c5158Smillert        # If :tc=...: found then search this file again
31023376045Sespie	while ($entry =~ s/:tc=([^:]+):/:/) {
31123376045Sespie	    $tmp_term = $1;
31223376045Sespie	    next if $seen->{$tmp_term};
31323376045Sespie	    $state = 2;
31423376045Sespie	    last;
31523376045Sespie	}
316b39c5158Smillert    }
317b39c5158Smillert
318035d1660Sespie    if ( !defined $entry ) {
319035d1660Sespie        if ( $^O eq 'VMS' ) {
320035d1660Sespie            $entry = $VMS_TERMCAP;
321035d1660Sespie       # this is getting desperate now
322035d1660Sespie        } elsif ( $self->{TERM} eq 'dumb' ){
323035d1660Sespie	  $entry = 'dumb|80-column dumb tty::am::co#80::bl=^G:cr=^M:do=^J:sf=^J:';
324035d1660Sespie	}
325035d1660Sespie    }
326035d1660Sespie
327035d1660Sespie    croak "Can't find $term" if !defined $entry;
328b39c5158Smillert    $entry =~ s/:+\s*:+/:/g;    # cleanup $entry
329b39c5158Smillert    $entry =~ s/:+/:/g;         # cleanup $entry
330b39c5158Smillert    $self->{TERMCAP} = $entry;  # save it
331b39c5158Smillert                                # print STDERR "DEBUG: $entry = ", $entry, "\n";
332b39c5158Smillert
333b39c5158Smillert    # Precompile $entry into the object
334b39c5158Smillert    $entry =~ s/^[^:]*://;
335b39c5158Smillert    foreach $field ( split( /:[\s:\\]*/, $entry ) )
336b39c5158Smillert    {
337b8851fccSafresh1        if ( defined $field && $field =~ /^(\w{2,})$/ )
338b39c5158Smillert        {
339b39c5158Smillert            $self->{ '_' . $field } = 1 unless defined $self->{ '_' . $1 };
340b39c5158Smillert
341b39c5158Smillert            # print STDERR "DEBUG: flag $1\n";
342b39c5158Smillert        }
343b8851fccSafresh1        elsif ( defined $field && $field =~ /^(\w{2,})\@/ )
344b39c5158Smillert        {
345b39c5158Smillert            $self->{ '_' . $1 } = "";
346b39c5158Smillert
347b39c5158Smillert            # print STDERR "DEBUG: unset $1\n";
348b39c5158Smillert        }
349b8851fccSafresh1        elsif ( defined $field && $field =~ /^(\w{2,})#(.*)/ )
350b39c5158Smillert        {
351b39c5158Smillert            $self->{ '_' . $1 } = $2 unless defined $self->{ '_' . $1 };
352b39c5158Smillert
353b39c5158Smillert            # print STDERR "DEBUG: numeric $1 = $2\n";
354b39c5158Smillert        }
355b8851fccSafresh1        elsif ( defined $field && $field =~ /^(\w{2,})=(.*)/ )
356b39c5158Smillert        {
357b39c5158Smillert
358b39c5158Smillert            # print STDERR "DEBUG: string $1 = $2\n";
359b39c5158Smillert            next if defined $self->{ '_' . ( $cap = $1 ) };
360b39c5158Smillert            $_ = $2;
361b39c5158Smillert            if ( ord('A') == 193 )
362b39c5158Smillert            {
363b39c5158Smillert               s/\\E/\047/g;
364b39c5158Smillert               s/\\(\d\d\d)/pack('c',oct($1) & 0177)/eg;
365b39c5158Smillert               s/\\n/\n/g;
366b39c5158Smillert               s/\\r/\r/g;
367b39c5158Smillert               s/\\t/\t/g;
368b39c5158Smillert               s/\\b/\b/g;
369b39c5158Smillert               s/\\f/\f/g;
370b39c5158Smillert               s/\\\^/\337/g;
371b39c5158Smillert               s/\^\?/\007/g;
372b39c5158Smillert               s/\^(.)/pack('c',ord($1) & 31)/eg;
373b39c5158Smillert               s/\\(.)/$1/g;
374b39c5158Smillert               s/\337/^/g;
375b39c5158Smillert            }
376b39c5158Smillert            else
377b39c5158Smillert            {
378b39c5158Smillert               s/\\E/\033/g;
379b39c5158Smillert               s/\\(\d\d\d)/pack('c',oct($1) & 0177)/eg;
380b39c5158Smillert               s/\\n/\n/g;
381b39c5158Smillert               s/\\r/\r/g;
382b39c5158Smillert               s/\\t/\t/g;
383b39c5158Smillert               s/\\b/\b/g;
384b39c5158Smillert               s/\\f/\f/g;
385b39c5158Smillert               s/\\\^/\377/g;
386b39c5158Smillert               s/\^\?/\177/g;
387b39c5158Smillert               s/\^(.)/pack('c',ord($1) & 31)/eg;
388b39c5158Smillert               s/\\(.)/$1/g;
389b39c5158Smillert               s/\377/^/g;
390b39c5158Smillert            }
391b39c5158Smillert            $self->{ '_' . $cap } = $_;
392b39c5158Smillert        }
393b39c5158Smillert
394b39c5158Smillert        # else { carp "junk in $term ignored: $field"; }
395b39c5158Smillert    }
396b39c5158Smillert    $self->{'_pc'} = "\0" unless defined $self->{'_pc'};
397b39c5158Smillert    $self->{'_bc'} = "\b" unless defined $self->{'_bc'};
398b39c5158Smillert    $self;
399b39c5158Smillert}
400b39c5158Smillert
401b39c5158Smillert# $terminal->Tpad($string, $cnt, $FH);
402b39c5158Smillert
403b39c5158Smillert=item B<Tpad>
404b39c5158Smillert
405b39c5158SmillertOutputs a literal string with appropriate padding for the current terminal.
406b39c5158Smillert
407b39c5158SmillertIt takes three arguments:
408b39c5158Smillert
409b39c5158Smillert=over 2
410b39c5158Smillert
411b39c5158Smillert=item B<$string>
412b39c5158Smillert
413b39c5158SmillertThe literal string to be output.  If it starts with a number and an optional
414b39c5158Smillert'*' then the padding will be increased by an amount relative to this number,
4156fb12b70Safresh1if the '*' is present then this amount will be multiplied by $cnt.  This part
416b39c5158Smillertof $string is removed before output/
417b39c5158Smillert
418b39c5158Smillert=item B<$cnt>
419b39c5158Smillert
420b39c5158SmillertWill be used to modify the padding applied to string as described above.
421b39c5158Smillert
422b39c5158Smillert=item B<$FH>
423b39c5158Smillert
424b39c5158SmillertAn optional filehandle (or IO::Handle ) that output will be printed to.
425b39c5158Smillert
426b39c5158Smillert=back
427b39c5158Smillert
428b39c5158SmillertThe padded $string is returned.
429b39c5158Smillert
430b39c5158Smillert=cut
431b39c5158Smillert
432b39c5158Smillertsub Tpad
433b39c5158Smillert{    ## public
434b39c5158Smillert    my $self = shift;
435b39c5158Smillert    my ( $string, $cnt, $FH ) = @_;
436b39c5158Smillert    my ( $decr, $ms );
437b39c5158Smillert
438b39c5158Smillert    if ( defined $string && $string =~ /(^[\d.]+)(\*?)(.*)$/ )
439b39c5158Smillert    {
440b39c5158Smillert        $ms = $1;
441b39c5158Smillert        $ms *= $cnt if $2;
442b39c5158Smillert        $string = $3;
443b39c5158Smillert        $decr   = $self->{PADDING};
444b39c5158Smillert        if ( $decr > .1 )
445b39c5158Smillert        {
446b39c5158Smillert            $ms += $decr / 2;
447b39c5158Smillert            $string .= $self->{'_pc'} x ( $ms / $decr );
448b39c5158Smillert        }
449b39c5158Smillert    }
450b39c5158Smillert    print $FH $string if $FH;
451b39c5158Smillert    $string;
452b39c5158Smillert}
453b39c5158Smillert
454b39c5158Smillert# $terminal->Tputs($cap, $cnt, $FH);
455b39c5158Smillert
456b39c5158Smillert=item B<Tputs>
457b39c5158Smillert
458b39c5158SmillertOutput the string for the given capability padded as appropriate without
459b39c5158Smillertany parameter substitution.
460b39c5158Smillert
461b39c5158SmillertIt takes three arguments:
462b39c5158Smillert
463b39c5158Smillert=over 2
464b39c5158Smillert
465b39c5158Smillert=item B<$cap>
466b39c5158Smillert
467b39c5158SmillertThe capability whose string is to be output.
468b39c5158Smillert
469b39c5158Smillert=item B<$cnt>
470b39c5158Smillert
471b39c5158SmillertA count passed to Tpad to modify the padding applied to the output string.
472b39c5158SmillertIf $cnt is zero or one then the resulting string will be cached.
473b39c5158Smillert
474b39c5158Smillert=item B<$FH>
475b39c5158Smillert
476b39c5158SmillertAn optional filehandle (or IO::Handle ) that output will be printed to.
477b39c5158Smillert
478b39c5158Smillert=back
479b39c5158Smillert
480b39c5158SmillertThe appropriate string for the capability will be returned.
481b39c5158Smillert
482b39c5158Smillert=cut
483b39c5158Smillert
484b39c5158Smillertsub Tputs
485b39c5158Smillert{    ## public
486b39c5158Smillert    my $self = shift;
487b39c5158Smillert    my ( $cap, $cnt, $FH ) = @_;
488b39c5158Smillert    my $string;
489b39c5158Smillert
490b39c5158Smillert    $cnt = 0 unless $cnt;
491b39c5158Smillert
492b39c5158Smillert    if ( $cnt > 1 )
493b39c5158Smillert    {
494b39c5158Smillert        $string = Tpad( $self, $self->{ '_' . $cap }, $cnt );
495b39c5158Smillert    }
496b39c5158Smillert    else
497b39c5158Smillert    {
498b39c5158Smillert
499b39c5158Smillert        # cache result because Tpad can be slow
500b39c5158Smillert        unless ( exists $self->{$cap} )
501b39c5158Smillert        {
502b39c5158Smillert            $self->{$cap} =
503b39c5158Smillert              exists $self->{"_$cap"}
504b39c5158Smillert              ? Tpad( $self, $self->{"_$cap"}, 1 )
505b39c5158Smillert              : undef;
506b39c5158Smillert        }
507b39c5158Smillert        $string = $self->{$cap};
508b39c5158Smillert    }
509b39c5158Smillert    print $FH $string if $FH;
510b39c5158Smillert    $string;
511b39c5158Smillert}
512b39c5158Smillert
513b39c5158Smillert# $terminal->Tgoto($cap, $col, $row, $FH);
514b39c5158Smillert
515b39c5158Smillert=item B<Tgoto>
516b39c5158Smillert
517b39c5158SmillertB<Tgoto> decodes a cursor addressing string with the given parameters.
518b39c5158Smillert
519b39c5158SmillertThere are four arguments:
520b39c5158Smillert
521b39c5158Smillert=over 2
522b39c5158Smillert
523b39c5158Smillert=item B<$cap>
524b39c5158Smillert
525b39c5158SmillertThe name of the capability to be output.
526b39c5158Smillert
527b39c5158Smillert=item B<$col>
528b39c5158Smillert
529b39c5158SmillertThe first value to be substituted in the output string ( usually the column
530b39c5158Smillertin a cursor addressing capability )
531b39c5158Smillert
532b39c5158Smillert=item B<$row>
533b39c5158Smillert
534b39c5158SmillertThe second value to be substituted in the output string (usually the row
535b39c5158Smillertin cursor addressing capabilities)
536b39c5158Smillert
537b39c5158Smillert=item B<$FH>
538b39c5158Smillert
539b39c5158SmillertAn optional filehandle (or IO::Handle ) to which the output string will be
540b39c5158Smillertprinted.
541b39c5158Smillert
542b39c5158Smillert=back
543b39c5158Smillert
544b39c5158SmillertSubstitutions are made with $col and $row in the output string with the
545b39c5158Smillertfollowing sprintf() line formats:
546b39c5158Smillert
547b39c5158Smillert %%   output `%'
548b39c5158Smillert %d   output value as in printf %d
549b39c5158Smillert %2   output value as in printf %2d
550b39c5158Smillert %3   output value as in printf %3d
551b39c5158Smillert %.   output value as in printf %c
552b39c5158Smillert %+x  add x to value, then do %.
553b39c5158Smillert
554b39c5158Smillert %>xy if value > x then add y, no output
555b39c5158Smillert %r   reverse order of two parameters, no output
556b39c5158Smillert %i   increment by one, no output
557b39c5158Smillert %B   BCD (16*(value/10)) + (value%10), no output
558b39c5158Smillert
559b39c5158Smillert %n   exclusive-or all parameters with 0140 (Datamedia 2500)
560b39c5158Smillert %D   Reverse coding (value - 2*(value%16)), no output (Delta Data)
561b39c5158Smillert
562b39c5158SmillertThe output string will be returned.
563b39c5158Smillert
564b39c5158Smillert=cut
565b39c5158Smillert
566b39c5158Smillertsub Tgoto
567b39c5158Smillert{    ## public
568b39c5158Smillert    my $self = shift;
569b39c5158Smillert    my ( $cap, $code, $tmp, $FH ) = @_;
570b39c5158Smillert    my $string = $self->{ '_' . $cap };
571b39c5158Smillert    my $result = '';
572b39c5158Smillert    my $after  = '';
573b39c5158Smillert    my $online = 0;
574b39c5158Smillert    my @tmp    = ( $tmp, $code );
575b39c5158Smillert    my $cnt    = $code;
576b39c5158Smillert
577b39c5158Smillert    while ( $string =~ /^([^%]*)%(.)(.*)/ )
578b39c5158Smillert    {
579b39c5158Smillert        $result .= $1;
580b39c5158Smillert        $code   = $2;
581b39c5158Smillert        $string = $3;
582b39c5158Smillert        if ( $code eq 'd' )
583b39c5158Smillert        {
584b39c5158Smillert            $result .= sprintf( "%d", shift(@tmp) );
585b39c5158Smillert        }
586b39c5158Smillert        elsif ( $code eq '.' )
587b39c5158Smillert        {
588b39c5158Smillert            $tmp = shift(@tmp);
589b39c5158Smillert            if ( $tmp == 0 || $tmp == 4 || $tmp == 10 )
590b39c5158Smillert            {
591b39c5158Smillert                if ($online)
592b39c5158Smillert                {
593b39c5158Smillert                    ++$tmp, $after .= $self->{'_up'} if $self->{'_up'};
594b39c5158Smillert                }
595b39c5158Smillert                else
596b39c5158Smillert                {
597b39c5158Smillert                    ++$tmp, $after .= $self->{'_bc'};
598b39c5158Smillert                }
599b39c5158Smillert            }
600b39c5158Smillert            $result .= sprintf( "%c", $tmp );
601b39c5158Smillert            $online = !$online;
602b39c5158Smillert        }
603b39c5158Smillert        elsif ( $code eq '+' )
604b39c5158Smillert        {
605b39c5158Smillert            $result .= sprintf( "%c", shift(@tmp) + ord($string) );
606b39c5158Smillert            $string = substr( $string, 1, 99 );
607b39c5158Smillert            $online = !$online;
608b39c5158Smillert        }
609b39c5158Smillert        elsif ( $code eq 'r' )
610b39c5158Smillert        {
611b39c5158Smillert            ( $code, $tmp ) = @tmp;
612b39c5158Smillert            @tmp = ( $tmp, $code );
613b39c5158Smillert            $online = !$online;
614b39c5158Smillert        }
615b39c5158Smillert        elsif ( $code eq '>' )
616b39c5158Smillert        {
617b39c5158Smillert            ( $code, $tmp, $string ) = unpack( "CCa99", $string );
6186fb12b70Safresh1            if ( $tmp[0] > $code )
619b39c5158Smillert            {
6206fb12b70Safresh1                $tmp[0] += $tmp;
621b39c5158Smillert            }
622b39c5158Smillert        }
623b39c5158Smillert        elsif ( $code eq '2' )
624b39c5158Smillert        {
625b39c5158Smillert            $result .= sprintf( "%02d", shift(@tmp) );
626b39c5158Smillert            $online = !$online;
627b39c5158Smillert        }
628b39c5158Smillert        elsif ( $code eq '3' )
629b39c5158Smillert        {
630b39c5158Smillert            $result .= sprintf( "%03d", shift(@tmp) );
631b39c5158Smillert            $online = !$online;
632b39c5158Smillert        }
633b39c5158Smillert        elsif ( $code eq 'i' )
634b39c5158Smillert        {
635b39c5158Smillert            ( $code, $tmp ) = @tmp;
636b39c5158Smillert            @tmp = ( $code + 1, $tmp + 1 );
637b39c5158Smillert        }
638b39c5158Smillert        else
639b39c5158Smillert        {
640b39c5158Smillert            return "OOPS";
641b39c5158Smillert        }
642b39c5158Smillert    }
643b39c5158Smillert    $string = Tpad( $self, $result . $string . $after, $cnt );
644b39c5158Smillert    print $FH $string if $FH;
645b39c5158Smillert    $string;
646b39c5158Smillert}
647b39c5158Smillert
648b39c5158Smillert# $terminal->Trequire(qw/ce ku kd/);
649b39c5158Smillert
650b39c5158Smillert=item B<Trequire>
651b39c5158Smillert
652b39c5158SmillertTakes a list of capabilities as an argument and will croak if one is not
653b39c5158Smillertfound.
654b39c5158Smillert
655b39c5158Smillert=cut
656b39c5158Smillert
657b39c5158Smillertsub Trequire
658b39c5158Smillert{    ## public
659b39c5158Smillert    my $self = shift;
660b39c5158Smillert    my ( $cap, @undefined );
661b39c5158Smillert    foreach $cap (@_)
662b39c5158Smillert    {
663b39c5158Smillert        push( @undefined, $cap )
664b39c5158Smillert          unless defined $self->{ '_' . $cap } && $self->{ '_' . $cap };
665b39c5158Smillert    }
666b39c5158Smillert    croak "Terminal does not support: (@undefined)" if @undefined;
667b39c5158Smillert}
668b39c5158Smillert
669b39c5158Smillert=back
670b39c5158Smillert
671b39c5158Smillert=head1 EXAMPLES
672b39c5158Smillert
673b39c5158Smillert    use Term::Cap;
674b39c5158Smillert
675b39c5158Smillert    # Get terminal output speed
676b39c5158Smillert    require POSIX;
677ab0ef1e6Sespie    my $termios = POSIX::Termios->new;
678b39c5158Smillert    $termios->getattr;
679b39c5158Smillert    my $ospeed = $termios->getospeed;
680b39c5158Smillert
681b39c5158Smillert    # Old-style ioctl code to get ospeed:
682b39c5158Smillert    #     require 'ioctl.pl';
683b39c5158Smillert    #     ioctl(TTY,$TIOCGETP,$sgtty);
684b39c5158Smillert    #     ($ispeed,$ospeed) = unpack('cc',$sgtty);
685b39c5158Smillert
686b39c5158Smillert    # allocate and initialize a terminal structure
687ab0ef1e6Sespie    my $terminal = Term::Cap->Tgetent({ TERM => undef, OSPEED => $ospeed });
688b39c5158Smillert
689b39c5158Smillert    # require certain capabilities to be available
690b39c5158Smillert    $terminal->Trequire(qw/ce ku kd/);
691b39c5158Smillert
692b39c5158Smillert    # Output Routines, if $FH is undefined these just return the string
693b39c5158Smillert
694b39c5158Smillert    # Tgoto does the % expansion stuff with the given args
695b39c5158Smillert    $terminal->Tgoto('cm', $col, $row, $FH);
696b39c5158Smillert
697b39c5158Smillert    # Tputs doesn't do any % expansion.
698b39c5158Smillert    $terminal->Tputs('dl', $count = 1, $FH);
699b39c5158Smillert
700b39c5158Smillert=head1 COPYRIGHT AND LICENSE
701b39c5158Smillert
702b8851fccSafresh1Copyright 1995-2015 (c) perl5 porters.
703b8851fccSafresh1
704b8851fccSafresh1This software is free software and can be modified and distributed under
705b8851fccSafresh1the same terms as Perl itself.
706b8851fccSafresh1
707b8851fccSafresh1Please see the file README in the Perl source distribution for details of
708b8851fccSafresh1the Perl license.
709b39c5158Smillert
710b39c5158Smillert=head1 AUTHOR
711b39c5158Smillert
712b39c5158SmillertThis module is part of the core Perl distribution and is also maintained
7136fb12b70Safresh1for CPAN by Jonathan Stowe <jns@gellyfish.co.uk>.
7146fb12b70Safresh1
7156fb12b70Safresh1The code is hosted on Github: https://github.com/jonathanstowe/Term-Cap
7166fb12b70Safresh1please feel free to fork, submit patches etc, etc there.
717b39c5158Smillert
718b39c5158Smillert=head1 SEE ALSO
719b39c5158Smillert
720b39c5158Smillerttermcap(5)
721b39c5158Smillert
722b39c5158Smillert=cut
723b39c5158Smillert
724b39c5158Smillert# Below is a default entry for systems where there are terminals but no
725b39c5158Smillert# termcap
726b39c5158Smillert1;
727b39c5158Smillert__DATA__
728b39c5158Smillertvt220|vt200|DEC VT220 in vt100 emulation mode:
729b39c5158Smillertam:mi:xn:xo:
730b39c5158Smillertco#80:li#24:
731b39c5158SmillertRA=\E[?7l:SA=\E[?7h:
732b39c5158Smillertac=kkllmmjjnnwwqquuttvvxx:ae=\E(B:al=\E[L:as=\E(0:
733b39c5158Smillertbl=^G:cd=\E[J:ce=\E[K:cl=\E[H\E[2J:cm=\E[%i%d;%dH:
734b39c5158Smillertcr=^M:cs=\E[%i%d;%dr:dc=\E[P:dl=\E[M:do=\E[B:
735b39c5158Smillertei=\E[4l:ho=\E[H:im=\E[4h:
736b39c5158Smillertis=\E[1;24r\E[24;1H:
737b39c5158Smillertnd=\E[C:
738b39c5158Smillertkd=\E[B::kl=\E[D:kr=\E[C:ku=\E[A:le=^H:
739b39c5158Smillertmb=\E[5m:md=\E[1m:me=\E[m:mr=\E[7m:
740b39c5158Smillertkb=\0177:
741b39c5158Smillertr2=\E>\E[24;1H\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h\E=:rc=\E8:
742b39c5158Smillertsc=\E7:se=\E[27m:sf=\ED:so=\E[7m:sr=\EM:ta=^I:
743b39c5158Smillertue=\E[24m:up=\E[A:us=\E[4m:ve=\E[?25h:vi=\E[?25l:
744b39c5158Smillert
745