Google
 

Trailing-Edge - PDP-10 Archives - bb-d868c-bm_tops20_v4_2020_distr - language-sources/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	Larry Samberg	7 Oct 77

;
;
;                COPYRIGHT (c) 1975,1976,1977,1978,1979
;                    DIGITAL EQUIPMENT CORPORATION
;
;     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.

	SEARCH	GLXMAC			;GLXLIB SYMBOLS AND MACROS

	PROLOG(GLXLNK,LNK)		;GENERATE MODULE PROLOGUE

	LNKEDT==5			;MODULE EDIT LEVEL

;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. Larry Samberg   7 Oct 77..................................   1
;    2. Table Of Contents.........................................   2
;    3. Revision History..........................................   3
;    4. Data Structures...........................................   4
;    5. Module Storage............................................   6
;    6. L%INIT  --  Initialize the GLXLNK Module..................   7
;    7. L%CLST  --  Create a list.................................   8
;    8. MORLST  --  Make room for more lists......................   9
;    9. L%DLST  --  Destroy a list................................  10
;   10. L%CENT  --  Create a list entry...........................  11
;   11. L%CBFR  --  Create entry "before" CURRENT.................  12
;   12. L%DENT  --  Delete list entry.............................  13
;   13. List Positioning Routines.................................  14
;   14. Global Utilities..........................................  16
;   15. LINKIN  --  Link an entry into a list.....................  18
;   16. FNDLST  --  Find header of list...........................  19
SUBTTL	Revision History

;0001	Create GLXLNK module.
;0002	L%DENT Did no clear "current" when deleting the only entry
;	1. Make L%DENT not return address of "current"
;	2. Make L%DENT not return ERBOL$ after deleting the first entry
;	3. Remove L%CFEN and add a new routine, L%CBFR
;0003	Fix bugs introduce in previous edit.
;0004	Make L%PREM return error code ERNRE$ instead of stopcode NRE
;	for No remembered entry.  (GCF #2).
;0005	Add routine L%APOS for positioning to an entry by address.
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                     \
;	\                                                       \
;	\                                                       \
;	!                                                       !
;	!=======================================================!

	XX=.
	PHASE	-2
LEN.SZ:	BLOCK	1			;SIZE OF THE CHUNK
	LE.SIZ==0,,-1			;THE SIZE FIELD
LEN.LK:	BLOCK	1			;LINK WORD
	LE.PTP==-1,,0			;POINTER TO PREVIOUS
	LE.PTN==0,,-1			;POINTER TO NEXT
LEN.DT:	BLOCK	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              !
;	!=======================================================!

	PHASE	0

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

	DEPHASE
	RELOC	XX
SUBTTL Module Storage

	$DATA	LSTNUM			;NUMBER OF LIST SLOTS
	$DATA	LSTADR			;ADDRESS OF LIST SLOTS
	$DATA	LSTFRE			;NUMBER OF FREE LIST SLOTS
SUBTTL	L%INIT  --  Initialize the GLXLNK Module

	ENTRY	L%INIT

L%INIT:	SETZM	LSTNUM			;CLEAR TOTAL NUMBER OF LISTS AVAILABLE
	SETZM	LSTFRE			;AND NUMBER FREE
	SETZM	LSTADR			;AND THE ADDRESS
	$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
	MOVE	S1,P1			;PUT IT IN THE CORRECT AC
	SOS	LSTFRE			;DECREMENT FREE LIST SLOTS
	$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
	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
	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
	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
	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
	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
	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
	;
	;Ret:	S1/ The List Id
	;	S2/ The Address of the Current Entry

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
	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' !!!
	$STOP(ENF,Entry Not Found)	;ELSE HE'S IN DEEEP SNEAKERS
	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
	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
	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
	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
	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
	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


FNDLST:	SKIPL	S1			;NEGATIVE OR
	CAML	S1,LSTNUM		;GREATER THAN ALLOWABLE?
	PUSHJ	P,S..NSL		;YES, GIVE "NO SUCH LIST" STOP CODE
	MOVE	S2,LSTADR		;GET ADDRESS OF LIST SLOTS
	ADD	S2,S1			;ADD IN THE OFFSET
	SKIPN	S2,0(S2)		;GET THE HEADER ADDRESS
	$STOP(NSL,No such list)
	$RETT





LNK%L:
	END