	.TITLE	FTS	"Main FTS code module"
	.IDENT /b1.0/
;+
; Facility:
;	FTS.MAR - Functionality Testing Suite
;	FTS.C	Copyright (c) 1991	Bruce R. Miller and TGV Inc.
;
; Abstract:
;	Self-defence for the VMS system hacker
;
; Author:
;	Bruce R. Miller, MILLER@TGV.COM
;	TGV, Inc.
;	603 Mission St.
;	Santa Cruz, CA 95060
;	(408) 427-4366
;
; Date:		May 14,1991
;
; Wishlist:
;	Can we monitor timer activity?
;	Ned's library monitor
;	Ehud's hotkey code
;
; Copyright (c) 1991 Bruce R. Miller
; All rights reserved.
;
;	Redistribution and use in source and binary forms are permitted
;	provided that the above copyright notice and this paragraph are
;	duplicated in all such forms and that any documentation,
;	advertising materials, and other materials related to such
;	distribution and use acknowledge that the software was developed
;	by Bruce R. Miller.
;	THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR
;	IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
;	WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
;
; Modifications:
;
;-

	.link		"sys$system:sys.stb"/SELECTIVE_SEARCH
	.library	"sys$Library:lib.mlb"

	$chfdef
	$climsgdef
	$rmsdef
	$ssdef
	$stsdef
	$smgdef



.EXTERNAL FTS_parse

exit_condition:	.BLKL		; condition causing exit
exh_block:
	.LONG	0		; Forward link
	.LONG	Exit_Handler	; Exit handler routine address
	.LONG	0		; arg_count
	.LONG	exit_condition	; pointer to exit signal
	.LONG	0		; first arg


Exit_error_str:	.ASCID	/Leaving in a huff...  !XL/

;++
;	Exit_Handler
;
; Function:
;	This routine is an exit handler.  It cleans up cleanly.
;
; Input:
;	4(AP) - Condition address
;--

.entry Exit_Handler,^m<R2,R3,R4,R5>

	; Did we get an error code?
	MOVL	@4(AP),R2
	BLBS	R2,100$

	; Print an error message
	PUSHL	R2
	PUSHAB	Exit_error_str
	CALLS	#2,Print_String

100$:	; Call it a day
	MOVL	R2,R0
	RET




;++
;	FTS_Handler - FTS signal catcher
;
; Input:
;	4(AP) - address of signal array
;	8(AP) - address of mechanism array
;	12(AP) - address of enable array
;
;--
.entry FTS_Handler,^m<R2,R3,R4,R5>

	MOVL	#SS$_RESIGNAL,R0		; Resignal by default
	MOVL	4(AP),R1			; Get signal array
	MOVL	chf$l_sig_name(R1),R1		; get signal code
	CMPL	R1,#SS$_UNWIND			; An unwind signal?
	BNEQ	20$				; br if not
	MOVL	#SS$_NORMAL,R0			;
	BRB	100$
20$:	CMPL	R1,#CLI$_NOCOMD			; No command?
	BNEQ	30$				; br if not
	MOVL	#SS$_CONTINUE,R0		;
	BRB	100$
30$:	CMPL	R1,#RMS$_EOF			; End of file?
	BNEQ	100$				; br if not
	CLRQ	-(SP)				; push two zeros
	CALLS	#2,G^SYS$UNWIND			; unwind the stack

100$:	RET



;++
;	Do_Abort - FTS command has failed, return to FTS> prompt
;
; Input:
;	4(AP) - address of signal array
;	8(AP) - address of mechanism array
;--

.entry Do_Abort,^M<R2,R3,R4,R5>
	MOVL	4(AP),R2			; Get signal array
	MOVL	8(AP),R3			; Get mechanism array
	SUBL	#2,chf$l_sig_args(R2)		; decrement arg count
	CLRL	-(SP)
	CLRL	-(SP)
	CLRL	-(SP)
	PUSHL	R2
	CALLS	#4,G^SYS$PUTMSG			; Print an error message
	MOVL	chf$l_sig_name(R2),-
		chf$l_mch_savr0(R3)
	CLRQ	-(SP)
	CALLS	#2,G^SYS$UNWIND
	RET

;++
;	Do_Continue - Print an error message then continue
;
; Input:
;	4(AP) - address of signal array
;	8(AP) - address of mechanism array
;--

.entry Do_Continue,^M<R2,R3,R4,R5>
	MOVL	4(AP),R2			; Get signal array
;	MOVL	8(AP),R3			; Get mechanism array
	SUBL	#2,chf$l_sig_args(R2)		; decrement arg count
	CLRL	-(SP)
	CLRL	-(SP)
	CLRL	-(SP)
	PUSHL	R2
	CALLS	#4,G^SYS$PUTMSG			; Print an error message
	MOVL	#SS$_CONTINUE,R0
	RET


