Google
 

Trailing-Edge - PDP-10 Archives - BB-L054E-RK - apex.r36
There are no other files named apex.r36 in the archive.
!
!                      COPYRIGHT (c) 1980 BY
!           Digital Equipment Corporation, Maynard, MA.
!
!   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: Require File for APEX
!
! ABSTRACT:
!
!
!
!
! ENVIRONMENT: TOPS-20 / TOPS-10
!
! AUTHOR: Donald R. Brandt, CREATION DATE: 19 March 1980
!
! MODIFIED BY:
!
!	Revision history follows
!
!--

!
! Edit History for APEX.R36
!
! APX001  by DRB on 14-Oct-80
!   Added 3 code prefix to all error message typeouts.
!    (Change made to $ERROR macro)
!
! APX002  by DRB on 15-Oct-80
!   Changed max_str_len to 80
!
! APX003  by ESB on 21-Dec-81
!   Add literal for source patching.
!
! 100 by HAH on 31-MAY-83
!   Implemented additional patch type 'REP' (replace). No action is taken
!   in GEN_CCL when this type is seen in the DPD file. This patch type is
!   intended for replacement modules where no patching is required during
!   the build process.
!   
! 121 by RBW on 27-FEB-84
!   Changed  the  definition  of  ASL:   to  PAT:,DIS:,SYS:,REL:,UNV:  for
!   TOPS-10. NOTE *** This change requires recompiling all modules!
!   
LITERAL APEX_EDT = %O'121' ;			! Edit level of this module
!
!   Define datatypes
!

LITERAL
    DT_COMPONENT	= 1,
    DT_EDIT		= 2,
    DT_FILE		= 3,
    DT_LIBRARY		= 4,
    DT_PATCH		= 5,
    DT_PRODUCT		= 6,
    DT_TABLE		= 7,

    DT_FD		= 8,	! Additional datatypes for checkpointing
    DT_STRING		= 9,
    DT_IP_TABLE		= 10,
    DT_MP_TABLE		= 11,
    DT_CKP_HEADER	= 12,	! Header of checkpointed data base file
    DT_CKP_TRAILER	= 13 ;	! Trailer of checkpointed data base file

!
!   Define logical names
!

MACRO
    LN_ASL = S('ASL') %,	! Logical name of autopatch search list
    LN_BAK = S('BAK') %,	! Logical name of backup directory
    LN_DIS = S('DIS') %,	! Logical name of distribution directory
    LN_INS = S('INS') %,	! Logical name of installation directory
    LN_PAT = S('PAT') %;	! Logical name of patching directory

![121]    LND_ASL = S('PAT:,DIS:,SYS:') % ;	! Defn of autopatch search list

MACRO						![121]
    LND_ASL =					![121]
	%IF %SWITCHES(TOPS20)			![121]
	%THEN					![121]
	    S('PAT:,DIS:,SYS:')			![121]
	%ELSE					![121]
	    S('PAT:,DIS:,SYS:,REL:,UNV:')	![121]
	%FI %;					![121]

!
!   Define patch status values
!

LITERAL
    PS_RET	= 1,		! retrieved
    PS_SEL	= 2,		! selected
    PS_EXC	= 3,		! excluded
    PS_APP	= 4,		! applied
    PS_INS	= 5,		! installed
    PS_PER	= 6 ;		! permanent

!
!   Define patch categories
!

LITERAL
    PC_MAN	= 1,		! mandatory
    PC_OPT	= 2 ;		! optional

!
!   Define edit types
!

LITERAL
    ET_FIX	= 1,		![100] .FIX file
    ET_REL	= 2,		![100] replacement REL module
    ET_REP	= 3,		![100] replacement 'ready-to-go'
    ET_SRC	= 4 ;		![100][003] source patch
!
!   Define product state values
!

