Google
 

Trailing-Edge - PDP-10 Archives - DEC_CMS-20_V1.0_SRC - cms/sources/chkgen.bli
There are no other files named chkgen.bli in the archive.
MODULE CHKGEN	(
		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:
!
!	Check the generation value against the command line in the text.
!	Set the KEEP flag according to what is seen.
!
! ENVIRONMENT:	VAX/VMS, DS-20
!
! AUTHOR: D. Knight , CREATION DATE: 01-May-79
!
!--
!
! TABLE OF CONTENTS
!

FORWARD ROUTINE
	CHKGEN : NOVALUE,		!Check generation value against text
	CMPGEN,				!Compare two generalized expressions
	G_NUM_LGT,			!Get length of numeric string
	GEN_SETUP : NOVALUE;		!Set up CHKGEN

!
! INCLUDE FILES:
!

%if %bliss(bliss32) %then
    library 'sys$library:starlet';
%else
    require 'jsys:';
%fi

LIBRARY 'XPORT:';

REQUIRE 'SCONFG:';			!CMS configuration options

REQUIRE 'BLISSX:';

REQUIRE 'COMUSR:';

REQUIRE 'HOSUSR:';

!
! MACROS:
!

FIELD
    INX_FLD =
	SET
	G_KEEP	= [0,0,%BPVAL/2,0],
	G_ONPATH= [0,%BPVAL/2,%BPVAL/2,0],
	G_PTR	= [1,0,%BPVAL,0],
	G_LEN	= [2,0,%BPVAL/2,0],
	G_INS	= [2,%BPVAL/2,%BPVAL/2,0]
	TES;

!
! EQUATED SYMBOLS:
!

LITERAL
	GEN_S_SIZE = 200,		!GET_CUR_MST stack size
	INDEX_SIZE = 3;			!Size of entry in stack

!
! OWN STORAGE:
!

GLOBAL
	LGEN,				!generation
	LGEN_L,				!generation length
	ONPATH;

OWN
	GEN,				!generation
	GEN_L,				!generation length
	GEN_INDEX,			!stack pointer
	GEN_PTR,
	GEN_STATUS: BLOCKVECTOR[GEN_S_SIZE,INDEX_SIZE] FIELD(INX_FLD), !stack
	GEN_STRING: VECTOR[CH$ALLOCATION(GEN_S_SIZE*gen_size)],
	INS_MKR;

!
! EXTERNAL REFERENCES:
!

EXTERNAL ROUTINE
	ASCDEC,
	BADLIB,
	BUG,
	GET_LXM;
GLOBAL ROUTINE CHKGEN (S_L_PTR,S_L_LGT,KEEP,GENERATION,G_LGT) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Keep track of any lines in the master file which have been
!	inserted or deleted by the respective generations.
!	Note that this routine keeps its own stack of information about
!	the input data, so don't try to process lines not in sequence, or
!	don't try to back up using it.
!
! FORMAL PARAMETERS:
!
!	S_L_PTR - Address of character pointer to line
!	S_L_LGT - Length of line
!	KEEP - Address of keep/discard flag
!	GENERATION - master generation pointer
!	G_LGT - length of master generation pointer
!
! IMPLICIT INPUTS:
!
!	Information is kept about the previous lineage commands which have
!	been encountered, this is used to keep overall track of the insertion
!	or deletion status.
!
! IMPLICIT OUTPUTS:
!
!	The stack is updated to reflect the current insertion or deletion status.
!	GEN - current generation of line scanned
!	KEEP - keep/discard line flag
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

    LOCAL
	CTL_CHAR,
	TMP_GEN,
	TMP_G_LGT;

    !Get the generation this record applies to
    TMP_GEN=.GEN_PTR;
    TMP_G_LGT=GET_LXM(.S_L_PTR,%C' ',.S_L_LGT,TMP_GEN)-1;

    !Back up over control character
    .S_L_PTR=CH$PLUS(..S_L_PTR,-1);

    !There must be a value here
    IF
	.TMP_G_LGT LEQ 0
    THEN
	BADLIB(LIT('Illegal control record.' ));

    !Pick up control character
    CTL_CHAR=CH$RCHAR_A(.S_L_PTR);

    !Check for end of correction entry which matches current generation
    IF
	.CTL_CHAR EQL %C'E' AND
	CH$EQL(.TMP_G_LGT,.GEN_PTR,.GEN_L,.GEN)
    THEN
	!End of change, pop previous level and continue
	BEGIN

	IF
	    .GEN_INDEX EQL -1
	THEN
	    !Something is badly wrong
	    BADLIB(LIT('Mismatched control records.'));

	!Pop generation and keep flag from stack
	.KEEP=.GEN_STATUS[.GEN_INDEX,G_KEEP];
	GEN=.GEN_STATUS[.GEN_INDEX,G_PTR];
	GEN_L=.GEN_STATUS[.GEN_INDEX,G_LEN];
	ONPATH=.GEN_STATUS[.GEN_INDEX,G_ONPATH];
	INS_MKR=.GEN_STATUS[.GEN_INDEX,G_INS];

	!Find the generation for listing which is on the correct
	!path and an insertion
	DECR I FROM .GEN_INDEX TO 0 DO
	    BEGIN
	    IF
		.GEN_STATUS[.I,G_KEEP] AND
		.GEN_STATUS[.I,G_ONPATH] AND
		.GEN_STATUS[.I,G_INS]
	    THEN
		BEGIN
		LGEN=.GEN_STATUS[.I,G_PTR];
		LGEN_L=.GEN_STATUS[.I,G_LEN];
		EXITLOOP
		END
	    END;

	GEN_PTR=CH$PLUS(.GEN,.GEN_L);
	GEN_INDEX=.GEN_INDEX-1;
	RETURN
	END
    ELSE
	!Examine the deletion and insertion control records
	!and set up the stack accordingly
	BEGIN
	IF
	    .CTL_CHAR EQL %C'D' OR
	    .CTL_CHAR EQL %C'I'
	THEN
	    !Deletion and insertion control records
	    BEGIN

	    !Push old control record on stack
	    GEN_INDEX=.GEN_INDEX+1;
	    if
		.gen_index geq gen_s_size
	    then
		bug(lit('Generation stack overflow in CHKGEN.'));
	    GEN_STATUS[.GEN_INDEX,G_KEEP]=..KEEP;
	    GEN_STATUS[.GEN_INDEX,G_PTR]=.GEN;
	    GEN_STATUS[.GEN_INDEX,G_LEN]=.GEN_L;
	    GEN_STATUS[.GEN_INDEX,G_ONPATH]=.ONPATH;
	    GEN_STATUS[.GEN_INDEX,G_INS]=.INS_MKR;

	    !Remember whether this is an insertion or deletion
	    IF
		.CTL_CHAR EQL %C'D'
	    THEN
		INS_MKR=FALSE
	    ELSE
		INS_MKR=TRUE;

	    !Assume reverse sense for generation counting
	    LGEN=.GEN;
	    LGEN_L=.GEN_L;

	    !Set up new control record
	    GEN=.GEN_PTR;
	    GEN_PTR=CH$PLUS(.GEN_PTR,.TMP_G_LGT);
	    if
		ch$diff(.gen_ptr,ch$plus(ch$ptr(gen_string),gen_s_size*gen_size))
			geq 0
	    then
		bug(lit('Generation string table overflow in CHKGEN.'));
	    GEN_L=.TMP_G_LGT;

	    !Keep only those lines that will show up in the final text
	    ONPATH=CMPGEN(.GEN,.GEN_L,.GENERATION,.G_LGT);

	    IF
		!On branch deletion
		.ONPATH AND .CTL_CHAR EQL %C'D' OR
		!Off branch insertion
		NOT .ONPATH AND .CTL_CHAR EQL %C'I' OR
		!Off branch anything nested in an on branch deletion
		NOT .ONPATH AND NOT .GEN_STATUS[.GEN_INDEX,G_KEEP] OR
		!On branch insertion nested in on branch deletion with
		! generation less than the deletion
		(.ONPATH AND
		 .CTL_CHAR EQL %C'I' AND
		 NOT .GEN_STATUS[.GEN_INDEX,G_KEEP] AND
		 NOT CMPGEN(.GEN_STATUS[.GEN_INDEX,G_PTR],.GEN_STATUS[.GEN_INDEX,G_LEN],.GEN,.GEN_L))
	    THEN
		BEGIN
		.KEEP=FALSE;
		!Normal generation sense
		IF
		    .CTL_CHAR NEQ %C'I'
		THEN
		    BEGIN
		    LGEN=.GEN;
		    LGEN_L=.GEN_L
		    END
		END
	    ELSE
		BEGIN
		.KEEP=TRUE;

		!See if generation is reversed in sense
		!(user asked for earlier generation than the latest)
		IF
		    .CTL_CHAR NEQ %C'D'
		THEN
		    !Normal sense, use current generation
		    BEGIN
		    LGEN=.GEN;
		    LGEN_L=.GEN_L
		    END
		ELSE
		    !Use the generation from a prior incarnation
		    !which is on the correct path
		    BEGIN
		    DECR I FROM .GEN_INDEX TO 0 DO
			BEGIN
			IF
			    .GEN_STATUS[.I,G_KEEP] AND
			    .GEN_STATUS[.I,G_ONPATH] AND
			    .GEN_STATUS[.I,G_INS]
			THEN
			    BEGIN
			    LGEN=.GEN_STATUS[.I,G_PTR];
			    LGEN_L=.GEN_STATUS[.I,G_LEN];
			    EXITLOOP
			    END
			END
		    END

		END;

	    RETURN
	    END
	ELSE
	    !Error
	    BEGIN
	    IF
		.CTL_CHAR EQL %C'E'
	    THEN
		BADLIB(LIT('Mismatched control records.'))
	    ELSE
		BADLIB(LIT('Unrecognized control character.' ))
	    END
	END

    END;				!End of CHKGEN
GLOBAL ROUTINE CMPGEN (G1,G1_L,G2,G2_L) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Compare two generalized expressions.  G1 is the generation from
!	the file or text, G2 is the generation requested by the caller.
!	Success is returned if G1 is on a direct path to G2.
!
! FORMAL PARAMETERS:
!
!	G1 - pointer to generation in text
!	G1_L - length of generation in text
!	G2 - pointer to generation requested
!	G2_L - length of generation requested
!
! IMPLICIT INPUTS:
!
!	NONE.
!
! IMPLICIT OUTPUTS:
!
!	NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	TRUE - Generation is on correct line of descent
!	FALSE - Generation is not on correct line of descent
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

    LOCAL
	G1_CHR,
	G1_LGT,
	G1_PTR,
	G1_TMP,
	G1_VAL,
	G2_CHR,
	G2_LGT,
	G2_PTR,
	G2_TMP,
	G2_VAL;

    !Setup
    G1_PTR=.G1;
    G1_LGT=.G1_L;
    G2_PTR=.G2;
    G2_LGT=.G2_L;

    !Process entire generation expression
    REPEAT
	BEGIN

	!Get length of integer parts
	G1_TMP=G_NUM_LGT(.G1_PTR,.G1_LGT);
	G2_TMP=G_NUM_LGT(.G2_PTR,.G2_LGT);

	!The lengths of both must be non-zero
	IF
	    .G1_TMP EQL 0 OR
	    .G2_TMP EQL 0
	THEN
	    BUG(LIT('Illegal generation expression in CHKGEN'));

	!Values
	G1_VAL=ASCDEC(G1_PTR,.G1_TMP);
	G1_LGT=.G1_LGT-.G1_TMP;
	G2_VAL=ASCDEC(G2_PTR,.G2_TMP);
	G2_LGT=.G2_LGT-.G2_TMP;

	IF
	    .G1_VAL EQL .G2_VAL
	THEN
	    !Integer parts match
	    BEGIN

	    !Pick up which branch for G1
	    IF
		.G1_LGT NEQ 0
	    THEN
		BEGIN
		G1_CHR=CH$RCHAR_A(G1_PTR);
		G1_LGT=.G1_LGT-1
		END
	    ELSE
		G1_CHR=0;

	    !Pick up which branch for G2
	    IF
		.G2_LGT NEQ 0
	    THEN
		BEGIN
		G2_CHR=CH$RCHAR_A(G2_PTR);
		G2_LGT=.G2_LGT-1
		END
	    ELSE
		G2_CHR=0;

	    !Quit successfully if we are at the end of the G1 branch
	    IF
		.G1_CHR EQL 0 AND
		.G2_CHR NEQ 0
	    THEN
		RETURN TRUE;

	    !No match if the branches are not the same
	    IF
		.G1_CHR NEQ .G2_CHR
	    THEN
		RETURN FALSE;

	    !Error if nothing follows branch marker
	    IF
		.G1_LGT EQL 0 AND
		.G2_LGT EQL 0 AND
		.G1_CHR NEQ 0 AND
		.G2_CHR NEQ 0
	    THEN
		!Error, illegal expression
		BUG(LIT('Illegal generation expression in CHKGEN'))

	    END
	ELSE
	    BEGIN

	    IF
		.G1_VAL GTR .G2_VAL
	    THEN
		!No match
		RETURN FALSE;

	    !Is this the end of G1?
	    IF
		.G1_LGT EQL 0
	    THEN
		RETURN TRUE;

	    !Can't possibly match
	    RETURN FALSE
	    END;

	IF
	    .G1_LGT EQL 0 AND
	    .G2_LGT EQL 0
	THEN
	    RETURN TRUE

	END

    END;				!End of CMPGEN
ROUTINE G_NUM_LGT (PTR,LGT) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Get the length of a decimal string
!
! FORMAL PARAMETERS:
!
!	PTR - pointer to string
!	LGT - length of string
!
! IMPLICIT INPUTS:
!
!	NONE.
!
! IMPLICIT OUTPUTS:
!
!	NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	Size of integer string
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

    LOCAL
	C_PTR,
	CNT;

    CNT=0;
    C_PTR=.PTR;

    INCR I FROM 1 TO .LGT DO
	BEGIN

	LOCAL
	    CHAR;

	CHAR=CH$RCHAR_A(C_PTR);

	IF
	    .CHAR GEQ %C'0' AND
	    .CHAR LEQ %C'9'
	THEN
	    CNT=.CNT+1
	ELSE
	    EXITLOOP
	END;

    .CNT

    END;				!End of G_NUM_LGT
GLOBAL ROUTINE GEN_SETUP (KEEP) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!
! FORMAL PARAMETERS:
!
!	KEEP - keep/nokeep flag
!
! IMPLICIT INPUTS:
!
!	NONE.
!
! IMPLICIT OUTPUTS:
!
!	GEN_INDEX, GEN_PTR, GEN, and GEN_L are initialized
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

    GEN_INDEX=-1;

    GEN_PTR=CH$PTR(GEN_STRING);

    GEN=.GEN_PTR;

    GEN_L=0;

    ONPATH=TRUE;

    INS_MKR=TRUE;

    .KEEP=TRUE

    END;				!End of GEN_SETUP
END				!End of Module CHKGEN
ELUDOM