Trailing-Edge
-
PDP-10 Archives
-
DEC_CMS-20_V1.0_SRC
-
cms/sources/create.bli
There are no other files named create.bli in the archive.
MODULE CREATE (
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:
!
! INSERT, REMOVE, and CREATE processor. CREATE CLASS places
! a new entry in the class table. CREATE ELEMENT places a new
! element in the library. INSERT and REMOVE are used to
! manipulate and modify the entries made by CREATE CLASS.
!
! ENVIRONMENT: DS-20, VAX/VMS
!
! AUTHOR: D. Knight , CREATION DATE: 20-Dec-79
!
!--
!
! TABLE OF CONTENTS
!
FORWARD ROUTINE
CREATE, !CREATE
INSERT, !INSERT/REMOVE processor
CLS_INP : NOVALUE, !close input file
CLS_OUT : NOVALUE, !Close output file
OPNINP, !open input class file
OPNOUT : NOVALUE, !open new output class file
RFILGEN, !retrieve file generation information
SETUP : NOVALUE; !common setup
!
! INCLUDE FILES:
!
%if %bliss(bliss32) %then
library 'sys$library:starlet';
%else
require 'jsys:';
%fi
LIBRARY 'XPORT:';
REQUIRE 'SCONFG:';
REQUIRE 'BLISSX:';
REQUIRE 'COMUSR:';
REQUIRE 'HOSUSR:';
REQUIRE 'LOGUSR:';
REQUIRE 'SHRUSR:';
!
! MACROS:
!
MACRO
STG(L,M) = OUTSTG(CH$PTR(UPLIT(L)),%CHARCOUNT(L),M) %;
!
! EQUATED SYMBOLS:
!
LITERAL
DELETE=TRUE, !Argument to TERMINATE to allow file deletion
NODELETE=FALSE, !Disallow file deletion in TERMINATE
FAILURE=-1, !Return values for
NORMAL=0, ! OPNINP
NOSUCHFILE=+1; ! processor
!
! OWN STORAGE:
!
OWN
FIRST_FIL, !First file read
GEN_BUF : VECTOR[CH$ALLOCATION(GEN_SIZE)],
GEN_LEN,
GEN_PTR,
$IO_BLOCK(INP),
INP_OPN,
$IO_BLOCK(OUT),
OUT_OPN,
PLUS_OP,
QUAL : REF QUALIFIER_BLOCK,
SUB_CMD,
USR_REM : REF DESC_BLOCK;
!Command qualifiers
OWN
IFABS, ! /IFABSENT
IFPRES, ! /IFPRESENT
SUPERS; ! /SUPERSEDE
!CRC accumulators and flags
OWN
EXISTING_CRC, !CRC already in file
FOUND_CRC, !Set is CRC is found
OLD_CRC ; !Re-calculated CRC from input file
!
! EXTERNAL REFERENCES:
!
external literal
s_biggen, !generation number too large
s_classro, !Class is read only
s_clsexists, !Class already exists
s_creclass, !Class created
s_elemexist, !Element already exists in class
s_enotincls,
s_insclass, !Class inserted
s_invcksum, !class file has an inv cksum(CRC)
s_noclassf, !Class does not exist
s_noelem, !No such element name in library
s_nocksum, !No checksum (CRC)
s_nogen, !Element has no generation
s_subcomerr, !Subcommand not yet implemented
s_remclass; !removed from class
external
f_perf_crc, ! If on,calculate CRC in OUTSTG
calc_crc, ! CRC calculated by OUTSTG
ignore_control; ! Tell OUTSTG to ignore the control line
EXTERNAL ROUTINE
ASCHEX, !Convert ASCII to hex
BADLIB,
BADXPO,
BEGTRN, !Mark start of transaction
BUG,
BUGXPO,
CANTRN, !Cancel transaction
CMPGEN,
COMAND,
CRCTABLE, !Set up ploynomial table
CRCCALC, !Calculate the CRC of a string
CRELM, ! CREATE ELEMENT
DELVRS, ! delete files(FILOPS)
DIRDES, ! check for direct descendant (SHWEXA)
DONLIB, !Unlock library
ENDTRN, !Mark end of transaction
ERS,
exits, !exit silently
GETATR,
GETELM,
GET_LXM,
HEXASZ, !Hex to ASCII
LOGTRN, ! write log entry
OUTINI,
OUTSTG,
SAFLIB, !Lock library
SETATR,
sysmsg,
trnlog, ! translate a logical name
TRNFIL; !Set protection, etc.
GLOBAL ROUTINE CREATE =
!++
! FUNCTIONAL DESCRIPTION:
!
! CREATE an class entry, either CLASS or ELEMENT, and place
! it in the master class file ATF.
!
! FORMAL PARAMETERS:
!
! NONE.
!
! IMPLICIT INPUTS:
!
! The arguments are passed from the command line typed by the user
! and parsed by COMAND.
!
! IMPLICIT OUTPUTS:
!
! An entry is made in the class file in the library.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! Normal system return values.
!
! SIDE EFFECTS:
!
! The obsolete class file is deleted.
!
!--
BEGIN
LOCAL
CMD,
OPN_VAL,
PAR : REF PARAMETER_BLOCK,
STATUS;
!Parse the command
IF
NOT COMAND(CMD,SUB_CMD,QUAL,PAR,USR_REM)
THEN
RETURN K_SILENT_ERROR;
!CREATE ELEMENT command
IF
.SUB_CMD EQL K_ELEMENT_SUB
THEN
RETURN CRELM(.QUAL,.PAR,.USR_REM)
ELSE
IF
.SUB_CMD NEQ K_CLASS_SUB
THEN
BEGIN
ERS(s_subcomerr,LIT('Subcommand not yet implemented'));
RETURN K_SILENT_ERROR
END;
!Do initial setup
SETUP();
!Lock the library
IF
NOT SAFLIB(K_UPDATE_LIB)
THEN
RETURN K_SILENT_SEVERE ;
!Open the old class file, if any
OPN_VAL=OPNINP();
!Mark start of transaction
BEGTRN();
!Open the new class file
OPNOUT();
!Initialize CRC variables
old_crc = 0;
existing_crc = 0;
found_crc = false;
calc_crc = 0;
f_perf_crc = true;
ignore_control = true;
! Set up polynomial table
crctable();
!Locate the position where the class is to be placed
IF
.OPN_VAL EQL NORMAL
THEN
BEGIN
REPEAT
BEGIN
LOCAL
CL_NM_LEN;
CL_NM_LEN=0;
!If end of file, the location must be right for insertion
STATUS =$STEP_GET(IOB=INP_IOB,failure=0);
IF .STATUS NEQ STEP$_EOF AND
CH$EQL(4,CH$PTR(UPLIT('*/C:')),4, .INP_IOB[IOB$A_STRING])
THEN
BEGIN
LOCAL
LEN,
PTR;
LEN = .INP_IOB[IOB$H_STRING] - 4;
PTR = CH$PLUS(.INP_IOB[IOB$A_STRING], 4);
EXISTING_CRC = ASCHEX(PTR, LEN);
found_crc = true;
! This must be the place to insert the new line
OUTSTG(.PAR[PAR_TEXT_PTR],.PAR[PAR_TEXT_LEN],FALSE);
!Put out the command comment also
STG(' ',FALSE);
OUTSTG(.USR_REM[DESC_PTR],.USR_REM[DESC_LEN],TRUE);
EXITLOOP ;
END;
IF .STATUS EQL STEP$_EOF
THEN
BEGIN
!Place the entry in the file
OUTSTG(.PAR[PAR_TEXT_PTR],.PAR[PAR_TEXT_LEN],FALSE);
!Put out the command comment also
STG(' ',FALSE);
OUTSTG(.USR_REM[DESC_PTR],.USR_REM[DESC_LEN],TRUE);
EXITLOOP
END;
! Calculate the CRC of this line
OLD_CRC = .OLD_CRC +
CRCCALC(.INP_IOB[IOB$H_STRING], .INP_IOB[IOB$A_STRING]);
!Get the length of the name only in the class file
INCR I FROM 0 TO .INP_IOB[IOB$H_STRING]-1 DO
BEGIN
IF
CH$RCHAR(CH$PLUS(.INP_IOB[IOB$A_STRING],.I)) EQL %C' '
THEN
EXITLOOP;
CL_NM_LEN=.CL_NM_LEN+1
END;
!See if we have found the position for an insertion
IF
CH$RCHAR(.INP_IOB[IOB$A_STRING]) NEQ %C' ' AND
CH$LSS(.PAR[PAR_TEXT_LEN],.PAR[PAR_TEXT_PTR],
.CL_NM_LEN,.INP_IOB[IOB$A_STRING])
THEN
BEGIN
!Build the entry and place it in the file
OUTSTG(.PAR[PAR_TEXT_PTR],.PAR[PAR_TEXT_LEN],FALSE);
!Put out the command comment also
STG(' ',FALSE);
OUTSTG(.USR_REM[DESC_PTR],.USR_REM[DESC_LEN],TRUE);
!Output the original entry also
OUTSTG(.INP_IOB[IOB$A_STRING],.INP_IOB[IOB$H_STRING],TRUE);
EXITLOOP
END;
!The class might already exist.
IF
CH$EQL(.PAR[PAR_TEXT_LEN],.PAR[PAR_TEXT_PTR],
.CL_NM_LEN,.INP_IOB[IOB$A_STRING])
THEN
BEGIN
ERS(s_clsexists,CAT(('Class '),PAR[PAR_TEXT],
(' already exists')));
!Close and delete incomplete new file
CLS_INP(NODELETE);
CLS_OUT(DELETE);
CANTRN();
!Unlock the library
DONLIB();
RETURN K_SILENT_ERROR
END;
!This isn't the right place, output the record and try again
OUTSTG(.INP_IOB[IOB$A_STRING],.INP_IOB[IOB$H_STRING],TRUE)
END
END
ELSE
BEGIN
!Nothing in file, start it
OUTSTG(.PAR[PAR_TEXT_PTR],.PAR[PAR_TEXT_LEN],FALSE);
!Put out the command comment also
STG(' ',FALSE);
OUTSTG(.USR_REM[DESC_PTR],.USR_REM[DESC_LEN],TRUE)
END;
!Write out the remainder of the file, if any
IF
.OPN_VAL EQL NORMAL
THEN
BEGIN
UNTIL
$STEP_GET(IOB=INP_IOB,failure=0) EQL STEP$_EOF
DO
BEGIN
IF CH$EQL(4,CH$PTR(UPLIT('*/C:')),4, .INP_IOB[IOB$A_STRING])
THEN
BEGIN
LOCAL
LEN,
PTR;
LEN = .INP_IOB[IOB$H_STRING] - 4;
PTR = CH$PLUS(.INP_IOB[IOB$A_STRING], 4);
EXISTING_CRC = ASCHEX(PTR, LEN);
found_crc = true;
EXITLOOP ;
END ;
! Calculate the CRC of this line
OLD_CRC = .OLD_CRC +
CRCCALC(.INP_IOB[IOB$H_STRING], .INP_IOB[IOB$A_STRING]);
OUTSTG(.INP_IOB[IOB$A_STRING],.INP_IOB[IOB$H_STRING],TRUE)
END;
END;
!Close the new class file
CLS_OUT(NODELETE);
! write log record
IF
NOT LOGTRN(K_NORMAL_LOG,0,K_NULL)
THEN
BUG(CAT('Unable to write log record. Error occurred in routine ',
'CREATE')) ;
!Mark the transaction end
ENDTRN();
!Now close and delete the old class file
CLS_INP(DELETE);
!Unlock the library
DONLIB();
!Tell the user all is OK
sysmsg(s_creclass,CAT(('Class '),PAR[PAR_TEXT],(' created')),0);
exits(s_creclass)
END; !End of CREATE
GLOBAL ROUTINE INSERT =
!++
! FUNCTIONAL DESCRIPTION:
!
! INSERT/REMOVE dispatcher. Transfer to the correct sub-processor.
!
! FORMAL PARAMETERS:
!
! NONE.
!
! IMPLICIT INPUTS:
!
! The arguments are passed through the command line and parsed
! by COMAND.
!
! IMPLICIT OUTPUTS:
!
! The class file is updated.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! The normal system values are returned.
!
! SIDE EFFECTS:
!
! NONE.
!
!--
BEGIN
LOCAL
cls_nm_lgt,
CMD,
ELEM : DESC_BLOCK, !Element name.
GEN_QUAL : REF QUALIFIER_BLOCK,
PAR : REF PARAMETER_BLOCK,
PAR1 : REF PARAMETER_BLOCK, !To class name parameter block.
RESULT, !Status from GETELM.
ret_val,
sup_elm, !element superseded flag
TREE : REF NODE_BLOCK, !To generation reference node block
!if INSERT, otherwise K_NULL.
GET_STATUS, !Status code from $XPO_GET of old
!class file.
STATUS; !Status code from $XPO_GET of old
!class file.
!Common setup
SETUP();
!Parse the command
IF
NOT COMAND(CMD,SUB_CMD,QUAL,PAR,USR_REM)
THEN
RETURN K_SILENT_ERROR;
!Lock the library
IF
NOT SAFLIB(K_UPDATE_LIB)
THEN
RETURN K_SILENT_SEVERE;
!Pick up generation reference, if any
GEN_LEN=0;
IF
.PAR[PAR_A_QUAL] NEQ K_NULL
THEN
BEGIN
GEN_QUAL=.PAR[PAR_A_QUAL];
IF
.GEN_QUAL[QUA_CODE] NEQ K_GEN_QUAL
THEN
BUG(LIT('Unrecognized parameter qualifier (INSERT)'));
GEN_PTR=CH$PTR(GEN_BUF);
IF
.GEN_QUAL[QUA_A_TREE] EQL K_NULL
THEN
!No plus operator exists
BEGIN
PLUS_OP=FALSE;
GEN_LEN=.GEN_QUAL[QUA_VALUE_LEN];
if
.gen_len gtr gen_size
then
begin
donlib();
ers(s_biggen,lit('Generation string is too long'));
return k_silent_error
end;
CH$MOVE(.GEN_LEN,.GEN_QUAL[QUA_VALUE_PTR],.GEN_PTR)
END
ELSE
!Plus operator was seen
BEGIN
PLUS_OP=TRUE;
TREE=.GEN_QUAL[QUA_A_TREE];
GEN_LEN=.TREE[NOD_DESC_1_LEN];
if
.gen_len gtr gen_size
then
begin
donlib();
ers(s_biggen,lit('Generation string is too long'));
return k_silent_error
end;
CH$MOVE(.GEN_LEN,.TREE[NOD_DESC_1_PTR],.GEN_PTR)
END;
!Check for user specified generation or class
IF
.GEN_LEN NEQ 0
THEN
BEGIN
IF
CH$RCHAR(.GEN_PTR) GEQ %C'A'
THEN
!This must be an class, try to find its value
BEGIN
!Make sure class exists
IF
NOT SETATR(.GEN_LEN,.GEN_PTR)
THEN
BEGIN
DONLIB();
ERS(s_noclassf,CAT(('Class '),(.GEN_LEN,.GEN_PTR),
(' does not exist')));
RETURN K_SILENT_ERROR
END;
IF
NOT GETATR(.PAR[PAR_TEXT_LEN],.PAR[PAR_TEXT_PTR],GEN_LEN,.GEN_PTR)
THEN
BEGIN
DONLIB();
ERS(s_enotincls,CAT(('Element '),PAR[PAR_TEXT],
(' does not exist in class '),(.GEN_LEN,.GEN_PTR)));
RETURN K_SILENT_ERROR
END
END
END
END;
!Initialize qualifiers
IFABS=FALSE;
IFPRES=FALSE;
SUPERS=FALSE;
!Check qualifier list
WHILE
.QUAL NEQ K_NULL
DO
BEGIN
!Process each individual qualifier
SELECTONE .QUAL[QUA_CODE] OF
SET
[K_IF_ABSENT_QUAL]:
IFABS=TRUE;
[K_IF_PRESENT_QUAL]:
IFPRES=TRUE;
[K_SUPERSEDE_QUAL]:
SUPERS=TRUE;
[K_NOSUPERSEDE_QUAL]:
SUPERS=FALSE;
TES;
QUAL=.QUAL[QUA_A_NEXT]
END;
!Point to the class name parameter
PAR1=.PAR[PAR_A_NEXT];
!Get the element name
$STR_DESC_INIT(DESCRIPTOR = ELEM, STRING = PAR[PAR_TEXT]);
!Open the old class file, error if no file exists
IF
OPNINP() EQL NOSUCHFILE
THEN
BEGIN
ERS(s_noclassf,CAT(('Class '),PAR1[PAR_TEXT],(' does not exist')));
DONLIB();
RETURN K_SILENT_ERROR
END;
!Get the needed element information for INSERT
IF
.CMD EQL K_INSERT_COM
THEN
BEGIN
!Retrieve the desired generation value
FIRST_FIL=TRUE;
RESULT=GETELM(.ELEM[DESC_PTR],.ELEM[DESC_LEN],RFILGEN);
!Check return value for error
IF
.RESULT EQL G_NO_ELM
THEN
BEGIN
local
d_log_nam : $str_desc(),
d_log_trn : $str_desc(),
log_trn_buf : vector[ch$allocation(log_nam_value_size)];
$str_desc_init(descriptor = d_log_nam,
string=(len_comma_ptr(lib)));
$str_desc_init(descriptor = d_log_trn,
string=(log_nam_value_size,ch$ptr(log_trn_buf)));
trnlog(d_log_nam,d_log_trn);
ERS(s_noelem,CAT(('Element '),elem,
(' does not exist in the CMS library '),d_log_trn));
END;
IF
.RESULT EQL G_ERMSG
THEN
BEGIN
CLS_INP(NODELETE);
DONLIB();
RETURN K_SILENT_ERROR
END;
IF
.RESULT NEQ G_OK
THEN
BUG(LIT('Error in element processing (INSERT)'))
END;
!Mark beginning of transaction
BEGTRN();
!Open the new class file
OPNOUT();
!Set up the CRC variales
calc_crc = 0;
existing_crc = 0;
old_crc = 0;
ignore_control = true;
f_perf_crc = true;
found_crc = false;
!set up polynomial table
crctable();
!Find the desired class table, copying old file to new
!file as the process advances
REPEAT
BEGIN
STATUS = $STEP_GET(IOB=INP_IOB,failure=0);
IF
.status eql step$_eof or
CH$EQL(4,CH$PTR(UPLIT('*/C:')),4, .INP_IOB[IOB$A_STRING])
THEN
BEGIN
ERS(s_noclassf,CAT(('Class '),PAR1[PAR_TEXT],(' does not exist')));
!Delete incomplete new file
CLS_INP(NODELETE);
CLS_OUT(DELETE);
!Cancel the transaction
CANTRN();
DONLIB();
RETURN K_SILENT_ERROR
END;
! Calculate the CRC of this line
OLD_CRC = .OLD_CRC +
CRCCALC(.INP_IOB[IOB$H_STRING], .INP_IOB[IOB$A_STRING]);
OUTSTG(.INP_IOB[IOB$A_STRING],.INP_IOB[IOB$H_STRING],TRUE);
!Get length of class name only
CLS_NM_LGT=0;
UNTIL
CH$RCHAR(CH$PLUS(.INP_IOB[IOB$A_STRING],.CLS_NM_LGT)) EQL %C' ' OR
.CLS_NM_LGT EQL .INP_IOB[IOB$H_STRING]
DO
CLS_NM_LGT=.CLS_NM_LGT+1;
IF
CH$RCHAR(.INP_IOB[IOB$A_STRING]) NEQ %C' ' AND
CH$EQL(.PAR1[PAR_TEXT_LEN],.PAR1[PAR_TEXT_PTR],.CLS_NM_LGT,.INP_IOB[IOB$A_STRING])
THEN
!We have located the correct table
EXITLOOP
END;
!Make sure the class we want is not read-only
%if VaxVms %then
if
.inp_iob[iob$h_string]-.cls_nm_lgt-1 gtr 11 and
ch$eql(11,ch$ptr(uplit('/READ_ONLY ')),
11,ch$plus(.inp_iob[iob$a_string],.cls_nm_lgt+1))
then
begin
ers(s_classro,cat(('Class '),par1[par_text],(' is READ_ONLY')));
%fi
%if Tops20 %then
if
.inp_iob[iob$h_string]-.cls_nm_lgt-1 gtr 11 and
ch$eql(11,ch$ptr(uplit('/READ-ONLY ')),
11,ch$plus(.inp_iob[iob$a_string],.cls_nm_lgt+1))
then
begin
ers(s_classro,cat(('Class '),par1[par_text],(' is READ-ONLY')));
%fi
!delete incomplete new file
cls_inp(nodelete);
cls_out(delete);
!cancel the transaction
cantrn();
donlib();
return k_silent_error
end;
!Find the position where the new entry can be placed
REPEAT
BEGIN
LOCAL
S_LEN, !Length of element name in file.
S_PTR; !Pointer to element name in file.
GET_STATUS = $STEP_GET(IOB=INP_IOB,failure=0);
IF .GET_STATUS NEQ step$_eof AND
CH$EQL(4,CH$PTR(UPLIT('*/C:')),4, .INP_IOB[IOB$A_STRING])
THEN
BEGIN
LOCAL
LEN,
PTR;
LEN = .INP_IOB[IOB$H_STRING] - 4;
PTR = CH$PLUS(.INP_IOB[IOB$A_STRING], 4);
EXISTING_CRC = ASCHEX(PTR, LEN);
found_crc = true;
! Fake an end of file
get_status = step$_eof;
END;
!See if there are no entries in the requested class.
IF
(IF
.GET_STATUS EQL STEP$_EOF
THEN
TRUE
ELSE
CH$RCHAR(.INP_IOB[IOB$A_STRING]) NEQ %C' '
)
THEN
BEGIN
IF
.CMD EQL K_INSERT_COM
THEN
EXITLOOP
ELSE
BEGIN
IF
NOT .IFPRES
THEN
BEGIN
ERS(s_enotincls,CAT('Element ',ELEM,
' does not exist in class ',PAR1[PAR_TEXT]));
!Delete incomplete new file
CLS_INP(NODELETE);
CLS_OUT(DELETE);
!Cancel the transaction
CANTRN();
DONLIB();
RETURN K_SILENT_ERROR
END
ELSE
!The user said that failure is allowed
BEGIN
CLS_INP(NODELETE);
CLS_OUT(DELETE);
!Cancel the transaction
CANTRN();
DONLIB();
RETURN K_SUCCESS
END;
END
END;
!Find the length of the element name
S_LEN=0;
S_PTR=CH$PLUS(.INP_IOB[IOB$A_STRING],1);
UNTIL CH$RCHAR_A(S_PTR) EQL %C' ' DO S_LEN=.S_LEN+1;
!See if the position is correct for an insertion
IF
CH$LSS(LEN_COMMA_PTR(ELEM),.S_LEN,CH$PLUS(.INP_IOB[IOB$A_STRING],1))
THEN
!The position is correct
BEGIN
IF
.CMD EQL K_INSERT_COM
THEN
EXITLOOP
ELSE
BEGIN
IF
NOT .IFPRES
THEN
BEGIN
ERS(s_enotincls,CAT('Element ',ELEM,' does not exist ',
'in class ',PAR1[PAR_TEXT]));
!Delete incomplete new file
CLS_INP(NODELETE);
CLS_OUT(DELETE);
!Cancel the transaction
CANTRN();
DONLIB();
RETURN K_SILENT_ERROR
END
ELSE
!The user said that failure is allowed
BEGIN
CLS_INP(NODELETE);
CLS_OUT(DELETE);
!Cancel the transaction
CANTRN();
DONLIB();
RETURN K_SUCCESS
END
END
END;
!assume entry won't be superseded
sup_elm=false;
!See if there is an entry that matches exactly
IF
CH$EQL(LEN_COMMA_PTR(ELEM),.S_LEN,CH$PLUS(.INP_IOB[IOB$A_STRING],1))
THEN
!Entry already exists
BEGIN
IF
.CMD EQL K_INSERT_COM
THEN
BEGIN
IF
.IFABS
THEN
BEGIN
CLS_INP(NODELETE);
CLS_OUT(DELETE);
!Cancel the transaction
CANTRN();
DONLIB();
RETURN K_SUCCESS
END;
IF
NOT .SUPERS
THEN
BEGIN
ERS(s_elemexist,CAT('Element ',ELEM,' already exists ',
'in class ',PAR1[PAR_TEXT]));
!Delete incomplete new file
CLS_INP(NODELETE);
CLS_OUT(DELETE);
!Cancel the transaction
CANTRN();
DONLIB();
RETURN K_SILENT_ERROR
END
ELSE
!Supersede the old entry
BEGIN
! Calculate the CRC of this line
OLD_CRC = .OLD_CRC +
CRCCALC(.INP_IOB[IOB$H_STRING], .INP_IOB[IOB$A_STRING]);
GET_STATUS=$step_get(IOB=INP_IOB,failure=0);
!entry is being superseded
sup_elm=true;
EXITLOOP
END
END
ELSE
!Skip this entry
BEGIN
! Calculate the CRC of this line
OLD_CRC = .OLD_CRC +
CRCCALC(.INP_IOB[IOB$H_STRING], .INP_IOB[IOB$A_STRING]);
GET_STATUS=$STEP_GET(IOB=INP_IOB,failure=0);
EXITLOOP
END
END;
! Calculate the CRC of this line
OLD_CRC = .OLD_CRC +
CRCCALC(.INP_IOB[IOB$H_STRING], .INP_IOB[IOB$A_STRING]);
!Write out the line and continue
OUTSTG(.INP_IOB[IOB$A_STRING],.INP_IOB[IOB$H_STRING],TRUE)
END;
IF
.CMD EQL K_INSERT_COM
THEN
!Format and place the new class in the table
BEGIN
!don't allow supersede if there isn't anything to supersede
if
not .sup_elm and
.supers
then
begin
ers(s_enotincls,cat('Element ',elem,' does not exist in class ',
par1[par_text]));
!Delete incomplete new file
CLS_INP(NODELETE);
CLS_OUT(DELETE);
!Cancel the transaction
CANTRN();
DONLIB();
RETURN K_SILENT_ERROR
end;
STG(' ',FALSE);
!Output element name
OUTSTG(.ELEM[DESC_PTR],.ELEM[DESC_LEN],FALSE);
STG(' ',FALSE);
!Output generation obtained by RFILGEN
OUTSTG(.GEN_PTR,.GEN_LEN,TRUE)
END;
IF
.GET_STATUS NEQ STEP$_EOF
THEN
BEGIN
IF CH$EQL(4,CH$PTR(UPLIT('*/C:')),4, .INP_IOB[IOB$A_STRING])
THEN
BEGIN
LOCAL
LEN,
PTR;
LEN = .INP_IOB[IOB$H_STRING] - 4;
PTR = CH$PLUS(.INP_IOB[IOB$A_STRING], 4);
EXISTING_CRC = ASCHEX(PTR, LEN);
found_crc = true;
end
else
begin
! Calculate the CRC of this line
OLD_CRC = .OLD_CRC +
CRCCALC(.INP_IOB[IOB$H_STRING], .INP_IOB[IOB$A_STRING]);
OUTSTG(.INP_IOB[IOB$A_STRING],.INP_IOB[IOB$H_STRING],TRUE);
end;
END;
!Copy the table and the rest of the old class file to the
!new file
UNTIL
$step_get(IOB=INP_IOB,failure=0) EQL STEP$_EOF
DO
BEGIN
IF CH$EQL(4,CH$PTR(UPLIT('*/C:')),4, .INP_IOB[IOB$A_STRING])
THEN
BEGIN
LOCAL
LEN,
PTR;
LEN = .INP_IOB[IOB$H_STRING] - 4;
PTR = CH$PLUS(.INP_IOB[IOB$A_STRING], 4);
EXISTING_CRC = ASCHEX(PTR, LEN);
found_crc = true;
EXITLOOP;
END;
! Calculate the CRC of this line
OLD_CRC = .OLD_CRC +
CRCCALC(.INP_IOB[IOB$H_STRING], .INP_IOB[IOB$A_STRING]);
OUTSTG(.INP_IOB[IOB$A_STRING],.INP_IOB[IOB$H_STRING],TRUE);
END;
!Close the files
CLS_OUT(NODELETE);
! log transaction
IF
.CMD EQL K_INSERT_COM
THEN
BEGIN ! log INSERT command
IF
NOT LOGTRN(K_NORMAL_LOG,.GEN_LEN,.GEN_PTR)
THEN
BUG(CAT('Unable to write log record (INSERT)'));
END ! log INSERT command
ELSE
BEGIN ! log remove command
IF
NOT LOGTRN(K_NORMAL_LOG,0,K_NULL)
THEN
BUG(CAT('Unable to write log record (INSERT)'));
END ; ! log remove command
!Mark the end of the transaction
ENDTRN();
CLS_INP(DELETE);
IF
.CMD EQL K_INSERT_COM
THEN
begin
ret_val=s_insclass;
sysmsg(s_insclass,CAT('Element ',ELEM,', Generation ',(.GEN_LEN,.GEN_PTR),
' inserted in class ',PAR1[PAR_TEXT]),0)
end
ELSE
begin
ret_val=s_remclass;
sysmsg(s_remclass,
CAT('Element ',ELEM,' removed from class ',PAR1[PAR_TEXT]),0);
end;
DONLIB();
exits(.ret_val)
END; !End of INSERT
ROUTINE CLS_INP (DEL_FLG) : NOVALUE =
!++
! FUNCTIONAL DESCRIPTION:
!
! Close and optionally delete the specified file
!
! FORMAL PARAMETERS:
!
! NONE.
!
! IMPLICIT INPUTS:
!
! NONE.
!
! IMPLICIT OUTPUTS:
!
! NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! NONE.
!
! SIDE EFFECTS:
!
! NONE.
!
!--
BEGIN
LOCAL
D_FIL_SPC: DESC_BLOCK ;
IF
.INP_OPN
THEN
BEGIN
IF
.DEL_FLG EQL DELETE
THEN
BEGIN
! Check checksums
IF NOT .FOUND_CRC
THEN
SYSMSG(s_nocksum,CAT(%STRING(LIB,ATF),' has no checksum'),0)
ELSE
IF .EXISTING_CRC NEQ .OLD_CRC
THEN
SYSMSG(s_invcksum,CAT('Class file has an invalid ',
'checksum'),0);
$STEP_CLOSE(IOB=INP_IOB) ;
$STR_DESC_INIT(DESCRIPTOR=D_FIL_SPC,STRING=(%STRING(LIB,ATF))) ;
DELVRS(FILVRS,.D_FIL_SPC[DESC_LEN],.D_FIL_SPC[DESC_PTR]) ;
END
ELSE
$STEP_CLOSE(IOB=INP_IOB)
END
END; !End of CLS_INP
ROUTINE CLS_OUT (DEL_FLG) : NOVALUE =
!++
! FUNCTIONAL DESCRIPTION:
!
! Close and optionally delete the specified file
!
! FORMAL PARAMETERS:
!
! NONE.
!
! IMPLICIT INPUTS:
!
! NONE.
!
! IMPLICIT OUTPUTS:
!
! NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! NONE.
!
! SIDE EFFECTS:
!
! NONE.
!
!--
BEGIN
IF
.OUT_OPN
THEN
BEGIN
IF
.DEL_FLG EQL DELETE
THEN
BEGIN
$STEP_CLOSE(IOB=OUT_IOB,OPTIONS=REMEMBER);
$STEP_DELETE(IOB=OUT_IOB)
END
ELSE
BEGIN
LOCAL
LEN,
NUM_BUF: VECTOR[CH$ALLOCATION(MAX_NUM_SIZE+5)],
PTR;
! Build control line
PTR = CH$MOVE(4,CH$PTR(UPLIT('*/C:')),CH$PTR(NUM_BUF)) ;
LEN = HEXASZ(.CALC_CRC, .PTR, 8) ;
PTR = CH$PLUS(.PTR, .LEN);
CH$WCHAR(%C' ', .PTR);
LEN = .LEN + 5 ;
$STEP_PUT(IOB = OUT_IOB, STRING=(.LEN,CH$PTR(NUM_BUF)),
FAILURE = 0);
$STEP_CLOSE(IOB=OUT_IOB)
END
END
END; !End of CLS_OUT
ROUTINE OPNINP =
!++
! FUNCTIONAL DESCRIPTION:
!
! Open input file
!
! FORMAL PARAMETERS:
!
! NONE.
!
! IMPLICIT INPUTS:
!
! NONE.
!
! IMPLICIT OUTPUTS:
!
! NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! 0 - normal
! +1 - no such file
!
! SIDE EFFECTS:
!
! NONE.
!
!--
BEGIN
LOCAL
OPN_FLG;
OPN_FLG=$STEP_OPEN(IOB=INP_IOB,FILE_SPEC=(%STRING(LIB,ATF)),OPTIONS=INPUT,FAILURE=0);
IF
.OPN_FLG EQL STEP$_NORMAL
THEN
BEGIN
INP_OPN=TRUE;
RETURN NORMAL
END;
IF
.OPN_FLG EQL STEP$_NO_FILE
THEN
RETURN NOSUCHFILE;
BUGXPO(.OPN_FLG,CAT(('Cannot open '),(%STRING(LIB,ATF))))
END; !End of OPNINP
ROUTINE OPNOUT : NOVALUE =
!++
! FUNCTIONAL DESCRIPTION:
!
! Open output file.
!
! FORMAL PARAMETERS:
!
! NONE.
!
! IMPLICIT INPUTS:
!
! NONE.
!
! IMPLICIT OUTPUTS:
!
! NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! NONE.
!
! SIDE EFFECTS:
!
! NONE.
!
!--
BEGIN
LOCAL
OPN_FLG;
OPN_FLG=$STEP_OPEN(IOB=OUT_IOB,FILE_SPEC=(%STRING(LIB,ATF)),OPTIONS=OUTPUT,FAILURE=0);
IF
not .OPN_FLG
THEN
BUGXPO(.OPN_FLG,CAT(('Output file failure on'),(%STRING(LIB,ATF))));
!Set protection, etc.
TRNFIL(OUT_IOB);
OUT_OPN=TRUE
END; !End of OPNOUT
ROUTINE RFILGEN (FIL_NAM_LEN,FIL_NAM_STR) =
!++
! FUNCTIONAL DESCRIPTION:
!
! Retrieve the desired generation from the specified element.
!
! FORMAL PARAMETERS:
!
! FIL_NAM_LEN - length of file name to be read
! FIL_NAM_STR - pointer to file name
!
! IMPLICIT INPUTS:
!
! FIRST_FIL means that this is the first file of the element.
!
! GEN_LEN and GEN_PTR indicate an explicit generation to be
! searched for, provided GEN_LEN is non-zero. PLUS_OP means that
! the latest in that line is to be found.
!
! The header record from the specified file is scanned.
!
! IMPLICIT OUTPUTS:
!
! FIRST_FIL is set to FALSE if it is TRUE.
!
! The generation to be used is stored in GEN_BUF, and GEN_LEN and
! GEN_PTR are set accordingly.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! NONE.
!
! SIDE EFFECTS:
!
! NONE.
!
!--
BEGIN
LOCAL
FIL : VECTOR[CH$ALLOCATION(EXTENDED_FILE_SPEC)],
FIL_PTR,
FIL_SIZ,
STS,
$io_BLOCK_DECL(WRK);
!Make this routine a no-op for all except the first call
IF
NOT .FIRST_FIL
THEN
RETURN G_OK;
FIRST_FIL=FALSE;
!Initialize IOB
$IO_BLOCK_INIT(WRK);
!Make the composite file name
FIL_PTR=CH$PTR(FIL);
FIL_PTR=CH$MOVE(%CHARCOUNT(LIB),CH$PTR(UPLIT(LIB)),.FIL_PTR);
FIL_PTR=CH$MOVE(.FIL_NAM_LEN,.FIL_NAM_STR,.FIL_PTR);
FIL_SIZ=CH$DIFF(.FIL_PTR,CH$PTR(FIL));
!Open the file in the library to retrieve the generation list
STS=$STEP_OPEN(IOB=WRK_IOB,FILE_SPEC=(.FIL_SIZ,CH$PTR(FIL)),OPTIONS=INPUT,FAILURE=0);
IF
NOT .STS
THEN
BADXPO(.STS,CAT(('Cannot open file '),(.FIL_SIZ,CH$PTR(FIL))));
!Do the necessary checking in the generation list
!Find a header record on the main line of descent
REPEAT
BEGIN
LOCAL
GENERATION,
S_L_PTR,
TG_BUF : VECTOR[CH$ALLOCATION(GEN_SIZE)],
TG_LGT;
!Get a header record
IF
$STEP_GET(IOB=WRK_IOB,failure=0) EQL STEP$_EOF
THEN
BADLIB(LIT('Illegal Library file format '));
S_L_PTR=.WRK_IOB[IOB$A_STRING];
!Look for a required header record
IF
CH$RCHAR_A(S_L_PTR) NEQ %C'+'
THEN
!No generations in file yet, this isn't allowed
BADLIB(LIT('Illegal Library file format '))
ELSE
!Pick up generation data
BEGIN
GENERATION=CH$PTR(TG_BUF);
TG_LGT=GET_LXM(S_L_PTR,%C' ',.WRK_IOB[IOB$H_STRING]-1,GENERATION);
if
.tg_lgt gtr gen_size
then
badlib(cat('Generation value too long in library file ',
(.fil_siz,ch$ptr(fil))));
!Blank terminate the generation
CH$WCHAR_A(%C' ',GENERATION);
IF
.TG_LGT LEQ 0
THEN
BADLIB(LIT('Illegal header record'));
IF
.GEN_LEN NEQ 0
THEN
!User specified which generation
!See if it matches a legal generation
BEGIN
!Did the user ask for the latest generation of a series?
IF
.PLUS_OP AND
dirdes(.GEN_LEN,.GEN_PTR,.TG_LGT,CH$PTR(TG_BUF))
THEN
!yes, pick up the first one that matches
BEGIN
CH$MOVE(.TG_LGT,CH$PTR(TG_BUF),CH$PTR(GEN_BUF));
GEN_LEN=.TG_LGT;
GEN_PTR=CH$PTR(GEN_BUF);
EXITLOOP
END
ELSE
!Did he ask for a specific generation?
IF
CH$EQL(.GEN_LEN,.GEN_PTR,.TG_LGT,CH$PTR(TG_BUF))
THEN
EXITLOOP
END
END;
!See if this entry is on the main line
! and the user did not specify which generation
IF
.GEN_LEN EQL 0
THEN
BEGIN
LOCAL
CHAR,
PTR;
PTR=CH$PTR(TG_BUF);
!Skip all leading numerics
REPEAT
BEGIN
CHAR=CH$RCHAR_A(PTR);
IF
.CHAR LSS %C'0' OR
.CHAR GTR %C'9'
THEN
EXITLOOP
END;
!If the character in CHAR is a blank we are on the main line.
IF
.CHAR EQL %C' '
THEN
BEGIN
CH$MOVE(.TG_LGT,CH$PTR(TG_BUF),CH$PTR(GEN_BUF));
GEN_LEN=.TG_LGT;
GEN_PTR=CH$PTR(GEN_BUF);
EXITLOOP
END
END;
!See if there are no more header records
IF
CH$EQL(2,CH$PTR(UPLIT('1 ')),.TG_LGT+1,CH$PTR(TG_BUF))
THEN
BEGIN
IF
.GEN_LEN NEQ 0
THEN
!No such generation
BEGIN
ERS(s_nogen,CAT('Generation ',(.GEN_LEN,.GEN_PTR),
' does not exist'));
$STEP_CLOSE(IOB=WRK_IOB);
RETURN G_ERMSG
END;
BUG(LIT('Failure in RFILGEN'))
END
END;
!Now close the file
$STEP_CLOSE(IOB=WRK_IOB);
G_OK
END; !End of RFILGEN
ROUTINE SETUP : NOVALUE =
!++
! FUNCTIONAL DESCRIPTION:
!
! Common setup code
!
! FORMAL PARAMETERS:
!
! NONE.
!
! IMPLICIT INPUTS:
!
! NONE.
!
! IMPLICIT OUTPUTS:
!
! NONE.
!
! ROUTINE VALUE:
! COMPLETION CODES:
!
! NONE.
!
! SIDE EFFECTS:
!
! NONE.
!
!--
BEGIN
!Keep track of what is open or not
INP_OPN=FALSE;
OUT_OPN=FALSE;
!Initialize the output routines
OUTINI(OUT_IOB);
END; !End of SETUP
END !End of Module CREATE
ELUDOM