LITERAL
    PROD_STATE_DIS	= 1,		! distribution
    PROD_STATE_SUC	= 2,		! SETUP completed
    PROD_STATE_PSC	= 3,		! Patch status changed
    PROD_STATE_RBB	= 4,		! ready to begin batch job
    prod_state_bfq	= 5,		! batch file submitted

    PROD_STATE_BJS	= 6,		! batch job succeeded
    PROD_STATE_BJF	= 7,		! batch job failed

    PROD_STATE_INI	= 8,		! install initiated
    PROD_STATE_INC	= 9,		! install completed

    PROD_STATE_REI	= 10,		! restore initiated
    PROD_STATE_REC	= 11 ;		! restore completed

!
!   Define file status values used during INSTALL & RESTORE
!

LITERAL
    FS_INI		= 1,		! installation initiated
    FS_IBC		= 2,		! backup completed
    FS_IRC		= 3,		! replacement completed

    FS_REI		= 4,		! restore initiated
    FS_RRC		= 5 ;		! restore replacement completed

!
!   The following  state  transitions  are  allowed.   Although
!   other  transitions  might  seem  reasonable,  they  are not
!   allowed since they could lead  to  a  situation  where  the
!   patch status would be incorrect.
!
!   current state		legal next states	transition
!   -------------		-----------------	----------
!
!   	DIS				PSC		INCLUDE/EXCLUDE
!	   				SUC		SETUP
!
!   	PSC				PSC		INCLUDE/EXCLUDE
!   					SUC		SETUP
!
!   	SUC				SUC		SETUP
!   					PSC		INCLUDE/EXCLUDE
!   					RBB		BUILD
!   					REI *		RESTORE
!
!   	RBB				RBB		BUILD
!   					BFS		(BUILD)
!   					BJS		(CK_BATCH)
!   					BJF		(CK_BATCH)
!   					SUC		SETUP
!							 (with caution)
!   					PSC		INCLUDE/EXCLUDE
!   							 (with caution)
!
!   	BFS				BJS		(CK_BATCH)
!	   				BJF		(CK_BATCH)
!	   				SUC		SETUP
!							 (with caution)
!	   				PSC		INCLUDE/EXCLUDE
!	   						 (with caution)
!
!   	BJF				SUC		SETUP
!	   				PSC		INCLUDE/EXCLUDE
!	   				REI *		RESTORE
!   			
!   	BJS				INI		INSTALL
!	   				SUC		SETUP
!	   				PSC		INCLUDE/EXCLUDE
!	   				REI *		RESTORE
!   			
!   	INI				INI		INSTALL
!	   				INC		(INSTALL)
!   			
!   	INC				SUC		SETUP
!	   				PSC		INCLUDE/EXCLUDE
!	   				REI		RESTORE
!
!   	REI				REI		RESTORE
!	   				REC		(RESTORE)
!
!   	REC				PSC		INCLUDE/EXCLUDE
!	   				SUC		SETUP
!
!   * provided the product has been previously INSTALLed
!

!
!   Define global values
!

LITERAL
    JBVER = %O'137' ;		! Version number address (.JBVER)

LITERAL
    max_str_len = 80,		! Maximum string length
				!  (used in CH$LEN macro)
    $$EOF_FLAG	= 2 ;		! EOF value returned by BUF_READ

!
!   Define GALAXY error codes
!     (These values are determined during the assembly of GLXMAC.MAC.)
!

LITERAL
	EREOF$	= 1, 		! End of File
	ERTBF$	= 23 ;		! Table is full

!
!   A simulated GALAXY error code
!   This value is also determined in GLXEXT.MAC
!

LITERAL
	ERNEF$	= %O'1000' ;	! Not .EXE format
!
! Define headers for checkpointed data file
!

!
!   Header fields for master header of checkpointed data file
!

FIELD
    MAST_HEADER_FIELDS =
	SET
	MASTER_HEADER		= [0,0,36,0],	! Header word
	MAST_HEADER_FORMAT	= [0,0,18,0],   ! Format field
	MAST_HEADER_DT		= [0,18,6,0],	! Datatype field
	MAST_HEADER_LEN		= [0,24,12,0]   ! Length field of header
	TES ;

LITERAL
    MAST_HEADER_SZ	= 1 ;

