Google
 

Trailing-Edge - PDP-10 Archives - CFS_TSU04_19910205_1of1 - update/galsrc/glxlnk.mac
There are 26 other files named glxlnk.mac in the archive. Click here to see a list.
	TITLE	GLXLNK  -  GALAXY Linked List Facility
	SUBTTL	Preliminaries

;	COPYRIGHT (c) DIGITAL EQUIPMENT CORPORATION 1975, 1988.
;	ALL RIGHTS RESERVED.
;
;	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 THAT IS NOT SUPPLIED BY DIGITAL.

	SEARCH	GLXMAC			;GLXLIB SYMBOLS AND MACROS

	PROLOG(GLXLNK,LNK)		;GENERATE MODULE PROLOGUE

	LNKMAN==:0			;Maintenance edit number
	LNKDEV==:26			;Development edit number
	VERSIN (LNK)			;Generate edit number

;THE GLXLNK MODULE PROVIDES A LINKED-LIST MANIPULATION FACILITY
;	FOR THE GALAXY COMPONENTS.  THE FACILITIES INCLUDE
;	CREATING AND DESTROYING LISTS, CREATING AND DESTROYING
;	ENTRIES WITHIN A LIST, SCANNING AND REARRANGING LISTS.
	Subttl	Table of Contents

;		     Table of Contents for GLXLNK
;
;				  Section		      Page
;
;
;    1. Revision History . . . . . . . . . . . . . . . . . . .   3
;    2. Data Structures  . . . . . . . . . . . . . . . . . . .   4
;    3. Module Storage . . . . . . . . . . . . . . . . . . . .   6
;    4. L%INIT - Initialize the GLXLNK Module  . . . . . . . .   7
;    5. L%CLST - Create a list . . . . . . . . . . . . . . . .   8
;    6. MORLST - Make room for more lists  . . . . . . . . . .   9
;    7. L%DLST - Destroy a list  . . . . . . . . . . . . . . .  10
;    8. L%CENT - Create a list entry . . . . . . . . . . . . .  11
;    9. L%CBFR - Create entry "before" CURRENT . . . . . . . .  12
;   10. L%DENT - Delete list entry . . . . . . . . . . . . . .  13
;   11. List Positioning Routines  . . . . . . . . . . . . . .  14
;   12. L%APOS - Position to the Entry whose address is in S1   15
;   13. Global Utilities . . . . . . . . . . . . . . . . . . .  17
;   14. LINKIN - Link an entry into a list . . . . . . . . . .  19
;   15. FNDLST - Find header of list . . . . . . . . . . . . .  20
SUBTTL	Revision History


COMMENT	\

11
	Add a check following each call to FNDLST to make sure that the
link'ed list exists...

*****  Release 4.2 -- begin maintenance edits  *****

*****  Release 5.0 -- begin development edits  *****

15	5.1002		28-Dec-82
	Move to new development area.  Clean up edit organization.  Update TOC.
*****	Release 5.0 -- begin maintenance edits	*****

20	Increment maintenance edit level for version 5 of GALAXY.

*****	Release 6.0 -- begin development edits	*****

25	6.1037		26-Oct-87
	Move sources from G5: to G6:

26	6.1225		8-Mar-88
	Update copyright notice.

\   ;End of Revision History
SUBTTL	Data Structures

;EACH ENTRY IN A LIST IS FORMATTED AS SHOWN BELOW.  WHEN A USER
;	IS RETURNED THE ADDRESS OF AN ENTRY, IT IS ACTUALLY
;	THE ADDRESS OF THE FIRST "USER DATA WORD" WHICH IS
;	RETURNED.

;	!=======================================================!
;	!                           !        CHUNK SIZE         !
;	!-------------------------------------------------------!
;	! POINTER TO PREVIOUS ENTRY !   POINTER TO NEXT ENTRY   !
;	!-------------------------------------------------------!
;	!                                                       !
;	\                    USER DATA AREA                     \
;	\                                                       \
;	\                                                       \
;	!                                                       !
;	!=======================================================!

LEN.SZ==-2				;SIZE OF THE CHUNK
	LE.SIZ==0,,-1			;THE SIZE FIELD
