Google
 

Trailing-Edge - PDP-10 Archives - DEC_CMS-20_V1.0_SRC - cms/sources/chkres.bli
There are no other files named chkres.bli in the archive.
MODULE CHKRES	(
		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:
!
!	Element reservation control.
!
! ENVIRONMENT:	VAX/VMS, DS-20
!
! AUTHOR: D. Knight , CREATION DATE: 29-Nov-78
!
!--
!++
!			General Description
!
!	CHKRES handles the manipulation of the reservation file.  No other
!	utility is allowed to modify the file.
!
!			File Structures
!
!	Each line in the file consists of 8 fields.  The first, in column one,
!	specifies whether the entry is a reservation or a replacement entry.
!	If it contains an "*" the line is a replacement field.  (The replacement
!	line will only exist if there are multiple reservations outstanding for
!	an element).  Field 2 contains the name of the element.  Field 3 holds
!	the generation reserved.  Field 4 has the user name of the reserver.
!	The 5th and 6th fields contain the date and time of the entry.
!	Field 7 holds the comment specified by the user, if any.  If non-existent,
!	it will be an empty quoted string.  The 8th field has any special qualifiers
!	that may need to be remembered.  Currently, only the "/NONOTES" qualifier
!	is possible.
!
!	Except for the first field, which is exactly one character long and
!	is in column one, all fields are variable length and terminated by
!	a single blank.
!
!--
!
! TABLE OF CONTENTS
!

FORWARD ROUTINE
	CHKRES,
	DELRES: NOVALUE,
	DMPRES: NOVALUE,
	MRKRES: NOVALUE,
	REMRES: NOVALUE,
	REPREP: NOVALUE,
	REPRES: NOVALUE,
	UPDRES: NOVALUE,
	WRT_STG: NOVALUE;

!
! INCLUDE FILES:
!

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

LIBRARY 'XPORT:';

REQUIRE 'SCONFG:';

REQUIRE 'BLISSX:';

require 'condit:';

REQUIRE 'RESV:';

!
! MACROS:
!

MACRO
	STG(L,M) = WRT_STG(CH$PTR(UPLIT(L)),%CHARCOUNT(L),M) %;

!
! EQUATED SYMBOLS:
!

LITERAL
	LINE_SIZE=500,			!Reservation line max. length
	res_max=150,			!Maximum number of multiple reservations
					!of a single element
	txt_max=5000;			!Number of characters allocated
					! each time text storage is needed.

!
! OWN STORAGE:
!

global
	res_head;			!Pointer to reservation text table

OWN
	cur_tab_siz,			!current size of character storage
	END_MARK,
	MARK,				!Position where reservation line would be placed
	NEW_CRC,			!Total CRC for new reservation file
	$IO_BLOCK(RD),			!Input IOB
	RES_LST : REF BLOCKVECTOR[RES_MAX,ENT_SIZ] FIELD(RES_FLD), !List space
	STRING: VECTOR[CH$ALLOCATION(extended_file_spec)], !File name storage
	STRING_SIZ,			!File name size
	TXT_PTR,
	$IO_BLOCK(WRT);

!
! EXTERNAL REFERENCES:
!

external literal
	s_invcksum,			!reserv file has invalid checksum
	s_nocksum,			!reservation file has no checksum
	s_repby,
	s_resby;

EXTERNAL
	GEN_BUF,
	GEN_LGT;

EXTERNAL ROUTINE
	ASCHEX,				!CONVERT ASCII TO hex
	BADLIB,
	badxpo,
	BUG,
	CRCTABLE:NOVALUE,		!Set up polynomial table
	CRCCALC,			!Calculate CRC of a string
    	DEQUOT,				!Take quotes away from user remark
	DATTIM,				!Get date and time
	DELVRS,				! delete file(FILOPS)
    	ENQUOT,				!Surround user remark and appended string with quotes
	GETACT,				!Get user name
	GET_LXM,
	GET_STG_CT,			!Get string size
	HEXASZ,
	PUT_STG_CT,			!Put away string size
	SAY,
	SAYLP,
	sysmsg,
	TRNFIL;
GLOBAL ROUTINE CHKRES (ELM,SIZE,LIST) =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Check for element reservation.
!
!	If one or more elements is reserved, return
!	a pointer to the list of reservation lines.  In any case,
!	position the reservation file to the proper place to allow
!	insertion or modification to the reservation status.  (This
!	is done using the MRKRES or REMRES routines).  Note that either
!	MRKRES or REMRES must always be called following a
!	CHKRES call.
!
! FORMAL PARAMETERS:
!
!	ELM - string pointer to element name to be found
!	SIZE - length of element name
!	LIST - cell address where list of reservations will be remembered
!
! IMPLICIT INPUTS:
!
!	NONE.
!
! IMPLICIT OUTPUTS:
!
!	NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	TRUE - reservations have been seen
!	FALSE - no reservations have been seen
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

    LOCAL
	CRC_COUNT,
	CHAIN_PTR,
	FILE_CRC,
	found_crc,
	LAST_LINE,
	status,
	TOTAL_CRC ;

    ! Initialize polynomial table
    crctable();
    TOTAL_CRC = 0;
    FILE_CRC = 0;
    found_crc = false;

    !Open reservation control file
    if
	(status=$STEP_OPEN(IOB=RD_IOB,FILE_SPEC=(%STRING(LIB,RES)),
		OPTIONS=INPUT,failure=0)) neq step$_normal
    then
	badxpo(.status,lit('Cannot open reservation file'));

    !Set up the reservation text buffer
    $XPO_GET_MEM(CHARACTERS=TXT_MAX,RESULT=res_head);
    cur_tab_siz=txt_max;

    !set up reservation list space also
    $xpo_get_mem(fullwords=res_max*ent_siz,result=res_lst);

    !Set up for text walk-through
    TXT_PTR=.res_head;
    CHAIN_PTR=0;
    MARK=-1;
    END_MARK=-1;

    !Search for the correct name
    UNTIL
	$step_get(IOB=RD_IOB) EQL STEP$_EOF
    DO
	BEGIN

	LOCAL
	    CTL_CHAR,
	    CRC_COUNT,
	    ELM_NAM : VECTOR[CH$ALLOCATION(EL_NAM_SIZE)],
	    ELM_PTR,
	    ELM_SIZ,
	    TMP_PTR;

	!Check for the last CRC line
	IF CH$EQL(4,CH$PTR(UPLIT('*/C:')),4,.RD_IOB[IOB$A_STRING])
	THEN
	    BEGIN
	    LOCAL
		LEN,
		PTR;
	    FOUND_CRC =TRUE;
	    LEN=.RD_IOB[IOB$H_STRING];
	    PTR=CH$PLUS(.RD_IOB[IOB$A_STRING],4);
	    FILE_CRC = ASCHEX(PTR,LEN);
	    exitloop ;
	    END;

	!See if there is room left for the new line
	IF
	    CH$DIFF(CH$PLUS(.res_head,.cur_tab_siz),CH$PLUS(.TXT_PTR,.RD_IOB[IOB$H_STRING]+1)) LEQ 0
	THEN
	    !get more room by reallocating the table
	    begin

	    local
		t_ptr;

	    !specify how much more to obtain
	    cur_tab_siz=.cur_tab_siz+txt_max;

	    !allocate new storage block
	    $xpo_get_mem(characters=.cur_tab_siz,result=t_ptr);

	    !move data from old to new table
	    txt_ptr=ch$move(ch$diff(.txt_ptr,.res_head),.res_head,.t_ptr);

	    !release old table
	    $xpo_free_mem(string=(.cur_tab_siz-txt_max,.res_head));

	    !point to new table
	    res_head=.t_ptr

	    end;

	!Place the line in the buffer
	LAST_LINE=.TXT_PTR;
	PUT_STG_CT(.RD_IOB[IOB$H_STRING],TXT_PTR);
	TMP_PTR=.TXT_PTR;
	TXT_PTR=CH$MOVE(.RD_IOB[IOB$H_STRING],.RD_IOB[IOB$A_STRING],.TXT_PTR);

	!Pick up the control character
	CTL_CHAR=CH$RCHAR_A(TMP_PTR);

	!Make sure it is at least plausible
	IF
	    .CTL_CHAR NEQ %C' ' AND
	    .CTL_CHAR NEQ %C'*'
	THEN
	    BADLIB(LIT('Illegal reservation file format. '));


	! Calculate the CRC of the line
	CRC_COUNT = CRCCALC(.RD_IOB[IOB$H_STRING],.RD_IOB[IOB$A_STRING]);
	TOTAL_CRC = .TOTAL_CRC + .CRC_COUNT ;

    	!Get the element name from the control line
    	ELM_PTR=CH$PTR(ELM_NAM);
    	ELM_SIZ=GET_LXM(TMP_PTR,%C' ',.RD_IOB[IOB$H_STRING],ELM_PTR);

    	IF
    	    CH$EQL(.SIZE,.ELM,.ELM_SIZ,CH$PTR(ELM_NAM))
    	THEN
	    !We have arrived at a point where we must either
	    !find a reservation or be in a position to insert a
	    !new one, or both
    	    BEGIN

	    !Make sure there is room to make the entry
	    IF
	        .CHAIN_PTR GEQ res_max
	    THEN
		bug(lit('Table overflow in CHKRES'));

	    !Remember start of reservations
	    IF
	        .MARK EQL -1
	    THEN
	        MARK=ch$diff(.LAST_LINE,.res_head);

	    !There is a reservation, construct a reservation
	    !chain entry containing this element
	    IF
	       .CHAIN_PTR EQL 0
	    THEN
	        .LIST=.RES_LST
	    ELSE
	        RES_LST[.CHAIN_PTR-1,LINK_ADR]=RES_LST[.CHAIN_PTR,LINK_ADR];

    	    !Enter line into reservation list
	    RES_LST[.CHAIN_PTR,STG_SIZ]=GET_STG_CT(LAST_LINE);
	    RES_LST[.CHAIN_PTR,STG_ADR]=ch$diff(.LAST_LINE,.res_head);
	    RES_LST[.CHAIN_PTR,LINK_ADR]=0;
	    RES_LST[.CHAIN_PTR,REP_MKR]=FALSE;
	    RES_LST[.CHAIN_PTR,CUR_RES]=TRUE;
	    RES_LST[.CHAIN_PTR,REM_FLG]=FALSE;

	    !See if the entry was a replace marker
	    IF
	       .CTL_CHAR EQL %C'*'
	    THEN
	         BEGIN

		 LOCAL
		    C_PTR,
		    CHAR_CT,
		    FLD_CT;

		!Set header to "replace"
		RES_LST[.CHAIN_PTR,REP_MKR]=TRUE;

		!Skip over first three fields to allow limited comparison
		CHAR_CT=0;
		FLD_CT=0;
		C_PTR=.LAST_LINE;

		UNTIL
		    .FLD_CT EQL 3
		DO 
		    BEGIN

		    LOCAL
		        CH;

		   CH=CH$RCHAR_A(C_PTR);
		   CHAR_CT=.CHAR_CT+1;

		   IF
		       .CH EQL %C' '
		   THEN
		       FLD_CT=.FLD_CT+1
		   END;

		!Look for matching reserve marker
		INCR I FROM 0 TO .CHAIN_PTR-1 DO
		    BEGIN

		    IF
			.RES_LST[.I,CUR_RES] AND
			NOT .RES_LST[.I,REP_MKR]
		    THEN
			!See if the reserve matches the replace
			BEGIN
			IF
			    CH$EQL(.CHAR_CT-1,
				CH$PLUS(.res_head,.RES_LST[.I,STG_ADR]+1),
				   .CHAR_CT-1,
				CH$PLUS(.res_head,.RES_LST[.CHAIN_PTR,STG_ADR]+1))
			THEN
			    BEGIN
			    !Set reserve entry as non-current and go away
			    RES_LST[.I,CUR_RES]=FALSE;
			    EXITLOOP
			    END
			END
		    END
		END;

	    !Advance to next entry in table
	    CHAIN_PTR=.CHAIN_PTR+1

	    END
	ELSE
	IF
	    CH$LSS(.SIZE,.ELM,.ELM_SIZ,CH$PTR(ELM_NAM)) AND
	    .END_MARK EQL -1
	THEN
	    !Save end of reservations
	    END_MARK=ch$diff(.LAST_LINE,.res_head)

	END;

    IF NOT .FOUND_CRC
    THEN
	SYSMSG(S_nocksum,CAT('No checksum found in reservation file'),0) 
    ELSE
	IF .FILE_CRC NEQ .TOTAL_CRC
   	THEN
	    sysmsg(s_invcksum,cat('Invalid checksum found in ',
			'reservation file'),0);

    !Close file and remember it for later deletion
    $step_close(IOB=RD_IOB,OPTIONS=REMEMBER);

    !Check for any reservations seen
    IF
	.CHAIN_PTR EQL 0
    THEN
	FALSE
    ELSE
	TRUE

    END;				!End of CHKRES
GLOBAL ROUTINE DELRES :NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Delete the obsolete reservation file
!
! FORMAL PARAMETERS:
!
!	NONE.
!
! IMPLICIT INPUTS:
!
!	RD_IOB - IOB set up with file data
!
! IMPLICIT OUTPUTS:
!
!	NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

    LOCAL
	D_FIL_SPC: DESC_BLOCK ;

    $STR_DESC_INIT(DESCRIPTOR=D_FIL_SPC,STRING=(%STRING(LIB,RES))) ;
    DELVRS(FILVRS,.D_FIL_SPC[DESC_LEN],.D_FIL_SPC[DESC_PTR]) ;

    END;				!End of DELRES
ROUTINE DMPRES (STLOC,ENLOC) :NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Dump a specified section of the information stored in the
!	reservations table.
!
! FORMAL PARAMETERS:
!
!	STLOC - offset (from .res_head) to start of area to be dumped
!		(if -1 then the routine is a no-op)
!	ENLOC - offset (from .res_head) to end of area to be dumped
!		(if -1 then go to end of table)
!
! IMPLICIT INPUTS:
!
!	NONE.
!
! IMPLICIT OUTPUTS:
!
!	NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

    LOCAL
	TEXT;

    if
	.stloc eql -1
    then
	return;

    !Remember starting location
    TEXT=ch$plus(.res_head,.stloc);

    !Dump successive records until ENLOC is reached
    REPEAT
	BEGIN

	LOCAL
	    CHAR_COUNT;

	!Make sure some text is left over
	IF
	    CH$DIFF(.TEXT,.TXT_PTR) GEQ 0
	THEN
	    EXITLOOP;

	CHAR_COUNT=GET_STG_CT(TEXT);

	!Quit if the destination has been reached
	IF
	    .ENLOC NEQ -1 AND
	    CH$DIFF(.TEXT,ch$plus(.res_head,.enloc)) GEQ 0
	THEN
	    EXITLOOP;

	WRT_STG(.TEXT,.CHAR_COUNT,TRUE);

	TEXT=CH$PLUS(.TEXT,.CHAR_COUNT)

	END

    END;				!End of DMPRES
GLOBAL ROUTINE MRKRES (ELM,SIZE,GEN,GENSIZ,REM,REMSIZ,QUAL,QUALSIZ) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Mark the file reserved.
!
! FORMAL PARAMETERS:
!
!	ELM - String pointer to same element name used in CHKRES
!	SIZE - element name size
!	GEN - String pointer to generation to be reserved
!	GENSIZ - size of generation string
!	REM - String pointer to accompanying remark
!	REMSIZ - size of remark
!	QUAL - pointer to any qualifier string to be remembered
!	QUALSIZ - length of qualifier string, 0 if none.
!
! IMPLICIT INPUTS:
!
!	END_MARK - end of text including reservations
!
! IMPLICIT OUTPUTS:
!
!	NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

    LOCAL
	COUNT,
	LEN,
	NUM_BUF : VECTOR[CH$ALLOCATION(MAX_NUM_SIZE+5)],
	PTR,
	TXBUF: VECTOR[CH$ALLOCATION(40)],
	status;

    !Open output file
    if
	(status=$STEP_OPEN(IOB=WRT_IOB,FILE_SPEC=(%STRING(LIB,RES)),
		OPTIONS=OUTPUT,failure=0)) neq step$_created
    then
	badxpo(.status,lit('Cannot open new reservation file. '));

    !Set protection, etc.
    TRNFIL(WRT_IOB);

    DMPRES(0,.END_MARK);

    !Save file name
    STG(' ',FALSE);
    WRT_STG(.ELM,.SIZE,FALSE);
    STG(' ',FALSE);

    !Remember generation
    WRT_STG(.GEN,.GENSIZ,FALSE);
    STG(' ',FALSE);

    !Add user name
    COUNT=GETACT(TXBUF);
    WRT_STG(CH$PTR(TXBUF),.COUNT,FALSE);
    STG(' ',FALSE);

    !Add date and time
    COUNT=DATTIM(TXBUF);
    WRT_STG(CH$PTR(TXBUF),.COUNT,FALSE);
    STG(' ',FALSE);

    !Put in the remark
    WRT_STG(.REM,.REMSIZ,FALSE);

    !Output the qualifiers, if any
    IF
	.QUALSIZ NEQ 0
    THEN
	BEGIN
	STG(' ',FALSE);
	WRT_STG(.QUAL,.QUALSIZ,TRUE)
	END
    ELSE
	WRT_STG(0,0,TRUE);

    !Now output the remainder of the file
    DMPRES(.END_MARK,-1);

    !Write out the new CRC
    PTR = CH$MOVE(4,CH$PTR(UPLIT('*/C:')),CH$PTR(NUM_BUF));
    LEN = HEXASZ(.NEW_CRC, .PTR, 8) ;
    PTR = CH$PLUS(.PTR, .LEN);
    CH$WCHAR(%C' ',.PTR);
    LEN = .LEN +5 ;
    $step_PUT ( IOB = WRT_IOB, STRING = (.LEN, CH$PTR(NUM_BUF)),
		FAILURE = 0) ;

    !Close new reservation file
    $step_close(IOB=WRT_IOB);

    !relinquish the storage used
    $xpo_free_mem(binary_data=(res_max*ent_siz,.res_lst));
    $xpo_free_mem(string=(.cur_tab_siz,.res_head))

    END;				!End of MRKRES
GLOBAL ROUTINE REMRES (R_FLG,REM,REMSIZ) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Remove a file reservation.
!
! FORMAL PARAMETERS:
!
!	R_FLG - If "REPL", keep track of replaces
!		If "NOT REPL" do not keep track of replaces
!		(for instance, used in UNRESERVE)
!	REM - pointer to remark (used only for concurrent replacement)
!	REMSIZ - Size of remark
!
! IMPLICIT INPUTS:
!
!	END_MARK - end of text including reservations
!	MARK - end of text excluding reservations
!
! IMPLICIT OUTPUTS:
!
!	NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

    LOCAL
	ALL_GONE,
	LIN : VECTOR[CH$ALLOCATION(LINE_SIZE)],
	LIN_SIZ,
	LEN,
	NUM_BUF : VECTOR[CH$ALLOCATION(MAX_NUM_SIZE+5)],
	PTR,
	REC_PTR: REF BLOCK FIELD(RES_FLD),
	status;

    ALL_GONE=TRUE;
    REC_PTR=.RES_LST;


    !Open output file
    if
	(status=$STEP_OPEN(IOB=WRT_IOB,FILE_SPEC=(%STRING(LIB,RES)),
		OPTIONS=OUTPUT,failure=0)) neq step$_created
    then
	badxpo(.status,lit('Cannot open new reservation file'));

    !Set protection, etc.
    TRNFIL(WRT_IOB);

    DMPRES(0,.MARK);

    !See if any active records remain for this reservation
    UNTIL
	.REC_PTR EQL 0
    DO
	BEGIN
	!Examine this reservation for currency
	IF
	    .REC_PTR[CUR_RES] AND
	    NOT .REC_PTR[REM_FLG] AND
	    NOT .REC_PTR[REP_MKR]
	THEN
	    ALL_GONE=FALSE;

	REC_PTR=.REC_PTR[LINK_ADR]

	END;

    !Leave tracks if any current reservations still exist for this element
    IF
	NOT .ALL_GONE
    THEN
	BEGIN
	REC_PTR=.RES_LST;

	!Mark record deleted
	REPEAT
	    BEGIN

	    IF
		.REC_PTR[REM_FLG]
	    THEN
		BEGIN
		LIN_SIZ=.REC_PTR[STG_SIZ];
		CH$MOVE(.REC_PTR[STG_SIZ],ch$plus(.res_head,.REC_PTR[STG_ADR]),CH$PTR(LIN));
		CH$WCHAR(%C'*',CH$PTR(LIN))
		END;

	    IF
		NOT (.REC_PTR[REM_FLG] AND
		     .R_FLG NEQ REPL)
	    THEN
		WRT_STG(ch$plus(.res_head,.REC_PTR[STG_ADR]),.REC_PTR[STG_SIZ],TRUE);

	    IF
		.REC_PTR[LINK_ADR] EQL 0
	    THEN
		EXITLOOP;

	    REC_PTR=.REC_PTR[LINK_ADR]
	    END;

	!Now output the removed flag
	IF
	    .R_FLG EQL REPL
	THEN
	    BEGIN

	    LOCAL
		CHAR_CT,
		FLD_CT,
		LIN_PTR,
		TX_BUF : VECTOR[CH$ALLOCATION(40)],
		TX_LEN;

	    LIN_PTR=CH$PTR(LIN);
	    CHAR_CT=0;
	    FLD_CT=0;

	    !Pick up the first three fields
	    UNTIL
		.FLD_CT EQL 3
	    DO
		BEGIN
		LOCAL
		    CH;

		CH=CH$RCHAR_A(LIN_PTR);
		CHAR_CT=.CHAR_CT+1;

		IF
		    .CH EQL %C' '
		THEN
		    FLD_CT=.FLD_CT+1
		END;

	    !Output field
	    WRT_STG(CH$PTR(LIN),.CHAR_CT,FALSE);

	    !Output new generation
	    WRT_STG(CH$PTR(GEN_BUF),.GEN_LGT,FALSE);
	    STG(' ',FALSE);

	    !Put in current date and time
	    TX_LEN=DATTIM(TX_BUF);
	    WRT_STG(CH$PTR(TX_BUF),.TX_LEN,FALSE);
	    STG(' ',FALSE);

	    !Put in the remark, if any
	    WRT_STG(.REM,.REMSIZ,TRUE)

	    END

	END;

    DMPRES(.END_MARK,-1);

    !Write out new CRC    
    PTR = CH$MOVE(4,CH$PTR(UPLIT('*/C:')),CH$PTR(NUM_BUF));
    LEN = HEXASZ(.NEW_CRC, .PTR, 8) ;
    PTR = CH$PLUS(.PTR, .LEN);
    CH$WCHAR(%C' ',.PTR);
    LEN = .LEN +5 ;
    $step_PUT ( IOB = WRT_IOB, STRING = (.LEN, CH$PTR(NUM_BUF)),
		FAILURE = 0) ;

    !Close file
    $step_close(IOB=WRT_IOB);

    !relinquish the storage used
    $xpo_free_mem(binary_data=(res_max*ent_siz,.res_lst));
    $xpo_free_mem(string=(.cur_tab_siz,.res_head))

    END;				!End of REMRES
GLOBAL ROUTINE REPREP (LIST_ARG) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Report the information about the replacements.
!
! FORMAL PARAMETERS:
!
!	LIST_ARG - address of list of reservations
!		   starting with reservation for current element
!
! IMPLICIT INPUTS:
!
!	NONE.
!
! IMPLICIT OUTPUTS:
!
!	NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

    LOCAL
	LIST_PTR : REF BLOCK FIELD(RES_FLD),
	MSG_PRT;

    LIST_PTR=.LIST_ARG;
    MSG_PRT=FALSE;

    UNTIL
	.LIST_PTR EQL 0
    DO
	BEGIN

	IF
	    .LIST_PTR[REP_MKR]
	THEN
	    BEGIN

	    LOCAL
		NAME_B : VECTOR[CH$ALLOCATION(40)],
		NAME_LEN,
		NAME_PTR,
		STG_L,
		STG_P,
		TXT_B : VECTOR[CH$ALLOCATION(40)],
		TXT_LEN,
		TXT_PTR;

	    IF
		NOT .MSG_PRT
	    THEN
		BEGIN
		sysmsg(s_repby,LIT('Replaced by'),0);
		MSG_PRT=TRUE
		END;

	    STG_L=.LIST_PTR[STG_SIZ];
	    STG_P=ch$plus(.res_head,.LIST_PTR[STG_ADR]);

	    !skip over marker character
	    CH$RCHAR_A(STG_P);
	    STG_L=.STG_L-1;

	    !Skip the element name
	    TXT_PTR=CH$PTR(TXT_B);
	    TXT_LEN=GET_LXM(STG_P,%C' ',.STG_L,TXT_PTR);
	    STG_L=.STG_L-.TXT_LEN-1;

	    !Skip the generation reserved
	    TXT_PTR=CH$PTR(TXT_B);
	    TXT_LEN=GET_LXM(STG_P,%C' ',.STG_L,TXT_PTR);
	    STG_L=.STG_L-.TXT_LEN-1;
	    TXT_PTR=CH$PTR(TXT_B);

	    !And the user name
	    NAME_PTR=CH$PTR(NAME_B);
	    NAME_LEN=GET_LXM(STG_P,%C' ',.STG_L,NAME_PTR);
	    STG_L=.STG_L-.NAME_LEN-1;
	    NAME_PTR=CH$PTR(NAME_B);

	    !Get the generation replaced
	    TXT_PTR=CH$PTR(TXT_B);
	    TXT_LEN=GET_LXM(STG_P,%C' ',.STG_L,TXT_PTR);
	    STG_L=.STG_L-.TXT_LEN-1;
	    TXT_PTR=CH$PTR(TXT_B);

	    !Now output the revised message
	    SAY(CAT(('  '),(.NAME_LEN,.NAME_PTR),(' Generation '),(.TXT_LEN,.TXT_PTR),(' '),(.STG_L,.STG_P)))

	    END;

	LIST_PTR=.LIST_PTR[LINK_ADR]
	END

    END;				!End of REPREP
GLOBAL ROUTINE REPRES (LIST_ARG,MY_RES) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Report the information about the reservations.
!
! FORMAL PARAMETERS:
!
!	LIST_ARG - address of list of reservations
!	MY_RES - address of reservation line to be ignored
!
! IMPLICIT INPUTS:
!
!	NONE.
!
! IMPLICIT OUTPUTS:
!
!	NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN

    LOCAL
	LIST_PTR : REF BLOCK FIELD(RES_FLD);

    LIST_PTR=.LIST_ARG;

    sysmsg(s_resby,LIT('Currently Reserved by'),0);

    UNTIL
	.LIST_PTR EQL 0
    DO
	BEGIN
	IF
	    .LIST_PTR NEQ .MY_RES AND
	    .LIST_PTR[CUR_RES] AND
	    NOT .LIST_PTR[REP_MKR]
	THEN
	    BEGIN

	    LOCAL
		NAME_B : VECTOR[CH$ALLOCATION(40)],
		NAME_LEN,
		NAME_PTR,
		STG_L,
		STG_P,
		TXT_B : VECTOR[CH$ALLOCATION(40)],
		TXT_LEN,
		TXT_PTR;

	    STG_L=.LIST_PTR[STG_SIZ];
	    STG_P=ch$plus(.res_head,.LIST_PTR[STG_ADR]);

	    !skip over marker character
	    CH$RCHAR_A(STG_P);
	    STG_L=.STG_L-1;

	    !Skip the element name
	    TXT_PTR=CH$PTR(TXT_B);
	    TXT_LEN=GET_LXM(STG_P,%C' ',.STG_L,TXT_PTR);
	    STG_L=.STG_L-.TXT_LEN-1;

	    !Get the generation reserved
	    TXT_PTR=CH$PTR(TXT_B);
	    TXT_LEN=GET_LXM(STG_P,%C' ',.STG_L,TXT_PTR);
	    STG_L=.STG_L-.TXT_LEN-1;
	    TXT_PTR=CH$PTR(TXT_B);

	    !And the user name
	    NAME_PTR=CH$PTR(NAME_B);
	    NAME_LEN=GET_LXM(STG_P,%C' ',.STG_L,NAME_PTR);
	    STG_L=.STG_L-.NAME_LEN-1;
	    NAME_PTR=CH$PTR(NAME_B);

	    !Now output the revised message
	    SAY(CAT(('  '),(.NAME_LEN,.NAME_PTR),(' Generation '),(.TXT_LEN,.TXT_PTR),(' '),(.STG_L,.STG_P)))

	    END;

	LIST_PTR=.LIST_PTR[LINK_ADR]
	END

    END;				!End of REPRES
GLOBAL ROUTINE UPDRES (ELM,SIZE,GEN,GENSIZ,REM,REMSIZ,QUAL,QUALSIZ) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Replace a file reservation.
!
! FORMAL PARAMETERS:
!
!	ELM - String pointer to same element name used in CHKRES
!	SIZE - element name size
!	GEN - String pointer to generation to be re-reserved
!	GENSIZ - size of generation string
!	REM - String pointer to accompanying remark
!	REMSIZ - size of remark
!	QUAL - pointer to any qualifier string to be remembered
!	QUALSIZ - length of qualifier string, 0 if none.
!
! IMPLICIT INPUTS:
!
!	END_MARK - end of text including reservations
!	MARK - end of text excluding reservations
!
! IMPLICIT OUTPUTS:
!
!	NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	NONE.
!
! SIDE EFFECTS:
!
!	NONE.
!
!--

    BEGIN
    
    OWN
    	D_NEW_STRING : DESC_BLOCK ,  		!Descriptor for appended string on remark
    	r_remark : ref desc_block ;

    LOCAL
    	ALL_GONE,
    	COUNT,
    	LIN : VECTOR[CH$ALLOCATION(LINE_SIZE)] ,
    	LIN_SIZ,
	LEN,
	NUM_BUF : VECTOR[CH$ALLOCATION(MAX_NUM_SIZE+5)],
	PTR,    
	REC_PTR: REF BLOCK FIELD(RES_FLD),
	status,
	TXBUF : VECTOR[CH$ALLOCATION(40)] ;

    REC_PTR=.RES_LST;
    ALL_GONE = TRUE ;

    !Open output file
    if
	(status=$STEP_OPEN(IOB=WRT_IOB,FILE_SPEC=(%STRING(LIB,RES)),
		OPTIONS=OUTPUT,failure=0)) neq step$_created
    then
	badxpo(.status,lit('Cannot open new reservation file (UPDRES)'));

    !Set protection, etc.
    TRNFIL(WRT_IOB);

    DMPRES(0,.MARK);

    !See if any active records remain for this reservation
    UNTIL 
    	.REC_PTR EQL 0
    DO
    	BEGIN
    	!Examine this record for currency
    	IF 
    	    .REC_PTR[CUR_RES] AND
    	    NOT .REC_PTR[REM_FLG] AND
    	    NOT .REC_PTR[REP_MKR]
    	THEN
    	    ALL_GONE = FALSE ;
    	
    	REC_PTR = .REC_PTR[LINK_ADR] ;
    	 
    	END ;

    !Leave tracks if any current reservations still exist for this element
    if
    	NOT .ALL_GONE
    THEN
    	BEGIN
    	REC_PTR = .RES_LST ;

	!Mark record deleted
	REPEAT
	    BEGIN

	    IF
		.REC_PTR[REM_FLG]
	    THEN
		BEGIN
		LIN_SIZ=.REC_PTR[STG_SIZ];
		CH$MOVE(.REC_PTR[STG_SIZ],ch$plus(.res_head,.REC_PTR[STG_ADR]),CH$PTR(LIN));
		CH$WCHAR(%C'*',CH$PTR(LIN))
		END;

            WRT_STG(ch$plus(.res_head,.REC_PTR[STG_ADR]),.REC_PTR[STG_SIZ],TRUE);

	    IF
		.REC_PTR[LINK_ADR] EQL 0
	    THEN
		EXITLOOP;

	    REC_PTR=.REC_PTR[LINK_ADR]
	    END;

	!Now output the removed flag

	    BEGIN

	    LOCAL
		CHAR_CT,
		FLD_CT,
		LIN_PTR,
		TX_BUF : VECTOR[CH$ALLOCATION(40)],
		TX_LEN;

	    LIN_PTR=CH$PTR(LIN);
	    CHAR_CT=0;
	    FLD_CT=0;

	    !Pick up the first three fields
	    UNTIL
		.FLD_CT EQL 3
	    DO
		BEGIN
		LOCAL
		    CH;

		CH=CH$RCHAR_A(LIN_PTR);
		CHAR_CT=.CHAR_CT+1;

		IF
		    .CH EQL %C' '
		THEN
		    FLD_CT=.FLD_CT+1
		END;

	    !Output field
	    WRT_STG(CH$PTR(LIN),.CHAR_CT,FALSE);

	    !Output new generation
	    WRT_STG(CH$PTR(GEN_BUF),.GEN_LGT,FALSE);
	    STG(' ',FALSE);

	    !Put in current date and time
	    TX_LEN=DATTIM(TX_BUF);
	    WRT_STG(CH$PTR(TX_BUF),.TX_LEN,TRUE)

	    END ;

    END ;

    !Save file name
    STG(' ',FALSE);
    WRT_STG(.ELM,.SIZE,FALSE);
    STG(' ',FALSE);

    !Remember generation
    WRT_STG(.GEN,.GENSIZ,FALSE);
    STG(' ',FALSE);

    !Add user name
    COUNT=GETACT(TXBUF);
    WRT_STG(CH$PTR(TXBUF),.COUNT,FALSE);
    STG(' ',FALSE);

    !Add date and time
    COUNT=DATTIM(TXBUF);
    WRT_STG(CH$PTR(TXBUF),.COUNT,FALSE);
    STG(' ',FALSE);

    !Put in the user remark with 'Changes after:' tacked on the front

    $STR_DESC_INIT (DESCRIPTOR = D_NEW_STRING,
    		    STRING = (.REMSIZ,.REM) ) ;

    DEQUOT (D_NEW_STRING) ;

    R_REMARK = ENQUOT(CAT('Changes after: ',D_NEW_STRING )) ;

    WRT_STG (.R_REMARK[DESC_PTR],.R_REMARK[DESC_LEN],FALSE ) ;

    !Output the qualifiers, if any
    IF
	.QUALSIZ NEQ 0
    THEN
	BEGIN
	STG(' ',FALSE);
	WRT_STG(.QUAL,.QUALSIZ,TRUE)
	END
    ELSE
	WRT_STG(0,0,TRUE);

    DMPRES(.END_MARK,-1);

    !Write out new CRC    
    PTR = CH$MOVE(4,CH$PTR(UPLIT('*/C:')),CH$PTR(NUM_BUF));
    LEN = HEXASZ(.NEW_CRC, .PTR, 8) ;
    PTR = CH$PLUS(.PTR, .LEN);
    CH$WCHAR(%C' ',.PTR);
    LEN = .LEN +5 ;
    $step_PUT ( IOB = WRT_IOB, STRING = (.LEN, CH$PTR(NUM_BUF)),
		FAILURE = 0) ;

    !Close file
    $step_close(IOB=WRT_IOB);

    !relinquish the storage used
    $xpo_free_mem(binary_data=(res_max*ent_siz,.res_lst));
    $xpo_free_mem(string=(.cur_tab_siz,.res_head))

    END;				!End of UPDRES
GLOBAL ROUTINE WRT_STG (PTR,LGT,TERM) : NOVALUE =

!++
! FUNCTIONAL DESCRIPTION:
!
!	Put a string into the output buffer and output it if desired.
!
! FORMAL PARAMETERS:
!
!	PTR - Pointer to string
!	LGT - length of string
!	TERM - if true, output the complete line
!
! IMPLICIT INPUTS:
!
!	NONE
!
! IMPLICIT OUTPUTS:
!
!	NONE
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
!	Length of line output
!
! SIDE EFFECTS:
!
!	NONE
!
!--

    BEGIN

    LOCAL
	CNT;

    OWN
	INIT : INITIAL(FALSE),
	LINE_BUF,
	LINEPTR;

    IF
	NOT .INIT
    THEN
	BEGIN
	$xpo_GET_MEM(CHARACTERS=LINE_SIZE,RESULT=LINE_BUF);
	LINEPTR=.LINE_BUF;
	INIT=TRUE
	END;

    CNT=0;

    !Move text into buffer if there is any
    IF
	.PTR NEQ 0 AND
	.LGT GTR 0
    THEN
	BEGIN

	!See if room exists
	IF
	    CH$DIFF(.LINEPTR,.LINE_BUF)+.LGT GTR LINE_SIZE
	THEN
	    BUG(LIT('Text buffer overflow in WRT_STG (CHKRES)'));

	LINEPTR=CH$MOVE(.LGT,.PTR,.LINEPTR)

	END;

    !See if line is to be terminated and output
    IF
	.TERM
    THEN
	BEGIN
	LOCAL
	    CRC;

	!See how many characters there are
	CNT=CH$DIFF(.LINEPTR,.LINE_BUF);

 	!Calculate the CRC of this line
	CRC = 0;
	CRC = CRCCALC(.CNT, .LINE_BUF);
	NEW_CRC = .NEW_CRC + .CRC ;
	!Output the entire line
	$step_put(IOB=WRT_IOB,STRING=(.CNT,.LINE_BUF));

	!Now reset the buffer pointer
	LINEPTR=.LINE_BUF

	END

    END;				!End of WRT_STG
END				!End of Module CHKRES
ELUDOM