MACRO
    MAST_HEADER$$ = BLOCK[MAST_HEADER_SZ] FIELD(MAST_HEADER_FIELDS) % ;


!
!   Header fields for checkpointed data objects
!

FIELD
    OBJ_HEADER_FIELDS =
	SET
	OBJECT_HEADER		= [0,0,36,0],	! Header word
	OBJ_HEADER_ADDRESS	= [0,0,18,0],   ! Address field
	OBJ_HEADER_DT		= [0,18,6,0],	! Datatype of object
	OBJ_HEADER_LEN		= [0,24,12,0]   ! Length field of header
	TES ;

LITERAL
    OBJ_HEADER_SZ	= 1 ;

MACRO
    OBJ_HEADER$$ = BLOCK[OBJ_HEADER_SZ] FIELD(OBJ_HEADER_FIELDS) % ;

!
!   Define common header fields for the data descriptors
!
!	COMPONENT$$
!	EDIT$$
!	FILE$$
!	LIBRARY$$
!	PATCH$$
!	PRODUCT$$
!	TABLE$$
!

FIELD
    HEADER_FIELDS =
	SET
	HEADER		= [0,0,36,0],	! Header word
	HEADER_DT	= [0,0,6,0],	! Datatype field of header
	HEADER_CKP_FLAG	= [0,6,1,0],	! Flag used during ckpting/reloc
	HEADER_LEN	= [0,18,18,0]   ! Length field of header
	TES ;
!
!   COMPONENT data descriptor
!

FIELD
    COMP_FIELDS =
	SET
	COMP_NAME	= [1,0,36,0],	! Address of ASCIZ string
	COMP_CODE	= [2,0,36,0],	! Address of ASCIZ string
	COMP_PROD	= [3,0,18,0],	! Address of "Product"
	COMP_BLD	= [3,18,18,0],	! Address of component build
					!  "File"
	COMP_INP_LIST	= [4,0,18,0],	! Address of "List" of input
					!  "Files"
	COMP_OUT_LIST	= [4,18,18,0]	! Address of "List" of output
					!  "Files"
	TES ;


LITERAL
    COMP_SZ	= 5 ;			! Length of COMPONENT

MACRO
    COMPONENT$$	= BLOCK[COMP_SZ] FIELD(HEADER_FIELDS,COMP_FIELDS) % ;

MACRO
    GET_COMPONENT =
	BEGIN
	STACKLOCAL
	    c: REF COMPONENT$$ ;
	$M_GMEM(comp_sz,c) ;
	c[HEADER_DT]	= dt_component ;
	c[HEADER_LEN]	= comp_sz ;
	c[COMP_INP_LIST] = GET_TABLE(def_tbluk_sz) ;
	c[COMP_OUT_LIST] = GET_TABLE(def_tbluk_sz) ;
	.c
	END % ;
!
!   EDIT data descriptor
!

FIELD
    EDIT_FIELDS =
	SET
	EDIT_NAME	= [1,0,36,0],	! Address of ASCIZ string
	EDIT_LIB	= [2,0,18,0],	! Address of target "Library"
	EDIT_FILE	= [2,18,18,0],	! Address of patch "File"
	EDIT_MOD_LIST	= [3,0,18,0],	! Address of "List" of modules
	EDIT_TYPE	= [3,18,9,0]	! Type of edit
	TES ;


LITERAL
    EDIT_SZ	= 4 ;			! Length of EDIT

MACRO
    EDIT$$	= BLOCK[EDIT_SZ] FIELD(HEADER_FIELDS,EDIT_FIELDS) % ;

MACRO
    GET_EDIT =
	BEGIN
	STACKLOCAL
	    e: REF EDIT$$ ;
	$M_GMEM(edit_sz,e) ;
	e[HEADER_DT]	= dt_edit ;
	e[HEADER_LEN]	= edit_sz ;
	e[EDIT_MOD_LIST] = GET_TABLE(def_tbluk_sz) ;
	.e
	END % ;
!
!   FILE data descriptor
!