LEN.LK==-1				;LINK WORD
	LE.PTP==-1,,0			;POINTER TO PREVIOUS
	LE.PTN==0,,-1			;POINTER TO NEXT
LEN.DT==0				;FIRST USER DATA WORD
	LENOVH==LEN.DT-LEN.SZ		;OVERHEAD PER ENTRY
;EACH LIST HAS AN INTERNAL LIST HEADER. THIS IS FORMATTED AS FOLLOWS:

;	!=======================================================!
;	!   POINTER TO LAST ENTRY   !  POINTER TO FIRST ENTRY   !
;	!-------------------------------------------------------!
;	!               ADDRESS OF CURRENT ENTRY                !
;	!-------------------------------------------------------!
;	!              ADDRESS OF REMEMBERED ENTRY              !
;	!=======================================================!

HDR.LK==0				;THE LINK WORD
	HD.PTL==-1,,0			;POINTER TO LAST ITEM
	HD.PTF==0,,-1			;POINTER TO FIRST ITEM
HDR.CU==1				;ADDRESS OF CURRENT ENTRY
HDR.RM==2				;ADDRESS OF REMEMBERED ENTRY
HDR.SZ==3				;SIZE OF THE HEADER
SUBTTL Module Storage

	$DATA	LNKBEG,0		;START OF ZEROABLE $DATA SPACE
	$DATA	LSTNUM			;NUMBER OF LIST SLOTS
	$DATA	LSTADR			;ADDRESS OF LIST SLOTS
	$DATA	LSTFRE			;NUMBER OF FREE LIST SLOTS
	$DATA	LNKEND,0		;END OF ZEROABLE $DATA SPACE
SUBTTL	L%INIT  -  Initialize the GLXLNK Module

	ENTRY	L%INIT

L%INIT:	MOVE	S1,[LNKBEG,,LNKBEG+1]	;SETUP BLT PTR TO ZEROABLE $DATA SPACE
	SETZM	LNKBEG			;DO THE FIRST LOC
	BLT	S1,LNKEND-1		;AND BLT THE REST TO ZERO
	$RETT				;AND RETURN
SUBTTL	L%CLST  -  Create a list

;L%CLST IS CALLED TO CREATE A LINKED-LIST.  THE ROUTINE CREATES
;	THE LIST AND RETURNS A LIST-NAME.  THE LIST IS POSITIONED
;	AT THE BEGINNING.

;CALL:			NO ARGUMENTS
;
;TRUE RETURN:		S1/ LIST NAME

	ENTRY	L%CLST

L%CLST:	SKIPN	LSTFRE			;ANY FREE SLOTS?
	PUSHJ	P,MORLST		;NO, MAKE SOME
	MOVE	S1,LSTADR		;GET ADDRESS OF THE SLOTS
	PUSHJ	P,.SAVE1		;SAVE P1

CLST.1:	SKIPE	0(S1)			;IS THIS SLOT FREE?
	AOJA	S1,CLST.1		;NO, LOOP FOR A FREE ONE
	MOVE	P1,S1			;YES, SAVE ITS ADDRESS
	MOVEI	S1,HDR.SZ		;GET HEADER SIZE
	PUSHJ	P,M%GMEM		;GET SOME CORE
	MOVEM	S2,0(P1)		;SAVE THE ADDRESS
	SUB	P1,LSTADR		;MAKE A LIST NAME
	SOS	LSTFRE			;DECREMENT FREE LIST SLOTS
	MOVE	S1,P1			;PUT IT IN THE CORRECT AC
	JUMPE	S1,L%CLST		;NEVER RETURN LIST 0
	$RETT				;AND RETURN
SUBTTL	MORLST  -  Make room for more lists

;MORLST IS CALLED WHEN WE RUN OUT OF FREE SLOTS WHILE TRYING TO
;	CREATE A NEW LIST.

