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