FIELD
    FILE_FIELDS =
	SET
	FILE_FD		= [1,0,18,0],	! Address of FD for this file
	FILE_IFN	= [1,18,9,0],	! Internal File Number
	FILE_STATUS	= [1,27,9,0],	! INSTALL/RESTORE file status
	FILE_EXP_CKSUM	= [2,0,18,0],	! Expected checksum of file
	FILE_ACT_CKSUM	= [2,18,18,0],	! Actual checksum of file
	FILE_EXP_VER	= [3,0,36,0],	! Expected version of file
	FILE_ACT_VER	= [4,0,36,0],	! Actual version of file
	FILE_BACKUP	= [5,0,18,0],	! Address of "File" that is
					!  backup instance of this file
	FILE_NEWEST	= [5,18,18,0]	! Address of "File" that is
					!  newest instance of this file
	TES ;


LITERAL
    FILE_SZ	= 6 ;			! Length of FILE

MACRO
    FILE$$	= BLOCK[FILE_SZ] FIELD(HEADER_FIELDS,FILE_FIELDS) % ;

MACRO
    GET_FILE =
	BEGIN
	STACKLOCAL
	    f: REF FILE$$ ;
	$M_GMEM(file_sz,f) ;
	f[HEADER_DT]	= dt_file ;
	f[HEADER_LEN]	= file_sz ;
	.f
	END % ;
!
!   LIBRARY data descriptor
!

FIELD
    LIB_FIELDS =
	SET
	LIB_NAME	= [1,0,36,0],	! Address of ASCIZ string
	LIB_PROD	= [2,0,18,0],	! Address of "Product"
	LIB_COMP_LIST	= [2,18,18,0],	! Address of "List" of "Compo-
					!  nents" that use this library
	LIB_FILE	= [3,0,18,0],	! Address of current "File"
	LIB_EDIT_LIST	= [3,18,18,0],	! Address of "List" of "Edits"
	LIB_EDIT_LEVEL	= [4,0,36,0],	! Edit level of this library
	LIB_EDT		= [5,0,18,0],	! Address of edit summary "File"
	LIB_STATUS	= [5,18,18,0]	! Status of library
	TES ;


LITERAL
    LIB_SZ	= 6 ;			! Length of LIBRARY

MACRO
    LIBRARY$$	= BLOCK[LIB_SZ] FIELD(HEADER_FIELDS,LIB_FIELDS) % ;

MACRO
    GET_LIBRARY =
	BEGIN
	STACKLOCAL
	    l: REF LIBRARY$$ ;
	$M_GMEM(lib_sz,l) ;
	l[HEADER_DT]	= dt_library ;
	l[HEADER_LEN]	= lib_sz ;
	l[LIB_COMP_LIST] = GET_TABLE(def_tbluk_sz) ;
	l[LIB_EDIT_LIST] = GET_TABLE(def_tbluk_sz) ;
	.l
	END % ;
!
!   PATCH data descriptor
!

FIELD
    PAT_FIELDS =
	SET
	PAT_NAME	= [1,0,36,0],	! Address of ASCIZ string
	PAT_PROD	= [2,0,18,0],	! Address of "Product"
	PAT_EDIT_LIST	= [2,18,18,0],	! Address of "List" of "Edits"
	PAT_CATEGORY	= [3,0,6,0],	! Patch category
	PAT_LEVEL	= [3,6,6,0],	! Autopatch level number
	PAT_STATUS	= [3,12,6,0],	! Patch status
	PAT_RP_LIST	= [3,18,18,0],	! Address of "List" of required
					!  "Patches"
	PAT_DESCRIPTION	= [4,0,36,0],	! Address of ASCIZ string
	PAT_SPR		= [5,0,36,0],	! Address of ASCIZ string
	PAT_DATE	= [6,0,36,0]	! Address of ASCIZ string
	TES ;


LITERAL
    PAT_SZ	= 7 ;			! Length of PATCH

MACRO
    PATCH$$	= BLOCK[PAT_SZ] FIELD(HEADER_FIELDS,PAT_FIELDS) % ;