;++
;	Do_Exit - Print an error message then exit image
;
; Input:
;	4(AP) - address of signal array
;	8(AP) - address of mechanism array
;--

.entry Do_Exit,^M<R2,R3,R4,R5>
	MOVL	4(AP),R2			; Get signal array
	MOVL	8(AP),R3			; Get mechanism array
	SUBL	#2,chf$l_sig_args(R2)		; decrement arg count
	CLRL	-(SP)
	CLRL	-(SP)
	CLRL	-(SP)
	PUSHL	R2
	CALLS	#4,G^SYS$PUTMSG			; Print an error message
	MOVL	chf$l_sig_name(R2),-
		chf$l_mch_savr0(R3)
	PUSHL	chf$l_sig_name(R2)
	BISL	#STS$M_INHIB_MSG,(SP)
	CALLS	#2,G^SYS$EXIT
	RET

;++
;	FTS_Routine_Handler - Caught a signal
;
; Functional Description:
;	Conditions that occure while processing FTS commands
;	come through here.  We decide whether to continue,
;	exit the image, or unwind back to the FTS> prompt.
;	We also handle internal signals here, like ACCVIO.
;
; Input:
;	4(AP) - address of signal array
;	8(AP) - address of mechanism array
;	12(AP) - address of enable array
;
;--

.entry FTS_Routine_Handler,^m<R2,R3,R4,R5>

	MOVL	4(AP),R1			; Get signal array
	MOVL	chf$l_sig_name(R1),R1
	CMPL	R1,#SS$_UNWIND			; An unwind signal?
	BNEQ	20$				; br if not
	MOVL	#SS$_NORMAL,R0
	BRB	100$
20$:	; Something as common and nasty as an ACCVIO we want to pass on
	CMPL	R1,#SS$_ACCVIO			; An accvio?
	BEQL	25$				; br if not
	CMPL	R1,#SS$_ROPRAND			; Reserved operand?
	BEQL	25$				; br if not
	CMPL	R1,#SS$_TBIT			; Trace failure?
	BEQL	25$				; br if not
	CMPL	R1,#SS$_RADRMOD			; Reserved address mode?
	BEQL	25$				; br if not
	CMPL	R1,#SS$_DEBUG			; the DEBUG signal
	BEQL	25$				; br if not
	BRB	30$
25$:	MOVL	R1,R0
	BRB	100$

30$:	; Call one of the routines above to handle the signal
	PUSHL	8(AP)				; Push mech array
	PUSHL	4(AP)				; Push Signal array
	CALLS	#2,Do_Abort
;	CALLS	#2,Do_Continue
;	CALLS	#2,Do_Exit
100$:	RET



.EXTERNAL	FTS_Get_Input
prompt:	.ASCID /FTS> /
Hello_Sailor_str:
   .ASCID /Hello, sailor!!!\nFor assistance, type 'HELP' at the FTS> prompt./

;++
;	Do_Parse - Run the command line through DCL
;
; Functional Description:
;	A routine to call the CLI$DCL_Parse routine with the right
;	arguements.  The reason that this isn't inline is because it
;	sets up the condition handler for handling the errors and
;	warnings and Control_C situations.
;
;	So, if someone types Control_C while getting input, he
;	will handle the Control_C in the appropriate fashion.
;
; Input:
;	None
;
; Values Returned:
;
;	1) Anything returned by the CLI Routines. Or
;	2) Anything that FTS_GET_INPUT would return.
;
; Note: that some CLI routine values are signalled others are merely
;	returned.
;--

.entry	Do_Parse,^m<R2,R3,R4,R5>

	; Establish a condition handler
	MOVAB	FTS_Routine_Handler,(FP)

	CLRQ	-(SP)
	MOVB	#DSC$K_DTYPE_T,2(SP)
	MOVB	#DSC$K_CLASS_D,3(SP)
	MOVL	SP,R2

	CLRL	-(SP)
	PUSHL	SP				; pointer to length
	PUSHAB	prompt				; pointer to prompt descriptor
	PUSHL	R2				; push input string descriptor
	CALLS	#3,FTS_Get_Input		; Get the command line
	CMPL	R0,#RMS$_EOF			; End of input?
	BEQL	100$				; if so, ignore it
	BLBC	R0,110$				; br on error

	POPL	R3				; Get the line length
	BEQL	20$
	MOVL	@4(R2),R4
	CMPB	R4,#^A/?/
	BNEQ	20$
	PUSHL	Hello_Sailor_str
	CALLS	#1,Print_String
	MOVL	#SS$_NORMAL,R3
	BRB	30$

20$:	; Send the line down to DCL to be parsed
	CLRL	-(SP)
	CLRL	-(SP)
	CLRL	-(SP)
	PUSHAB	FTS_parse
	PUSHL	R2
	CALLS	#5,G^CLI$DCL_PARSE
	MOVL	R0,R3