MORLST:	MOVE	S1,LSTNUM		;GET CURRENT NUMBER OF SLOTS
	ADDI	S1,^D20			;ADD THE INCREMENT
	PUSHJ	P,M%GMEM		;AND GET THE SPACE
	EXCH	S2,LSTADR		;SAVE THE NEW ADDRESS
	JUMPE	S2,MORL.1		;IF FIRST CALL, NO OLD LIST ADDR
	PUSH	P,S2			;SAVE THE OLD ADDRESS
	HRL	S2,S2			;START BUILDING A BLT PTR
	HRR	S2,LSTADR		;FINISH BUILDING A BLT POINTER
	MOVE	S1,LSTADR		;GET START OF NEW TABLE
	ADD	S1,LSTNUM		;ADD LENGTH OF OLD TABLE
	BLT	S2,-1(S1)		;AND BLT OLD TO NEW
	POP	P,S2			;GET ADDRESS OF OLD TABLE BACK
	MOVE	S1,LSTNUM		;GET ITS LENGTH
	PUSHJ	P,M%RMEM		;RETURN THE MEMORY
MORL.1:	MOVEI	S1,^D20			;GET INCREMENT SIZE
	ADDM	S1,LSTNUM		;INCREMENT THE TOTAL
	ADDM	S1,LSTFRE		;AND THE FREE CELL COUNT
	$RETT				;AND RETURN
SUBTTL	L%DLST  -  Destroy a list

;L%DLST IS CALLED WITH A LIST NAME TO DESTROY THE LIST.  ALL
;	ENTRIES IN THE LIST ARE RETURNED TO THE FREE SPACE POOL
;	AND THE LIST IS DESTROYED.

;CALL:			S1/ LIST NAME
;
;TRUE RETURN:		ALWAYS

	ENTRY	L%DLST

L%DLST:	PUSH	P,S1			;SAVE LIST ID
	PUSHJ	P,L%LAST		;POSITION TO THE LAST
	JUMPF	DLST.2			;DONE ALREADY!

DLST.1:	PUSHJ	P,L%DENT		;DELETE THE ENTRY
	JUMPT	DLST.1			;AND LOOP

DLST.2:	POP	P,S1			;RESTORE LIST NAME
	ADD	S1,LSTADR		;GET ADDRESS OF LIST SLOT
	MOVEI	S2,0			;LOAD A ZERO
	EXCH	S2,0(S1)		;CLEAR LST SLOT AND LD ADDRESS
	MOVEI	S1,HDR.SZ		;GET HEADER SIZE
	PUSHJ	P,M%RMEM		;RETURN THE MEMORY
	AOS	LSTFRE			;INCREMENT FREE SLOT COUNT
	$RETT				;AND RETURN
SUBTTL	L%CENT  -  Create a list entry

;L%CENT IS CALLED TO CREATE AN ENTRY AND LINK IT IN "AFTER" THE
;	CURRENT ENTRY IN A LIST.  IF THERE IS "NO" CURRENT ENTRY,
;	THE ENTRY IS LINKED AS THE FIRST ENTRY.
;
;THE NEWLY CREATED ENTRY BECOMES CURRENT.
;
;CALL:			S1/  LIST NAME
;			S2/  ENTRY SIZE (IN WORDS)
;
;TRUE RETURN:		S1/  LIST NAME
;			S2/  ADDRESS OF CURRENT ("NEW") ENTRY

	ENTRY	L%CENT

L%CENT:	PUSHJ	P,.SAVE2		;SAVE P1 AND P2
	DMOVE	P1,S1			;SAVE LIST NAME AND SIZE
	PUSHJ	P,FNDLST		;FIND THE HEADER
	JUMPF	[$RET]			;NO SUCH LIST,,RETURN ERROR
	EXCH	P2,S2			;SAVE HEADER ADR GET SIZE
	MOVEI	S1,LENOVH(S2)		;GET SIZE+OVERHEAD IN S1
	PUSHJ	P,M%GMEM		;GET THE SPACE
	ADDI	S2,LENOVH		;POINT TO USER DATA
	STORE	S1,LEN.SZ(S2),LE.SIZ	;STORE CHUNK SIZE
	EXCH	S2,P2			;GET HEADER ADDRESS
	MOVE	S1,S2			;PUT HEADER ADDRESS IN S1
	MOVE	S2,P2			;PUT ENTRY ADDRESS IN S2
	PUSHJ	P,LINKIN		;GO LINK IT IN
	DMOVE	S1,P1			;GET LIST NAME AND ENTRY ADR
	$RETT				;AND RETURN SUCCESS
SUBTTL 	L%CBFR  -  Create entry "before" CURRENT

	ENTRY	L%CBFR