MACRO
    GET_PATCH =
	BEGIN
	STACKLOCAL
	    pa: REF PATCH$$ ;
	$M_GMEM(pat_sz,pa) ;
	pa[HEADER_DT]	= dt_patch ;
	pa[HEADER_LEN]	= pat_sz ;
	pa[PAT_EDIT_LIST] = GET_TABLE(def_tbluk_sz) ;
	pa[PAT_RP_LIST] = GET_TABLE(def_tbluk_sz) ;
	.pa
	END % ;
!
!   PRODUCT data descriptor
!

FIELD
    PROD_FIELDS =
	SET
	PROD_NAME	= [1,0,36,0],	! Address of ASCIZ string
	PROD_CODE	= [2,0,36,0],	! Address of ASCIZ string
	PROD_STATUS	= [3,0,4,0],	! Status code
	PROD_PAT_LEVEL	= [3,4,5,0],	! Patch level
	PROD_PAT_COUNT	= [3,9,8,0],	! Patch count
	PROD_INS_FLAG	= [3,17,1,0],	! Set after initial INSTALL
	PROD_UTL_LIST	= [3,18,18,0],	! Address of Utility "List"
	PROD_PAT_LIST	= [4,0,18,0],	! Address of Patch "List"
	PROD_COMP_LIST	= [4,18,18,0],	! Address of Component "List"
	PROD_LIB_LIST	= [5,0,18,0],	! Address of Library "List"
	PROD_CTL_FILE	= [5,18,18,0],	! Address of patch/build "File"
	PROD_PCF_FILE	= [6,0,18,0],	! Address of patch cmd "File"
	PROD_BCF_FILE	= [6,18,18,0],	! Address of Batch Communication
					!  "File"
	PROD_BAK_LND	= [7,0,36,0],	! Address of ASCIZ string
	PROD_INS_LND	= [8,0,36,0],	! Address of ASCIZ string
	PROD_DIS_LND	= [9,0,36,0],	! Address of ASCIZ string
	PROD_PAT_LND	= [10,0,36,0],	! Address of ASCIZ string
	PROD_SP_LIST	= [11,0,18,0]	! Address of selected patch
					!  "List"
	TES ;


LITERAL
    PROD_SZ	= 12 ;			! Length of PRODUCT

MACRO
    PRODUCT$$	= BLOCK[PROD_SZ] FIELD(HEADER_FIELDS,PROD_FIELDS) % ;

MACRO
    GET_PRODUCT =
	BEGIN
	STACKLOCAL
	    p: REF PRODUCT$$ ;
	$M_GMEM(prod_sz,p) ;
	p[HEADER_DT]	= dt_product ;
	p[HEADER_LEN]	= prod_sz ;
	p[PROD_INS_FLAG] = false ;
	p[PROD_UTL_LIST] = GET_TABLE(def_tbluk_sz) ;
	p[PROD_PAT_LIST] = GET_TABLE(def_tbluk_sz) ;
	p[PROD_COMP_LIST] = GET_TABLE(def_tbluk_sz) ;
	p[PROD_LIB_LIST] = GET_TABLE(def_tbluk_sz) ;
	p[PROD_SP_LIST] = GET_TABLE(def_tbluk_sz) ;
	.p
	END % ;
!
!   TABLE data structure
!
!   This data structure consists of a 2 word descriptor  and  a
!   TOPS-20  TBLUK  formatted  table.  The TBLUK portion of the
!   table need not be contiguous to the descriptor.  The second
!   word  of  the  descriptor  points to the TBLUK table.  This
!   makes it possible to expand a TABLE, by pointing to  a  new
!   TBLUK table.
!
!   If t  is  the  address  of  a  TABLE,  then  the  following
!   references will supply these values:
!
!	.t[HEADER_DT]		the datatype field in the
!				 descriptor header
!
!	.t[HEADER_LEN]		the length field in the
!				 descriptor header
!
!	.t[TABLE_REF]		the address of the TBLUK
!				 formatted table
!
!	.t[TBL_MAX_ENTRIES]	the maximum entries field in
!				 the TBLUK table header
!
!	.t[TBL_ACTUAL_ENTRIES]	the actual entries field in
!				 the TBLUK table header
!
!	.t[n,TBL_ITEM]		item number n in the table
!				 ( 1 <= n <= max_entries )
!
!	.t[n,TBL_ITEM_ADR]	address field (left half) of
!				 item number n in the table
!
!	.t[n,TBL_ITEM_VALUE]	value field (right half) of
!				 item number n in the table
!

