home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / MURUTIL4.ZIP / DIFF.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1988-04-18  |  15.2 KB  |  639 lines

  1. PROGRAM DIFF;
  2.  
  3. {$N-  Don't use the numeric coprocessor.}
  4.  
  5. {  This Turbo Pascal V4.0 program compares two text files  and  displays
  6.    the differences (if any) and writes an optional difference file.
  7.  
  8.    DIFF syntax:  DIFF A_file.ext B_file.ext [outfile.ext]
  9.  
  10.    Version:  21 January 1988.
  11.  
  12.    Program by:  Harry M. Murphy, Consultant
  13.                 3912 Hilton Avenue, NE
  14.                 Albuquerque, NM  87110
  15.                 Tel:  (505) 881-0519
  16.  
  17.  
  18.                                 NOTICE
  19.  
  20.                     Copyright 1988, Harry M. Murphy.
  21.  
  22.        A general license is hereby  granted  for  non-commercial
  23.        use,  copying and free exchange of this  program  without
  24.        payment of any royalties,  provided that  this  copyright
  25.        notice is not altered nor deleted.   All other rights are
  26.        reserved.   This program is supplied as-is and the author
  27.        hereby disclaims all warranties,  expressed  or  implied,
  28.        including any and all warranties of  merchantability  and
  29.        any and all warranties of suitability  for  any  purpose.
  30.        Use of this program in  any  way  whatsoever  constitutes
  31.        acceptance of the terms of this license. }
  32.  
  33. USES
  34.   CRT,
  35.   DOS;
  36.  
  37. CONST
  38.   BUFFSIZE = 2048; { I/O file buffer size.                    }
  39.   DELWIND  = 4;    { Display window half-width.               }
  40.   LBUFFMAX = 31;   { Line buffer maximum index.  Must = 2^n-1 }
  41.   RECDLEN  = 133;  { Text record maximum length.              }
  42.   SPECLEN  = 65;   { File specification maximum length.       }
  43.   SYNTAX   = 'DIFF syntax:  DIFF A_file.ext B_file.ext [outfile.ext]';
  44.   WINDOW   = 9;    { The display window size;  2*DELWIND+1.   }
  45.  
  46. TYPE
  47.   FILESPEC   = STRING[SPECLEN];
  48.   RECD       = STRING[RECDLEN];
  49.  
  50. VAR
  51.   ABUF : ARRAY[1..BUFFSIZE] OF CHAR;
  52.   AEOF : BOOLEAN;
  53.   AFIL : TEXT;
  54.   AINP : WORD;
  55.   ALNC : INTEGER;
  56.   ALNO : ARRAY[0..LBUFFMAX] OF INTEGER;
  57.   APTR : WORD;
  58.   AREC : ARRAY[0..LBUFFMAX] OF RECD;
  59.   ASPC : FILESPEC;
  60.  
  61.   BBUF : ARRAY[1..BUFFSIZE] OF CHAR;
  62.   BEOF : BOOLEAN;
  63.   BFIL : TEXT;
  64.   BINP : WORD;
  65.   BLNC : INTEGER;
  66.   BLNO : ARRAY[0..LBUFFMAX] OF INTEGER;
  67.   BPTR : WORD;
  68.   BREC : ARRAY[0..LBUFFMAX] OF RECD;
  69.   BSPC : FILESPEC;
  70.  
  71.   DFIL : TEXT;
  72.   DOPN : BOOLEAN;
  73.   DSPC : FILESPEC;
  74.  
  75.   ABRT : BOOLEAN;
  76.   BAR1 : BOOLEAN;
  77.   DIFR : BOOLEAN;
  78.   DONE : BOOLEAN;
  79.   NDIF : WORD;
  80.  
  81. { -------------------------------- }
  82.  
  83. PROCEDURE BEEP(FREQ, DUR: WORD);
  84.  
  85. {  This Turbo Pascal V4.0 procedure outputs sound of frequency FREQ Hz
  86.    and duration DUR milliseconds,
  87.  
  88.    where:  20 <= FREQ <= 8192 Hz,
  89.      and:  10 <= DUR  <= 10000 milliseconds.
  90.  
  91.    Note:  USES CRT;
  92.  
  93.    Procedure by Harry M. Murphy  --  31 December 1987.  }
  94.  
  95. CONST
  96.   LOFREQ = 20;
  97.   HIFREQ = 8192;
  98.   MINDUR = 10;
  99.   MAXDUR = 10000;
  100.  
  101. BEGIN
  102.   IF FREQ < LOFREQ
  103.     THEN
  104.       FREQ := LOFREQ
  105.     ELSE
  106.       IF FREQ > HIFREQ
  107.         THEN
  108.           FREQ := HIFREQ;
  109.   SOUND(FREQ);
  110.   IF DUR < MINDUR
  111.     THEN
  112.       DUR := MINDUR
  113.     ELSE
  114.       IF DUR > MAXDUR
  115.         THEN
  116.           DUR := MAXDUR;
  117.   DELAY(DUR);
  118.   NOSOUND
  119. END { Procedure BEEP };
  120.  
  121. { -------------------------------- }
  122.  
  123. FUNCTION DATTIMST: STRING;
  124.  
  125. {  This Turbo Pascal function returns the current date/time as an
  126.    seventeen-byte string of the form:  "14:57h, 20 Jun 87".
  127.  
  128.    Note:  USES DOS;
  129.  
  130.    Function by Harry M. Murphy,  20 June 1987.
  131.    Updated for Turbo Pascal V4.0 by H.M.M. on 28 November 1987. }
  132.  
  133. CONST
  134.       MONTHS = ' Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ';
  135.  
  136.   VAR
  137.       DA  : WORD;
  138.       DTG : STRING[18];
  139.       HR  : WORD;
  140.       MN  : WORD;
  141.       MO  : WORD;
  142.       REG : REGISTERS;
  143.       SC  : WORD;
  144.       TH  : WORD;
  145.       WK  : WORD;
  146.       YR  : WORD;
  147.  
  148.  FUNCTION DIGIT(N: INTEGER): CHAR;  { Internal to DATTIMST. }
  149.  
  150.  BEGIN
  151.    DIGIT := CHR((N MOD 10)+ORD('0'))
  152.  END { Internal Function DIGIT };
  153.  
  154.  
  155. BEGIN { DATTIMST }
  156.   GETDATE(YR,MO,DA,WK);
  157.   GETTIME(HR,MN,SC,TH);
  158.   DTG := DIGIT(HR DIV 10)+DIGIT(HR)+':'+
  159.          DIGIT(MN DIV 10)+DIGIT(MN)+'h, '+
  160.          DIGIT(DA DIV 10)+DIGIT(DA)+
  161.          COPY(MONTHS,4*MO-3,5)+
  162.          DIGIT(YR DIV 10)+DIGIT(YR);
  163.   IF DTG[9] = '0' THEN DTG[9] := ' ';
  164.   DATTIMST := DTG
  165. END { Function DATTIMST };
  166.  
  167. { -------------------------------- }
  168.  
  169. PROCEDURE PUTBLANK;
  170.  
  171. {  This procedure displays a blank line and writes a blank line to the
  172.    output file, DFIL, if that file is open.  }
  173.  
  174. BEGIN
  175.   WRITELN;
  176.   IF DOPN THEN WRITELN(DFIL)
  177. END { Procedure PUTBLANK };
  178.  
  179. { -------------------------------- }
  180.  
  181. PROCEDURE PUTSTRING(S: STRING);
  182.  
  183. {  This procedure displays the string, S, and writes the string to the
  184.    output file, DFIL, if that file is open.  }
  185.  
  186. BEGIN
  187.   WRITELN(S);
  188.   IF DOPN THEN WRITELN(DFIL,S)
  189. END { Procedure PUTSTRING };
  190.  
  191. { -------------------------------- }
  192.  
  193. FUNCTION STRI(N: LONGINT; W: INTEGER): STRING;
  194.  
  195. {  This Turbo Pascal V4.0 function returns the string representation  of
  196.    its integer argument, N.   If W is greater than zero,  it is used  to
  197.    define the Width of the number.
  198.  
  199.    Function by Harry M. Murphy  --  17 December 1987.  }
  200.  
  201. VAR
  202.   S : STRING;
  203.  
  204. BEGIN
  205.   IF W > 0
  206.     THEN
  207.       STR(N:W,S)
  208.     ELSE
  209.       STR(N,S);
  210.   STRI := S
  211. END { Function STRI };
  212.  
  213. { -------------------------------- }
  214.  
  215. FUNCTION TRIMSTRING(S: STRING): STRING;
  216.  
  217. {  This function returns the string,  S,  with trailing blanks,  if any,
  218.    removed.  An all-blank string is returned as a null string.
  219.  
  220.    Function by Harry M. Murphy  --  24 December 1987.  }
  221.  
  222. VAR
  223.   L : BYTE;
  224.  
  225. BEGIN
  226.   L := LENGTH(S);
  227.   WHILE (S[L] = ' ') AND (L > 1) DO L := PRED(L);
  228.   IF S[L] = ' '
  229.     THEN
  230.       TRIMSTRING := ''
  231.     ELSE
  232.       TRIMSTRING := COPY(S,1,L)
  233. END { Function TRIMSTRING };
  234.  
  235. { -------------------------------- }
  236.  
  237. FUNCTION UPSTRING(S : STRING): STRING;
  238.  
  239. {  This Turbo Pascal V4.0 function returns its input string with all
  240.    lower-case alphabetic characters changed to uppercase.
  241.  
  242.    Function by Harry M. Murphy  --  1 January 1988.  }
  243.  
  244. VAR
  245.   L : WORD;
  246.  
  247. BEGIN
  248.   FOR L :=1 TO LENGTH(S) DO S[L] := UPCASE(S[L]);
  249.   UPSTRING := S
  250. END { Function UPSTRING };
  251.  
  252. { -------------------------------- }
  253.  
  254. PROCEDURE CHECKKEYBD;
  255.  
  256. {  This Turbo Pascal V4.0 procedure  checks  the  keyboard  for  a  user
  257.    interrupt.   If a key was struck,  the procedure pauses and waits for
  258.    the user to hit another key before returning.   If the struck key  is
  259.    a control-C or an Esc, the procedure sets the flag, DONE, to TRUE. }
  260.  
  261. CONST
  262.    NOTE =
  263.        'Pausing...  Hit Esc or ^C to quit;  any other key to continue.';
  264.    TAB  = '        ';
  265.  
  266. TYPE
  267.   TEXTLINE = ARRAY[1..80] OF WORD;
  268.  
  269. VAR
  270.   CH     : CHAR;
  271.   LINE25 : TEXTLINE ABSOLUTE $B800: $0F00;  { Line 25 in video memory. }
  272.   SAVE   : WORD;
  273.   SAVE25 : TEXTLINE;
  274.   XS,YS  : BYTE;
  275.  
  276. BEGIN
  277.   IF KEYPRESSED
  278.     THEN
  279.       BEGIN
  280.         WHILE KEYPRESSED DO CH := READKEY;
  281.         SAVE25 := LINE25;
  282.         SAVE := TEXTATTR;
  283.         TEXTATTR := (SAVE AND $0080) OR
  284.                    ((SAVE SHR 4) AND $0007) OR
  285.                    ((SAVE SHL 4) AND $0070);
  286.         XS := WHEREX;
  287.         YS := WHEREY;
  288.         GOTOXY(1,25);
  289.         WRITE(TAB,NOTE,TAB);
  290.         TEXTATTR := SAVE;
  291.         GOTOXY(XS,YS);
  292.         BEEP(880,50);
  293.         WHILE NOT KEYPRESSED DO;
  294.         LINE25 := SAVE25;
  295.         CH := READKEY;
  296.         ABRT := CH IN [#3,#27];
  297.         IF ABRT THEN DONE := TRUE;
  298.         WHILE KEYPRESSED DO CH := READKEY
  299.       END
  300. END { Procedure CHECKKEYBD };
  301.  
  302. { -------------------------------- }
  303.  
  304. PROCEDURE COMPARE(VAR DIFR: BOOLEAN);
  305.  
  306. {  This procedure compares the A- and B-records at the  current  pointer
  307.    positions.  If they do not compare, DIFR, is returned as TRUE and the
  308.    difference counter,  NDIF is incremented,  otherwise DIFR is returned
  309.    FALSE.   If either pointer is at end-of-file,  the global flag, DONE,
  310.    is set to TRUE.  }
  311.  
  312. BEGIN
  313.   DIFR := AREC[APTR] <> BREC[BPTR];
  314.   IF DIFR THEN NDIF := SUCC(NDIF);
  315.   IF (ALNO[APTR] < 0) OR (BLNO[BPTR] < 0) THEN DONE := TRUE
  316. END { Procedure COMPARE };
  317.  
  318. { -------------------------------- }
  319.  
  320. PROCEDURE FILLBUFF;
  321.  
  322. CONST
  323.   EOFMARK = '<<<<<   E N D   O F   F I L E   >>>>>';
  324.  
  325. VAR
  326.   LINE : RECD;
  327.   TOP  : WORD;
  328.  
  329. BEGIN
  330.   IF NOT AEOF
  331.     THEN
  332.       BEGIN
  333.         TOP := (APTR+LBUFFMAX-DELWIND) AND LBUFFMAX;
  334.         WHILE (AINP <> TOP) AND (NOT EOF(AFIL)) DO
  335.           BEGIN
  336.             READLN(AFIL,LINE);
  337.             ALNC := SUCC(ALNC);
  338.             ALNO[AINP] := ALNC;
  339.             AREC[AINP] := TRIMSTRING(LINE);
  340.             AINP := SUCC(AINP) AND LBUFFMAX
  341.           END;
  342.         IF AINP <> TOP
  343.           THEN
  344.             BEGIN
  345.               ALNO[AINP] := -SUCC(ALNC);
  346.               AREC[AINP] := EOFMARK;
  347.               AEOF := TRUE
  348.             END
  349.       END;
  350.  
  351.   IF NOT BEOF
  352.     THEN
  353.       BEGIN
  354.         TOP := (BPTR+LBUFFMAX-DELWIND) AND LBUFFMAX;
  355.         WHILE (BINP <> TOP) AND (NOT EOF(BFIL)) DO
  356.           BEGIN
  357.             READLN(BFIL,LINE);
  358.             BLNC := SUCC(BLNC);
  359.             BLNO[BINP] := BLNC;
  360.             BREC[BINP] := TRIMSTRING(LINE);
  361.             BINP := SUCC(BINP) AND LBUFFMAX
  362.           END;
  363.         IF BINP <> TOP
  364.           THEN
  365.             BEGIN
  366.               BLNO[BINP] := -SUCC(BLNC);
  367.               BREC[BINP] := EOFMARK;
  368.               BEOF := TRUE
  369.             END
  370.       END
  371.  
  372. END { Procedure FILLBUFF };
  373.  
  374. { -------------------------------- }
  375.  
  376. PROCEDURE GETFILES;
  377.  
  378.   PROCEDURE ABORT(FS: FILESPEC); { Internal to GETFILES }
  379.  
  380.   BEGIN
  381.     HIGHVIDEO;
  382.     WRITELN('ERROR!  Can''t open file ',FS);
  383.     NORMVIDEO;
  384.     BEEP(220,200);
  385.     HALT
  386.   END  { Internal Procedure ABORT };
  387.  
  388. BEGIN { Procedure GETFILES }
  389.   IF (PARAMCOUNT < 2) OR (PARAMCOUNT > 3)
  390.     THEN
  391.       BEGIN
  392.         WRITELN(SYNTAX);
  393.         BEEP(880,100);
  394.         HALT
  395.       END
  396.     ELSE
  397.       BEGIN
  398.         ASPC := UPSTRING(PARAMSTR(1));
  399.         ASSIGN(AFIL,ASPC);
  400.         SETTEXTBUF(AFIL,ABUF,BUFFSIZE);
  401.         {$I-} RESET(AFIL) {$I+};
  402.         IF IORESULT <> 0 THEN ABORT(ASPC);
  403.  
  404.         BSPC := UPSTRING(PARAMSTR(2));
  405.         ASSIGN(BFIL,BSPC);
  406.         SETTEXTBUF(BFIL,BBUF,BUFFSIZE);
  407.         {$I-} RESET(BFIL) {$I+};
  408.         IF IORESULT <> 0 THEN ABORT(BSPC);
  409.  
  410.         IF PARAMCOUNT = 3
  411.           THEN
  412.             BEGIN
  413.               DSPC := UPSTRING(PARAMSTR(3));
  414.               IF (DSPC = ASPC) OR (DSPC = BSPC) THEN ABORT(DSPC);
  415.               ASSIGN(DFIL,DSPC);
  416.               {$I-} REWRITE(DFIL) {$I+};
  417.               IF IORESULT <> 0 THEN ABORT(DSPC);
  418.               DOPN := TRUE
  419.             END
  420.           ELSE
  421.             DOPN := FALSE
  422.       END
  423. END { Procedure GETFILES };
  424.  
  425. { -------------------------------- }
  426.  
  427. PROCEDURE INCRBUFF;
  428.  
  429. {  This procedure increments the A- and B-buffer pointers.  }
  430.  
  431. BEGIN
  432.   IF ALNO[APTR] >= 0 THEN APTR := SUCC(APTR) AND LBUFFMAX;
  433.   IF BLNO[BPTR] >= 0 THEN BPTR := SUCC(BPTR) AND LBUFFMAX
  434. END { Procedure INCRBUFF };
  435.  
  436. { -------------------------------- }
  437.  
  438. PROCEDURE INITBUFF;
  439.  
  440. {  This procedure initializes the A- and B-buffers, line numbers and
  441.    pointers.  }
  442.  
  443. BEGIN
  444.   FOR APTR := 0 TO DELWIND DO
  445.     BEGIN
  446.       ALNO[APTR] := 0;
  447.       AREC[APTR] := ''
  448.     END;
  449.   APTR := DELWIND;
  450.   AINP := DELWIND;
  451.   ALNC := 0;
  452.   AEOF := EOF(AFIL);
  453.  
  454.   FOR BPTR := 0 TO DELWIND DO
  455.     BEGIN
  456.       BLNO[BPTR] := 0;
  457.       BREC[BPTR] := ''
  458.     END;
  459.   BPTR := DELWIND;
  460.   BINP := DELWIND;
  461.   BLNC := 0;
  462.   BEOF := EOF(BFIL)
  463.  
  464. END { Procedure INITBUFF };
  465.  
  466. { -------------------------------- }
  467.  
  468. PROCEDURE SHOWDIFF;
  469.  
  470. {  This procedure shows the differences between the "A" and the "B"
  471.    files as two windows separated by a short bar.  }
  472.  
  473. CONST
  474.   BAR = '-------------------------------------';
  475.  
  476. VAR
  477.   IEND : WORD;
  478.   IPTR : WORD;
  479.   JPTR : WORD;
  480.   TAG  : STRING[3];
  481.  
  482. BEGIN
  483.   IF BAR1
  484.     THEN
  485.       BEGIN
  486.         BAR1 := FALSE;
  487.         PUTBLANK;
  488.         PUTSTRING(BAR+BAR)
  489.       END;
  490.  
  491.   IEND := (APTR+DELWIND) AND LBUFFMAX;
  492.   IPTR := (APTR+LBUFFMAX-DELWIND) AND LBUFFMAX;
  493.   JPTR := (BPTR+LBUFFMAX-DELWIND) AND LBUFFMAX;
  494.   REPEAT
  495.     IPTR := SUCC(IPTR) AND LBUFFMAX;
  496.     JPTR := SUCC(JPTR) AND LBUFFMAX;
  497.     IF ALNO[IPTR] <> 0
  498.       THEN
  499.         BEGIN
  500.           IF AREC[IPTR] = BREC[JPTR]
  501.             THEN
  502.               TAG := ':  '
  503.             ELSE
  504.               TAG := ':> ';
  505.           PUTSTRING('A:'+STRI(ALNO[IPTR],6)+TAG+AREC[IPTR])
  506.         END
  507.   UNTIL (IPTR = IEND) OR (ALNO[IPTR] < 0);
  508.  
  509.   PUTSTRING(BAR);
  510.   IEND := (BPTR+DELWIND) AND LBUFFMAX;
  511.   IPTR := (BPTR+LBUFFMAX-DELWIND) AND LBUFFMAX;
  512.   JPTR := (APTR+LBUFFMAX-DELWIND) AND LBUFFMAX;
  513.   REPEAT
  514.     IPTR := SUCC(IPTR) AND LBUFFMAX;
  515.     JPTR := SUCC(JPTR) AND LBUFFMAX;
  516.     IF BLNO[IPTR] <> 0
  517.       THEN
  518.         BEGIN
  519.           IF BREC[IPTR] = AREC[JPTR]
  520.             THEN
  521.               TAG := ':  '
  522.             ELSE
  523.               TAG := ':> ';
  524.           PUTSTRING('B:'+STRI(BLNO[IPTR],6)+TAG+BREC[IPTR])
  525.         END
  526.   UNTIL (IPTR = IEND) OR (BLNO[IPTR] < 0);
  527.  
  528.   PUTSTRING(BAR+BAR)
  529. END { Procedure SHOWDIFF };
  530.  
  531. { -------------------------------- }
  532.  
  533. PROCEDURE SYNCHRONIZE;
  534.  
  535. {  This procedure attempts to "synchronize" the comparison points of the
  536.    two files so as to avoid a never-ending series of differences  caused
  537.    by the insertion or deletion of a few records in either  one  of  the
  538.    files.  }
  539.  
  540. VAR
  541.   IAMAX : WORD;
  542.   IAPTR : WORD;
  543.   IBMAX : WORD;
  544.   IBPTR : WORD;
  545.   JAPTR : WORD;
  546.   JBPTR : WORD;
  547.   KAPTR : WORD;
  548.   KBPTR : WORD;
  549.   NCNTR : BYTE;
  550.   SYNC  : BOOLEAN;
  551.  
  552. BEGIN
  553.   IAMAX := (APTR+WINDOW) AND LBUFFMAX;
  554.   JAPTR := APTR;
  555.   KAPTR := SUCC(APTR) AND LBUFFMAX;
  556.   REPEAT
  557.     IAPTR := JAPTR;
  558.     JAPTR := KAPTR;
  559.     KAPTR := SUCC(KAPTR) AND LBUFFMAX;
  560.     IBMAX := (BPTR+WINDOW) AND LBUFFMAX;
  561.     JBPTR := BPTR;
  562.     KBPTR := SUCC(BPTR) AND LBUFFMAX;
  563.     REPEAT
  564.       IBPTR := JBPTR;
  565.       JBPTR := KBPTR;
  566.       KBPTR := SUCC(KBPTR) AND LBUFFMAX;
  567.       SYNC := (AREC[IAPTR] = BREC[IBPTR]) AND
  568.               (AREC[JAPTR] = BREC[JBPTR]) AND
  569.               (AREC[KAPTR] = BREC[KBPTR])
  570.     UNTIL SYNC OR (IBPTR = IBMAX)
  571.   UNTIL SYNC OR (IAPTR = IAMAX);
  572.  
  573.   IF SYNC
  574.     THEN
  575.       BEGIN
  576.         APTR := IAPTR;
  577.         BPTR := IBPTR
  578.       END
  579.     ELSE
  580.       FOR NCNTR := 1 TO WINDOW DO INCRBUFF
  581.  
  582. END { Procedure SYNCHRONIZE };
  583.  
  584. { -------------------------------- }
  585.  
  586. BEGIN  { Program DIFF }
  587.   GETFILES;
  588.   IF DOPN
  589.     THEN
  590.       BEGIN
  591.         WRITE(DFIL,'Difference output file, ',DSPC);
  592.         WRITELN(DFIL,', generated at ',DATTIMST,':');
  593.         WRITELN(DFIL)
  594.       END;
  595.   PUTSTRING('DIFF comparing two ASCII files, File "A" and File "B":');
  596.   PUTSTRING('     File "A" is '+ASPC);
  597.   PUTSTRING('     File "B" is '+BSPC);
  598.   ABRT := FALSE;
  599.   BAR1 := TRUE;
  600.   DONE := FALSE;
  601.   NDIF := 0;
  602.   INITBUFF;
  603.   FILLBUFF;
  604.   REPEAT
  605.     COMPARE(DIFR);
  606.     IF DIFR
  607.       THEN
  608.         BEGIN
  609.           SHOWDIFF;
  610.           SYNCHRONIZE
  611.         END
  612.       ELSE
  613.         INCRBUFF;
  614.      FILLBUFF;
  615.      CHECKKEYBD
  616.   UNTIL DONE;
  617.   CLOSE(AFIL);
  618.   CLOSE(BFIL);
  619.   BEEP(880,100);
  620.   IF ABRT
  621.     THEN
  622.       BEGIN
  623.         PUTBLANK;
  624.         PUTSTRING('This run was aborted by the user.');
  625.       END
  626.     ELSE
  627.       IF NDIF = 0 THEN WRITELN('     No differences found.');
  628.   IF DOPN
  629.     THEN
  630.       BEGIN
  631.         CLOSE(DFIL);
  632.         IF NDIF = 0
  633.           THEN
  634.             ERASE(DFIL)
  635.           ELSE
  636.             WRITELN('The difference output file is ',DSPC)
  637.       END
  638. END.
  639.