; L%CBFR IS CALLED TO CREATE AN ENTRY IMMEDIATELY BEFORE THE CURRENT ONE

L%CBFR:	PUSHJ	P,.SAVE2		;SAFE STOREAGE
	DMOVE	P1,S1			;SAVE INPUT ARGS
	PUSHJ	P,L%PREV		;GET PREVIOUS
	JUMPF	CBFR.1			;CHECK THE ERROR
	DMOVE	S1,P1			;RESTORE ARGUMENTS
	PJRST	L%CENT			;CREATE ENTRY HERE

CBFR.1:	MOVE	S1,P1			;GET LIST NAME
	PUSHJ	P,FNDLST		;FIND IT
	JUMPF	[$RET]			;NO SUCH LIST,,RETURN ERROR
	SETZM	HDR.CU(S2)		;CLEAR CURRENT ENTRY
	MOVE	S2,P2			;GET THE SIZE BACK
	PJRST	L%CENT			;GO CREATE THE ENTRY
SUBTTL	L%DENT  -  Delete list entry

;L%DENT IS CALLED TO DELETE THE CURRENT ENTRY IN A LIST.  AFTER THE
;	ENTRY IS DELETED, THE LIST IS POSITIONED TO THE IMMEDIATELY
;	PREVIOUS ENTRY.  IF THE ENTRY DELETED WAS THE FIRST ENTRY,
;	CURRENT IS CLEARED.

;CALL:			S1/  LIST NAME
;
;TRUE RETURN:		S1/  LIST NAME

;FALSE RETURN:	S1/ ERNCE$

	ENTRY	L%DENT

L%DENT:	PUSHJ	P,.SAVE3		;SAVE P1, P2, P3
	PUSHJ	P,FNDLST		;FIND THE LST HEADER
	JUMPF	[$RET]			;NO SUCH LIST,,RETURN ERROR
	DMOVE	P1,S1			;SAVE THE RETURNED INFO
	SKIPN	P3,HDR.CU(S2)		;GET THE ADDRESS OF CURRENT
	$RETE(NCE)			;LOSE
	CAMN	P3,HDR.RM(S2)		;IS THIS THE "REMEMBERED" ENTRY?
	ZERO	HDR.RM(S2)		;YES, CLEAR "REMEMBERED"
	LOAD	S1,LEN.LK(P3),LE.PTP	;GET POINTER TO PREVIOUS
	LOAD	S2,LEN.LK(P3),LE.PTN	;GET POINTER TO NEXT
	JUMPE	S1,DENT.1		;JUMP IF IT IS THE FIRST
	JUMPE	S2,DENT.2		;JUMP IF IT IS THE LAST
	STORE	S1,LEN.LK(S2),LE.PTP	;STORE NEXT'S PREVIOUS
	STORE	S2,LEN.LK(S1),LE.PTN	;STORE PREVIOUS' NEXT
	MOVEM	S1,HDR.CU(P2)		;STORE AS "CURRENT"
	JRST	DENT.4			;AND FINISH UP

;HERE IF DESTROYING THE FIRST
DENT.1:	JUMPE	S2,DENT.3		;JUMP IF THIS IS THE "ONLY"
	STORE	S2,HDR.LK(P2),HD.PTF	;SET NEXT TO BE FIRST
	STORE	S1,LEN.LK(S2),LE.PTP	;CLEAR OUT THE "PREVIOUS
	PUSHJ	P,DENT.4		;DO COMMON CODE FOR DELETE
	ZERO	HDR.CU(P2)		;CLEAR "CURRENT"
	$RETT				;AND RETURN

;HERE IF DESTROYING THE LAST
DENT.2:	STORE	S1,HDR.LK(P2),HD.PTL	;SET PREVIOUS TO BE LAST
	STORE	S2,LEN.LK(S1),LE.PTN	;CLEAR OUT THE "NEXT"
	MOVEM	S1,HDR.CU(P2)		;STORE NEW "CURRENT"
	JRST	DENT.4			;AND FINISH UP

;HERE IF DESTROYING THE ONLY
DENT.3:	SETZM	HDR.LK(P2)		;CLEAR THE LINK WORDS
	SETZM	HDR.CU(P2)		;CLEAR THE "CURRENT" WORD