MACRO
    					!Item fields
    TBL_ITEM = 0,36,1% ,		!Full item field
    TBL_ITEM_VALUE = 0,18,1% ,		!Value field of item
    TBL_ITEM_ADR = 18,18,1% ;		!Address field of item

FIELD
    TABLE_FIELDS =
	SET
	TABLE_REF	= [1,0,18,0],	! REF pointer to TBLUK formatted
					!  table
	TABLE_DYN_FLAG	= [1,18,1,0],	! TBLUK table is dynamic storage
	TABLE_CKP_FLAG	= [1,19,1,0],	! Checkpoint/Relocation flag
	TBL_MAX_ENTRIES = [0,0,18,1],	! Header fields of TBLUK header
	TBL_ACTUAL_ENTRIES = [0,18,18,1]
	TES ;

LITERAL
    DEF_TBLUK_SZ = 3,			! Default size for TBLUK portion
    TDESC_SZ = 2 ;			! Size of descriptor portion
STRUCTURE
    TBL [i,j,k,l;tbluk_sz=def_tbluk_sz] =
	[tdesc_sz + tbluk_sz + 1]
	(CASE l FROM 0 TO 1 OF
	    SET
	    [0]: (TBL + i) ;
	    [1]: (.(TBL + 1) + i) ;
	    TES
	)<j,k,0> ;

!
!   TABLE for REF and MAP references
!

MACRO
    TABLE$$ = TBL[] FIELD(HEADER_FIELDS,TABLE_FIELDS) % ;

!
!   Descriptor portion of TABLE
!

MACRO
    DTABLE$$(tbluk) = TBL[-1] FIELD(HEADER_FIELDS,TABLE_FIELDS)
		INITIAL(TDESC_SZ^18 + DT_TABLE,tbluk) % ;

!
!   TBLUK portion of TABLE
!

MACRO
    TBLUK$$(size) = VECTOR[size+1] INITIAL(size,REP size of (0)) % ;

!
!   Static generation of table (note REF link is null)
!

MACRO
    TABLE$$$(tbl_sz) = TBL[tbl_sz] FIELD(HEADER_FIELDS,TABLE_FIELDS)
		INITIAL(TDESC_SZ^18 + DT_TABLE,
			0,
			tbl_sz,
			REP tbl_sz OF (0)) % ;

!
!   Allocate a TABLE (descriptor and TBLUK portion)
!
MACRO
    GET_TABLE(t_size) =
	BEGIN
	STACKLOCAL
	    t: REF TABLE$$ ;
	$M_GMEM(tdesc_sz+t_size+1,t) ;
	t[HEADER_DT]	= dt_table ;
	t[HEADER_LEN]	= tdesc_sz ;
	t[TABLE_REF]	= .t + tdesc_sz ;
	t[TABLE_DYN_FLAG] = true ;
	t[TBL_MAX_ENTRIES] = t_size ;
	.t
	END % ;

!
!  Deallocate the TBLUK portion of a table
!
MACRO
    DELETE_TABLE(t) =
	IF .t[TABLE_DYN_FLAG]
	THEN
	    $M_RMEM(.t[TBL_MAX_ENTRIES],.t[TABLE_REF])
	ELSE
	    false % ;

!
!   Purge all entries in table t.
!
MACRO
    PURGE_TABLE(t) =
	BEGIN
	LOCAL
	    n ;
	n = 0 ;
	WHILE (n=.n+1) LEQ .t[TBL_ACTUAL_ENTRIES] DO
	    t[.n,TBL_ITEM] = 0 ;
	t[TBL_ACTUAL_ENTRIES] = 0 ;
	true
	END % ;

