	.TITLE	LOG HANDLER FUNCTION CODE
	.SBTTL	INTRODUCTION
	.IDENT	/LG001/

	.SBTTL	MACROS
;
; LOCAL MACROS
;
 
	.MACRO	.INH
	MOV	@#PS,-(SP)
	BIS	#340,@#PS
	.ENDM	.INH
 
	.MACRO	.ENB
	MOV	(SP)+,@#PS
	.ENDM	.ENB
 
	.MACRO	PRINT,A,B
	mov	a,$QIO$+Q.IOPL
	mov	b,$QIO$+Q.IOPL+2
	DIR$	#$QIO$
	.endm	print

	.SBTTL	UTILITY FUNCTIONS
;+
; THE FOLLOWING FUNCTIONS ARE CURRENTLY IMPLEMENTED:
;
; CODE	DESCRIPTION
; ---- ----------------------------------------------------------------
;
;  0   KILL I/O -- UNLOAD HANDLER
;  1   WRITE TO THE LOG FILE LOCATED ON LB:[1,1]SYSLOG.LST
;  3   ATTACH (ALWAYS SUCEEDS)
;  4   DETACH (ALWAYS SUCEEDS)
; 22   WRITE VIRTUAL -- FOR THOSE PEOPLE THAT PREFER IO.WVB INSTEAD OF IO.WLB
;
;
;
; ERRORS:	ALL ERRORS ARE RETURNED IN THE 1ST WORD OF THE I/O STATUS
;		BLOCK.  ALL ERROR CODES MATCH EXISTING HANDLER ERRORS OR DIR-
;		RECTIVE ERRORS.  IF THE HIGH ORDER BYTE IS NEGATIVE, THE ERROR
;		IS A DIRECTIVE-TYPE ERROR. IF IT IS ZERO, THE LOW BYTE
;		CONTAINS A HANDLER-TYPE ERROR.
;-

	.sbttl	FCS Stuff

	.mcall	fsrsz$,fdbdf$,fdat$a,fdop$a,fdrc$a,open$w,open$a
	.mcall	ofid$a,put$,close$,push,pop,dir$,C$C,mrkt$s,astx$s
	.mcall	gtim$s,OPEN$R

	C$C				; define control characters
	lglun==2			; lun for FCS
	FSRSZ$	1			; define buffer area for FCS
 
;	This handler only records data to a file. Its
;	main purpose is to allow a means to record all
;	messages that are normally sent to the operator's
;	console from ...PDS or other tasks, make a record
;	of them, then display them to the operator's console.
	
LGFDB::	FDBDF$				;Allocate space for a File
					;Descriptor Block.
 
	FDAT$A	R.VAR,FD.CR,160.,-10.,-10. ; Record Attributes: ...
					; ...Variable Length
					; ...Implied carriage control
					; ...Maxbuf of 160. bytes
					; ...Create 10. blocks initially
					; ...Extend by 10. blocks each time
	
	FDRC$A	,LGBUF,LGBUFS		; File Access: ...
					; Input buffer is LGBUF
					; Input buffer size is LGBUFS
 
	FDOP$A	LGLUN,LGDPST,,FO.APD!FA.SHR,FA.DLK   ; File Open: ...
					; ...File lun is LGLUN
					; ...File name block pointer 
					; ...Open for append
					; ...and shared access
					; ...Don't lock file if aborted.
 
LGDPST:: .WORD	LGDEVS,LGDEV		; File name block descriptor
	.WORD	LGUICS,LGUIC		;
	.WORD	LGNAMS,LGNAM		;
 
LGDEV:	.ASCII	"DB0:"			; Output device
	LGDEVS=.-LGDEV
LGUIC:	.ASCII	"[1,2]"			; Output UIC
	LGUICS=.-LGUIC
LGNAM:	.ASCII	"       .LOG"		; Output File name
	LGNAMS=.-LGNAM
CRERR:	.ascii	<CR><LF>"LG  --  Unable to open LOG file"<BEL>
	CRERRS=.-CRERR
	.even
fidadr:	.blkb	N.unit+2		; area to store filename block
lgbuf:	.blkb	160.			; output buffer
	lgbufs=.-lgbuf			; buffer size
	.EVEN
TIMBUF:	.blkw	8.			; buffer for GTIM

	.SBTTL	Attach and Detach
$START::
 
;	Attach and Detach function

ATTC::	MOV	#1,$STAT0		; set sucess
	call	$iodun			; perform I/O done
	jmp	$wait			; and go back to wait loop

;	Write logical and Write Virtual function
	.SBTTL	WRITE LOG FUNCTION

WRTLOG::
	
;	This function will output to a log file any information
;	regarding the system that is sent to it via a IO.WLB
;	QIO function code. All other function codes are invalid 
;	for this release of thie routine.
 
;	First move the users output string into our buffer area
 
	mov	$rqio,r1		; R1 = QI/O request node address
	br	okarg

iodun:	call	$iodun			; perform I/O done
	jmp	$wait			; go back to wait loop
 
OKARG:	mov	r.pb(r1),r2		; get pointer to line descriptor
	mov	r.pb+2(r1),r3		; set length of transfer
	mov	#lgbuf,r4		; set output buffer address
	call	..blxi			; get user string
	bcc	noerr			; cc - then no errors