DENT.4:	LOAD	S1,LEN.SZ(P3),LE.SIZ	;GET ENTRY SIZE
	SUBI	P3,LENOVH		;POINT TO BEGINNING OF CHUNK
	MOVE	S2,P3			;PUT IN IN S2
	PUSHJ	P,M%RMEM		;RETURN THE MEMORY
	MOVE	S1,P1			;GET LIST NAME BACK
	$RETT				;AND RETURN
SUBTTL	List Positioning Routines

;ROUTINES TO POSITION TO VARIOUS PLACES IN A LIST


;CALL:			S1/ LIST NAME
;
;TRUE RETURN:		S1/ LIST NAME
;			S2/ ADDRESS OF CURRENT ENTRY
;
;FALSE RETURN:		S1/ ERBOL$   EREOL$   ERNCE$

	ENTRY	L%NEXT,L%FIRST,L%LAST,L%PREVIOUS,L%PREM

L%NEXT:	PUSHJ	P,.SAVE1		;SAVE P1
	MOVE	P1,S1			;SAVE LIST NAME IN P1
	PUSHJ	P,FNDLST		;GET THE HEADER
	JUMPF	[$RET]			;NO SUCH LIST,,RETURN ERROR
	SKIPN	HDR.CU(S2)		;GET THE CURRENT
	JRST	L%FIRST			;NO CURRENT, USE FIRST
	MOVE	S1,HDR.CU(S2)		;GET "CURRENT" ENTRY
	LOAD	S1,LEN.LK(S1),LE.PTN	;GET POINTER TO NEXT
	SKIPN	S1			;IS THERE A NEXT ONE?
	$RETE(EOL)			;NO, RETURN END-OF-LIST
	JRST	POSRET			;FINISH UP AND RETURN


L%FIRST:
	PUSHJ	P,.SAVE1		;SAVE P1
	MOVE	P1,S1			;SAVE LIST NAME IN P1
	PUSHJ	P,FNDLST		;GET THE HEADER
	JUMPF	[$RET]			;NO SUCH LIST,,RETURN ERROR
	LOAD	S1,HDR.LK(S2),HD.PTF	;GET POINTER TO FIRST
	SKIPN	S1			;IS THERE ONE?
	$RETE(EOL)			;NO, EOL
	JRST	POSRET			;FINISH UP AND RETURN


L%LAST:	PUSHJ	P,.SAVE1		;SAVE P1
	MOVE	P1,S1			;SAVE LIST NAME IN P1
	PUSHJ	P,FNDLST		;GET THE HEADER
	JUMPF	[$RET]			;NO SUCH LIST,,RETURN ERROR
	LOAD	S1,HDR.LK(S2),HD.PTL	;GET POINTER TO LAST
	SKIPN	S1			;IS THERE ONE?
	$RETE(EOL)			;NO, RETURN EOL
	JRST	POSRET			;CLEAN-UP AND RETURN
	SUBTTL	L%APOS - Position to the Entry whose address is in S1

; Call:	S1/ The List Id
;	S2/ The Address of the Entry to be positioned to
;
; TRUE return:	S1/ The List Id
;		S2/ The Address of the Current Entry
; FALSE return:	S1/ ERENF$

L%APOS:	PUSHJ	P,.SAVE2		;SAVE P1 & P2 FOR A MINUTE
	DMOVE	P1,S1			;SAVE THE INPUT ARGS
	PUSHJ	P,FNDLST		;GO FIND THE LIST WE WANT
	JUMPF	[$RET]			;NO SUCH LIST,,RETURN ERROR
	MOVE	S1,S2			;SAVE THE LIST HEADER ADDRESS
	LOAD	S2,HDR.LK(S2),HD.PTF	;GET THE ADDRESS OF THE FIRST ENTRY
	SKIPA				;SKIP THE FIRST TIME THROUGH
APOS.1:	LOAD	S2,LEN.LK(S2),LE.PTN	;GET THE ADDRESS OF THE NEXT ENTRY
	SKIPN	S2			;CAN'T BE 'END OF LIST' !!!
	  $RETE	(ENF)			;?ENTRY NOT FOUND
	CAME	S2,P2			;DO THE ADDRESSES MATCH ???
	JRST	APOS.1			;NO,,TRY THE NEXT ENTRY
	MOVEM	S2,HDR.CU(S1)		;MAKE THIS THE CURRENT ENTRY
	DMOVE	S1,P1			;RESTORE THE INPUT ARGS
	$RETT				;AND RETURN
