{--------------------------------------------------------------}
{                          HexDump                             }
{                                                              }
{            Hex dump program for all disk files               }
{                                                              }
{                             by Jeff Duntemann                }
{                             Turbo Pascal V3.0                }
{                             Last update 2/1/86               }
{                                                              }
{    From the book, COMPLETE TURBO PASCAL, by Jeff Duntemann   }
{    Scott, Foresman & Co. (c) 1986,1987  ISBN 0-673-18600-8   }
{--------------------------------------------------------------}

PROGRAM HexDump;

{$V-}  { Relaxes String length type checking on VAR paramaters }

CONST
  Up   = True;
  Down = False;

TYPE
  String255   = String[255];
  String128   = String[128];
  String80    = String[80];
  String40    = String[40];
  Block       = ARRAY[0..127] OF Byte;  { One disk sector   }
  BlockArray  = ARRAY[0..15] OF Block;  { BlockRead reads   }
                                        { 16 Blocks at once }


VAR
  I,J,K       : Integer;
  Parm        : String80;
  Ch          : Char;
  DumpFile    : FILE;
  XBlock      : Block;
  DiskData    : BlockArray;
  Blocks      : Integer;        { Counts Blocks within }
                                { BlockArray }
  BlockCount  : Integer;        { Tallies total # Blocks Read }
  Buffers     : Integer;
  Remains     : Integer;
  Device      : Text;           { Will be either LST: or CON: }



{$I FRCECASE.SRC }   { Described in Section 15.3 }
{$I YES.SRC }        { Described in Section 17.2 }
{$I WRITEHEX.SRC }   { Described in Section 20.2 }


{>>>>DumpBlock<<<<}

PROCEDURE DumpBlock(XBlock : Block; VAR Device : Text);

VAR
  I,J,K : Integer;
  Ch    : Char;

BEGIN
  FOR I:=0 TO 7 DO        { Do a hexdump of 8 lines of 16 chars }
    BEGIN
      FOR J:=0 TO 15 DO   { Show hex values }
        BEGIN
          WriteHex(Device,Ord(XBlock[(I*16)+J]));
          Write(Device,' ')
        END;
      Write(Device,'   |');    { Bar to separate hex & ASCII }
      FOR J:=0 TO 15 DO        { Show printable chars or '.' }
        BEGIN
          Ch:=Chr(XBlock[(I*16)+J]);
          IF ((Ord(Ch)<127) AND (Ord(Ch)>31))
          THEN Write(Device,Ch) ELSE Write(Device,'.')
        END;
      Writeln(Device,'|')
    END;
  FOR I:=0 TO 1 DO Writeln(Device,'')
END;  { DumpBlock }


{<<<<ShowHelp>>>>}

PROCEDURE ShowHelp(HelpName : String80);

VAR
  HelpFile : Text;
  HelpLine : String80;
  I        : Integer;

BEGIN
  Writeln;
  Assign(HelpFile,HelpName);
  {$I-} Reset(HelpFile); {$I+}
  IF IOResult = 0 THEN
    FOR I := 1 TO 20 DO
      BEGIN
        Readln(HelpFile,HelpLine);
        Writeln(HelpLine)
      END;
  Close(HelpFile)
END;


BEGIN
  CLRSCR;                        { Clear the CRT }
  Parm := '';
                                 { Caps lock printer parameter }
  IF ParamCount > 1 THEN Parm := ForceCase(Up,ParamStr(2));
  IF ParamCount < 1 THEN         { Error - no parms given }
    BEGIN
      Writeln('<<Error!>> You must enter a filename after invoking');
      Write  ('           HexDump.COM.  Display help screen? (Y/N): ');
      IF Yes THEN ShowHelp('DUMPHELP.TXT')
    END
  ELSE
    BEGIN
      Assign(DumpFile,ParamStr(1));  { Attempt to open the file }
      {$I-} Reset(DumpFile); {$I+}
      IF IOResult <> 0 THEN       { Error if file won't open }
        BEGIN
          Writeln('<<Error!>> File ',ParamStr(1),' does not exist.');
          Write  ('           Display help screen? (Y/N): ');
          IF Yes THEN ShowHelp('DUMPHELP.TXT');
        END
      ELSE
        BEGIN                     { See if print Parm was entered; }
                                  { and select output Device }
          IF (Pos('PRINT',Parm) = 1) OR (Pos('P',Parm) = 1) THEN
            Assign(Device,'LST:') ELSE Assign(Device,'CON:');
          Reset(Device);
          BlockCount := FileSize(DumpFile);  { FileSize in 128-Byte Blocks }
          IF BlockCount = 0 THEN
            Writeln('File ',ParamStr(1),' is empty.')
          ELSE
            BEGIN
              Buffers := BlockCount DIV 16;  { # of 16-Block Buffers }
              Remains := BlockCount MOD 16;  { # of Blocks in last buffer }
              FOR I := 1 TO Buffers DO       { Dump full 16-Block Buffers }
                BEGIN
                  BlockRead(DumpFile,DiskData,16); { Read 16 disk Blocks }
                  FOR J := 0 TO 15 DO
                    DumpBlock(DiskData[J],Device)  { Dump 'em... }
                END;
              IF Remains > 0 THEN  { If fractional buffer Remains, dump it }
                BEGIN
                  BlockRead(DumpFile,DiskData,Remains); { Read last buffer }
                  FOR I := 0 TO Remains-1 DO
                    DumpBlock(DiskData[I],Device)       { Dump it }
                END
            END;
          Close(DumpFile)
        END
    END
END.
