1#!/usr/local/bin/perl 2# 3# $Id: log2ansi,v 1.9 2004/03/08 21:31:26 peder Exp $ 4# 5# Copyright (C) 2002, 2003 by Peder Stray <peder@ninja.no> 6# 7# This is a standalone perl program and not intended to run within 8# irssi, it will complain if you try to... 9 10use strict; 11use Getopt::Long; 12use vars qw(%ansi %base %attr %old); 13use vars qw(@bols @nums @mirc @irssi @mc @mh @ic @ih); 14 15use vars qw{$VERSION %IRSSI}; 16($VERSION) = '$Revision: 1.9 $' =~ / (\d+\.\d+) /; 17%IRSSI = ( 18 name => 'log2ansi', 19 authors => 'Peder Stray', 20 contact => 'peder@ninja.no', 21 url => 'http://ninja.no/irssi/log2ansi', 22 license => 'GPL', 23 description => 'convert mirc color and irssi interal formatting to ansi colors, useful for log filtering', 24 ); 25 26if (__PACKAGE__ =~ /^Irssi/) { 27 # we are within irssi... die! 28 Irssi::print("%RWarning:%n log2ansi is should not run from within irssi"); 29 die "Suicide to prevent loading\n"; 30} 31 32my $clear = 0; 33 34GetOptions( 35 '--clear!' => \$clear, 36 ); 37 38for (@ARGV) { 39 if (/\.bz2$/) { 40 $_ = "bunzip2 < '$_' |"; 41 } elsif (/\.gz$/) { 42 $_ = "gunzip < '$_' |"; 43 } 44} 45 46my($n) = 0; 47%ansi = map { $_ => $n++ } split //, 'krgybmcw'; 48 49@bols = qw(bold underline blink reverse fgh bgh); 50@nums = qw(fgc bgc); 51 52@base{@bols} = qw(1 4 5 7 1 5); 53@base{@nums} = qw(30 40); 54 55@mirc = split //, 'WkbgRrmyYGcCBMKw'; 56@irssi = split //, 'kbgcrmywKBGCRMYW'; 57 58@mc = map {$ansi{lc $_}} @mirc; 59@mh = map {$_ eq uc $_} @mirc; 60 61@ic = map {$ansi{lc $_}} @irssi; 62@ih = map {$_ eq uc $_} @irssi; 63 64sub defc { 65 my($attr) = shift || \%attr; 66 $attr->{fgc} = $attr->{bgc} = -1; 67 $attr->{fgh} = $attr->{bgh} = 0; 68} 69 70sub defm { 71 my($attr) = shift || \%attr; 72 $attr->{bold} = $attr->{underline} = 73 $attr->{blink} = $attr->{reverse} = 0; 74} 75 76sub def { 77 my($attr) = shift || \%attr; 78 defc($attr); 79 defm($attr); 80} 81 82sub setold { 83 %old = %attr; 84} 85 86sub emit { 87 my($str) = @_; 88 my(%elem,@elem); 89 90 my(@clear) = ( (grep { $old{$_} > $attr{$_} } @bols), 91 (grep { $old{$_}>=0 && $attr{$_}<0 } @nums) 92 ); 93 94 $elem{0}++ if @clear; 95 96 for (@bols) { 97 $elem{$base{$_}}++ 98 if $attr{$_} && ($old{$_} != $attr{$_} || $elem{0}); 99 } 100 101 for (@nums) { 102 $elem{$base{$_}+$attr{$_}}++ 103 if $attr{$_} >= 0 && ($old{$_} != $attr{$_} || $elem{0}); 104 } 105 106 @elem = sort {$a<=>$b} keys %elem; 107 108 if (@elem) { 109 @elem = () if @elem == 1 && !$elem[0]; 110 printf "\e[%sm", join ";", @elem 111 unless $clear; 112 } 113 114 print $str; 115 116 setold; 117} 118 119while (<>) { 120 chomp; 121 def; 122 setold; 123 124 while (length) { 125 if (s/^\cB//) { 126 # toggle bold 127 $attr{bold} = !$attr{bold}; 128 129 } elsif (s/^\cC//) { 130 # mirc colors 131 132 if (/^[^\d,]/) { 133 defc; 134 } else { 135 136 if (s/^(\d\d?)//) { 137 $attr{fgc} = $mc[$1 % 16]; 138 $attr{fgh} = $mh[$1 % 16]; 139 } 140 141 if (s/^,//) { 142 if (s/^(\d\d?)//) { 143 $attr{bgc} = $mc[$1 % 16]; 144 $attr{bgh} = $mh[$1 % 16]; 145 } else { 146 $attr{bgc} = -1; 147 $attr{bgh} = 0; 148 } 149 } 150 } 151 152 } elsif (s/^\cD//) { 153 # irssi format 154 155 if (s/^a//) { 156 $attr{blink} = !$attr{blink}; 157 } elsif (s/^b//) { 158 $attr{underline} = !$attr{underline}; 159 } elsif (s/^c//) { 160 $attr{bold} = !$attr{bold}; 161 } elsif (s/^d//) { 162 $attr{reverse} = !$attr{reverse}; 163 } elsif (s/^e//) { 164 # indent 165 } elsif (s/^f([^,]*),//) { 166 # indent_func 167 } elsif (s/^g//) { 168 def; 169 } elsif (s/^h//) { 170 # cleol 171 } elsif (s/^i//) { 172 # monospace 173 } else { 174 s/^(.)(.)//; 175 my($f,$b) = map { ord($_)-ord('0') } $1, $2; 176 if ($f<0) { 177# $attr{fgc} = -1; $attr{fgh} = 0; 178 } else { 179 # c>7 => bold, c -= 8 if c>8 180 $attr{fgc} = $ic[$f]; 181 $attr{fgh} = $ih[$f]; 182 } 183 if ($b<0) { 184# $attr{bgc} = -1; $attr{bgh} = 0; 185 } else { 186 # c>7 => blink, c -= 8 187 $attr{bgc} = $ic[$b]; 188 $attr{bgh} = $ih[$b]; 189 } 190 } 191 192 } elsif (s/^\cF//) { 193 # blink 194 $attr{blink} = !$attr{blink}; 195 196 } elsif (s/^\cO//) { 197 def; 198 199 } elsif (s/^\cV//) { 200 $attr{reverse} = !$attr{reverse}; 201 202 } elsif (s/^\c[\[([^m]*)m//) { 203 my(@ansi) = split ";", $1; 204 my(%a); 205 206 push @ansi, 0 unless @ansi; 207 208 for my $code (@ansi) { 209 if ($code == 0) { 210 def(\%a); 211 } elsif ($code == $base{bold}) { 212 $a{bold} = 1; 213 } elsif ($code == $base{underline}) { 214 $a{underline} = 1; 215 } elsif ($code == $base{blink}) { 216 $a{underline} = 1; 217 } elsif ($code == $base{reverse}) { 218 $a{reverse} = 1; 219 } elsif ($code => 30 && $code <= 37) { 220 $a{fgc} = $code - 30; 221 } elsif ($code => 40 && $code <= 47) { 222 $a{bgc} = $code - 40; 223 } else { 224 $a{$code} = 1; 225 } 226 } 227 228 if ($a{fgc} >= 0 && $a{bold}) { 229 $a{fgh} = 1; 230 $a{bold} = 0; 231 } 232 233 if ($a{bgc} >= 0 && $a{blink}) { 234 $a{bgh} = 1; 235 $a{blink} = 0; 236 } 237 238 for my $key (keys %a) { 239 $attr{$key} = $a{$key}; 240 } 241 242 } elsif (s/^\c_//) { 243 $attr{underline} = !$attr{underline}; 244 245 } else { 246 s/^(.[^\cB\cC\cD\cF\cO\cV\c[\c_]*)//; 247 emit $1; 248 } 249 } 250 251 def; 252 emit "\n"; 253} 254