L%PREVIOUS:
	PUSHJ	P,.SAVE1		;SAVE P1
	MOVE	P1,S1			;SAVE LIST NAME IN P1
	PUSHJ	P,FNDLST		;GET THE HEADER
	JUMPF	[$RET]			;NO SUCH LIST,,RETURN ERROR
	SKIPN	S1,HDR.CU(S2)		;GET THE CURRENT ENTRY
	$RETE(NCE)			;NO CURRENT ENTRY
	LOAD	S1,LEN.LK(S1),LE.PTP	;GET POINTER TO PREVIOUS
	SKIPN	S1			;DID WE HIT BOL?
	$RETE(BOL)			;YES, GIVE THE ERROR
	JRST	POSRET			;AND FINISH UP

L%PREM:	PUSHJ	P,.SAVE1		;SAVE P1
	MOVE	P1,S1			;SAVE LIST NAME IN P1
	PUSHJ	P,FNDLST		;GET THE HEADER
	JUMPF	[$RET]			;NO SUCH LIST,,RETURN ERROR
	SKIPN	S1,HDR.RM(S2)		;GET "REMEMBERED"
	$RETE(NRE)			;RETURN NO REMEMBERED ENTRY
	JRST	POSRET			;AND FINISH UP




;HERE TO FINISH UP AND RETURN AFTER POSITIONING OPERATIONS
;CALL WITH:	S1/  ADDRESS OF NEW CURRENT ENTRY
;		S2/  ADDRESS OF LIST HEADER
;		P1/  LIST NAME
;
;RETURN WITH:	S1/  LIST NAME
;		S2/  ADDRESS OF CURRENT ENTRY
;
;STORES THE NEW CURRENT ENTRY IN THE HEADER ALSO.
POSRET:	MOVEM	S1,HDR.CU(S2)		;STORE THE NEW CURRENT
	MOVE	S2,S1			;GET THE NEW CURRENT
	MOVE	S1,P1			;GET THE LIST NAME
	$RETT				;AND RETURN
SUBTTL	Global Utilities

;L%CURR  -  IS CALLED TO RETURN THE ADDRESS OF THE "CURRENT" ITEM
;	IN A LIST.
;
;CALL:			S1/ LIST NAME
;
;TRUE RETURN:		S1/ LIST NAME
;			S2/ ADDRESS OF "CURRENT" ENTRY
;
;FALSE RETURN:		S1/ ERNCE$

	ENTRY	L%CURR

L%CURR:	PUSHJ	P,FNDLST		;FIND THE LIST HEADER
	JUMPF	[$RET]			;NO SUCH LIST,,RETURN ERROR
	SKIPN	S2,HDR.CU(S2)		;GET THE CURRENT ENTRY
	$RETE(NCE)			;THERE IS NONE
	$RETT				;RETURN TRUE


;L%SIZE  -  IS CALLED TO RETURN THE SIZE OF THE CURRENT ENTRY IN A
;	LIST.

;CALL:			S1/ LIST NAME
;
;TRUE RETURN:		S1/ LIST NAME
;			S2/ SIZE OF "CURRENT ENTRY"
;
;FALSE RETURN:		S1/ ERNCE$

	ENTRY	L%SIZE

L%SIZE:	PUSHJ	P,FNDLST		;FIND THE LIST
	JUMPF	[$RET]			;NO SUCH LIST,,RETURN ERROR
	SKIPN	S2,HDR.CU(S2)		;GET ADDRESS OF CURRENT ENTRY
	$RETE(NCE)			;THERE IS NONE
	LOAD	S2,LEN.SZ(S2),LE.SIZ	 ;GET THE CHUNK SIZE
	SUBI	S2,LENOVH		;SUBTRACT OFFSET TO DATA-AREA
	$RETT				;AND RETURN
;L%RENT  -  CALLED TO "REMEMBER" THE ADDRESS OF THE CURRENT ENTRY
;	IN A LIST.

