#!/usr/bin/perl -w use strict; use warnings; use Encode::Guess; sub DEFAULT_ENCODING_NAME () { 'utf8'; } sub DEFAULT_STATIC_READ_LINE () { 256; } my $global_previous_multibyte_encoding_name = DEFAULT_ENCODING_NAME; my $global_static_encoding_name; sub is_encode_command ($) { $_[0] =~ /^(diff|annotate|blame)$/; } sub get_program_full_path () { $0 =~ m!/?([^/]+)$!; my $program = $1; my $program_full_path; $_ = "/usr/local/bin/$program"; $program_full_path = $_ if -f $_; $_ = "/usr/bin/$program"; $program_full_path = $_ if -f $_; $_ = "$ENV{'HOME'}/local/bin/$program"; $program_full_path = $_ if -f $_; $program_full_path; } sub check_or_die_program_full_path ($) { my $program_full_path = $_[0]; die unless defined($program_full_path); my @tmp_a = stat($0); my @tmp_b = stat($program_full_path); die if $tmp_a[1] == $tmp_b[1]; } sub set_binmode () { my $binmode = ':encoding(' . DEFAULT_ENCODING_NAME . ')'; my $lang = defined($ENV{'LANG'}) ? $ENV{'LANG'} : ''; if ($lang =~ /utf/i) { $binmode = ':encoding(utf8)'; } elsif ($lang =~ /euc/i) { $binmode = ':encoding(euc-jp)'; } elsif ($lang =~ /sjis|shiftjis|shift_jis/i or defined($ENV{'CYGWIN'})) { $binmode = ':encoding(shiftjis)'; } elsif ($lang =~ /junet|\.jis/i) { $binmode = ':encoding(7bit-jis)'; } elsif (`uname` =~ /darwin/i) { $binmode = ':encoding(utf8)'; } binmode(STDOUT, $binmode); } sub print_core ($) { my $cooked_line = $_[0]; $cooked_line =~ s/[\x0d\x0a]+//; if (defined($cooked_line) and $cooked_line ne '') { if (defined($global_static_encoding_name)) { $cooked_line = eval{ Encode::decode($global_static_encoding_name, $cooked_line, Encode::FB_DEFAULT) }; $cooked_line = "failed\n" unless defined $cooked_line; } else { my $encoding = guess_encoding($cooked_line); if (ref($encoding)) { $global_previous_multibyte_encoding_name = $encoding->name if $encoding->name ne 'ascii'; $cooked_line = eval{ Encode::decode($encoding->name, $cooked_line, Encode::FB_DEFAULT) }; $cooked_line = "failed\n" unless defined $cooked_line; } else { $cooked_line = eval{ Encode::decode($global_previous_multibyte_encoding_name, $cooked_line, Encode::FB_DEFAULT) }; $cooked_line = "failed\n" unless defined $cooked_line; } } print "$cooked_line\n"; } else { print "\n"; } } my $program_full_path = get_program_full_path(); check_or_die_program_full_path($program_full_path); if ($program_full_path =~ /diff$/ or grep(is_encode_command($_), @ARGV)) { set_binmode(); my $pid = open(my $fh, '-|'); if ($pid == 0) { exec($program_full_path, @ARGV); } else { Encode::Guess->set_suspects(qw/euc-jp shiftjis 7bit-jis/); my @static_line; { my $counter = DEFAULT_STATIC_READ_LINE; my $tmp = ''; while (<$fh>) { $tmp .= $_; push(@static_line, $_); last unless --$counter >= 0; } my $encoding = guess_encoding($tmp); if (ref($encoding)) { $global_static_encoding_name = $encoding->name if $encoding->name ne 'ascii'; } } foreach (@static_line) { print_core($_); } while (<$fh>) { print_core($_); } close($fh); exit($? >> 8); } } else { exec($program_full_path, @ARGV); }