30$:	; Free up the command line string
	PUSHL	R2
	CALLS	#1,G^STR$FREE1_DX
	BLBC	R0,110$

	MOVL	R3,R0
100$:	RET

110$:	; Signal this error
	PUSHL	R0
	CALLS	#1,G^LIB$SIGNAL
	BRB	100$



;++
;	FTS_Dispatch - 
;
; Functional Description:
;
;	This routine simply calls CLI$DISPATCH.  The reason we don't
;	call CLI$DISPATCH directly is that we might want to attach
;	a condition handler to this stack frame.  Then, when a command
;	fails, we can unwind back to this point.
;
; Input:
;	None.
;
; Output:
;	Whatever the dispatched routines return.
;--

.entry FTS_Dispatch,^m<R2,R3,R4,R5>
	MOVAB	FTS_Routine_Handler,(FP)

	CALLS	#0,G^CLI$DISPATCH
	RET



;++
;	Command_Loop
;
; Functional Description:
;	This routines prompts for the command and then
;	dispatches to the correct routine.
;--

.entry Command_Loop,^m<R2,R3,R4,R5>

10$:
	CALLS	#0,Do_Parse
	BLBC	R0,20$
	CALLS	#0,FTS_Dispatch
20$:	CMPL	R0,#RMS$_EOF
	BEQL	100$
	BRB	10$

100$:	MOVL	#SS$_NORMAL,R0
	RET



;++
;	Check_Invocation_Line
;
; Functional Description:
;	Parse the arguements on the command line when program invoked.
;--

.entry Check_Invocation_Line,^m<R2,R3,R4,R5>

	; Establish a condition catcher
;	MOVAB	FTS_Routine_Handler,(FP)

	; Read command line
	CLRQ	-(SP)				; build descriptor
	MOVB	#DSC$K_DTYPE_T,2(SP)
	MOVB	#DSC$K_CLASS_D,3(SP)
	MOVL	SP,R5
	CLRL	-(SP)				; longward for length
	MOVL	SP,R2

	CLRL	-(SP)				;
	PUSHL	R2				; pointer to length
	CLRL	-(SP)				;
	PUSHL	R5				; Input line descriptor
	CALLS	#4,G^LIB$GET_FOREIGN		; read in the line
	BLBS	R0,10$
	BRW	100$

10$:	POPL	R0
	BEQL	100$
	MOVL	@4(R5),R4
	CMPB	R4,#^A/?/
	BNEQ	20$
	PUSHL	Hello_Sailor_str
	CALLS	#1,Print_String
	MOVL	#SS$_NORMAL,R3
	BRB	30$

20$:	; Send the line down to DCL to be parsed
	CLRL	-(SP)
	CLRL	-(SP)
	CLRL	-(SP)
	PUSHAB	FTS_parse
	PUSHL	R5				; Input line descriptor
	CALLS	#5,G^CLI$DCL_PARSE
	BLBS	R0,25$
	MOVL	#SS$_NORMAL,R0
	BRB	100$
25$:	CALLS	#0,FTS_Dispatch
	MOVL	R0,R3

30$:	; Free up the command line string
	PUSHL	R5
	CALLS	#1,G^STR$FREE1_DX
	BLBC	R0,110$

;	MOVL	R3,R0
	MOVL	#SS$_NORMAL,R0
100$:	RET

110$:	; Signal this error
	PUSHL	R0
	CALLS	#1,G^LIB$SIGNAL
	BRB	100$



.EXTERNAL FTS_SMG_Init

.entry	FTS_Init,^m<R2,R3,R4,R5>

	; Declare the exit handler block
	PUSHAB	exh_block
	CALLS	#1,G^SYS$DCLEXH
	BLBC	R0,110$

	; Initialize the terminal interface
	CALLS	#0,FTS_SMG_Init

100$:	RET

110$:	; Signal this error
	PUSHL	R0
	CALLS	#1,G^LIB$SIGNAL
	BRB	100$



;++
;	main - image entry point
;
; Functional Description:
;	The main routine.  Parse the arguements. Get the log file.
;	Start the I/O. Then Hibernate while the AST's do all the
;	work.
;--

.entry main,^m<R2,R3,R4,R5>

	; Establish a condition handler, first thing
	MOVAB	FTS_Handler,(FP)

	; Do initialization
	CALLS	#0,FTS_Init

	; Invoked with a command line?
	CALLS	#0,Check_Invocation_Line
	BLBS	R0,100$				; if not, EXIT

10$:	CALLS	#0,Command_Loop
	MOVL	#SS$_NORMAL,R0

100$:
	PUSHL	R0
	CALLS	#1,G^SYS$EXIT
	RET

.END main