;CALL:			S1/ LIST NAME
;
;TRUE RETURN:		S1/ LIST NAME
;			S2/ ADDRESS OF CURRENT ENTRY
;
;FALSE RETURN:		S1/ ERNCE$

	ENTRY	L%RENT

L%RENT:	PUSHJ	P,FNDLST		;GET THE LIST HEADER
	JUMPF	[$RET]			;NO SUCH LIST,,RETURN ERROR
	PUSHJ	P,.SAVE1		;SAVE P1
	SKIPN	P1,HDR.CU(S2)		;GET ADDRESS OF CURRENT
	$RETE(NCE)			;NONE!
	MOVEM	P1,HDR.RM(S2)		;REMEMBER IT
	MOVE	S2,P1			;COPY ADDRESS OVER
	$RETT				;AND RETURN SUCCESS
SUBTTL	LINKIN  -  Link an entry into a list

;CALLED TO LINK AN ENTRY INTO A LIST "AFTER" THE CURRENT ENTRY.
;	IF THERE IS NO CURRENT ENTRY, THE NEW ENTRY IS LINKED
;	IN AT THE BEGINNING OF THE LIST.

;CALL:			S1/  HEADER ADDRESS
;			S2/  ENTRY ADDRESS
;
;MAKES THE NEW ENTRY THE "CURRENT" ENTRY IN THE LIST

LINKIN:	PUSHJ	P,.SAVE2		;SAVE P1 AND P2
	DMOVE	P1,S1			;AND SAVE THE CALL ARGS
	SKIPN	S1,HDR.CU(P1)		;IS THERE A CURRENT ENTRY?
	JRST	LINK.1			;NO, LINK AT THE TOP
	LOAD	S2,LEN.LK(S1),LE.PTN	;GET ADDRESS OF NEXT
	STORE	S2,LEN.LK(P2),LE.PTN	;MAKE IT NEW PTN
	STORE	P2,LEN.LK(S1),LE.PTN	;MAKE THIS ITS PRED.
	STORE	S1,LEN.LK(P2),LE.PTP	;MAKE CURR NEW PRED.
	JUMPE	S2,LINK.2		;JUMP IF THIS IS THE LAST
	STORE	P2,LEN.LK(S2),LE.PTP	;MAKE PRED. OF SUCC.
	MOVEM	P2,HDR.CU(P1)		;STORE NEW CURRENT
	$RETT				;AND RETURN

LINK.1:	LOAD	S1,HDR.LK(P1),HD.PTF	;GET POINTER TO FIRST
	STORE	P2,HDR.LK(P1),HD.PTF	;MAKE THIS THE FIRST
	STORE	S1,LEN.LK(P2),LE.PTN	;MAKE IT 2ND
	JUMPE	S1,LINK.2		;JUMP IF ALSO LAST ELEMENT
	STORE	P2,LEN.LK(S1),LE.PTP	;STORE OLD FIRST'S PREV POINTER
	SKIPA				;AND DONT STORE AS LAST
LINK.2:	STORE	P2,HDR.LK(P1),HD.PTL	;ELSE STORE AS LAST
	MOVEM	P2,HDR.CU(P1)		;STORE NEW CURRENT
	$RETT				;AND RETURN
SUBTTL	FNDLST  -  Find header of list

;FNDLST IS CALLED WITH A LIST NAME.  IT SEARCHES FOR THE LIST
;	HEADER AND RETURNS IT'S ADDRESS.

;CALL:			S1/ LIST NAME
;
;TRUE RETURN:		S1/ LIST NAME
;			S2/ ADDRESS OF LIST HEADER
;FALSE RETURN:		s1/ ERNSL$


FNDLST:	SKIPL	S1			;NEGATIVE OR
	CAML	S1,LSTNUM		;GREATER THAN ALLOWABLE?
	  $RETE	(NSL)			;?NO SUCH LIST
	MOVE	S2,LSTADR		;GET ADDRESS OF LIST SLOTS
	ADD	S2,S1			;ADD IN THE OFFSET
	SKIPN	S2,0(S2)		;GET THE HEADER ADDRESS
	  $RETE	(NSL)			;?NO SUCH LIST
	$RETT





LNK%L:
	END