#!/usr/bin/perl
use strict;
use warnings;

die "Usage: $0 <Datei> ...\n" unless (@ARGV);

# Eingabedatei, Eingabezeile, Eingabezeichen
my ($file, $line, $char);

# aktuelle Leseposition in der Datei
my $filepos = 0;

# Dateiinhalt als ASCII-Zeichenfolge
# fuer die jeweils aktuelle Ausgabezeile
# (Zeilenepuffer)
my $asciistring = '';

# Alle angegebenen Dateien bearbeiten
foreach $file(@ARGV)
  {
  open FILE, '<', $file or die "Oops: $!\n";
  print "Datei: $file ...\n";
  print "Adresse|  0  1  2  3   4  5  6  7   "
      . "8  9  A  B   C  D  E  F  | 0123456789ABCDEF\n";
  print "-" x 79,"\n";    
  while ($line = <FILE>)
    {
    # fuer jede Zeile jedes Zeichen bearbeiten
    for $char (split(//,$line))
      { dochar($char, 0); }
    }
  # letzte (unvollstaendige) Zeile bearbeiten
  dochar(' ', 1) while(length($asciistring) != 0);
  close FILE;
  print "-" x 79,"\n";    
  print "\n";
  }

# ein Zeichen hexadezimal ausgeben
# nach 16 Hexzeichen diese auch als ASCII ausgeben
# und Zeilenende ausgeben
sub dochar
  {
  # aktuelles Zeichen,
  # Flag, ob führende Leezeichen auszugeben sind
  # (nur fuer letzte Zeile)
  my($char, $blank) = @_;
  if(length($asciistring) == 0)
    {
    # Zeilenanfang, Adresse ausgeben
    printf("%06X | ", $filepos);
    }
  # Zeichen in den ASCII-String aufnehmen, falls druckbar
  # sonst einen Punkt einfuegen
  $asciistring .= ($char =~ m/[!-~ ]/)? $char : '.';
  if ($blank)
    { print '   '; }
  else
    { printf("%02X ", ord($char)); }
  # alle 4 Bytes ein Leerzeichen einfuegen
  print ' ' if(length($asciistring)%4 == 0);
  # alle 16 Zeichen eine neue Zeile
  if (length($asciistring) == 16)
    {
    # Dateiinhalt als ASCII-Zeichenfolge ausgeben
    print "| $asciistring\n";
    # Zeilenpuffer loeschen
    $asciistring = '';
    # Dateizeiger erhoehen
    $filepos += 16;
    }
  }
