Trailing-Edge
-
PDP-10 Archives
-
DEC_CMS-20_V1.0_SRC
-
cms/sources/diff.bli
There are no other files named diff.bli in the archive.
MODULE DIFF (
IDENT = '1',
%IF
%BLISS(BLISS32)
%THEN
LANGUAGE(BLISS32),
ADDRESSING_MODE(EXTERNAL=LONG_RELATIVE,
NONEXTERNAL=LONG_RELATIVE)
%ELSE
LANGUAGE(BLISS36)
%FI
) =
BEGIN
!
! COPYRIGHT (c) 1982 BY
! DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.
!
! THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
! ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH THE
! INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER
! COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
! OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY
! TRANSFERRED.
!
! THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
! AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
! CORPORATION.
!
! DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
! SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.
!
!++
! FACILITY: CMS Library Processor
!
! ABSTRACT:
!
! Compare a master file with a variation file and generate a differences
! listing file showing all of the corrections or changes implied by the
! variation.
!
! ENVIRONMENT: VAX/VMS, DS-20
!
! AUTHOR: D. Knight , CREATION DATE: 29-Oct-79
!
!--
!
! TABLE OF CONTENTS
!
FORWARD ROUTINE
DIFF, !Basic comparison algorithm
CKPAGE, !test for page mark
GET_CUR_MST, !Check line for legal processing
GET_LIN, !Get variation line
OUTDIFF: NOVALUE, !Output the differences found to the output file
SETUP, !Initialize the world
TERMINATE : NOVALUE, !Terminate the world
WRT_LINE : NOVALUE; !Output line of text
!
! INCLUDE FILES:
!
%if
%bliss(bliss32)
%then
library 'sys$library:starlet';
%else
require 'jsys:';
%fi
LIBRARY 'XPORT:'; !XPORT I/O macros
REQUIRE 'SCONFG:'; !configuration options
REQUIRE 'BLISSX:';
REQUIRE 'COMUSR:';
REQUIRE 'HOSUSR:';
!
! MACROS:
!
MACRO
IOB$H_RESULTANT=$SUB_FIELD(IOB$T_RESULTANT,STR$H_LENGTH) %,
IOB$A_RESULTANT=$SUB_FIELD(IOB$T_RESULTANT,STR$A_POINTER) %,
STG(L,M) = OUTSTG(CH$PTR(UPLIT(L)),%CHARCOUNT(L),M) %;
!
! EQUATED SYMBOLS:
!
LITERAL
T_LINE_SIZE=250; !Temporary header line buffer size
!
! OWN STORAGE:
!
OWN
AFLAG, !Append qualifier flag
D_NAM_LEN, !Difference (output) file name length
D_NAM_PTR, !Difference (output) file name pointer
DIFF_FLG, !Difference seen flag
FIELD_WIDTH, !(page width)/2 (always a multiple of 8)
I_OPN, !Input file open flag
KEEP, !GET_CUR_MST keep flag
M_NAM_LEN, !Master file name length
M_NAM_PTR, !Master file name pointer
M_OPN, !Master file open flag
O_OPN, !Output file open flag
M_PAGE, !master page number
PAGE_SIZE, !Page width (always a multiple of 8)
PARL_L, !Parallel flag
QUIET_Q, !Inhibit terminal messages
V_NAM_LEN, !Variation file name length
V_NAM_PTR, !Variation file name pointer
V_PAGE; !Variation file page number
!
! EXTERNAL REFERENCES:
!
external literal
s_different, !Files are different
s_doanoopen, !Can't open default file for append
s_erropen, !File open error
s_errfile, !File has wrong attributes
s_identical, !Files are identical
s_maxwiddif, !Maximum width
s_minwiddif, !Minimum width
s_nouodel, !Can't delete unneeded output file
s_noopen, !Not able to be opened
s_oanoopen, !Can't open file for append
s_onoopen; !Can't open output file
EXTERNAL
INPUT_IOB : $XPO_IOB(), !Variation file IOB
LIN_MST, !Current line in master buffer
LIN_VAR, !Current line in variation buffer
L_LN_MST, !Last line in master buffer
L_LN_VAR, !Last line in variation buffer
MASTER_IOB : $XPO_IOB(), !Master file IOB
MST_EOF, !EOF seen on master file
MST_PTR : REF VECTOR, !Master buffer pointer
OUTPUT_IOB : $XPO_IOB(), !Output file IOB
VAR_EOF, !EOF seen on variation file
VAR_PTR : REF VECTOR; !Variation buffer pointer
EXTERNAL ROUTINE
ASCDEC, !Ascii to Decimal
BUG, !Error
CMPINI, !Set up comparison algorithm
CMPTXT, !Compare two texts
COMAND, !Parse command
DATTIM, !Get current date and time
DECASC, !Decimal to ASCII
DECASZ, !Decimal to ASCII filled
ERS, !User error
ERSIOB,
ERSXPO,
exits, !exit silently
filtyp, !file attributes?
GETACT, !Get user's name
GET_LXM, !Get text lexeme
GET_STG_CT, !Get size of string
LOCALF, !Report error for network spec.
OUTINI, !Initialize text output
OUTNUM, !Output numeric field
OUTNMZ, !Output filled numeric field
OUTSTG, !Output text string
PACK, !Repack buffer
sysmsg;
GLOBAL ROUTINE DIFF =
!++
! FUNCTIONAL DESCRIPTION:
!
! Compare two files, one being the "master", the other
! being the "variation". Generate a differences listing file from the
! differences.
!
! The algorithm is relatively simple. First, look for two lines that
! match in the two files. Once they are found, make sure that they
! comprise a unique match, namely, there are no other lines which
! could also match similarly (if they are not unique, assume that no
! match exists). Once a unique match is found, scan the text backwards
! and find as many matching lines as possible (this gets rid of redundant
! non-unique matches). This establishes the boundaries of matched lines
! which then can be passed to OUTDIFF to place in the output file.
!
! The purpose of this procedure is to prevent false matches which may
! occur because of multiple blank lines or multiple lines of "boilerplate"
! which so often occur and cause unwarranted matches.
!
! FORMAL PARAMETERS:
!
! NONE.
!
! IMPLICIT INPUTS:
!
! NONE.
!
! IMPLICIT OUTPUTS:
!
! NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! Standard GETELM returns as described in SCONFG.
!
! SIDE EFFECTS:
!
! NONE.
!
!--
BEGIN
LOCAL
CMD,
FIL_PTR,
FIL_LEN,
PAR : REF PARAMETER_BLOCK,
QUAL : REF QUALIFIER_BLOCK,
RETVAL, !Return value temp
SUB_CMD,
USR_REM : REF DESC_BLOCK;
!Parse the command line
IF
NOT COMAND(CMD,SUB_CMD,QUAL,PAR,USR_REM)
THEN
RETURN K_SILENT_ERROR;
!Set no parallel for now
PARL_L=FALSE;
!Set no append for now
AFLAG = FALSE;
!Don't inhibit terminal messages for now
QUIET_Q = FALSE;
!Initialize field_width; default for page_size and field_width is in SETUP.
FIELD_WIDTH = 0;
!Initialize output file "descriptors"
D_NAM_LEN = 0;
D_NAM_PTR = K_NULL;
!Set up qualifiers, if any
WHILE
.QUAL NEQ K_NULL
DO
BEGIN
SELECTONE .QUAL[QUA_CODE] OF
SET
[K_APPEND_QUAL] : AFLAG = TRUE;
[K_PARALLEL_QUAL]: PARL_L = TRUE ;
[K_OUTPUT_QUAL] : BEGIN
D_NAM_LEN = .QUAL[QUA_VALUE_LEN];
D_NAM_PTR = .QUAL[QUA_VALUE_PTR];
END;
[K_WIDTH_QUAL]: BEGIN
LOCAL P; !for ascdec to change
P = .QUAL[QUA_VALUE_PTR];
PAGE_SIZE = ASCDEC(P, .QUAL[QUA_VALUE_LEN]);
IF .PAGE_SIZE LSS 48
THEN
BEGIN
sysmsg(s_minwiddif,
LIT('Minimum LINE_WIDTH is 48'),0);
PAGE_SIZE=48;
FIELD_WIDTH=24;
END
ELSE
IF .PAGE_SIZE GTR 128
THEN !changed max to 128 for docu-
!ment consistency...multiples
BEGIN !of 8
sysmsg(s_maxwiddif,
LIT('Maximum LINE_WIDTH is 128'),0);
PAGE_SIZE=128;
FIELD_WIDTH=64;
END
ELSE
BEGIN !Compute to nearest mult of 8.
PAGE_SIZE=.PAGE_SIZE-(.PAGE_SIZE MOD 8);
FIELD_WIDTH=.PAGE_SIZE/2;
FIELD_WIDTH=.FIELD_WIDTH-(.FIELD_WIDTH MOD 8);
END;
END;
[K_NOAPPEND_QUAL] : AFLAG = FALSE;
[K_NOPARALLEL_QUAL]: PARL_L = FALSE;
[K_NOOUTPUT_QUAL] : BEGIN
D_NAM_LEN = 0;
D_NAM_PTR = K_NULL;
END;
TES;
QUAL=.QUAL[QUA_A_NEXT]
END;
!Get master file name
M_NAM_PTR=.PAR[PAR_TEXT_PTR];
M_NAM_LEN=.PAR[PAR_TEXT_LEN];
!Advance to variation name
PAR=.PAR[PAR_A_NEXT];
!Variation file name
V_NAM_PTR=.PAR[PAR_TEXT_PTR];
V_NAM_LEN=.PAR[PAR_TEXT_LEN];
!Start up the world
IF
NOT SETUP(.M_NAM_LEN,.M_NAM_PTR,.V_NAM_LEN,.V_NAM_PTR,.D_NAM_LEN,
.D_NAM_PTR)
THEN
BEGIN
TERMINATE();
RETURN K_SILENT_ERROR
END;
!Generate the updated master file
!This always starts at the beginning
RETVAL=CMPTXT(L_LN_MST,L_LN_VAR);
! Convert RETVAL to a system status code, and inform the user.
IF .RETVAL EQL G_OK
THEN
BEGIN ! Success.
IF
.DIFF_FLG
THEN
BEGIN ! Different.
IF NOT .QUIET_Q THEN sysmsg(s_different,
LIT('Files are different'),0) ;
RETVAL = s_different;
END ! Different.
ELSE
BEGIN ! Identical.
IF NOT .QUIET_Q THEN sysmsg(s_identical,
LIT('Files are identical'),0) ;
RETVAL = s_identical;
END ! Identical.
END ! Success.
ELSE
RETVAL = K_SILENT_ERROR ; ! Message has been output by CMPTXT.
!All is complete, exit quietly
TERMINATE();
exits(.RETVAL)
END; !End of DIFF
ROUTINE CKPAGE (LEN,PTR,SEQ) =
!++
! FUNCTIONAL DESCRIPTION:
!
! Check a line to see if it is a legal page mark
!
! FORMAL PARAMETERS:
!
! LEN - length of line
! PTR - pointer to line
! SEQ - TRUE if sequence information needs to be skipped
!
! IMPLICIT INPUTS:
!
! NONE.
!
! IMPLICIT OUTPUTS:
!
! NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! TRUE - line is page mark
! FALSE - line is not a page mark
!
! SIDE EFFECTS:
!
! NONE.
!
!--
BEGIN
LOCAL
L,
P;
IF
.LEN EQL 0 OR
.PTR EQL 0
THEN
!Not a page mark
RETURN FALSE;
L=.LEN;
P=.PTR;
IF
.SEQ
THEN
!Skip over the sequence information
DO
L=.L-1
UNTIL
CH$RCHAR_A(P) EQL %C';';
!See if the page mark is all that is left
.L EQL 1 AND
CH$RCHAR(.P) EQL FORM_FEED
END; !end of CKPAGE
ROUTINE GET_CUR_MST (LINE_NUM) =
!++
! FUNCTIONAL DESCRIPTION:
!
! See if a master line is a legal text line which can be processed
!
! FORMAL PARAMETERS:
!
! LINE_NUM - line number of line in master buffer
!
! IMPLICIT INPUTS:
!
! NONE.
!
! IMPLICIT OUTPUTS:
!
! NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! TRUE - line is legal line for processing
! FALSE - line is not to be processed
!
! SIDE EFFECTS:
!
! NONE.
!
!--
BEGIN
.LINE_NUM LSS .L_LN_MST
END; !End of GET_CUR_MST
ROUTINE GET_LIN (LGT,PTR) =
!++
! FUNCTIONAL DESCRIPTION:
!
! Get a variation line from the input file
!
! FORMAL PARAMETERS:
!
! LGT - address of cell where length is to be placed
! PTR - address of cell where address of data is placed
!
! IMPLICIT INPUTS:
!
! NONE.
!
! IMPLICIT OUTPUTS:
!
! NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! I/O completion code
!
! SIDE EFFECTS:
!
! NONE.
!
!--
BEGIN
LOCAL
COMPLETION;
COMPLETION=$step_get(IOB=INPUT_IOB,FAILURE=0);
.LGT=.INPUT_IOB[IOB$H_STRING];
.PTR=.INPUT_IOB[IOB$A_STRING];
.COMPLETION
END; !End of GET_LIN
ROUTINE OUTDIFF (M_LINE,V_LINE) : NOVALUE =
!++
! FUNCTIONAL DESCRIPTION:
!
! Output any differences between the master and variation files seen
! so far. This recognizes both deletions and insertions. Comments
! and control lines are ignored.
!
! FORMAL PARAMETERS:
!
! M_LINE - Source line pointer
! V_LINE - Variation line pointer
!
! IMPLICIT INPUTS:
!
! The lines of text are stored in the master and variation buffers.
!
! IMPLICIT OUTPUTS:
!
! NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! NONE.
!
! SIDE EFFECTS:
!
! PACK is called to repack the buffer and get rid of the lines that
! have been output.
!
!--
BEGIN
LOCAL
COUNT,
L_PTR,
L_SIZ,
TXT_M_SEEN,
TXT_V_SEEN;
IF
.M_LINE EQL -1 AND
.V_LINE EQL -1
THEN
BUG(LIT('Two null OUTDIFF pointers (COMPAR)'));
!Check for potential bug
IF
.M_LINE LSS .LIN_MST AND
.M_LINE NEQ -1
THEN
BUG(LIT('Master line pointer out of range in OUTDIFF (COMPAR)'));
IF
.V_LINE LSS .LIN_VAR AND
.V_LINE NEQ -1
THEN
BUG(LIT('Variation line pointer out of range in OUTDIFF (COMPAR)'));
TXT_M_SEEN=FALSE;
TXT_V_SEEN=FALSE;
!Get number of lines per entry maximum
IF
.M_LINE NEQ -1 AND
.V_LINE NEQ -1
THEN
BEGIN
IF
.M_LINE-.LIN_MST GTR .V_LINE-.LIN_VAR
THEN
COUNT=.M_LINE-.LIN_MST
ELSE
COUNT=.V_LINE-.LIN_VAR
END
ELSE
IF
.M_LINE EQL -1
THEN
COUNT=.V_LINE-.LIN_VAR
ELSE
COUNT=.M_LINE-.LIN_MST;
IF
.COUNT NEQ 0
THEN
DIFF_FLG=TRUE;
!Check to see which kind of listing is desired
IF
NOT .PARL_L
THEN
BEGIN
LOCAL
ADJLEN, !Adjust length
LFLAG, !If m_nam_len larger then 1,else 0
MORE,
POS,
SAVEPOS, !position of last dash output
TEMP, !all-purpose variable
TEMPV, !all-purpose variable
TL, !current total output line length
XTRA; !difference between lengths of file names
!Initialize variables to enable matching the dashes at the end of any
!pair of difference lines. EX.
!- - - - longname.dat Line 32 - - - -
!- - - - temp.dat Line 0 - - - - - -
! ^
!Find out whether the "header" lines for the two files will fit on
! a line of size .page_size
TEMP = .MASTER_IOB[IOB$V_SEQUENCED];
TEMP = 30 + (IF .TEMP THEN 2*SEQ_NUM_SIZE+1 ELSE 5);
TEMPV = .INPUT_IOB[IOB$V_SEQUENCED];
TEMPV = 30 + (IF .TEMPV THEN 2*SEQ_NUM_SIZE+1 ELSE 5);
IF .PAGE_SIZE GEQ .TEMP+.M_NAM_LEN
THEN
TEMP = .M_NAM_LEN
ELSE
TEMP = 8; !8 is length of "FILE (1)"
IF .PAGE_SIZE GEQ .TEMPV+.V_NAM_LEN
THEN
TEMPV = .V_NAM_LEN
ELSE
TEMPV = 8; !8 is length of "FILE (2)"
!Now TEMP & TEMPV stand for the length of whatever will go in the
! file name field (note that in any case, we use whatever the user
! typed in for files instead of the resultant file specification.
TL = 0;
XTRA = ABS(.TEMP - .TEMPV);
IF .TEMP GEQ .TEMPV
THEN
LFLAG = 1
ELSE
LFLAG = 0;
!Run through the master text
IF
.M_LINE NEQ -1
THEN
BEGIN
INCR I FROM .LIN_MST TO .M_LINE-1 DO
BEGIN
LOCAL
M_SEQ,
T_PTR;
!Read a line
L_PTR=.MST_PTR[.I-.LIN_MST];
L_SIZ=GET_STG_CT(L_PTR);
T_PTR=.L_PTR;
!Get sequence number if it exists
IF
.MASTER_IOB[IOB$V_SEQUENCED]
THEN
BEGIN
M_SEQ=ASCDEC(L_PTR,0);
!Skip over ";"
CH$RCHAR_A(L_PTR);
!Readjust count
L_SIZ=.L_SIZ-CH$DIFF(.L_PTR,.T_PTR)
END
ELSE
M_SEQ=0;
IF
NOT .TXT_M_SEEN
THEN
BEGIN
STG('- - - - ',FALSE);
TL = .TL + 12;
IF .TEMP NEQ .M_NAM_LEN
THEN !don't use real file name
BEGIN
STG('FILE (1)',FALSE);
TL = .TL + 8;
END
ELSE !use real file name
BEGIN
OUTSTG(.M_NAM_PTR,.M_NAM_LEN,FALSE);
TL = .TL + .M_NAM_LEN;
END;
STG(' Line ',FALSE);
TL = .TL + 6;
IF
.M_SEQ EQL 0
THEN
BEGIN
OUTNUM(.LIN_MST+1,FALSE);
ADJLEN = DECASC(.LIN_MST+1,0);
END
ELSE
!Sequenced file
BEGIN
IF
CKPAGE(.L_SIZ,.L_PTR,FALSE)
THEN
!a page mark will appear as line 0 of the next page
BEGIN
OUTNMZ(0,SEQ_NUM_SIZE,FALSE);
STG('/',FALSE);
OUTNUM(.M_PAGE+1,FALSE);
ADJLEN = SEQ_NUM_SIZE + 1 + DECASC(.M_PAGE+1,0);
END
ELSE
BEGIN
OUTNMZ(.M_SEQ,SEQ_NUM_SIZE,FALSE);
STG('/',FALSE);
OUTNUM(.M_PAGE,FALSE);
ADJLEN = SEQ_NUM_SIZE + 1 + DECASC(.M_PAGE,0);
END
END;
TL = .TL + .ADJLEN;
IF (.TL MOD 3) EQL 0
THEN !Add one space after line number
BEGIN
STG(' ',FALSE);
TL = .TL + 1;
END;
IF .V_LINE NEQ -1
THEN
BEGIN !Prepare to match dashes
! of master and variation
IF .LFLAG
THEN
MORE = 0
ELSE
MORE = .XTRA;
!Seq_num_size included here in case that master is
! unsequenced, and variation is sequenced. This
! could lead to numbers of form "xx.." and
! "xx.../xx..." ,and the latter might be so long
! in the variation file that it would go past
! .tl+12+.more (12 is the amount of space required
! to place four dashes after the line to match
! the four preceding it). When this code was written,
! seq_num_size was equal to 5--hence the 7.
INCR POS FROM .TL+1 TO .TL+SEQ_NUM_SIZE+7+.MORE
DO
IF ( (.POS - 1) MOD 3 ) EQL 0
THEN
BEGIN !LAST POSITION WAS MULT. OF 3
STG('-',FALSE);
SAVEPOS = .POS; !Keep position of last dash
END
ELSE
STG(' ',FALSE);
OUTSTG(0,0,TRUE);
END
ELSE
STG(' - - - -',TRUE);
TXT_M_SEEN=TRUE
END;
STG(' 1)',FALSE);
IF
CKPAGE(.L_SIZ,.L_PTR,FALSE)
THEN
BEGIN
STG('<PAGE>',TRUE);
M_PAGE=.M_PAGE+1
END
ELSE
!Length of ' 1)' is 8
WRT_LINE(.L_PTR,.L_SIZ,.PAGE_SIZE-8,TRUE)
END
END;
!Process variation text
IF
.LIN_VAR NEQ .V_LINE AND
.V_LINE NEQ -1
THEN
BEGIN
!Output the text proper
INCR I FROM .LIN_VAR TO .V_LINE-1 DO
BEGIN
LOCAL
V_SEQ,
T_PTR;
L_PTR=.VAR_PTR[.I-.LIN_VAR];
L_SIZ=GET_STG_CT(L_PTR);
T_PTR=.L_PTR;
!Get sequence number if it exists
IF
.INPUT_IOB[IOB$V_SEQUENCED]
THEN
BEGIN
V_SEQ=ASCDEC(L_PTR,0);
!Skip over ";"
CH$RCHAR_A(L_PTR);
!Readjust count
L_SIZ=.L_SIZ-CH$DIFF(.L_PTR,.T_PTR)
END
ELSE
V_SEQ=0;
IF
NOT .TXT_V_SEEN
THEN
BEGIN
TXT_V_SEEN=TRUE;
TL = 0;
STG('- - - - ',FALSE);
TL = .TL + 12;
IF .TEMPV NEQ .V_NAM_LEN
THEN !don't use real file name
STG('FILE (2)',FALSE)
ELSE !use real file name
OUTSTG(.V_NAM_PTR,.V_NAM_LEN,FALSE);
TL = .TL + .TEMPV;
STG(' Line ',FALSE);
TL = .TL + 6;
IF
.V_SEQ EQL 0
THEN
BEGIN
OUTNUM(.LIN_VAR+1,FALSE);
ADJLEN = DECASC(.LIN_VAR+1,0);
END
ELSE
!Sequenced file
BEGIN
IF
CKPAGE(.L_SIZ,.L_PTR,FALSE)
THEN
!A page mark will appear as line 0 of the next page
BEGIN
OUTNMZ(0,SEQ_NUM_SIZE,FALSE);
STG('/',FALSE);
OUTNUM(.V_PAGE+1,FALSE);
ADJLEN = SEQ_NUM_SIZE + 1 + DECASC(.V_PAGE+1,0);
END
ELSE
BEGIN
OUTNMZ(.V_SEQ,SEQ_NUM_SIZE,FALSE);
STG('/',FALSE);
OUTNUM(.V_PAGE,FALSE);
ADJLEN = SEQ_NUM_SIZE + 1 + DECASC(.V_PAGE,0);
END
END;
TL = .TL + .ADJLEN;
IF (.TL MOD 3) EQL 0
THEN !Add 1 space after line number
BEGIN
STG(' ',FALSE);
TL = .TL + 1;
END;
IF .TXT_M_SEEN
THEN
BEGIN
IF NOT .LFLAG
THEN
MORE = 0
ELSE
MORE = .XTRA;
INCR POS FROM .TL+1 TO .SAVEPOS
DO
IF ((.POS - 1) MOD 3) EQL 0
THEN !IF MULT. OF 3,PRINT "-"
STG('-',FALSE)
ELSE
STG(' ',FALSE);
OUTSTG(0,0,TRUE);
END
ELSE
STG(' - - - -',TRUE);
END;
STG(' 2)',FALSE);
IF
CKPAGE(.L_SIZ,.L_PTR,FALSE)
THEN
BEGIN
STG('<PAGE>',TRUE);
V_PAGE=.V_PAGE+1
END
ELSE
!Length of ' 2)' is 8
WRT_LINE(.L_PTR,.L_SIZ,.PAGE_SIZE-8,TRUE)
END
END;
IF
.TXT_M_SEEN OR
.TXT_V_SEEN
THEN
BEGIN
IF .PAGE_SIZE GEQ 75
THEN
INCR I FROM 1 TO 25 DO STG('- ',FALSE)
ELSE
INCR I FROM 1 TO .PAGE_SIZE/3 DO STG('- ',FALSE);
OUTSTG(0,0,TRUE);
OUTSTG(0,0,TRUE);
OUTSTG(0,0,TRUE)
END
END
ELSE
!Parallel listing format
BEGIN
LOCAL
L_TRLR,
R_TRLR,
WRK_LINE : VECTOR[CH$ALLOCATION(15)],
WRK_LEN,
WRK_PTR;
L_TRLR=FALSE;
R_TRLR=FALSE;
!Now output the header for the change sequence
IF
.COUNT NEQ 0
THEN
BEGIN
LOCAL
M_SEQ,
V_SEQ;
!Get alignment for header line
INCR I FROM 1 TO .FIELD_WIDTH-19 DO STG(' ',FALSE);
!Get line
WRK_PTR=CH$PTR(WRK_LINE);
!Generate header data on left part of listing
IF
.MASTER_IOB[IOB$V_SEQUENCED] AND
.M_LINE NEQ -1
THEN
BEGIN
L_PTR=.MST_PTR[0];
L_SIZ=GET_STG_CT(L_PTR);
IF
CKPAGE(.L_SIZ,.L_PTR,TRUE)
THEN
!A page mark will appear as sequence 0 of the next page
BEGIN
INCR I FROM 1 TO SEQ_NUM_SIZE DO CH$WCHAR_A(%C'0',WRK_PTR);
CH$WCHAR_A(%C'/',WRK_PTR);
WRK_LEN=SEQ_NUM_SIZE+1+DECASC(.M_PAGE+1,.WRK_PTR)
END
ELSE
!Pick up sequence number needed
BEGIN
M_SEQ=ASCDEC(L_PTR,0);
WRK_LEN=DECASZ(.M_SEQ,.WRK_PTR,SEQ_NUM_SIZE);
WRK_PTR=CH$PLUS(.WRK_PTR,.WRK_LEN);
CH$WCHAR_A(%C'/',WRK_PTR);
WRK_LEN=.WRK_LEN+1+DECASC(.M_PAGE,.WRK_PTR)
END
END
ELSE
!Unsequenced
WRK_LEN=DECASC(.LIN_MST+1,.WRK_PTR);
!Output the assembled data
INCR I FROM 1 TO 10-.WRK_LEN DO STG('-',FALSE);
STG(' Line ',FALSE);
OUTSTG(CH$PTR(WRK_LINE),.WRK_LEN,FALSE);
STG(' ',FALSE);
STG('---',FALSE);
!Generate header data on the right part of the listing
WRK_PTR=CH$PTR(WRK_LINE);
IF
.INPUT_IOB[IOB$V_SEQUENCED] AND
.V_LINE NEQ -1
THEN
BEGIN
L_PTR=.VAR_PTR[0];
L_SIZ=GET_STG_CT(L_PTR);
IF
CKPAGE(.L_SIZ,.L_PTR,TRUE)
THEN
!A page mark will appear as line 0 of the next page
BEGIN
INCR I FROM 1 TO SEQ_NUM_SIZE DO CH$WCHAR_A(%C'0',WRK_PTR);
CH$WCHAR_A(%C'/',WRK_PTR);
WRK_LEN=SEQ_NUM_SIZE+1+DECASC(.V_PAGE+1,.WRK_PTR)
END
ELSE
!Pick up sequence number needed
BEGIN
V_SEQ=ASCDEC(L_PTR,0);
WRK_LEN=DECASZ(.V_SEQ,.WRK_PTR,SEQ_NUM_SIZE);
WRK_PTR=CH$PLUS(.WRK_PTR,.WRK_LEN);
CH$WCHAR_A(%C'/',WRK_PTR);
WRK_LEN=.WRK_LEN+1+DECASC(.V_PAGE,.WRK_PTR)
END
END
ELSE
!Unsequenced
WRK_LEN=DECASC(.LIN_VAR+1,.WRK_PTR);
!Output the assembled data
STG(' Line ',FALSE);
OUTSTG(CH$PTR(WRK_LINE),.WRK_LEN,FALSE);
STG(' ',FALSE);
INCR I FROM 1 TO 10-.WRK_LEN DO STG('-',FALSE);
OUTSTG(0,0,TRUE)
END;
!Now put out the two texts
INCR I FROM 0 TO .COUNT-1 DO
BEGIN
!Left part
IF
.LIN_MST+.I LSS .M_LINE AND
.M_LINE NEQ -1
THEN
BEGIN
L_PTR=.MST_PTR[.I];
L_SIZ=GET_STG_CT(L_PTR);
IF
.MASTER_IOB[IOB$V_SEQUENCED]
THEN
!Skip sequence number
DO
L_SIZ=.L_SIZ-1
UNTIL
CH$RCHAR_A(L_PTR) EQL %C';'
END
ELSE
BEGIN
L_PTR=0;
L_SIZ=0
END;
IF
.L_PTR NEQ 0 OR
.L_TRLR
THEN
BEGIN
IF
CKPAGE(.L_SIZ,.L_PTR,FALSE)
THEN
BEGIN
WRT_LINE(CH$PTR(UPLIT('<PAGE>')),6,.FIELD_WIDTH,FALSE);
M_PAGE=.M_PAGE+1
END
ELSE
WRT_LINE(.L_PTR,.L_SIZ,.FIELD_WIDTH,FALSE)
END
ELSE
BEGIN
INCR I FROM 1 TO .FIELD_WIDTH-19 DO STG(' ',FALSE);
STG('------------------',FALSE);
L_TRLR=TRUE
END;
STG('|',FALSE);
!Right part
IF
.LIN_VAR+.I LSS .V_LINE AND
.V_LINE NEQ -1
THEN
BEGIN
L_PTR=.VAR_PTR[.I];
L_SIZ=GET_STG_CT(L_PTR);
IF
.INPUT_IOB[IOB$V_SEQUENCED]
THEN
!Skip sequence number
DO
L_SIZ=.L_SIZ-1
UNTIL
CH$RCHAR_A(L_PTR) EQL %C';'
END
ELSE
BEGIN
L_PTR=0;
L_SIZ=0
END;
IF
.L_PTR NEQ 0 OR
.R_TRLR
THEN
BEGIN
IF
CKPAGE(.L_SIZ,.L_PTR,FALSE)
THEN
BEGIN
WRT_LINE(CH$PTR(UPLIT('<PAGE>')),6,.FIELD_WIDTH,TRUE);
V_PAGE=.V_PAGE+1
END
ELSE
WRT_LINE(.L_PTR,.L_SIZ,.FIELD_WIDTH,TRUE)
END
ELSE
BEGIN
STG('------------------',TRUE);
R_TRLR=TRUE
END
END;
!Now output the trailer
IF
.COUNT NEQ 0
THEN
BEGIN
IF
NOT .L_TRLR
THEN
BEGIN
INCR I FROM 1 TO .FIELD_WIDTH-19 DO STG(' ',FALSE);
STG('------------------',FALSE)
END;
IF
NOT .R_TRLR AND
.L_TRLR
THEN
WRT_LINE(0,0,.FIELD_WIDTH,FALSE);
IF
NOT .R_TRLR OR
NOT .L_TRLR
THEN
STG('-',FALSE);
IF
NOT .R_TRLR
THEN
STG('------------------',FALSE);
OUTSTG(0,0,TRUE);
OUTSTG(0,0,TRUE)
END
END;
!Advance the page count if a page break is seen. Remember
!that the two lines at the end are always the same so
!checking only one is necessary here.
IF
.M_LINE LSS .L_LN_MST AND
.M_LINE NEQ -1
THEN
BEGIN
L_PTR=.MST_PTR[.M_LINE-.LIN_MST];
L_SIZ=GET_STG_CT(L_PTR);
IF
CKPAGE(.L_SIZ,.L_PTR,.MASTER_IOB[IOB$V_SEQUENCED])
THEN
BEGIN
M_PAGE=.M_PAGE+1;
V_PAGE=.V_PAGE+1
END
END;
!Repack the text
PACK(.M_LINE,.V_LINE)
END; !End of OUTDIFF
ROUTINE SETUP (LGT,STR,LGTV,STRV,LGTD,STRD) =
!++
! FUNCTIONAL DESCRIPTION:
!
! Initialize the tables, get the command line, and initially fill
! the buffers.
!
! FORMAL PARAMETERS:
!
! LGT - length of master file name to be processed
! STR - pointer to master file name to be processed
! LGTV - length of variation file name to be processed
! STRV - pointer to variation file name to be processed
! LGTD - length of difference (output) file name to be processed
! STRD - pointer to difference (output) file name to be processed
! (note that LGTD and STRD may have to be computed here
! if they contain K_NULL)
! IMPLICIT INPUTS:
!
! NONE.
!
! IMPLICIT OUTPUTS:
!
! NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! TRUE - files opened OK
! FALSE - files not opened successfully
!
! SIDE EFFECTS:
!
! NONE.
!
!--
BEGIN
LOCAL
CFIL: VECTOR[CH$ALLOCATION(EXTENDED_FILE_SPEC)],
CFIL_PTR,
CFIL_SIZ,
FIL: VECTOR[CH$ALLOCATION(EXTENDED_FILE_SPEC)],
FIL_PTR,
FIL_SIZ,
GENERATION,
NAME_PTR,
S_L_PTR,
S_L_SIZ,
STG_CNT,
STS;
OWN ISB: $XPO_SPEC_BLOCK;
M_OPN=FALSE;
I_OPN=FALSE;
O_OPN=FALSE;
M_PAGE=1;
V_PAGE=1;
! Prevent network operations in this release.
IF
NOT LOCALF(.LGT,.STR)
THEN
RETURN FALSE ;
IF
NOT LOCALF(.LGTV,.STRV)
THEN
RETURN FALSE ;
if
.lgtd neq 0 and
.strd neq k_null
then
begin
if
not localf(.lgtd,.strd)
then
return false
end;
STS=$CMS_OPEN(IOB=MASTER_IOB,FILE_SPEC=(.LGT,.STR),FAILURE=0);
IF
NOT .STS
THEN
BEGIN
ERSXPO(S_NOOPEN,.STS,CAT(('Cannot open '),(.LGT,.STR)));
END;
M_OPN=TRUE;
STS=$CMS_OPEN(IOB=INPUT_IOB,FILE_SPEC=(.LGTV,.STRV),FAILURE=0);
IF
NOT .STS
THEN
BEGIN
ERSXPO(S_NOOPEN,.STS,CAT(('Cannot open '),(.LGTV,.STRV)));
END;
I_OPN=TRUE;
!Now open differences file
!If output qualifier not specified, construct default
IF
.LGTD EQL 0 AND
.STRD EQL K_NULL
THEN
!no output qualifier given
BEGIN
!+
! We must remove any device and direcotry specification so that
! the dif file ends up in the default directory
!-
LOCAL
mst_spec_blk : $xpo_spec_block;
sts = $xpo_parse_spec (spec_block = mst_spec_blk,
file_spec = master_iob[iob$t_resultant],
failure = 0);
if not .sts
then
bug(cat('Cannot parse valid file name ',master_iob[iob$t_resultant]));
IF
.AFLAG
THEN
BEGIN !Try opening for append
IF
NOT (STS=$CMS_OPEN( IOB=OUTPUT_IOB,
FILE_SPEC=CMPDEF,
default=mst_spec_blk[xpo$t_file_name],
OPTIONS=APPEND,
FAILURE=0))
THEN
ERSIOB(s_doanoopen,OUTPUT_IOB,
CAT('Cannot open default output file for append'));
!+
! Make sure the file has the correct attributes
!-
IF
filtyp(output_iob) NEQ 1
THEN
BEGIN
$cms_close(iob=output_iob,options=remember,failure=0);
ers(s_errfile,cat('File ',output_iob[iob$t_resultant],
' is not a sequential, variable length, non-sequenced file'));
END;
END
ELSE
BEGIN !Try opening for output
IF
NOT (STS=$CMS_OPEN( IOB=OUTPUT_IOB,
FILE_SPEC=CMPDEF,
default=mst_spec_blk[xpo$t_file_name],
OPTIONS=output,
FAILURE=0))
THEN
ERSIOB(s_erropen,OUTPUT_IOB,
CAT('Cannot open default output file'))
END
END
ELSE
!Output qualifier given
BEGIN
IF
.AFLAG
THEN
BEGIN !Try opening for append
IF
NOT (STS=$CMS_OPEN( IOB=OUTPUT_IOB,
file_spec=(.lgtd,.strd),
default=CMPDEF,
OPTIONS=APPEND,
FAILURE=0))
THEN
ERSIOB(s_doanoopen,OUTPUT_IOB,
CAT('Cannot open output file ',(.lgtd,.strd),
' for append'));
!+
! Make sure the file has the correct attributes
!-
IF
filtyp(output_iob) NEQ 1
THEN
BEGIN
$cms_close(iob=output_iob,options=remember,failure=0);
ers(s_errfile,cat('File ',output_iob[iob$t_resultant],
' is not a sequential, variable length, non-sequenced file'));
END;
END
ELSE
BEGIN !Try opening for output
IF
NOT (STS=$CMS_OPEN( IOB=OUTPUT_IOB,
file_spec=(.lgtd,.strd),
default=CMPDEF,
OPTIONS=output,
FAILURE=0))
THEN
ERSIOB(s_onoopen,OUTPUT_IOB,
CAT('Cannot open output file ',(.lgtd,.strd)))
END
END;
O_OPN=TRUE;
!Initialize comparison algorithm and fill the buffer
CMPINI(FALSE,0,GET_CUR_MST,OUTDIFF,GET_LIN);
OUTINI(OUTPUT_IOB);
!If /append, then add form-feed
IF .AFLAG AND (.STS EQL STEP$_NORMAL)
THEN
OUTSTG(CH$PTR(UPLIT(%STRING(%CHAR(FORM_FEED)))),1,TRUE);
!Supply defaults if necessary. Must be multiple of 8
IF .FIELD_WIDTH EQL 0
THEN
BEGIN
FIELD_WIDTH=64;
PAGE_SIZE=128;
END;
DIFF_FLG=FALSE;
!Generate listing header
STG(%string(fac_name,' File Comparison Utility'),TRUE);
STG('Files Compared By ',FALSE);
FIL_SIZ=GETACT(FIL);
OUTSTG(CH$PTR(FIL),.FIL_SIZ,FALSE);
STG(' On ',FALSE);
FIL_SIZ=DATTIM(FIL);
OUTSTG(CH$PTR(FIL),.FIL_SIZ,TRUE);
BEGIN
OWN OMFN, !master file name entirely outputed flag
OIFN; !input file name entirely outputed flag
ROUTINE HEADER (A_DESC,FIELD_SIZE,PART,CENTER) =
!spaces out all the way to field_size;if .center then center else write
BEGIN
OWN ASB: $XPO_SPEC_BLOCK;
BIND DESC = .A_DESC: $STR_DESCRIPTOR();
LOCAL DLEN,
DPTR;
$XPO_PARSE_SPEC(FILE_SPEC=DESC,SPEC_BLOCK=ASB);
DLEN = .DESC[STR$H_LENGTH];
DPTR = .DESC[STR$A_POINTER];
IF .DLEN GTR .FIELD_SIZE
THEN !String will not fit on one line
BEGIN
LOCAL PTR,
DIFF_FLG;
PTR=CH$FIND_SUB(LEN_COMMA_PTR(DESC,ASB[XPO$T_DIRECT]));
IF CH$FAIL(.PTR) THEN BUG(CAT('COMPARE/SETUP CAN''T FIND DIRECTORY IN ',DESC));
PTR=CH$PLUS(.PTR,.ASB[XPO$H_DIRECT]);
!Separate file name,type,and version from node,device,and directory
DIFF_FLG = CH$DIFF(.PTR,.DPTR);
IF .PART EQL 1
THEN !Write out node and directory
BEGIN
IF .DIFF_FLG GTR .FIELD_SIZE
THEN
BEGIN !Truncate node/device/dir on left
DPTR=CH$PLUS(.PTR,-.FIELD_SIZE);
DIFF_FLG=.FIELD_SIZE;
END;
IF .CENTER
THEN !center node and directory
BEGIN
INCR I FROM 1 TO (.FIELD_SIZE-.DIFF_FLG)/2 DO STG(' ',FALSE);
OUTSTG(.DPTR,.DIFF_FLG,FALSE);
INCR I FROM 1 TO .FIELD_SIZE-(.FIELD_SIZE-.DIFF_FLG)/2-.DIFF_FLG
DO STG(' ',FALSE);
END
ELSE !don't center node and directory
BEGIN
OUTSTG(.DPTR,.DIFF_FLG,FALSE);
INCR I FROM 1 TO .FIELD_SIZE-.DIFF_FLG DO STG(' ',FALSE);
END;
RETURN FALSE !Return false (more output exists)
END
ELSE !Write out file name,type, and version
BEGIN
LOCAL DIF;
DIF=.DLEN-.DIFF_FLG;
IF .DIF GTR .FIELD_SIZE
THEN !Truncate file name/type/ver# on right
DIF=.FIELD_SIZE;
IF .CENTER
THEN !center file name
BEGIN
INCR I FROM 1 TO (.FIELD_SIZE-.DIF)/2 DO STG(' ',FALSE);
OUTSTG(CH$PLUS(.DPTR,.DIFF_FLG),.DIF,FALSE);
INCR I FROM 1 TO .FIELD_SIZE-(.FIELD_SIZE-.DIF)/2-.DIF
DO STG(' ',FALSE);
END
ELSE !don't center file name
BEGIN
OUTSTG(.PTR,.DIF,FALSE);
INCR I FROM 1 TO .FIELD_SIZE-.DIF DO STG(' ',FALSE);
END;
RETURN TRUE !return true (no more output)
END
END
ELSE !file name fits on one line
BEGIN
IF .CENTER
THEN
BEGIN !Center output
INCR I FROM 1 TO (.FIELD_SIZE-.DLEN)/2 DO STG(' ',FALSE);
OUTSTG(.DPTR,.DLEN,FALSE);
INCR I FROM 1 TO .FIELD_SIZE - (.FIELD_SIZE-.DLEN)/2 - .DLEN
DO STG(' ',FALSE);
END
ELSE
BEGIN !Don't center output
OUTSTG(.DPTR,.DLEN,FALSE);
INCR I FROM 1 TO .FIELD_SIZE - .DLEN DO STG(' ',FALSE);
END;
RETURN TRUE !Return true (no more output)
END
END; !END HEADER
IF
NOT .PARL_L
THEN
BEGIN
STG(' (1) ',FALSE);
OMFN = HEADER(MASTER_IOB[IOB$T_RESULTANT],.PAGE_SIZE-9,1,FALSE);
IF NOT .OMFN
THEN
BEGIN
OUTSTG(0,0,TRUE);
STG(' ',FALSE); !18 Spaces
HEADER(MASTER_IOB[IOB$T_RESULTANT],.PAGE_SIZE-18,2,FALSE);
END;
OUTSTG(0,0,TRUE);
STG(' (2) ',FALSE);
OIFN = HEADER(INPUT_IOB[IOB$T_RESULTANT],.PAGE_SIZE-9,1,FALSE);
IF NOT .OIFN
THEN
BEGIN
OUTSTG(0,0,TRUE);
STG(' ',FALSE); !18 Spaces
HEADER(INPUT_IOB[IOB$T_RESULTANT],.PAGE_SIZE-18,2,FALSE);
END;
INCR I FROM 1 TO 4 DO OUTSTG(0,0,TRUE)
END
!Parallel format
ELSE
BEGIN
OUTSTG(0,0,TRUE);
OMFN = HEADER(MASTER_IOB[IOB$T_RESULTANT],.FIELD_WIDTH-1,1,TRUE);
STG(' ',FALSE);
OIFN = HEADER(INPUT_IOB[IOB$T_RESULTANT],.FIELD_WIDTH,1,TRUE);
OUTSTG(0,0,TRUE);
IF NOT .OMFN
THEN
BEGIN
HEADER(MASTER_IOB[IOB$T_RESULTANT],.FIELD_WIDTH-1,2,TRUE);
STG(' ',FALSE);
END;
IF .OMFN AND NOT .OIFN
THEN
BEGIN
INCR I FROM 1 TO .FIELD_WIDTH DO STG(' ',FALSE);
OIFN = HEADER(INPUT_IOB[IOB$T_RESULTANT],.FIELD_WIDTH,2,TRUE);
END;
IF NOT .OIFN
THEN
HEADER(INPUT_IOB[IOB$T_RESULTANT],.FIELD_WIDTH,2,TRUE);
OUTSTG(0,0,TRUE);
OUTSTG(0,0,TRUE);
END;
END; !end block
TRUE
END; !End of SETUP
ROUTINE TERMINATE : NOVALUE =
!++
! FUNCTIONAL DESCRIPTION:
!
! Clean up the loose ends and go away.
!
! FORMAL PARAMETERS:
!
! NONE.
!
! IMPLICIT INPUTS:
!
! All of the logical unit numbers of open files.
!
! IMPLICIT OUTPUTS:
!
! NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! NONE.
!
! SIDE EFFECTS:
!
! All of the files are closed.
!
!--
BEGIN
IF
.I_OPN
THEN
$cms_close(IOB=INPUT_IOB);
IF
.M_OPN
THEN
$cms_close(IOB=MASTER_IOB);
IF
.O_OPN
THEN
begin
if
not .aflag and
not .diff_flg
then
!no output file if no differences seen
begin
local status;
$cms_close(iob=output_iob,options=remember);
status = $step_delete(iob=output_iob,failure=0);
!I don't know what these codes mean or why there're here
! if not .status
! then
! if not(.status eql xpo$_bad_req or .status eql xpo$_sys_error)
! then
! ersxpo(s_nouodel,.status, lit('Cannot delete output file.'));
end
else
begin
stg('**** End of Differences ****',true);
$cms_close(IOB=OUTPUT_IOB)
end
end
END; !End of TERMINATE
ROUTINE WRT_LINE (POINTER,LENGTH,FIELD_LENGTH,TERM) : NOVALUE =
!++
! FUNCTIONAL DESCRIPTION:
!
! Write a text line, counting tabs and blanks correctly
!
! FORMAL PARAMETERS:
!
! LENGTH - length of text line
! POINTER - pointer to text line
! FIELD_LENGTH - length of output field (either field_width or page size)
!
! IMPLICIT INPUTS:
!
! Input and output IOBs
!
! IMPLICIT OUTPUTS:
!
! NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! NONE.
!
! SIDE EFFECTS:
!
! NONE.
!
!--
BEGIN
LOCAL
COL_POS,
PRT_SIZ;
COL_POS=0;
PRT_SIZ=.LENGTH;
!Count the effective length of the line
INCR I FROM 1 TO .LENGTH DO
BEGIN
LOCAL
CHAR,
OLD_POS;
CHAR=CH$RCHAR(CH$PLUS(.POINTER,.I-1));
OLD_POS=.COL_POS;
!Ignore non-printing characters
IF
.CHAR GEQ %C' ' OR
.CHAR EQL %C' '
THEN
BEGIN
IF
.CHAR NEQ %C' '
THEN
COL_POS=.COL_POS+1
ELSE
COL_POS=.COL_POS-(.COL_POS MOD 8)+8
END;
IF
.COL_POS GEQ .FIELD_LENGTH-1
THEN
BEGIN
COL_POS=.OLD_POS+1;
PRT_SIZ=.I;
!mark line as being overflowed
CH$WCHAR(%C'+',CH$PLUS(.POINTER,.PRT_SIZ-1));
EXITLOOP
END
ELSE
OLD_POS=.COL_POS
END;
OUTSTG(.POINTER,.PRT_SIZ,FALSE);
IF
NOT .TERM
THEN
BEGIN
!Fill to nearest tab
IF
.COL_POS+8-(.COL_POS MOD 8) LEQ .FIELD_LENGTH-1
THEN
BEGIN
STG(' ',FALSE);
COL_POS=.COL_POS+8-(.COL_POS MOD 8)
END;
!Tab as close to end as possible
UNTIL
.COL_POS+8 GTR .FIELD_LENGTH-2
DO
BEGIN
STG(' ',FALSE);
COL_POS=.COL_POS+8
END;
!Fill in the remainder
INCR I FROM .COL_POS+1 TO .FIELD_LENGTH-1 DO
STG(' ',FALSE)
END;
OUTSTG(0,0,.TERM)
END; !End of WRT_LINE
END !End of Module DIFF
ELUDOM