html/log2ansi.pl
1 #! /usr/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
10 use strict;
11 use Getopt::Long;
12 use vars qw(%ansi %base %attr %old);
13 use vars qw(@bols @nums @mirc @irssi @mc @mh @ic @ih);
14
15 use 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
26 if (__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
32 my $clear = 0;
33
34 GetOptions(
35 '--clear!' => \$clear,
36 );
37
38 for (@ARGV) {
39 if (/\.bz2$/) {
40 $_ = "bunzip2 < '$_' |";
41 } elsif (/\.gz$/) {
42 $_ = "gunzip < '$_' |";
43 }
44 }
45
46 my($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
64 sub defc {
65 my($attr) = shift || \%attr;
66 $attr->{fgc} = $attr->{bgc} = -1;
67 $attr->{fgh} = $attr->{bgh} = 0;
68 }
69
70 sub defm {
71 my($attr) = shift || \%attr;
72 $attr->{bold} = $attr->{underline} =
73 $attr->{blink} = $attr->{reverse} = 0;
74 }
75
76 sub def {
77 my($attr) = shift || \%attr;
78 defc($attr);
79 defm($attr);
80 }
81
82 sub setold {
83 %old = %attr;
84 }
85
86 sub 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
119 while (<>) {
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 }