DataMuseum.dk

Presents historical artifacts from the history of:

DANOSI

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DANOSI

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦e7fc18e43⟧ TextFile

    Length: 18763 (0x494b)
    Types: TextFile
    Names: »COMPARE.PAS«

Derivation

└─⟦e2123b2a1⟧ Bits:30010498 DVBS1.SW2103.src.1.8-1 Pascal TOOLS JTAS 1989-04-26 LEIF NIELSEN E.d.
    └─⟦this⟧ »COMPARE.PAS« 

TextFile

      {[A=20,I=2,L=4,E=3,W=1-100] PASCFORM direktiv }\r
  PROGRAM Compare(FileA, FileB, Output);\r
 \r
      { Original text occured in: Pascal News #12 p. 20-23.\r
      Made arround 1978-03-01 by James F. Miner,\r
      Social Science Research, Univ. of Minnesota.\r
 \r
      Corrections and additions made by Willett Kempton,\r
      Univ. of California, Berkley\r
      occured in: Pascal News #15 p. 28-30, September 1979,\r
      and these additions are included.\r
 \r
      Retyped  and modifyed to fit Borland Turbo Pascal\r
      1988-04-09 by Hans JЏrgen Jakobsen JTAS, Јrhus, Denmark.\r
      ----------------------------------------------------------------------------\r
      Date.      Init. Vers. Explanation.\r
 \r
      1989-02-04  LEI  1.4  Improved call parameter processing.\r
      1989-04-24  LEI  1.5  Check for Heap owerflow inserted.\r
      ---------------------------------------------------------------------------}\r
 \r
      {$M 16000, 0, 655000 }\r
      {$R+,S+}\r
 \r
  USES\r
    Dos,\r
    Param,\r
    Dosutil,\r
    Help;\r
 \r
 \r
  CONST\r
    Version = '1.5';\r
    Linelength = 140;            { Maximum significant input line length }\r
 \r
    MaxParam  = 2;\r
    MaxOption = 4;\r
 \r
    ParamList : ARRAY[1..MaxParam] OF ParamRec =\r
     ((Kind:KnownFile; Defined:FALSE; KeyWord:'A'; NumVal:0; TextVal:''),\r
      (Kind:KnownFile; Defined:FALSE; KeyWord:'B'; NumVal:0; TextVal:''));\r
 \r
    OptionList : ARRAY[1..MaxOption] OF ParamRec =\r
     ((Kind:Numeric;  Defined:FALSE ;KeyWord:'LINES';NumVal:6;TextVal:''),\r
      (Kind:OnOff;    Defined:FALSE ;KeyWord:'MARK';NumVal:0;TextVal:'OFF'),\r
      (Kind:OnOff;    Defined:FALSE ;KeyWord:'TRAILING';NumVal:0;TextVal:'OFF'),\r
      (Kind:OnOff;    Defined:FALSE ;KeyWord:'XRAY';NumVal:0;TextVal:'OFF') );\r
 \r
 \r
  TYPE\r
    LinePointer = ^Line;         { Single line buffer }\r
    Line =\r
    PACKED RECORD\r
              NextLine : LinePointer;\r
              Length : 0 .. LineLength;\r
              Image : STRING[LineLength];\r
           END;\r
    Stream =                     { Bookkeeping for each input file }\r
    RECORD\r
       Name : Char;\r
       Cursor, Head, Tail: LinePointer;\r
       CursorLineNo, HeadLineNo, TailLineNo: Integer;\r
       Endfile : Boolean;\r
    END;\r
 \r
  VAR\r
    FileA, FileB: text;\r
    FileABuffer, FileBBuffer: ARRAY[1..4096] OF char;\r
    A, B: Stream;\r
    Match: Boolean;\r
    Endfile: Boolean;            { Set if end of stream A or B }\r
 \r
    Test_requested: boolean;\r
 \r
    InitialFree: longint;  { Heap available for line storage }\r
 \r
    Templine:\r
    RECORD                     { Used by readline }\r
       Length: Integer;\r
       Image: STRING[LineLength]\r
    END;\r
 \r
    FreeLines: LinePointer;      { Free list of line buffers }\r
 \r
    Same: Boolean;               { FALSE if no mis-match occur }\r
 \r
    LinesTooLong: Boolean;\r
 \r
    Inname1, Inname2: STRING[255];\r
 \r
    MinLinesForMatch: integer;   { Number of consecutive equivalent lines }\r
      { to end a mis-match }\r
    MarkUnequalColumns: Boolean; { If unequal lines are to be paired, }\r
      { and unequal columns marked         }\r
    TrailingBlanksIgnored: Boolean; { If trailing blanks not matched   }\r
 \r
    Date: DateTime;\r
    CurrentDateText: STRING[20];\r
 \r
    FUNCTION FullFileName(part_name: STRING): STRING;\r
    VAR\r
      SR: SearchRec;\r
      dt: DateTime;\r
 \r
    BEGIN\r
      FindFirst(part_name, 0, SR);\r
      UnpackTime( SR.time, dt);\r
 \r
      FullFileName := FExpand(part_name) + '   (' + DateTimeText(dt) + ')';\r
 \r
    END {FullFileName };\r
 \r
 \r
    PROCEDURE CompareFiles;\r
 \r
      FUNCTION EndStream(VAR X: Stream): Boolean;\r
      BEGIN { EndStream }\r
        EndStream := (X.Cursor = NIL) AND X.EndFile\r
      END; { EndStream }\r
 \r
      PROCEDURE Mark(VAR X: Stream);\r
          { Causes beginning of stream to be positioned before }\r
          { current stream cursor. Buffers get reclaimed, line }\r
          { counters reset, etc.                               }\r
      VAR\r
        P: LinePointer;\r
      BEGIN { Mark }\r
        WITH X DO\r
          IF Head <> NIL THEN\r
            BEGIN\r
              WHILE Head <> Cursor DO { Reclaim Buffer }\r
                BEGIN\r
                  WITH Head^ DO\r
                    BEGIN\r
                      P := NextLine;\r
                      NextLine := FreeLines;\r
                      FreeLines := Head;\r
                    END; { WITH }\r
                  Head := P;\r
                END; { WHILE }\r
              HeadLineNo := CursorLineNo;\r
              IF Cursor = NIL THEN\r
                BEGIN\r
                  Tail := NIL;\r
                  TailLineNO := CursorLineNo;\r
                END;\r
            END; { IF Head }\r
      END; { Mark }\r
 \r
      PROCEDURE MoveCursor(VAR X: Stream; VAR FileX: Text);\r
          { FileX is the input file associated with stream X. The }\r
          { cursor for x is moved forwaard one line. Reading from X }\r
          { if necessary, and incrementing the line count. Endfile }\r
          { is set if eof is encountered on either stream. }\r
        PROCEDURE ReadLine;\r
        VAR\r
          NewLine: LinePointer;\r
          C, C2: 0 .. LineLength;\r
        BEGIN { ReadLine }\r
          IF NOT X.EndFile THEN\r
            BEGIN\r
              C := 0;\r
              NewLine := FreeLines;\r
              IF NewLine = NIL THEN\r
                BEGIN\r
                  IF MaxAvail <= SizeOf( Line) THEN\r
                    BEGIN\r
                      Writeln(' Run out of Heap storage. COMPARE aborted. ');\r
                      halt;\r
                    END\r
                  ELSE\r
                    New(NewLine);\r
                END\r
              ELSE\r
                FreeLines := FreeLines^.NextLine;\r
              NewLine^.Image[0] := Chr(LineLength);\r
              readln(FileX, NewLine^.Image);\r
 \r
                (*  WHILE NOT Eoln(FileX) AND (C < LineLength) DO\r
                BEGIN\r
                C := C + 1;\r
                Read(FileX, NewLine^.Image[C]);\r
                END; { WHILE }\r
                IF NOT Eoln(FileX) THEN LinesTooLong := True;\r
                ReadLn(FileX);\r
                *)\r
              C := ord(NewLine^.Image[0]);\r
              LinesTooLong := C >= LineLength;\r
              IF TrailingBlanksIgnored THEN\r
                BEGIN\r
                  WHILE NewLine^.Image[C] = ' ' DO C := C - 1;\r
                  NewLine^.Image[0] := Chr(C);\r
                END;\r
              NewLine^.Length := C;\r
              NewLine^.NextLine := NIL;\r
              IF X.Tail = NIL THEN\r
                BEGIN\r
                  X.Head := NewLine;\r
                  X.TailLineNo := 1;\r
                  X.HeadLineNo := 1;\r
                END\r
              ELSE\r
                BEGIN\r
                  X.Tail^.NextLine := NewLine;\r
                  X.TailLineNo := X.TailLineNo + 1;\r
                END;\r
              X.Tail := NewLine;\r
              X.EndFile := Eof(FileX);\r
            END; { IF }\r
        END; { ReadLine }\r
 \r
      BEGIN { MoveCursor }\r
        IF X.Cursor <> NIL THEN\r
          BEGIN\r
            IF X.Cursor = X.Tail THEN ReadLine;\r
            X.Cursor := X.Cursor^.NextLine;\r
            IF X.Cursor = NIL THEN EndFIle := True;\r
            X.CursorLineNo := X.CursorLineNo + 1;\r
          END\r
        ELSE\r
          IF NOT X.EndFile THEN { Begining of stream }\r
            BEGIN\r
              ReadLine;\r
              X.Cursor := X.Head;\r
              X.CursorLineNo := X.HeadLineNo;\r
            END\r
          ELSE { End of stream }\r
            EndFile := True;\r
      END; { MoveCursor }\r
 \r
      PROCEDURE BackTrack(VAR X: Stream; VAR XLines: Integer);\r
          { Causes the current position of stream x to become that  }\r
          { of the last mark operation.  I. E. the current line     }\r
          { when the stream was marked last becommes the new cursor. }\r
          { XLines is set to the number of lines from the new cursor }\r
          { to the old cursor inclusive.                             }\r
      BEGIN { BackTrack }\r
        XLines := X.CursorLineNo + 1 - X.HeadLineNo;\r
        X.Cursor := X.Head;\r
        X.CursorLineNo := X.HeadLineNo;\r
        EndFile := EndStream(A) OR EndStream(B);\r
      END; { BackTrack }\r
 \r
      PROCEDURE CompareLines(VAR Match : Boolean);\r
          { Compare the current lines of streams A and B, returning    }\r
          { match to signal their (non-) equivalence. Eof on both streams }\r
          { is considered a match, but eof on only one stream is a mismatch }\r
      BEGIN { CompareLines }\r
        IF (A.Cursor = NIL) OR (B.Cursor = NIL) THEN\r
          Match := EndStream(A) AND EndStream(B)\r
        ELSE\r
          BEGIN\r
            Match := (A.Cursor^.Length = B.Cursor^.Length);\r
            IF Match THEN\r
              Match := (A.Cursor^.Image = B.Cursor^.Image);\r
          END\r
      END; { CompareLines }\r
 \r
      PROCEDURE FindMisMatch;\r
      BEGIN { FindMisMatch }\r
          { NOT EndFile AND Match }\r
        REPEAT\r
          MoveCursor(A, FileA);\r
          MoveCursor(B, FileB);\r
          Mark(A);\r
          Mark(B);\r
          CompareLines(Match);\r
        UNTIL EndFile OR NOT Match;\r
      END; { FindMisMatch }\r
 \r
      PROCEDURE FindMatch;\r
      VAR\r
        AdvanceB: Boolean; { Toggle one-line lookahead between streams }\r
 \r
        PROCEDURE Search(VAR X:     Stream;  { Stream to search }\r
          VAR FileX: Text;\r
          VAR Y:     Stream;  { Stream to lookahead }\r
          VAR FileY: Text);\r
            { Look ahead one line on stream Y, and search for that line }\r
            { backtracking on stream X                                  }\r
 \r
        VAR\r
          Count: Integer; { Number of lines backtracked on X }\r
 \r
          PROCEDURE CheckFullMatch;\r
              { From the current positions in X and Y, which match,  }\r
              { make sure that the next MinLinesForMatch - 1 lines also  }\r
              { match, or else set match := false                        }\r
          VAR\r
            N: Integer;\r
            SaveXCur, SaveYCur: LinePointer;\r
            SaveXLine, SaveYLine: Integer;\r
          BEGIN { CheckFullMatch }\r
            SaveXCur := X.Cursor;\r
            SaveYCur := Y.Cursor;\r
            SaveXLine := X.CursorLineNo;\r
            SaveYLine := Y.CursorLineNo;\r
            CompareLines(match);\r
            N := MinLinesForMatch - 1;\r
            WHILE Match AND (N <> 0) DO\r
              BEGIN\r
                MoveCursor(X, FileX);\r
                MoveCursor(Y, FileY);\r
                CompareLines(match);\r
                N := N - 1;\r
              END; { WHILE }\r
            X.Cursor := SaveXCur;\r
            Y.Cursor := SaveYCur;\r
            X.CursorLineNo := SaveXLine;\r
            Y.CUrsorLineNo := SaveYLine;\r
          END; { CheckFullMatch }\r
 \r
        BEGIN { Search }\r
          MoveCursor(Y, FileY);\r
          BackTrack(X, Count);\r
          CheckFullMatch;\r
          Count := Count - 1;\r
          WHILE (Count <> 0) AND NOT Match DO\r
            BEGIN\r
              MoveCursor(X, FileX);\r
              Count := Count - 1;\r
              CheckFullMatch;\r
            END\r
        END; { Search }\r
 \r
        PROCEDURE PrintMisMatch;\r
        VAR\r
          EmptyA, EmptyB: Boolean;\r
 \r
          PROCEDURE WriteOneLine(Name: Char; L: Integer; P: Linepointer);\r
          BEGIN { WriteOneLIne }\r
            Write('   ', Name, L:5, '  ');\r
            IF P^.Length = 0 THEN WriteLn\r
            ELSE WriteLn(P^.Image: P^.Length);\r
          END; { WriteOneLine }\r
 \r
          PROCEDURE WriteText(VAR X:Stream);\r
              { Write from X.Head to one line before X.Cursor }\r
          VAR\r
            P, Q: LinePointer; LineNo: Integer;\r
          BEGIN { WriteText }\r
            P := X.Head;\r
            Q := X.Cursor;\r
            LineNo := X.HeadLineNo;\r
            WHILE (P <> NIL) AND (P <> Q) DO\r
              BEGIN\r
                WriteOneLine(X.Name, LineNo, P);\r
                P := P^.NextLine;\r
                LineNo := LineNo + 1;\r
              END; { WHILE }\r
            IF p = NIL THEN WriteLn(' *** eof ***');\r
            WriteLn;\r
          END; { WriteText }\r
 \r
          PROCEDURE WritePairs (Pa, Pb: LinePointer; La, Lb: Integer);\r
              { This writes from the head to the cursor, like procedure WriteText. }\r
              { Unklike WriteText, this procedure writes from both files at once }\r
              { Compares columns within lines, and marks unequal columns }\r
          VAR\r
            Col, MaxCol : Integer;\r
          BEGIN { WritePairs }\r
            REPEAT\r
              WriteOneLine('a', La, Pa);\r
              WriteOneLine('b', Lb, Pb);\r
              IF Pa^.Length > Pb^.Length THEN MaxCol := Pa^.Length\r
              ELSE MaxCol := Pb^.Length;\r
              Write(' ':11);\r
              FOR Col := 1 TO MaxCol DO\r
                IF Pa^.Image[Col] = Pb^.Image[Col] THEN Write(' ')\r
                ELSE Write('^');\r
              WriteLn;\r
              WriteLn;\r
              Pa := Pa^.NextLine;\r
              La := La + 1;\r
              Pb := Pb^.NextLine;\r
              Lb := Lb + 1;\r
            UNTIL (Pa= A.Cursor) OR (Pa= NIL);\r
          END; { WritePairs }\r
 \r
          PROCEDURE WriteLineNo(VAR X: Stream);\r
          VAR\r
            F, L: Integer;\r
          BEGIN { WriteLineNO }\r
            F := X.HeadLineNo;\r
            L := X.CursorLineNo - 1;\r
            Write('Line');\r
            IF F = L THEN Write(' ', F:1)\r
            ELSE Write('s ', F:1, ' thru ', L:1);\r
            IF X.Cursor = NIL THEN Write(' (before eof)');\r
          END; { WriteLineNo }\r
 \r
          PROCEDURE PrintExtraText(VAR X: Stream;\r
            VAR Y: Stream);\r
          BEGIN { PrintExtraText }\r
            Write(' extra text:  on file', X.Name, ', ');\r
            IF Y.Head = NIL THEN\r
              WriteLn(' Before eof on file', Y.Name)\r
            ELSE\r
              WriteLn(' between lines ', Y.HeadLineNo-1:1, ' and ',\r
              Y.HeadLineNo:1, ' of file', Y.Name);\r
            WriteLn;\r
            WriteText(X);\r
          END; { PrintExtraText }\r
 \r
        BEGIN { PrintMisMatch }\r
          WriteLn(' ':11, '********************************************');\r
          EmptyA := (A.Head = A.Cursor);\r
          EmptyB := (B.Head = B.Cursor);\r
          IF EmptyA OR EmptyB THEN\r
            IF EmptyA THEN PrintExtraText(B, A)\r
            ELSE PrintExtraText(A, B)\r
            ELSE\r
              BEGIN\r
                Write(' mismatch:   ');\r
                Write(' filea, ');\r
                WriteLineNo(A);\r
                WriteLn('   not equal to   ');\r
                Write(' fileb, ');\r
                WriteLineNo(B);\r
                WriteLn(':');\r
                WriteLn;\r
                IF MarkUnequalColumns AND\r
                  ((A.CursorLineNo - A.HeadLineNo) = (B.CursorLineNo - B.HeadLineNo))\r
                  THEN\r
                  WritePairs(A.Head, B.Head, A.HeadLineNo, B.HeadLineNO)\r
                ELSE\r
                  BEGIN\r
                    WriteText(A);\r
                    WriteText(B);\r
                  END;\r
              END;\r
        END; { PrintMisMatch }\r
 \r
      BEGIN { FindMatch }\r
          { NOT Match }\r
        AdvanceB := True;\r
        REPEAT\r
          IF NOT EndFile THEN AdvanceB := NOT AdvanceB\r
          ELSE AdvanceB := EndStream(A);\r
          IF AdvanceB THEN Search(A, FileA, B, FileB)\r
          ELSE Search(B, FileB, A, FileA)\r
        UNTIL Match;\r
        PrintMisMatch;\r
      END; { FindMatch }\r
 \r
    BEGIN { CompareFiles }\r
      Match := True; { I. E. Beginning-of-files match }\r
      REPEAT\r
        IF Match THEN FindMisMatch\r
        ELSE\r
          BEGIN\r
            Same := False;\r
            FindMatch;\r
          END\r
      UNTIL EndFile AND Match;\r
        { Mark(A); Mark(B); Mark end of files, thereby disposing buffers }\r
    END; { CompareFiles }\r
 \r
    PROCEDURE Initialize;\r
 \r
      PROCEDURE InitStream(VAR X: Stream; VAR FileX: Text);\r
      BEGIN { InitStream }\r
        WITH X DO\r
          BEGIN\r
            Cursor := NIL;\r
            Head := NIL;\r
            Tail := NIL;\r
            CursorLineNo := 0;\r
            HeadLineNo := 0;\r
            TailLineNO := 0;\r
          END;\r
        Reset(FileX);\r
        X.EndFile := eof(FileX);\r
      END; { InitStream }\r
 \r
    BEGIN { Initialize }\r
 \r
      IF ( ParamCount = 0 ) OR\r
        ( ParamCount >= 1) AND ( ParamStr(1 ) = '?') THEN\r
        BEGIN\r
          ShowHelp;\r
          Halt;\r
        END;\r
 \r
      GetParams(ParamList, MaxParam, OptionList, MaxOption);\r
 \r
      MinLinesForMatch := OptionList[1].NumVal;\r
      MarkUnequalColumns := OptionList[2].Textval = 'ON';\r
      TrailingBlanksIgnored := OptionList[3].Textval = 'OFF';\r
      Test_requested := OptionList[4].Textval = 'ON';\r
 \r
      InName1 := ParamList[1].TextVal;\r
      InName2 := ParamList[2].TextVal;\r
 \r
      GetSysDate(Date);\r
      CurrentDateText := DateTimeText(Date);\r
 \r
        { Connect Output back to std. DOS out. }\r
        { (Because Crt unit is used) }\r
        { Then it is possible to use redirection of Output. }\r
      Assign(Output, '');\r
      Rewrite(Output);\r
      Assign(FileA, InName1);\r
      SetTextBuf(FileA, FileABuffer);\r
      Assign(FileB, InName2);\r
      SetTextBuf(FileB, FileBBuffer);\r
      InitStream(A, FileA);\r
      InitStream(B, FileB);\r
      A.Name := 'a';\r
      B.Name := 'b';\r
      LinesTooLong := False;\r
      EndFile := A.EndFile OR B.EndFile;\r
      same := true;\r
      FreeLines := NIL;\r
      TempLine.Length := LineLength;\r
        { TempLine.Image[0] := 'x'; Sentinel }\r
      InitialFree := MaxAvail;  { Heap free for line images }\r
    END; { Initialize }\r
 \r
 \r
  BEGIN { MAIN of Compare }\r
    Initialize;\r
    WriteLn(' COMPARE  (v.', version,\r
    ')           At: ', CurrentDateText);\r
    WriteLn;\r
    Writeln('  Filea =  ', FullFileName( InName1) );\r
    Writeln('  Fileb =  ', FullFileName( InName2) );\r
    WriteLn(' Match criterion = ', MinLinesForMatch:1, ' lines.');\r
    WriteLn;\r
    IF A.EndFile THEN WriteLn(' Filea is Empty');\r
    IF B.EndFile THEN WriteLn(' Fileb is Empty');\r
 \r
    IF NOT EndFile THEN\r
      BEGIN\r
        CompareFiles;\r
        IF Same THEN WriteLn(' No Differences.');\r
        IF LinesTooLong THEN\r
          BEGIN\r
            WriteLn;\r
            WriteLn(' WARNING:  Some lines were longer than ',\r
            Linelength:1, ' characters.');\r
            WriteLn('           They were not compared past that point.');\r
          END;\r
        IF Test_requested THEN\r
          writeln(' Heap storage used: ', InitialFree - MaxAvail:0 , ' bytes.   ',\r
          MaxAvail:0, ' bytes remaining. ');\r
      END;\r
  END.\r
\r