perm filename STRSER.KL[S,AIL] blob sn#220485 filedate 1976-06-20 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00007 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	EQU
C00004 00003	STRNGC Service routines -- SOURCE and DEST
C00008 00004	DEST:
C00014 00005	COMPIL(CAT,<CAT,CATCHR,CHRCAT,CHRCHR,CAT.RV>
C00021 00006	DSCR .SONTP(STRING SINTEGER CNT)
C00024 00007	COMPIL(OUT,<OUT>,<SAVE,RESTR,GETCHN,SIMIO,NOTOPN,X11,X22>
C00028 ENDMK
C⊗;
EQU
	DMOVEM	RF-2,DTEMPM
	HRRZ	RF-2,-3(SP)		;#CHARS(1)
	MOVE	RF-1,-2(SP)		;BP(1)
	HRRZ	RF+1,-1(SP)		;#CHARS(2)
	MOVE	RF+2,(SP)		;BP(2)
	CAIN	RF-2,(RF+1)		;SAIL STRINGS MUST BE SAME LENGTH TO BE EQU
	EXTEND	RF-2,[CMPSE]
	 TDZA	1,1
	SETO	1,
	DMOVE	RF-2,DTEMPM
	ADJSP	SP,-4
	POPJ	P,

SUBSR
	SOS	TEMP,-1(P)		;NEW LENGTH-1
	ADD	TEMP,-2(P)		;PLUS START CHAR #
	MOVEM	TEMP,-1(P)		;EQUALS NEW END CHAR #
					;FALL INTO SUBST
SUBST
	HRRZ	TEMP,-1(SP)		;OLD LENGTH
	SETZM	.SKIP.
	SKIPG	USER,-1(P)		;END CHAR #
	 TDZA	TEMP,TEMP		;WAS NEG, WILL BE SET TO ZERO
	CAILE	USER,(TEMP)		;NEW END MUST NOT EXCEED OLD END
	 JRST	[MOVEI	USER,(TEMP)
		HLLOS	.SKIP.
		JRST	.+1]
	SOSGE	TEMP,-2(P)		;START CHAR # -1
	 JRST	SB1			;LENGTH OF RESULT IS (TEMP)
	CAIL	TEMP,(USER)		;NEW LENGTH MUST BE POSITIVE
	 JRST	[SETZB	USER,-1(SP)	;RESULT IS NULL
	    SB1:HRROS	.SKIP.
		JRST	SBRT]		;WE KNOW NEW LENGTH AND B.P.
	SUBI	USER,(TEMP)		;NEW LENGTH
	ADJBP	TEMP,(SP)
	MOVEM	TEMP,(SP)
SBRT:	HRRM	USER,-1(SP)
	ADJSP	P,-3
	JRST	@3(P)

;STRNGC Service routines -- SOURCE and DEST
;SOURCE:
;<** B => source space
;<** .LIST(B) => first descriptor of next nest to move, or 0 (space done)
;Q2 is negative iff SGLIGN is on
;
;strings look like
; -------------------------------
; | NEXT in space |   length    |
; -------------------------------
; |   char # (rel. to space)    |
; -------------------------------
;
; 1. Move to next space, if necessary -- this one done. No-skip if no more.
; 2. Create BP to start of nest, save.  Save first space-relative count.
; 3. Move down list, identify end of nest -- convert all descriptor
;    counts to nest-relative counts
; 4. Update .LIST
; 5. Skip (found a nest) Return:
;    FF -- total # chars in nest
;    A -- BP to source string (nest)
;<   E -- =>first in nest -- last link in nest zeroed
; 6. Non-skip (no more nests) Return.
; 7. Don't change C!!!

SOURCE:	SKIPN	E,.LIST(B)
	 JRST	[SKIPN B,.NEXT(B)
		   POPJ P,		;no-skip, return
		   JRST SOURCE]
	MOVE	A,1(E)		;A←chr #
	HRLI	B,440700	;B←0 BP for space
	ADJBP	A,B		;A←BP to nest
	HRLI	E,(E)
	MOVN	FF,1(E)		;-(nest start char)
	HRRZ	D,(E)		;length of first in nest
	SUB	D,FF		;nest end char +1

	MOVE	T,1(E)
	SUB	T,REMCHR(USER)	;T←max char # that will fit in dest
	SETZM	1(E)		;Adjust 1st descr. location count to nest-rel.
	JRST	SRCBOT
;** FF is -(nest start char)
;** A is BP to start of nest
;** D is Nest end char +1
;<<** E is => first elt of nest,, => current elt.
;** First nest descriptor already count-relative adjusted
;Loop until a descriptor is not in the nest
SRCLUP:	HRRZ	TEMP,(Q1)	;length(next)
	ADD	TEMP,1(Q1)	;end chr +1
	CAMG	D,1(Q1)		;Is next string part of nest?
	 JRST	[JUMPL	Q2,NONEST	;No.  If SGLIGN then must stop.
		CAMN	D,1(Q1)		;Is next string adjacent to nest
		CAMLE	TEMP,T		; and will it fit in dest?
		 JRST	NONEST		;No.
		JRST	SRC.1]		;Known to extend the nest
	CAMGE	D,TEMP		;Adjust nest-end location, if new string
SRC.1:	 MOVE	 D,TEMP		; extends beyond old nest
	ADDM	FF,1(Q1)	;Adjust location count to nest-relative.
	HRRI	E,(Q1)		;Will be last descriptor in nest at NONEST
SRCBOT:	HLRZ	Q1,(E)		;Addr of next string
	JUMPN	Q1,SRCLUP

NONEST:	HRRZM	Q1,.LIST(B)	;Update list
	HRRZS	(E)		;Clear last elt in nest
	HLRZ	E,E		;Return ptr. to 1st
	ADD	FF,D		;Length of nest
	AOS	(P)		;Skip return
	POPJ	P,

;DEST:
;** B inviolate
;<** C => dest space
;** TOPBYTE(USER) is free in current dest space
;** REMCHR(USER) is -(number remaining) in current dest space
;<** E is  =>first in nest -- last elt. is zeroed
;** FF is nest size in chars
;** A is nest source byte pointer
;Q2 is negative iff SGLIGN is on

; 1. Adjust to FW bdry if SGLIGN
; 2. Find room, this dest space or next -- error if out of spaces.
; 3. Adjust REMCHR
; 4. Move nest, adjust TOPBYTE
; 5. Recreate BP for each descriptor

DEST:	MOVE	D,FF		;SAVE LENGTH
DEST1:	JUMPGE	Q2,NOLIGN
	PUSHJ	P,INSET			;Inset aligns TOPBYTE to full word
	ADJBP	D,TOPBYTE(USER)		;D better not be zero!
	SETZM	(D)			;clear out last word
	MOVE	D,FF			;and get nest length back

NOLIGN:	ADDB	D,REMCHR(USER)		;Standard room test
	JUMPLE	D,ISROOM
;!HOOK! If you decided to move the DEST being left (in DSTSET, see below),
; Do it now.  Move it to (C)+OFFSET(USER).
NOROOM:	PUSHJ	P,WASTE			;Count waste in space being left
	HRRZ	C,.NEXT(C)		;Since we are moving strings "down",
	JUMPE	C,[ERR <DRYROT -- No more room for strings -- very strange>]
					; running out of already existent
	PUSHJ	P,DSTSET		; space is a fatal error.
	JRST	DEST1			;Try again, C, REMCHR, TOPBYTE are adjusted.

ISROOM:	SKIPG	D,TOPBYTE(USER)
	 SUB	D,[<POINT 7,1>-<POINT 7,0,34>]	;change from 440700 to 010700
	CAME	D,A			;Avoid moving the nest to its previous
	 JRST	 MV			; location (expensive NO-OP).
	MOVE	D,FF
	ADJBP	D,TOPBYTE(USER)		;Dont move nest, but update TOPBYTE
	JRST	 MVDON

MV:	MOVE	TEMP,C			;save
	MOVE	C,FF			;count
	EXTEND	FF,[MOVSO]		;FF,A to C,D
	 ERR	<DRYROT MOVSO>,1
	MOVE	C,TEMP

MVDON:	EXCH	D,TOPBYTE(USER)
	MOVEI	A,40		;flag for non-const. string
FIXTOP:	MOVE	T,1(E)		;count rel. to nest
	ADJBP	T,D		;form BP
	JUMPG	Q2,.+3
	TLNN	T,700000	;If SGLIGN then
	 ADD	T,[<POINT 7,1>-<POINT 7,0,34>]	;change from 010700 TO 440700
;!HOOK!	ADD	T,OFFSET(USER)	;activate when space-moving becomes reality.
;; !! But topbyte fix is messed up some by this, watch it.
	MOVEM	T,1(E)
	MOVEI	T,(E)		;save current
	HLRZ	E,(E)		;next in nest
	HRLM	A,(T)		;flag non-const.
	JUMPN	E,FIXTOP
	POPJ	P,


;DSTSET:
;<** C => destination space
;Result: TOPBYTE(USER) is destination byte pointer -- to beginning of space
;	 REMCHR(USER) is -(size of space in characters)
DSTSET:	HRLI	C,(<POINT 7,0>)
	MOVEM	C,TOPBYTE(USER)
	MOVN	TEMP,.SIZE(C)
	IMULI	TEMP,5
	MOVEM	TEMP,REMCHR(USER)
;!HOOK! This is probably the best place to decide, perhaps to minimize
; checkerboarding or memory use, that the DEST just prepared should be
; moved to a new location.  This move will not happen until the space
; has been filled, and all descriptors for it adjusted.  Decide where
; to move the block, then put the difference between its future location
; and its current one into OFFSET(USER).  The DEST routine will use this
; to adjust all descriptor byte pointers.
	POPJ	P,

;When leaving a DEST for a new one, keep track of the unfilled space
; within that space.
WASTE:	PUSH	P,TEMP+1
	MOVN	TEMP,REMCHR(USER)	;Unused characters this space
	IDIVI	TEMP,5			;Just rough estimate.
	POP	P,TEMP+1
	ADDM	TEMP,SGCWASTE(USER)
	POPJ	P,
COMPIL(CAT,<CAT,CATCHR,CHRCAT,CHRCHR,CAT.RV>
	  ,<SAVE,RESTR,X22,X33,STRNGC,INSET,GOGTAB,CONFIG,PUTCH>
	  ,<CAT -- CONCATENATION ROUTINE>)

;;#GI# DCS 2-5-72 OPTIMIZE CAT SOME MORE, REMOVE TOPSTR
DSCR "STRING"←CAT("STR1","STR2");
CAL SAIL
DES CALL GENERATED BY COMPILER FOR & OPERATOR
⊗
	
HERE (CAT.RV)
	DMOVE	TEMP,-1(SP)
	EXCH	TEMP,-3(SP)
	EXCH	TEMP+1,-2(SP)
	DMOVEM	TEMP,-1(SP)

HERE (CAT)
	MOVE	USER,GOGTAB
	POP	P,UUO1(USER)		;SAVE FOR STRNGC ERR MESSAGE
	HRRZ	TEMP,-1(SP)
	JUMPE	TEMP,RETFRS		;SECOND IS NULL
	HRRZ	TEMP,-3(SP)
	JUMPE	TEMP,RETSEC		;FIRST IS NULL
CATGO:	DMOVEM	A,RACS+A(USER)		;SAVE A,B
	DMOVEM	D,RACS+D(USER)		;SAVE D,E
	MOVEM	RF,RACS+RF(USER)	;SAVE F-REGISTER

CATGO1:	HRRZ	E,-3(SP)		;LENGTH(FIRST)
	ADJBP	E,-2(SP)		;BP TO END
	CAMN	E,TOPBYTE(USER)	;(TOPBYTE=440700 AND FIRST AT TOP) UNLIKELY
	 JRST	ONLY1		;FIRST IS AT TOP
	SKIPG	LPSA,(SP)
	 SUB	LPSA,[<POINT 7,1>-<POINT 7,0,34>]	;GET RID OF 440700
	CAMN	TEMP,LPSA
	 JRST	ADJRET		;ALREADY CAT (BUT NEED ALIGNMENT CHECK)

; TWO STRINGS TO MOVE

MOVTWO:	HRRZ	A,-3(SP)	;#CHARS(1)
	ADD	A,-1(SP)	;FINAL LENGTH
	MOVEI	A,(A)		;ALLOW ROOM FOR POSSIBLE INSET
	ADDM	A,REMCHR(USER)	;#CHARS(NEW) - REMAINING #CHARS
	SKIPLE	REMCHR(USER)	;ENOUGH ROOM?
	 PUSHJ	P,STRNGC	;NO, GO MAKE SOME
	SKIPE	SGLIGN(USER)	;IF ALIGNING,
	 PUSHJ	P,INSET		; ALIGN
	HRRZ	D,-3(SP)	;#CHARS(1)
	MOVE	E,TOPBYTE(USER)	;WILL BE RESULT BP
	HRROM	A,-3(SP)	;LENGTH OF RESULT
	MOVE	B,E		;TOPBYTE
	EXCH	B,-2(SP)	;TRADE WITH FIRST BP
	MOVEI	A,(D)		;#CHARS(1)
	EXTEND	A,[MOVSO]	;COPY FIRST STRING
	 ERR	<DRYROT MOVSO>,1
	HRRZ	A,-1(SP)	;#CHARS(2)
	JRST	CATB		;AND GO COPY 2ND


;  ONLY ONE STRING TO MOVE

ONLY1:	SKIPE	SGLIGN(USER)	;CHECK ALIGNMENT?
;;#GY# SEE JUST BELOW
	JSP	LPSA,CHKLGN	;YES, DON'T RETURN IF MISALIGNED
;;#GY#
;;#QE#	DCS 12-30-73 Avoid problems when STRNGC expands
	HRRZ	A,-1(SP)	;#CHARS(2)
	ADDM	A,REMCHR(USER)	; - REMAINING CHARS
	SKIPLE	REMCHR(USER)	;ROOM?
	 JRST	[PUSHJ	P,STRNGC	;no, collect, then start from scratch
		MOVNS	A		;since new string space may void
		ADDM	A,REMCHR(USER)	;the ONLY1 condition.
		JRST	CATGO1]		;CATGO1 is new for this fix.
;;#QE#
	ADDM	A,-3(SP)	;NEW #CHARS
				;TOPBYTE ALREADY IN E

;  MOVE 2D

CATB:	MOVE	B,(SP)		;2D BYTE POINTER
	MOVEI	D,(A)		;SAME LENGTH FOR DEST AS SRC
	EXTEND	A,[MOVSO]
	 ERR	<DRYROT MOVSO>,1
	MOVEM	E,TOPBYTE(USER)	;PUT THIS AWAY, BY ALL MEANS
REST.4:
	DMOVE	A,RACS+A(USER)
ADJRT1:	DMOVE	D,RACS+D(USER)
RETFRS:	ADJSP	SP,-2		;REMOVE NON-RESULT
	JRST	@UUO1(USER)	;RETURN

RETSEC:	DMOVE	LPSA,-1(SP)
	DMOVEM	LPSA,-3(SP)
	JRST	RETFRS

;;#GY# DCS 5-11-72 ASSURE FULL-WORD ALIGN IF SGLIGN AND ALREADY CATTED
ADJRET:	SKIPE	SGLIGN(USER)	;IF NEED ALIGNMENT, MUST CHECK IT
	 JSP	 LPSA,CHKLGN	;DON'T RETURN IF NOT ALIGNED
OKLG:	HRRZ	TEMP,-1(SP)	;COUNT OF 2D
	ADDM	TEMP,-3(SP)	;INCREASE COUNT OF FIRST
	JRST	ADJRT1		;RESTORE E

CHKLGN:	MOVE	TEMP,-2(SP)	;Check the position field of first arg --
	TLNN	TEMP,300000	;44, 01 are aligned, 35,27,17,10 not.  Bits
	 JRST	 (LPSA)		; 1 and 2 are both off only for 44 and 01.
	 JRST	 MOVTWO		;Not aligned, move both
;;#GY#

DSCR "STRING"←CHRCAT(CHAR,"STR")
⊗
HERE (CHRCAT)
	HRRZ	TEMP,-1(SP)	;CHECK OTHER STRING NULL
	JUMPE	TEMP,ITSNUL
	PUSH	SP,-1(SP)	;MAKE ROOM FOR ONE UNDERNEATH
	PUSH	SP,-1(SP)
	DMOVE	TEMP,[ONECH: 1
		      POINT 7,RACS+6(USER),28] ;CONSTANT IN
	DMOVEM	TEMP,-3(SP)
	JRST	CATCGO		;GO DO SPECIAL CAT

DSCR "STRING"←CATCHR("STR",CHAR)
⊗
HERE (CATCHR)
	HRRZ	TEMP,-1(SP)
	JUMPE	TEMP,ITSNUL
	PUSH	SP,ONECH	;PUT ONE-CHAR DESCRIPTOR ON
	PUSH	SP,ONECH+1	;TOP
CATCGO:	MOVE	USER,GOGTAB
	POP	P,UUO1(USER)	;RETURN ADDRESS
	POP	P,RACS+6(USER)	;PUT IT SOMEWHERE SAFE
	JRST	CATGO		;EVERYBODY'S NON-NULL
	
ITSNUL:	ADJSP	SP,-2
	JRST	PUTCH		;ZAP

DSCR "STRING"←CHRCHR(CHAR,CHAR)
⊗
HERE (CHRCHR)
	MOVE	USER,GOGTAB
	MOVEM	RF,RACS+RF(USER)
	PUSH	P,A
	MOVEI	A,2		;NEED 2 CHARS
	ADDB	A,REMCHR(USER)
	JUMPLE	A,.+2
	 PUSHJ	 P,STRNGC	;THE USUAL
	MOVE	A,-3(P)		;CHAR 1
	EXCH	A,(P)		;GET BACK SAVED
	PUSHJ	P,PUTCH		;A STRING
	AOS	-1(SP)		;2 CHARACTER STRING
	MOVE	TEMP,-1(P)	;CHAR 2
	IDPB	TEMP,TOPBYTE(USER);A 2-CHAR STRING
	ADJSP	P,-3
	JRST	@3(P)		;QUICK AS A BUNNY

;;#GI#

ENDCOM (CAT)
DSCR .SONTP(STRING S;INTEGER CNT)
DES 	This routine returns (on sp) a string EQU to S (may be S)
	which is aligned with TOPBYT & ensures that there are at least
	an additional CNT chars left in the current string space.
SID 	updates REMCHR.  Sets USER to GOGTAB, mangles TEMP
	may call STRNGC
⊗
HERE(.SONTP)

BEGIN 	SONTP

	MOVE	USER,GOGTAB
	MOVEM	A,RACS+A(USER)
	SKIPG	A,TOPBYTE(USER)
	 SUB	A,[<POINT 7,1>-<POINT 7,0,34>]	;I HATE 440700
	MOVE	TEMP,-1(SP)	;LENGTH
	ADJBP	TEMP,(SP)	;END OF ARG
	CAME	TEMP,A
	 JRST	NOTONT		;DRAT
	MOVE	TEMP,-1(P)
	ADDB	TEMP,REMCHR(USER)
	JUMPG	TEMP,NOFIT	;CNT DOES NOT FIT
XIT:	ADJSP	P,-2
	MOVE	A,RACS+A(USER)
	JRST	@2(P)

NOTONT:	HRRZ	TEMP,-1(SP)	;STRING IS NOT ON TOP. IS THERE ROOM FOR STRING
	ADD	TEMP,-1(P)	;PLUS CNT
	ADDB	TEMP,REMCHR(USER)	;IN STRING SPACE?
	JUMPLE	TEMP,COPY	;YES
NOFIT:	HRRZ	A,-1(SP)	;NO
	ADD	A,-1(P)		;GET ENOUGH FOR BOTH
	PUSHJ	P,STRNGC
	MOVN	A,A		;WE DIDNT USE THE SPACE YET
	ADDM	A,REMCHR(USER)	;SO RETURN IT
	JRST	.SONTP

COPY:	DMOVEM	A,RACS+A(USER)
	DMOVEM	D,RACS+D(USER)
	SKIPE	SGLIGN(USER)
	 PUSHJ	P,INSET
	HRRZ	A,-1(SP)	;LENGTH
	MOVE	B,(SP)		;SOURCE
	MOVEI	D,(A)		;LENGTH
	MOVE	E,TOPBYTE(USER)	;DEST
	MOVEM	E,(SP)		;RECORD IT
	EXTEND	A,[MOVSO]
	 ERR	<DRYROT MOVSO>,1
	MOVEM	E,TOPBYTE(USER)
	DMOVE	A,RACS+A(USER)
	DMOVE	D,RACS+D(USER)
	JRST	XIT
BEND SONTP

COMPIL(OUT,<OUT>,<SAVE,RESTR,GETCHN,SIMIO,NOTOPN,X11,X22>
	  ,<STRING OUTPUT ROUTINE>)
COMMENT ⊗Out ⊗

DSCR OUT(CHANNEL,"STRING");
CAL SAIL
⊗
COMMENT ⊗
Simply places all characters of string in output buffer for channel.
Close file if device is TTY    ⊗

.OUT.:
HERE (OUT)	PUSHJ	P,SAVE		;ACS, GET USER, SAVE RETURN FOR ERROR
	MOVE	LPSA,X22
	MOVE	CHNL,-1(P)	;CHANNEL NUMBER
	LOADI7	A,<OUT>
	PUSHJ	P,GETCHN	;VALIDATE AND GET CDB, ETC.
	HRRE	A,-1(SP)	;#CHARS
	MOVE	B,(SP)
	ADJSP	SP,-2
;;#WZ# JFR 6-17-76 TRAP OUT WITH NO PLACE TO PUT STRING
.OUT2:	SKIPN	E,OBP(CDB)
	 JRST	[ERRSPL	1,[[ASCIZ/
OUT: No buffer. Channel @D file @F:  @F  @F/]
			PWORD	CHNL
			PWORD	DNAME(CDB)
			PWORD	INAME(CDB)
			PWORD	ONAME(CDB)]
		JRST	RESTR]
;;#WZ# ↑
	MOVE	D,OCOWNT(CDB)

.OUT:	SUBM	A,OCOWNT(CDB)	;COUNT DOWN BUFFER
	MOVNS	OCOWNT(CDB)
	CAILE	D,(A)		;IF MORE LEFT IN BUFFER THAN STRING
	 MOVEI	D,(A)		; THEN PRETEND BUFFER IS SHORTER
	EXTEND	A,[MOVSO]
	 JRST	OUT1		;STRING WAS LONGER THAN BUFFER
OUTDUN:	MOVEM	E,OBP(CDB)	;PUT BP AWAY
	SKIPGE	TTYDEV(CDB)	;TTY?
	XCT	IOOUT,SIMIO	; YES, FORCE OUTPUT
	JRST	RESTR
	JRST	RESTR

OUT1:	LDB	TEMP,[POINT 4,DMODE(CDB),35] ;MODE
	CAIL	TEMP,15		;DUMP?
	 JRST	 DMPO		;YES
	MOVEM	E,OBP(CDB)	;PUT REAL BP AWAY
	XCT	IOOUT,SIMIO	;DO THE OUTPUT
	JFCL			;ERRORS HANDLED IN SIMIO
	JRST	.OUT2		;CONTINUE

; SPECIAL DUMP-MODE OUTPUT STUFF

DMPO:	PUSH	P,D
	HRRZ	D,OBUF(CDB)	;PTR TO BUFFER AREA
	SUBI	D,1		;ADDR-1 FOR IOWD
	HRLI	D,-=128		;-WORD COUNT
	MOVEI	D+1,0
	XCT	IODOUT,SIMIO	;OUT D,
	JFCL			;ERRORS HANDLED IN SIMIO
OKO:	HRRZ	B,D		;SAVE ADDR
	HRLI	D,1(D)		;BLT WORD
	HRRI	D,2(D)
	SETZM	-1(D)
	BLT	D,=128(B)	;CLEAR BUFFER
	POP	P,D		;RESTORE INPUT BYTE POINTER
	AOS	@ENDFL(CDB)	;SPECIAL TREATMENT
	HRLI	E,700		;POINT 7,-1(1ST WORD),35
	MOVEM	E,OBP(CDB)
	MOVEI	D,5*=128	;CHAR COUNT
	MOVEM	D,OCOWNT(CDB)
	JRST	.OUT		;AFTER OUTPUT SIMULATION, GO ON

ENDCOM(OUT)