#!/usr/local/bin/perl -w use strict; use Getopt::Std; use vars qw($VERSION); $VERSION = q$Revision: 1.3 $ =~ /Revision:\s*(\S*)/; use vars qw($opt_b $opt_f $opt_p $opt_x $opt_l); use vars qw($opt_e $opt_E $opt_s $opt_t); $opt_f = 0; getopts('bfpxl:eEst') || die "Bad options.\n"; if ($opt_l and $opt_l !~ /\D/) { # multiply by 2 for half-lines $opt_l *= 2; } else { $opt_l = 512; } my @buf = []; # character buffer my $col = 0; # current column number my $row = 0; # current row number my $max_row = -2; # max populated row my $iset = 1; # current input character set (1 or 2) my $oset = 1; # current output character set (1 or 2) my $front = 0; # note whether at front of line in output my $spaces = ''; # save spaces for converting to tabs # prepare regexes for matching linefeeds # any full reverse half reverse half forward my @re; if ($opt_E) { # as for IRIX @re = qw( [7-9] ^7$ ^8$ ^9$ ); } elsif ($opt_e) { # as for BSD @re = qw( [\x07-\x09] ^\x07$ ^\x08$ ^\x09$ ); } else { # accept either @re = qw( [7-9\x07-\x09] ^[7\x07]$ ^[8\x08]$ ^[9\x09]$ ); } # INPUT while (<>) { # chop trailing characters not followed by a linefeed of any kind if ($opt_t) { $_ =~ s/^(.*(?:\x0A|\e$re[0])|).*$/$1/sxo; } my @chars = split m//; my $i; for ($i=0; $i<=$#chars; ++$i) { my $c = $chars[$i]; if ($c eq "\x1B" or $c eq "\x0B") { if ($c eq "\x0B" or $chars[++$i] =~ /$re[1]/xo) { # reverse line feed $row -= 2; $row >= 0 or $row = 0; } elsif ($chars[$i] =~ /$re[2]/xo) { # half reverse line feed $row -= 1; $row >= 0 or $row = 0; } elsif ($chars[$i] =~ /$re[3]/xo) { # half forward line feed $row += 1; } else { # unrecognized escape if ($opt_p) { add_char("\x1B"); add_char($chars[$i]); } else { } } } elsif ($c eq "\x08") { # backspace $col--; $col >= 0 or $col = 0; } elsif ($c eq "\x0D") { # carriage return $col = 0; } elsif ($c eq "\x0A") { # line feed $row += 2; $col = 0; } elsif ($c eq "\x0F") { # shift in $iset = 1; } elsif ($c eq "\x0E") { # shift out $iset = 2; } elsif ($c eq "\x20") { # space $col++; } elsif ($c eq "\x09") { # tab $col += (($col % 8) || 8); } elsif ($c gt "\x20") { # printable character add_char($c); } else { # unrecognized ctl char } # start row if necessary $buf[$row] ||= []; # check buffer size if (@buf > $opt_l) { print_line(0); if ($buf[1] and @{$buf[1]}) { # print next half line print "\e9"; print "\x0D" if !$front; $front = 1; print_line(1); print "\e9"; print "\x0D" if !$front; $front = 1; } else { # skip to next full line print "\x0A"; $front = 1; } # splice off top two rows splice(@buf, 0, 2); $max_row -= 2; } } } # add_char # add a character at the current row and column # uses globals @buf, $row, $max_row, $col, $iset, $opt_f, $opt_b sub add_char { my($char) = @_; # move to next full line, if necessary my $r = $row; if (!$opt_f) { $r += $row & 1; # start row if necessary $buf[$r] ||= []; } # start column if necessary $buf[$row][$col] ||= []; if ($opt_b) { # no backspacing - just save last character/set $buf[$r][$col][0] = [$char, $iset]; } else { # backspacing - add character/set to end of list push @{$buf[$r][$col]}, [$char, $iset]; } $col++; $max_row = $r if $r > $max_row; } # OUTPUT # add a blank row if buffer does not end with one if ($max_row == $#buf) { push @buf, []; } # add a blank row if buffer ends on half line if ($#buf & 1) { push @buf, []; } for ($row=0; $row < $max_row; ) { # print the current line print_line($row); # print appropriate line ending if ($buf[$row+1] and @{$buf[$row+1]}) { # half line feed print "\e9"; print "\x0D" if !$front; $front = 1; } else { # full line feed print "\x0A"; # skip half line ++$row; $front = 1; } ++$row; } # print the last populated line ($row == $max_row) print_line($row); # shift in if necessary if (!$opt_s) { if ($oset == 2) { print "\x0F"; $oset = 1; } } # print linefeeds for remaining blank lines for ($row++; $row < $#buf; $row += 2) { print "\x0A"; $front = 1; } # print half line feed if necessary if ($max_row & 1) { print "\e9"; print "\x0D" if !$front; $front = 1; } # print_line # print the current line # return character set of the last character # uses globals @buf, $oset, $front, $opt_x, $opt_s sub print_line { my($row) = @_; my $char; if (@{$buf[$row]}) { $front = 0; } my $col; for ($col=0; $col<=$#{$buf[$row]}; ++$col) { if ($buf[$row][$col]) { if ($spaces) { # print saved spaces print $spaces; $spaces = ''; } my $b; foreach $char (@{$buf[$row][$col]}) { # print backspace if necessary print "\x08" if $b++; # switch character set if necessary if ($char->[1] != $oset) { $oset = $char->[1]; print ($oset == 1 ? "\x0F" : "\x0E"); } # print character print $char->[0]; } } else { # no characters; space if ($opt_x) { print ' '; } else { if (not (($col+1) % 8)) { # at tab stop print "\t"; $spaces = ''; } else { $spaces .= ' '; } } } } # switch to character set 1 for line ending if ($opt_s) { if ($oset == 2) { print "\x0F"; $oset = 1; } } } exit 0; __END__ =pod =head1 NAME B