MACRO
    COPY_TABLE(st,dt) =
	BEGIN
	LOCAL
	    n ;
	IF .st[TBL_ACTUAL_ENTRIES] LEQ .dt[TBL_MAX_ENTRIES]
	THEN
	    BEGIN
	    n = 0 ;
	    WHILE (n=.n+1) LEQ .st[TBL_ACTUAL_ENTRIES] DO
		dt[.n,TBL_ITEM] = .st[.n,TBL_ITEM] ;
	    dt[TBL_ACTUAL_ENTRIES] = .st[TBL_ACTUAL_ENTRIES] ;
	    true
	    END
	ELSE
	    false
	END % ;

MACRO
    EXPAND_TABLE(t) =
	BEGIN
	STACKLOCAL
	    ttem:	REF TABLE$$ ;
	ttem =
	 GET_TABLE(.t[TBL_MAX_ENTRIES] + .t[TBL_MAX_ENTRIES]/3 + 1) ;
	IF COPY_TABLE(t,ttem)
	THEN
	    IF DELETE_TABLE(t)
	    THEN
		BEGIN
		t[TABLE_REF] = .ttem[TABLE_REF] ;
		$M_RMEM(.ttem[HEADER_LEN],.ttem)
		END
	    ELSE
		false
	ELSE
	    false
	END % ;

!
!   Useful MACROS
!

!
!   Verifys the datatype of a data descriptor.
!
!   Calling sequence:
!
!   	CK_DATATYPE (item,type)
!
!   where
!   	item is the address of the descriptor or the REF pointer to
!   	     the descriptor
!
!   	type is the datatype to check for
!
!   Invokes IDT error message and RETURN false processing if
!           datatype is incorrect
!

MACRO
    CK_DATATYPE (item,type) =
	IF (.item[HEADER_DT] NEQ %NAME('DT_',type))
	THEN
	    RETURN $ERROR(C$IDT,*,FMT_NUM(%NAME('DT_',TYPE)))% ;

MACRO
    DATATYPE (item) = (.item[HEADER_DT] EQL %NAME('DT_',item))% ;

MACRO
    CH$ASCIZ [ ] =
	(%O'440700000000' OR (UPLIT (%ASCIZ %STRING (%REMAINING)))) % ;

MACRO TRUE = 1 % ;

MACRO FALSE = 0 % ;

MACRO CR_LF = %CHAR (%O'15', %O'12') % ;

MACRO
    CH$LEN(a) =
	BEGIN
	LOCAL
	    p1,
	    p2 ;
	p1 = CH$PTR(a) ;
	p2 =  CH$FIND_CH(max_str_len,.p1,0) ;
	IF CH$FAIL(.p2)
	THEN
	    max_str_len
	ELSE
	    CH$DIFF(.p2,.p1)
	END % ;

!
!   Make a copy of ASCIZ string in dynamic memory
!    s is address of string
!

MACRO
    COPY_STR(s) =
	BEGIN
	LOCAL
	    a,
	    len ;
	len = CH$LEN(s) + 1 ;		! Length of string + zero byte
	$M_GMEM(((.len-1)/5)+1,a) ;
	CH$COPY(.len,CH$PTR(s),
		0,
		.len,CH$PTR(.a) ) ;
	.a				! Return address of new string
	END % ;

!
!   Compare two ASCIZ strings
!    s1 is address of string1
!    s2 is address of string2
!   Returns true if strings are equal; otherwise returns false
!

MACRO
    EQL_STR(s1,s2) =
	BEGIN
	CH$EQL(CH$LEN(s1),CH$PTR(s1),CH$LEN(s2),CH$PTR(s2))
	END % ;

MACRO
    OUT(f,a) =
	IF NOT BUF_WRITE(f,CH$LEN(a),a)
	THEN
	    RETURN false % ;

MACRO FMT_FILE (file) =
    IF .file[FILE_IFN] EQL 0
    THEN
	$FMT$FD(.file[FILE_FD])
    ELSE
	$FMT$FD($F_FD(.file[FILE_IFN],-1)) % ;