;	
;	error stuff goes here
;
	mov	#ie.spc,$stat0		; error - out of address space
	jmp	iodun			; go tell someone about it

noerr:	
;	Now try to open the output file using conventional FCS techniques.
;
;	If the file open fails, then try to create a new file.
;	also, let's store the file ID to allow for quicker opens
;
	OFID$A	#lgfdb			; open log file for append
	bcc	opok			; CC - then file already exists

;	create error

	PRINT	#CRERR,#CRERRS		; Print Create error to O.C
	MOV	#IE.BAD,$STAT0		; Set bad code
	JMP	IODUN			; Go do IODONE

;	Now output the completed record to the output file
;
opok:	put$	#lgfdb,#LGBUF,r.pb+2(r1)	; output the record
	close$	#lgfdb			; close the file
	print	#lgbuf,r.pb+2(r1)	; also output to operator's console
 
;	Now restore the file id information to the FDB
 
	call	UNSFID			; restore file ID
	mov	#1,$stat0		; set I/O success
	jmp	iodun			; do i/o done


	.sbttl	New file stuff
 
;	The way that this routine works, is that it is
;	initially entered 5 minutes after the handler is
;	loaded. It checks to see what the time is, and schedules
;	itself to be entered after midnite to print up the system
;	log for the previous day, then requests itself again.
    
NEWFIL:: Call	$saval			; Save all registers
	GTIM$S	#TIMBUF			; Get current time
	MOV	#23.,R1			; 24-1 hours in a day
	SUB	TIMBUF+G.TIHR,R1	; Get hours left today
	MUL	#60.,R1			; Convert to minutes
	MOV	#60.,R0			; Set up for miutes this hour
	ADD	#5,R0			; BE SURE TO GET INTO TOMORROW
	SUB	TIMBUF+G.TIMI,R0	; Correct the minutes left
	ADD	R0,R1			; Add in minutes so far this hour
	MRKT$S	#0,R1,#3,#NEWAST	; Set up AST to create next file
	MOV	#$BUFF,R0		; Point to output area
	MOV	#TIMBUF+G.TIYR,R1	; Point to input area
	CALL	$DAT			; Convert date to ascii
	MOV	#$BUFF,R0		; Reset pointer
	MOV	#9.,R1			; Set counter
	MOV	#LGNAM,r2		; Set output pointer
FLMOV:	CMPB	#40,(R0)		; Is it a blank ?
	BNE	10$			; NE - then go on.
	MOVB	#'0,(R2)+		; Replace the blank with a 0
	BR	40$			; Go to end of block
10$:	CMPB	#'-,(R0)		; Is it a hyphen ??
	BEQ	40$			; EQ - then go on.
	MOVB	(R0),(R2)+		; Move into position
40$:	INC	R0			; Point to next character
	SOB	R1,FLMOV		; Loop till Thru.
 
	CLOSE$	#LGFDB			; Clear out any previous info.
	OPEN$R	#LGFDB			; Does the file already exist??
	BCC	100$			; CC - Yup
	OPEN$W	#LGFDB			; Create the file
100$:	CALL	SAVFID			; Save file ID for subsequent opens
	CLOSE$	#LGFDB			; Close the file.
	CALL	UNSFID			; Unsave the file ID.
	RETURN				; Return to calling proc.
 

	.Sbttl	Support Subroutines
 
;	SAVFID  -- Save file ID
 
;	This routine saves the file name block information
;	in the FDB so that it can be restored when the
;	file is subsequently re-opened. This routine destroys
;	registers R0,R1, and R2
;
SAVFID:: CALL	$SAVAL			; Save all registers
	MOV	#LGFDB+F.FNB,R0		; Point to file name block in FDB
	MOV	#N.UNIT+2/2,R1		; Get size of file name block in words
	MOV	#FIDADR,R2		; Set pointer to save area
	CALL	MOVDAT			; Call common move routine
	RETURN				; Return to calling proc.
 
;	UNSFID  -- Unsave file ID
 
;	This routine takes the file name block information
;	and restores it to the File Descriptor Block
;	This routine destroys registers R0, R1, and R2.

UNSFID:: CALL	$SAVAL			; Save all registers
	MOV	#FIDADR,R0		; Point to save area
	MOV	#N.UNIT+2/2,R1		; Get size of filename block in words
	MOV	#LGFDB+F.FNB,R2		; Set pointer to file name block
	CALL	MOVDAT			; Call common move routine
	RETURN
 
 
;	MOVFID  --  Move data routine
 
;	This routine will move a block of data from a location
;	referenced by r0 to the location referenced by r2
;	for a length specified by r1.
;	NOTE: This routine performs a word move. All data
;	that is to be moved must be aligned on a fullword
;	boundary, else the program will trap out.
 
MOVDAT:: MOV	(R0)+,(R2)+		; Move a word of data
	SOB	R1,MOVDAT		; Loop till thru
	RETURN				; Return to calling proc.
 


	.sbttl	New file AST routine.
 
;	This AST is entered at MIDNITE each day. The
;	purpose of this routine is to create a new log
;	file for that particular day. This AST is queued by 
;	the NEWFIL routine.
 
NEWAST:: TST (SP)+			; Clear off event flag info
	CALL	NEWFIL			; Create a new file
	ASTX$S				; Exit the AST

	.end

