#!/usr/bin/perl
#
# wwwfixpl v.2.1 - konwerter stron WWW (c)JS. *** PUBLIC DOMAIN ***
# Wiecej informacji: ftp://ftp.agh.edu.pl/ogonki/konwertery/js/wwwfixpl.txt
#

use Getopt::Std;
getopts( 'mctfUe:qQvNDl' );
$|=1;

$isoset    = "\241\306\312\243\321\323\246\254\257\261\346\352\263\361\363\266\274\277";
$cp1250set = "\245\306\312\243\321\323\214\217\257\271\346\352\263\361\363\234\237\277";
$cp852set  = "\244\217\250\235\343\340\227\215\275\245\206\251\210\344\242\230\253\276";

if( $opt_m != 1 ) { $add_meta = 1; }
if( $opt_c != 1 ) { $fix_cr = 1; }
if( $opt_t != 1 ) { $add_html_tag = 1; }
if( $opt_f != 1 ) { $rm_face = 1; }  
if( $opt_U == 1 ) { $update_time = 1; }
if( $opt_e ne '' ) { $exts = $opt_e; } else { $exts = "html|htm|shtml"; }
if( $opt_q == 1 ) { $verbose=0; } else { $verbose=1; }
if( $opt_v == 1 ) { $Verbose=1; } else { $Verbose=0; }
if( $opt_N == 1 ) { $nomod = 1; }
if( $opt_D == 1 ) { $cp852 = 1; }
if( $opt_l == 1 ) { $lc_fnames = 1; }


# Ktos w firmie [...] zwariowal i wstawil do programu [...] kod, 
# ktory czasem sie uwaktywnia i powoduje ze polskie litery sa
# zapisywane na nastepujacych pozycjach:
# Pozycje z kodem 0 oznaczają kod, którego jeszcze nie znam.
#                    A   C   E   L   N   O   S   Zi rZy  
@crazy_codes = ( qw( 0   0   0   321 0   0   346 0   0
                     261 263 281 322 324 0   347 378 380 ) );


if( $opt_Q != 1 )
{
  print "### wwwfixpl - konwerter stron WWW (c)JS. *** PUBLIC DOMAIN ***\n";
  print "### Wiecej informacji: ftp://ftp.agh.edu.pl/ogonki/konwertery/js/wwwfixpl.txt\n";
  
  print "### Opcje: ";
  $a = '';
  if( $add_meta == 1 ) { $a .= "dodaj META, "; }
  if( $fix_cr == 1 ) { $a .= "usun CRy, "; }
  if( $add_html_tag == 1 ) { $a .= "dodaj <HTML>, "; }
  if( $update_time == 1 ) { $a .= "tworz flage, "; }
  chop $a; chop $a; print "$a.\n";
}


