	.title	$$put	Write a record -- RSX only
	.ident	/000005/
;
;+
;
; Internal
;
; Index		Write a logical record
;
; Usage
;
;	mov	#bufadr,r0	;r0 -> buffer start
;	mov	nbytes,r1	;r1 := number of bytes
;	mov	#iov,r4		;r4 -> i/o vector
;	call	$$put		;Internal put buffer routine
;
;	Return, r1..r4 preserved.
;
; Description
;
;	$$put is called by RSX-mode routines to write a record.
;	$$put only runs under the RSX library.  Using it
;	in RT11-mode will cause the job to abort with a BPT trap.
;	The byte count may be zero for RSX Terminal I/O.
;
;	If output is to a terminal, stderr will be flushed (first).
;
; Bugs
;
;-
;
; Edit history
; 000001 14-Oct-81 MM	Split out from fflush.mac
; 000002 02-Jul-82 MM	Newer library
; 000003 24-Jul-82 MM	Fix extraneous newlines (ancient bug!)
; 000004 09-Sep-82 MM	Flush stderr, too.
;	 27-Oct-82 RBD	Change comments only. Regarding initial
;			setting of VF$NEWL on stdout/stderr.
; 000005 19-Dec-82 RBD	Set null carriage control byte on terminal
;			output in "n" mode.
;
.iif	ndf	rsx	rsx	=	1	;Assume RSX11M
.if ne	rsx

	.MCALL	PUT$,QIOW$S

CR	=	015		; Carriage return		;03
LF	=	012		; Line feed			;03

	.psect	c$code
;
; Write a record.  Calling sequence:
;
;	MOV	#BUFADR,R0	;R0 -> first byte of buffer
;	MOV	NBYTES,R1	;R1 := number of bytes to do
;	MOV	#IOV,R4		;R4 -> I/O vector
;	CALL	$$PUT
;
; Return, all registers are preserved.
;
; Note: this routine understands newline stuff.  It does real live
; QIO's on terminal devices.
;
$$put::
	jsr	r5,$$svr1
	mov	r0,r2			;Copy buffer address
	add	r1,r2			;Point to just past buffer
	bit	#VF$TTY,V$FLAG(r4)	;Terminal device		;02
	beq	dodisk			;No, do a disk output
	cmp	r4,stderr		;Is it stderr?
	beq	5$			;yep, don't go forever.		;04+
	mov	r4,-(sp)		;save old r4
	mov	stderr,r4		;get stderr
	call	$$flsh			;flush it
	mov	(sp)+,r4		;restore our device
5$:					;main sequence			;04-
;
; You may be wondering what is happening here:
; The routines attempt to act reasonably on "real" terminals.
; The following code (which may well be a contender for the
; Guiness Book of Records "world's largest NOP") does the following:
;
; 1. If the user is controlling newlines directly, the carriage-
;    control character is NULL.
;
; 2. Else, we control newlines.  The VF$NEWL flag indicates whether
;    the previous line ended with a newline:
;
;       Carriage Control Character   EOL <LF> VF$NEWL becomes
;	NUL	     ...		 no	0	0
;	 $	<LF> ...		 no	1	0
;	 +	     ... <CR>		yes	0	1
;	 SP	<LF> ... <CR>		yes	1	1
;
; 4. If a linefeed was erased from the record, and the record
;    was or became empty, a dummy single-byte record is created
;    as RSX gets unhappy only doing carriage control.
;
; 5. Finally, the monitor-level QIOW routine is called to output
;    the record and appropriate carriage-control.  All this work
;    is then undone in the terminal service.
;
; VF$NEWL is erased by the scget() routine in screen.mac to prevent
; the "cursor" from moving when reading from the terminal after a prompt.
;
	bit	#VF$NOS,V$FLAG(r4)	;User does all newline stuff?	;02
	beq	10$			;Branch if we do it
	tst	r1			;Was there anything?
	beq	putxit			;Duck out if not.
	clr	r2			;Set NULL carriage control	;05
	mov	#IO.WAL,r3		;Get the QIO operation -- write all.
	br	30$			;Off we go
;
10$:	mov	#IO.WVB,r3		;Write virtual block.
	mov	#cctab,-(sp)		;CC table start
	bit	#VF$NEWL,V$FLAG(r4)	;Was flag set?
	beq	12$			;Br if not
	inc	(sp)			;Yes, increment the flag
12$:	bic	#VF$NEWL,V$FLAG(r4)	;Ain't set now
	tst	r1			;Empty record?
	bne	13$			;Continue if not
	mov	#hack+1,r2		;Get a legal address...
13$:	cmpb	-(r2),#LF		;Record ends with '\n'?
	bne	14$			;Nope.
	add	#2,(sp)			;Yes, step the flag and
	bis	#VF$NEWL,V$FLAG(r4)	;set the flag for next time
	dec	r1			;Erase '\n' from the string
14$:	movb	@(sp)+,r2		;Get the cc byte.
	tst	r1			;Is there a real record?
	bgt	30$			;Output it if so.
					;Strictly speaking this is
					;incorrect as the count is unsigned.
	tst	r2			;But if it's a NULL cc,
	beq	putxit			;Duck out.
	mov	#hack,r0		;Get the hack byte
	mov	#1,r1			;Force one byte record
;
; Here to do I/O.  When we get here:
;	R0	-> Output line
;	R2	:= EOL byte
;	R1	:= Byte count -- never zero
;	R3	:= QIO operation
; Somehow, I find it hard to believe that QIOW$S doesn't know that
; the LUN is a byte.
;
30$:
	movb	V$LUN(r4),r5		;Lun (R5 is restored by $$svr1)
	QIOW$S	r3,r5,#1,,#$$iosb,,<r0,r1,r2>				;03-
	bcc	putxit			;Common exit.
	bis	#VF$ERR,V$FLAG(r4)	;Set error flag
	movb	$$iosb,r0		;Error code
	mov	r0,$$ferr		;Saved
	br	putxit			;and exit			;02-
;
; Do a normal file output
;
dodisk:	bit	#VF$NOS,V$FLAG(r4) ;Never do linefeed?			;02
	bne	10$		;No, user does it.
	cmpb	-(r2),#12	;Linefeed terminated record?
	bne	10$		;No, continue
	dec	r1		;Yes, erase it (FCS puts it back)
10$:	mov	r0,r2		;Hide Buffer address from PUT$
	mov	r4,r0		;Locate the FDB
	add	#V$FDB,r0	;Now it's in R0
	PUT$	r0,r2,r1	;Write the record
;
putdon:	bcc	putxit		;Normal exit from directive		;02+
	bis	#VF$ERR,V$FLAG(r4) ;Set error bit in IOV
	movb	V$FDB+F.ERR(r4),r0 ;Error code
	mov	r0,$$ferr	;Store error code

putxit:	return			;And exit -- $$svr1 restores registers	;02-

	.psect	c$strn
;
; Carriage control table.  hack is used for the dummy record RSX needs.	;03+
hack:
cctab:	.byte	000		; no <LF>, VF$NEWL == 0
	.ascii	"$"		; no <LF>, VF$NEWL == 1 <LF> ...
	.ascii	"+"		;    <LF>, VF$NEWL == 0      ... <CR>
	.ascii	" "		;    <LF>, VF$NEWL == 1 <LF> ... <CR>
	.even

.iff
;
; Just in case
;
$$put::
	crash

.endc								;03-
	.end
