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