# Zbieranie nazw plikow do konwersji (do tablicy @files)
if( $#ARGV >= 0 )
{
  @args = @ARGV;
}
else
{
  @args = ( '.' );
}
@files = ();
$files_sum_size = 0;
@update_time_files = (); 
$update_time_file_name = ".wwwfixpl_flag";

if( $verbose ) { print "*** Przeszukuje katalogi w poszukiwaniu plikow do konwersji:\n"; }
while( $arg = shift @args )
{
  lstat($arg);
  if( -d _ ) 
  { 
    if( $update_time == 1) { push( @update_time_files, "$arg/$update_time_file_name" ); }
    if( $verbose ) { print "* Przeszukuje: '$arg' "; }
    if( opendir( DIR, $arg ) )
    {
      $n=0;
      if( $update_time == 1 )
      {
        $saved_last_mtime = (-M "$arg/$update_time_file_name");
        print ":$saved_last_mtime:";
        if( $saved_last_mtime eq '' ) { $saved_last_mtime = '9'x9; };
      }
      while( $fn = readdir( DIR ) )
      {
        if( $fn !~ /^\./ )
        {
          $newarg = "$arg/$fn";
          lstat( $newarg );
          if( -f _ and $newarg =~ /\.($exts)$/ )
          {
            if( not $update_time or (-M _) < $saved_last_mtime  )
            {
              $n++;
              push( @files, $newarg ); 
              $files_sum_size += -s _; 
            }
          }
          elsif( -d _ )
          {
            $n++;
            push( @args, "$arg/$fn" ); 
          }
        }
      }
      if( $verbose ) { printf( "(%d/%d/%d)\n", $n, $#args+1, $#files+1 ); }
      closedir( DIR );
    }
    else
    {
      if( $verbose ) { print "Nie da sie czytac !!!\n"; }
    }
  }
  elsif( -f _ )
  {
    push( @files, $arg ); 
    $files_sum_size += -s _; 
  }
}

if( $opt_Q != 1 )
{
  printf( "### Konwersja %d plikow o lacznym rozmiarze %d KB.\n", 
          $#files +1, $files_sum_size / 1024 );
}




# Konwersja wyszukanych plikow
$done_size = 0;
$nsaved = 0; $saved_size = 0; $nskipped = 0; 
while( $fn = shift @files )
{
  $percent = ($done_size * 100 / $files_sum_size);
  $percent =~ s/\.*$//;
  if( $verbose ) { printf( "[%3d%%] ", $percent ); }
  &conv_file( $fn );
}
if( $verbose ) { print "[100%] "; } 
if( $opt_Q != 1 ) 
{
  printf( "Poprawilem %d plikow (%d KB); zostawilem niezmienione %d plikow.\n",
          $nsaved, $saved_size/1024, $nskipped ); 
}


# Zapis flag czasu konwersji
while( $fn = shift @update_time_files )
{
  if( $verbose ) { print "* Tworze plik-flage czasu konwersji: $fn\n"; }
  if( open( F, ">$fn" ) ) { close F; } else { print "    Nie moge pisac! ($!)\n"; }
}

exit 0;





### 
### Wlasciwa konwersja
###
sub conv_file
{
  my( $fn ) = @_;
  if( $verbose ) { print "$fn: "; }

  if( $nomod == 1 )
  {
    $atime = (stat($fn))[8];
    $mtime = (stat($fn))[9];
  }

  # Czytaj plik do pamieci
  if( $Verbose ) { print "<"; }
  local $/ = undef;
  unless( open( F, $fn ) )
  {
    print STDERR "NIE MOGE CZYTAC!\n";
    next;
  }
  $_ = <F>;
  close F;
  $done_size += length( $_ );

  # Zapamietaj stare zawartosc by moc stwierdzic czy cos sie zmienilo
  if( $Verbose ) { print "."; }
  $prev = $_;

  if( $Verbose ) { print "%"; }
  s/\&\#6\;/&nbsp;/g;
  #s/\&#(339|347)\;/\266/g;  # To jakies dziwactwo tworzone przez HTML save w MS Word
  #tr/\343\323\320/""-/; # Polskie cudzyslowy i dluga pauza z CP1250


  if( $Verbose ) { print "#"; }
  s/\&\#(\d+)\;/robchr($1)/eg;

  if( $Verbose ) { print "P"; }
  if( $cp852 == 1 )
  {
    tr/\244\217\250\235\343\340\227\215\275\245\206\251\210\344\242\230\253\276/\241\306\312\243\321\323\246\254\257\261\346\352\263\361\363\266\274\277/;
  }
  else
  {
    tr/\245\306\312\243\321\323\214\217\257\271\346\352\263\361\363\234\237\277/\241\306\312\243\321\323\246\254\257\261\346\352\263\361\363\266\274\277/;
    # Nie wiem jeszcze czemu to poniżej nie działa:
    # tr/${cp1250set}/${isoset}/;
  }

  if( $Verbose ) { print "&"; }
  # Jesli by jakies wadliwe paskudztwo zapisalo polskie litery jako 
  # entitles ISO-8859-1 to zamien je na wlasciwe znaki
  s/\&yen\;/\241/g;      s/\&iexcl\;/\241/g;
  s/\&AElig\;/\306/g;
  s/\&Ecirc\;/\312/g;
  s/\&pound\;/\243/g;
  s/\&Ntilde\;/\321/g;
  s/\&Oacute\;/\323/g;
                       s/\&brvbar\;/\246/g;
                       s/\&not\;/\254/g;
  s/\&macr\;/\257/g;
  s/\&sup1\;/\261/g;     s/\&plusmn\;/\261/g;
  s/\&aelig\;/\346/g;
  s/\&ecirc\;/\352/g;
  s/\&sup3\;/\263/g;
  s/\&ntilde\;/\361/g;
  s/\&oacute\;/\363/g;
                       s/\&para\;/\266/g;
                       s/\&frac14\;/\274/g;
  s/\&iquest\;/\277/g;

  if( $fix_cr )
  {
    if( $Verbose ) { print "c"; }
    s/\r\n/\n/g;
  }

#  if( $add_meta )
#  {
#    if( $Verbose ) { print "m"; }
#    if( /<HEAD>.*<\/HEAD>/is )
#    {
#      unless( s/^(.*<HEAD>.*)<META\s+http-equiv="content-type"\s+content="[^"]+">(.*<\/HEAD>)/$1<META http-equiv="content-type" content="text\/html; charset=ISO-8859-2">$2/is )
#      {
#        s/^(.*<HEAD>)/$1\n  <META http-equiv="content-type" content="text\/html; charset=ISO-8859-2">\n/is;
#      }
#    }
#    else
#    {
#      $_ = "<HEAD>\n  <META http-equiv=\"content-type\" content=\"text/html; charset=ISO-8859-2\">\n</HEAD>\n\n$_";
#    }
# }
#
#  if( $add_html_tag && not /<html>/is )
#  {
#    if( $Verbose ) { print "h"; }
#    $_ = "<HTML>\n\n$_\n\n</HTML>\n";
#  }

  if( $rm_face == 1 )
  {
#    if( $Verbose ) { print "f"; }
#    s/(<font [^>]*)face="[^"]+"([^>]*>)/$1$2/gis;
#    s/<(font) +>/<$1>/gis;
#    s/<(font) +/<$1 /gis;

    # A teraz usun powstale pary <FONT> ... </FONT> (bez argumentow)
    $flevel=0;
    $fixed = '';
    %fdel = ();
    while( /<(font)([^>]*)>|<(\/font)>/is )
    {
      $_ = $';
      $fixed .= $`;

      if( $1 ne '' )
      {
        $flevel++;
        if( $2 eq '' )
        {
          $fdel{$flevel} = 1;
        }
        else
        {
          $fixed .= "<$1$2>";
        }
      }
      else
      {
        if( $fdel{$flevel} == 1 )
        {
          delete $fdel{$flevel};
        }
        else
        {
          $fixed .= "<$3>";
        }
        $flevel--;
      }
    }
    $_ = "${fixed}$_";
  }

  if( $lc_fnames == 1 )
  {
    if( $Verbose ) { print "l"; }
    s/<img\s+[^>]*src="?[^>"]+"?[^>]*>/\L$&/gis;
    s/<a\s+[^>]*href="?[^>"]+"?[^>]*>/\L$&/gis;
  }


  if( $Verbose ) { print ">"; }


  # Jesli nic sie nie zmienilo to nie zapisuj
  if( $_ eq $prev )
  {
    if( $verbose ) { print " bez zmian.\n"; }
    $nskipped++;
    next;
  }

  # Zapisz zmiany
  $nsaved++;
  $saved_size += length( $_ );
  unless( open( F, ">$fn" ) )
  {
    print "\n----- $fn:NIE MOGE PISAC! ($!)\n";
    next;
  }
  print F $_;
  close F;

  if( $nomod == 1 ) { utime $atime, $mtime, $fn; }
  if( $verbose ) { print " POPRAWIONY.\n"; }
}


# Pomocnicze: zwraca znak o podanym kodzie, z uwzględnieniem kodów > 256
# (patrz komentarz przed @crazy_codes). Jeśli nie potrafi obsłużyć 
# jakiegoś kodu to wypisuje go i zwraca sekwencję &#kod; niezmienioną
sub robchr()
{
  my( $kod ) = @_;
  if( $kod < 256 ) { return chr($kod); }

  for( $i=0; $i<18; $i++ )
  {
    if( $crazy_codes[$i] == $kod )
    {
      return substr($isoset,$i,1);
    }
  }

  print "[&#$kod;]";
  return "&#$kod;";
}
