diff options
Diffstat (limited to 'lib/Term/Cap.pm')
-rw-r--r-- | lib/Term/Cap.pm | 251 |
1 files changed, 182 insertions, 69 deletions
diff --git a/lib/Term/Cap.pm b/lib/Term/Cap.pm index e1476a3411..061ca704b7 100644 --- a/lib/Term/Cap.pm +++ b/lib/Term/Cap.pm @@ -1,74 +1,138 @@ +# Term::Cap.pm -- Termcap interface routines package Term::Cap; -require 5.000; -require Exporter; -use Carp; -@ISA = qw(Exporter); -@EXPORT = qw(&Tgetent &Tputs &Tgoto $ispeed $ospeed %TC); - -# $RCSfile: termcap.pl,v $$Revision: 4.1 $$Date: 92/08/07 18:24:16 $ +# Converted to package on 25 Feb 1994 <sanders@bsdi.com> # # Usage: # require 'ioctl.pl'; -# ioctl(TTY,$TIOCGETP,$foo); -# ($ispeed,$ospeed) = unpack('cc',$foo); -# use Termcap; -# &Tgetent('vt100'); # sets $TC{'cm'}, etc. -# &Tputs(&Tgoto($TC{'cm'},$col,$row), 0, 'FILEHANDLE'); -# &Tputs($TC{'dl'},$affcnt,'FILEHANDLE'); +# ioctl(TTY,$TIOCGETP,$sgtty); +# ($ispeed,$ospeed) = unpack('cc',$sgtty); +# +# require Term::Cap; +# +# $term = Tgetent Term::Cap { TERM => undef, OSPEED => $ospeed }; +# sets $term->{'_cm'}, etc. +# $this->Trequire(qw/ce ku kd/); +# die unless entries are defined for the terminal +# $term->Tgoto('cm', $col, $row, $FH); +# $term->Tputs('dl', $cnt = 1, $FH); +# $this->Tpad($string, $cnt = 1, $FH); +# processes a termcap string and adds padding if needed +# if $FH is undefined these just return the string +# +# CHANGES: +# Converted to package +# Allows :tc=...: in $ENV{'TERMCAP'} (flows to default termcap file) +# Now die's properly if it can't open $TERMCAP or if the eval $loop fails +# Tputs() results are cached (use Tgoto or Tpad to avoid) +# Tgoto() will do output if $FH is passed (like Tputs without caching) +# Supports POSIX termios speeds and old style speeds +# Searches termcaps properly (TERMPATH, etc) +# The output routines are optimized for cached Tputs(). +# $this->{_xx} is the raw termcap data and $this->{xx} is a +# cached and padded string for count == 1. # -sub Tgetent { - local($TERM) = @_; - local($TERMCAP,$_,$entry,$loop,$field); - warn "Tgetent: no ospeed set" unless $ospeed; - foreach $key (keys(%TC)) { - delete $TC{$key}; +# internal routines +sub getenv { defined $ENV{$_[0]} ? $ENV{$_[0]} : ''; } +sub termcap_path { + local @termcap_path = ('/etc/termcap', '/usr/share/misc/termcap'); + local $v; + if ($v = getenv(TERMPATH)) { + # user specified path + @termcap_path = split(':', $v); + } else { + # default path + @termcap_path = ('/etc/termcap', '/usr/share/misc/termcap'); + $v = getenv(HOME); + unshift(@termcap_path, $v . '/.termcap') if $v; } - $TERM = $ENV{'TERM'} unless $TERM; - $TERM =~ s/(\W)/\\$1/g; - $TERMCAP = $ENV{'TERMCAP'}; - $TERMCAP = '/etc/termcap' unless $TERMCAP; - if ($TERMCAP !~ m:^/:) { - if ($TERMCAP !~ /(^|\|)$TERM[:\|]/) { - $TERMCAP = '/etc/termcap'; - } - } - if ($TERMCAP =~ m:^/:) { - $entry = ''; + # we always search TERMCAP first + $v = getenv(TERMCAP); + unshift(@termcap_path, $v) if $v =~ /^\//; + grep(-f, @termcap_path); +} + +sub Tgetent { + local($type) = shift; + local($this) = @_; + local($TERM,$TERMCAP,$term,$entry,$cap,$loop,$field,$entry,$_); + + warn "Tgetent: no ospeed set\n" unless $this->{OSPEED} > 0; + $this->{DECR} = 10000 / $this->{OSPEED} if $this->{OSPEED} > 50; + $term = $TERM = $this->{TERM} = + $this->{TERM} || getenv(TERM) || die "Tgetent: TERM not set\n"; + + $TERMCAP = getenv(TERMCAP); + $TERMCAP = '' if $TERMCAP =~ m:^/: || $TERMCAP !~ /(^|\|)$TERM[:\|]/; + local @termcap_path = &termcap_path; + die "Tgetent: Can't find a valid termcap file\n" + unless @termcap_path || $TERMCAP; + + # handle environment TERMCAP, setup for continuation if needed + $entry = $TERMCAP; + $entry =~ s/:tc=([^:]+):/:/ && ($TERM = $1); + if ($TERMCAP eq '' || $1) { # the search goes on + local $first = $TERMCAP eq '' ? 1 : 0; # make it pretty + local $max = 32; # max :tc=...:'s + local $state = 1; # 0 == finished + # 1 == next file + # 2 == search again do { + if ($state == 1) { + $TERMCAP = shift @termcap_path + || die "Tgetent: failed lookup on $TERM\n"; + } else { + $max-- || die "Tgetent: termcap loop at $TERM\n"; + $state = 1; # back to default state + } + + open(TERMCAP,"< $TERMCAP\0") || die "Tgetent: $TERMCAP: $!\n"; + # print STDERR "Trying... $TERMCAP\n"; $loop = " - open(TERMCAP,'<$TERMCAP') || croak \"Can't open $TERMCAP\"; - while (<TERMCAP>) { - next if /^#/; - next if /^\t/; - if (/(^|\\|)${TERM}[:\\|]/) { - chop; - while (chop eq '\\\\') { - \$_ .= <TERMCAP>; + while (<TERMCAP>) { + next if /^\t/; + next if /^#/; + if (/(^|\\|)${TERM}[:\\|]/) { chop; + s/^[^:]*:// unless \$first++; + \$state = 0; + while (chop eq '\\\\') { + \$_ .= <TERMCAP>; + chop; + } + \$_ .= ':'; + last; } - \$_ .= ':'; - last; } - } - close TERMCAP; - \$entry .= \$_; + \$entry .= \$_; "; eval $loop; - } while s/:tc=([^:]+):/:/ && ($TERM = $1); - $TERMCAP = $entry; + die $@ if $@; + #print STDERR "$TERM: $_\n--------\n"; # DEBUG + close TERMCAP; + # If :tc=...: found then search this file again + $entry =~ s/:tc=([^:]+):/:/ && ($TERM = $1, $state = 2); + } while $state != 0; } + die "Tgetent: Can't find $term\n" unless $entry ne ''; + $entry =~ s/:\s+:/:/g; + $this->{TERMCAP} = $entry; + #print STDERR $entry, "\n"; # DEBUG - foreach $field (split(/:[\s:\\]*/,$TERMCAP)) { + # Precompile $entry into the object + foreach $field (split(/:[\s:\\]*/,$entry)) { if ($field =~ /^\w\w$/) { - $TC{$field} = 1; + $this->{'_' . $field} = 1 unless defined $this->{'_' . $1}; + } + elsif ($field =~ /^(\w\w)\@/) { + $this->{'_' . $1} = ""; } elsif ($field =~ /^(\w\w)#(.*)/) { - $TC{$1} = $2 unless defined $TC{$1}; + $this->{'_' . $1} = $2 unless defined $this->{'_' . $1}; } elsif ($field =~ /^(\w\w)=(.*)/) { - $entry = $1; + next if defined $this->{'_' . ($cap = $1)}; $_ = $2; s/\\E/\033/g; s/\\(\d\d\d)/pack('c',oct($1) & 0177)/eg; @@ -82,40 +146,77 @@ sub Tgetent { s/\^(.)/pack('c',ord($1) & 31)/eg; s/\\(.)/$1/g; s/\377/^/g; - $TC{$entry} = $_ unless defined $TC{$entry}; + $this->{'_' . $cap} = $_; } + # else { warn "Tgetent: junk in $term: $field\n"; } } - $TC{'pc'} = "\0" unless defined $TC{'pc'}; - $TC{'bc'} = "\b" unless defined $TC{'bc'}; + $this->{'_pc'} = "\0" unless defined $this->{'_pc'}; + $this->{'_bc'} = "\b" unless defined $this->{'_bc'}; + $this; } -@Tputs = (0,200,133.3,90.9,74.3,66.7,50,33.3,16.7,8.3,5.5,4.1,2,1,.5,.2); +# delays for old style speeds +@Tpad = (0,200,133.3,90.9,74.3,66.7,50,33.3,16.7,8.3,5.5,4.1,2,1,.5,.2); + +# $term->Tpad($string, $cnt, $FH); +sub Tpad { + local($this, $string, $cnt, $FH) = @_; + local($decr, $ms); -sub Tputs { - local($string,$affcnt,$FH) = @_; - local($ms); if ($string =~ /(^[\d.]+)(\*?)(.*)$/) { $ms = $1; - $ms *= $affcnt if $2; + $ms *= $cnt if $2; $string = $3; - $decr = $Tputs[$ospeed]; + $decr = $this->{OSPEED} < 50 ? $Tpad[$this->{OSPEED}] : $this->{DECR}; if ($decr > .1) { $ms += $decr / 2; - $string .= $TC{'pc'} x ($ms / $decr); + $string .= $this->{'_pc'} x ($ms / $decr); } } print $FH $string if $FH; $string; } +# $term->Tputs($cap, $cnt, $FH); +sub Tputs { + local($this, $cap, $cnt, $FH) = @_; + local $string; + + if ($cnt > 1) { + $string = Tpad($this, $this->{'_' . $cap}, $cnt); + } else { + $string = defined $this->{$cap} ? $this->{$cap} : + ($this->{$cap} = Tpad($this, $this->{'_' . $cap}, 1)); + } + print $FH $string if $FH; + $string; +} + +# %% output `%' +# %d output value as in printf %d +# %2 output value as in printf %2d +# %3 output value as in printf %3d +# %. output value as in printf %c +# %+x add x to value, then do %. +# +# %>xy if value > x then add y, no output +# %r reverse order of two parameters, no output +# %i increment by one, no output +# %B BCD (16*(value/10)) + (value%10), no output +# +# %n exclusive-or all parameters with 0140 (Datamedia 2500) +# %D Reverse coding (value - 2*(value%16)), no output (Delta Data) +# +# $term->Tgoto($cap, $col, $row, $FH); sub Tgoto { - local($string) = shift(@_); - local($result) = ''; - local($after) = ''; - local($code,$tmp) = @_; - local(@tmp); - @tmp = ($tmp,$code); - local($online) = 0; + local($this, $cap, $code, $tmp, $FH) = @_; + local $string = $this->{'_' . $cap}; + local $result = ''; + local $after = ''; + local $online = 0; + local @tmp = ($tmp,$code); + local $cnt = $code; + while ($string =~ /^([^%]*)%(.)(.*)/) { $result .= $1; $code = $2; @@ -127,10 +228,10 @@ sub Tgoto { $tmp = shift(@tmp); if ($tmp == 0 || $tmp == 4 || $tmp == 10) { if ($online) { - ++$tmp, $after .= $TC{'up'} if $TC{'up'}; + ++$tmp, $after .= $this->{'_up'} if $this->{'_up'}; } else { - ++$tmp, $after .= $TC{'bc'}; + ++$tmp, $after .= $this->{'_bc'}; } } $result .= sprintf("%c",$tmp); @@ -168,7 +269,19 @@ sub Tgoto { return "OOPS"; } } - $result . $string . $after; + $string = Tpad($this, $result . $string . $after, $cnt); + print $FH $string if $FH; + $string; +} + +# $this->Trequire($cap1, $cap2, ...); +sub Trequire { + local $this = shift; + local $_; + foreach (@_) { + die "Trequire: Terminal does not support: $_\n" + unless defined $this->{'_' . $_} && $this->{'_' . $_}; + } } 1; |