MACRO FMT_NUM (num) =
    $FMT$NUM(num) % ;

MACRO FMT_OCT (num) =
    $FMT$OCT(num) % ;

MACRO FMT_VER (num) =
    $FMT$VRS(num) % ;

MACRO S [] = UPLIT(%ASCIZ %STRING(%REMAINING)) % ;

MACRO TTY_ASOUT (STR_ADDR) = $K_SOUT(STR_ADDR) % ;

MACRO TTY_SOUT [] = $K_SOUT(UPLIT(%ASCIZ %STRING(%REMAINING))) % ;

MACRO TTY_FILE (file) =
    IF .file[FILE_IFN] EQL 0
    THEN
	$T$FD(.file[FILE_FD])
    ELSE
	$T$FD($F_FD(.file[FILE_IFN],-1)) % ;

MACRO TTY_OK = TTY_SOUT('  [OK]') % ;


!
!   Displays 
!	0 patches
!	1 patch
!	<value> patches
!
!   depending on value.
!

MACRO
    TTY_PAT_COUNT(value) =
	BEGIN
	IF value EQL 0
	THEN
	   TTY(('No patches'))
	ELSE
	    IF value EQL 1
	    THEN
		TTY(('1 patch'))
	    ELSE
		TTY(FMT_NUM(value),(' patches')) ;
	END % ;
MACRO
    TTY [] =
	BEGIN
	TT(%REMAINING) ;
	true
	END % ,

    TT [a] =
	%IF STRING(a)
	%THEN
	    TTY_SOUT(%REMOVE(a))
	%ELSE
	    TTY_ASOUT(a)
	%FI % ,
	
    STRING(c) =
	%IF ARGNUM(%REMOVE(C))
	%THEN
	    true
	%ELSE
	    %IF %IDENTICAL(c,%REMOVE(c))
	    %THEN
		false
	    %ELSE
		true
	    %FI
	%FI % ,

    ARGNUM [] =
	%IF %LENGTH GTR 1
	%THEN
	    true
	%ELSE
	    false
	%FI % ;
!
!  Parse a field and move the data item
!
!   Calling sequence:
!
!	$PM(f,adr)
!
!   where f is the parse function, and adr is the address to
!   store the address of the moved data item.
!
!   Two of the arguments of f must be c, the count of the number
!   of words in the data item, and a, the address of the data item
!   within the command message returned by the parser.
!

MACRO
    $PM (f,adr) =
	BEGIN
	f ;
	$M_GMEM(.c,adr) ;
	INCR n FROM 0 to .c-1 DO
	    (.adr + .n) = .(.a + .n)
	END % ;
MACRO
    $ERROR(error_code) =
	BEGIN
	$ERR(%EXPLODE(error_code)) ;
	$ERRARG(%REMAINING) ;
	false
	END % ,

    $ERR(type,dollar) =
	EXTERNAL err_list: TABLE$$ ;
	STACKLOCAL
	    v ;
	BIND
	    skey = (UPLIT(%ASCIZ %STRING(%REMAINING))) ;
!	TTY_SOUT(cr_lf,$ERRCHAR(type)) % ,	! without prefix message
!	TTY_SOUT(cr_lf,$ERRCHAR(type),'PEP',%REMAINING,' ') % , !with it
	TTY_SOUT(cr_lf,$ERRCHAR(type),,%REMAINING,' ') % , !with it

    $ERRARG [a] =
	%IF %IDENTICAL(a,*)
	%THEN
	    IF T_LOOKUP(err_list,skey,v)
	    THEN
		TTY_ASOUT(.v)
	%ELSE
	    TTY_ASOUT(a)
	%FI % ,

    $ERRCHAR(ch) =
	%IF %IDENTICAL(ch,'W')
	%THEN
	    '%'
	%ELSE
	    %IF (%IDENTICAL(ch,'F') OR %IDENTICAL(ch,'C'))
	    %THEN
		'?'
	    %ELSE
		' '
	    %FI
	%FI % ;

MACRO
    $GERROR(n) =
	S(' ('),$FMT$ERR(n),S(')') % ;