C*****************************************************************************
C	Subroutines for establishing & using the DCL subprocess.
C*****************************************************************************
C
C  Revisions (Version 6.x)            August, 1986
C	Dale E. Coy
C	Los Alamos National Laboratory
C	(505) 667-3270
C
C*****************************************************************************
C--------------------------------------------------------------------
C	Create Mailbox and Open unit for MailBox Output
C--------------------------------------------------------------------
	Subroutine Setup_For_DCL
	
	Integer Stat
	Integer*4 MaxMsg
	Integer*2 Dst_Len
	Character*20 TTname

	Include	'($LNMDEF)'
	Include 'Common.Dat'
	
	Data MaxMsg /256/
	
	Structure /TrnLnm_Item_List/
	  Integer*2 BufLen
	  Integer*2 Code		/LNM$_String/
	  Integer*4 Dst_Address
	  Integer*4 Length_Address
	  Integer*4 End_List		/0/
	End Structure

	Record /TrnLnm_Item_List/ T_ItmLst

C-------------------------------------------------------------------

	STAT = Sys$Crembx(,%Ref(Channel),,,,,%Descr(Mbx_Name))

C 	Call Lib$Sys_Trnlog('TT',%Ref(Dst_Len),%Descr(TTname))
C 	Call Lib$Sys_Trnlog('SYS$COMMAND',%Ref(Dst_Len),%Descr(TTname))
	
	T_ItmLst.BufLen			=	LEN(TTname)
	T_ItmLst.Dst_Address		=	%LOC(TTname)
	T_ItmLst.Length_Address		=	%LOC(Dst_Len)
	
	TTname = ' '
	Call SYS$TrnLnm(LNM$M_Case_Blind, 'LNM$FILE_DEV', 
	1	'SYS$COMMAND',, T_ItmLst)
	
1000	K = Index (TTname(:Dst_Len),'__')
	If (K .NE. 0) then
		TTname (K:) = TTname (K+1:)
		Dst_Len = Dst_Len - 1
		Go To 1000
	End If
	Call Lib$Set_Logical('SYS$COMMAND',%Descr(TTname(:Dst_Len)))


	Stat = Lib$Get_Lun (Mbx_Lun)
	Open(Unit=Mbx_Lun,File=Mbx_Name,CarriageControl = 'List',
  	1	Recl = MaxMsg, Status = 'New', Shared)

	If (.NOT.Have_SubProcess) Call Create_SubProcess

	Have_DCL_Setup = .TRUE.

	Return
	End

C--------------------------------------------------------------------
C	Handle Unexpected Exit from SubProcess
C--------------------------------------------------------------------
	Subroutine Subprocess_Quit_AST
	Integer*4 Stat
	Integer*4 New_Mbx_Lun
	Character*255 Dummy
	Include 'Common.Dat'

C--------------------------------------------------------------------

	If (Have_SubProcess) then   ! Necessary to handle forced exit.
	  Have_SubProcess = .FALSE.
          If (Doing_Command) then
	      Stat = Lib$Get_Lun (New_Mbx_Lun)
	      Open(Unit=New_Mbx_Lun,File=Mbx_Name,
	1	 CarriageControl = 'List',Status = 'New',Shared)
	      Read(New_Mbx_Lun,1000) Dummy
	  Else
	      Call Sys$Cancel (%Val(Channel))
	  End If

1000	Format (A)

	End If

	Return
	End


C--------------------------------------------------------------------
C	Create DCL SubProcess
C--------------------------------------------------------------------
	Subroutine Create_SubProcess
	Integer*4 Stat
	Include 'Common.Dat'

	EXTERNAL SUBPROCESS_QUIT_AST
C--------------------------------------------------------------------

	Call SMG$Paste_Virtual_Display (Working_Display,
	1		Pasteboard_ID,1,1)
	Call SMG$Flush_Buffer (Pasteboard_ID)

	Doing_Command = .FALSE.

	Stat = LIB$SPAWN(,%Descr(Mbx_Name),
	1      %Descr('TT:'),%Ref(1),,%Ref(Process_ID),,,
	2	SUBPROCESS_QUIT_AST)


	Have_SubProcess = .TRUE.
	Call SMG$UnPaste_Virtual_Display (Working_Display,
	1		Pasteboard_ID)

	Return
	End

C--------------------------------------------------------------------
C	Do one DCL command, when we want to open a "window" for
C	output to the screen.  Used for /LOG internal DM
C	functions (copy, purge, etc....)
C--------------------------------------------------------------------
	Subroutine Do_Controlled_DCL

	Implicit Integer*4 (A-Z)

	Integer*4 Saved_Display_ID
	Integer*4 Window_Top, Window_Bottom, Window_Left

	Include 'Common.Dat'
	Data Window_Top    / 3/
	Data Window_Bottom /10/
	Data Window_Left   / 1/
C-------------------------------------------------------------------

1000	Format (A)
  
	If (.NOT.Have_DCL_Setup)  Call Setup_For_DCL
	If (.NOT.Have_SubProcess) then
		Call Create_SubProcess
	End If
                 
C		Can't Use SMG$ -- DCL Insists it has the whole thing.
C		But ... we're going to "fake" it
C		We use a window, and then a "save" inside the window.
C		Window1 is 8x80 and bordered.

	Call SMG$Erase_Display (Window1_Display)

	Call SMG$Paste_Virtual_Display (Window1_Display,Pasteboard_ID,
	1	Window_Top,Window_Left)

	Call SMG$Set_Physical_Cursor (Pasteboard_ID, 
	1	Window_Top,Window_Left)

	Call SMG$Save_Physical_Screen (Pasteboard_ID,
	1	 Saved_Display_ID,Window_Top,Window_Bottom)

	Call SMG$Set_Display_Scroll_Region (Window1_Display)

 	Write (Mbx_Lun,1000) CmdLine1
	Write (Mbx_Lun,1000) CmdLine2

	Doing_Command = .TRUE.
	Write (Mbx_Lun,1000) Exit_Com

	Write (Mbx_Lun,1000) '$'

C	Call Lib$Wait (Wait_Time)

        Call Mess_Wait (' DM Operation Complete')	

	Call SMG$Set_Cursor_Abs (Files_Display, Current_Line, 1)

	Call SMG$Begin_Pasteboard_Update (Pasteboard_ID)

	Call SMG$Restore_Physical_Screen (Pasteboard_ID,
	1	 Saved_Display_ID)

	Call SMG$Unpaste_Virtual_Display (Window1_Display,Pasteboard_ID)

	If (.NOT.ReLoad) 
	1	Call SMG$End_Pasteboard_Update (Pasteboard_ID)

	Doing_Command = .FALSE.

	Return
	End

C--------------------------------------------------------------------
C  DO_NoShow_DCL
C     	Do one DCL command, when we know the result WILL not do
C	something funny to the screen.  Used for internal DM
C	functions ( purge, etc....) where /LOG is not used.
C	NOTE: Any error can really garbage up the screen here.
C--------------------------------------------------------------------
	Subroutine Do_NoShow_DCL
	Integer*4 Saved_Display,Screen_Line
                             
	Include 'Common.Dat'

C-------------------------------------------------------------------

1000	Format (A)
  
	If (.NOT.Have_DCL_Setup)  Call Setup_For_DCL
	If (.NOT.Have_SubProcess) then
		Call Create_SubProcess
	End If

	Write (Mbx_Lun,1000) CmdLine1
  	Write (Mbx_Lun,1000) CmdLine2

	Doing_Command = .TRUE.
	Write (Mbx_Lun,1000) Exit_Com

	Write (Mbx_Lun,1000) '$'

C	Call Lib$Wait (Wait_Time)

	Doing_Command = .FALSE.

	Return
	End

C--------------------------------------------------------------------
C  DO_Immediate_DCL
C     	Do one DCL command, when we know the result WILL not do
C	something funny to the screen, and where we won't wait for
C	the results.  Used for things like setting the default directory
C	for the subprocess.
C	NOTE: Any error can really garbage up the screen here.
C--------------------------------------------------------------------
	Subroutine Do_Immediate_DCL
	Integer*4 Saved_Display,Screen_Line
                             
	Include 'Common.Dat'

C-------------------------------------------------------------------

1000	Format (A)
  
	If (.NOT.Have_DCL_Setup)  Call Setup_For_DCL
	If (.NOT.Have_SubProcess) then
		Call Create_SubProcess
	End If

	Write (Mbx_Lun,1000) CmdLine1
  	Write (Mbx_Lun,1000) CmdLine2

	Doing_Command = .TRUE.
	Write (Mbx_Lun,1000) Exit_Com

C	Write (Mbx_Lun,1000) '$'
C	Call Lib$Wait (Wait_Time)

	Doing_Command = .FALSE.

	Return
	End

C--------------------------------------------------------------------
C  DO_Hidden_DCL
C     	Do one DCL command, when we know the result should not do
C	something funny to the screen.  Used for internal DM
C	functions (copy,  etc....) where /LOG is not used.
C	NOTE: We DO provide a 2-line scrolling region, in case of errors.
C--------------------------------------------------------------------
	Subroutine Do_Hidden_DCL
	Integer*4 Saved_Display,Screen_Line

	Include 'Common.Dat'

C-------------------------------------------------------------------

1000	Format (A)
  
	If (.NOT.Have_DCL_Setup)  Call Setup_For_DCL
	If (.NOT.Have_SubProcess) then
		Call Create_SubProcess
	End If

C		Create somewhere to put a short message or (horrors)
C		the process-exit message from the subprocess.
	Screen_Line = Current_Line - TopLine + 1
	If (Screen_Line .GE. 22) Screen_Line = 21

	Call SMG$Save_Physical_Screen (Pasteboard_ID,Saved_Display,
	1	Screen_Line, Screen_Line + 1 )


	Write (Mbx_Lun,1000) CmdLine1
  	Write (Mbx_Lun,1000) CmdLine2

	Doing_Command = .TRUE.
	Write (Mbx_Lun,1000) Exit_Com

	Write (Mbx_Lun,1000) '$'

C	Call Lib$Wait (Wait_Time)              

	Call SMG$Restore_Physical_Screen (Pasteboard_ID,Saved_Display)

	If (ReLoad) Call SMG$Begin_Pasteboard_Update (Pasteboard_ID)

	Doing_Command = .FALSE.

	Return
	End

C--------------------------------------------------------------------
C--------------------------------------------------------------------
C	Do one DCL command, when we must have the entire screen.
C	Used for "one-line" DCL commands ($ Command).
C	Holds screen upon return.
C	Assumes that we won't know the state of file upon return,
C		so ReLoad is set automatically
C--------------------------------------------------------------------
	Subroutine Do_One_DCL
	Integer*4 Saved_Display_ID

	Include 'Common.Dat'

C-------------------------------------------------------------------

1000	Format (A)                        
  
	If (.NOT.Have_DCL_Setup)  Call Setup_For_DCL
	If (.NOT.Have_SubProcess) then
		Call Create_SubProcess
	End If
                 

C 		Cover up everything
	Call SMG$Erase_Display (Window2_Display)
	Call SMG$Paste_Virtual_Display (Window2_Display,
	1	Pasteboard_ID,1,1)
	
C	Call SMG$Erase_Display (Line23MSG_Display)
	Call SMG$Put_Line (Line23MSG_Display,Blanks,0,
	1		SMG$M_Reverse,SMG$M_Reverse)
	Call SMG$Paste_Virtual_Display
	1	 (Line23MSG_Display,Pasteboard_ID,23,1)

	Call SMG$Erase_Display (Line24MSG_Display)
	Call SMG$Paste_Virtual_Display
	1	 (Line24MSG_Display,Pasteboard_ID,24,1)


 	Write (Mbx_Lun,1000) CmdLine1
	Write (Mbx_Lun,1000) CmdLine2

	Doing_Command = .TRUE.
	Write (Mbx_Lun,1000) Exit_Com

  	Write (Mbx_Lun,1000) '$'

C	Call Lib$Wait (Wait_Time)

50	If (.NOT.Have_SubProcess) then
		Call Create_SubProcess
	End If
C 		Scroll up so we have lines for message
	Write (Mbx_Lun,1000) 'Write SYS$OUTPUT " "'
	Write (Mbx_Lun,1000) 'Write SYS$OUTPUT " "'
	Write (Mbx_Lun,1000) 'Write SYS$OUTPUT " "'

	Call Lib$Wait (Wait_Time)
	Doing_Command = .FALSE.

        Call Mess_Wait (' DM Operation Complete')	

	Call SMG$Erase_Pasteboard (Pasteboard_ID)
	
	Call SMG$Begin_Pasteboard_Update (Pasteboard_ID)

	Call SMG$UnPaste_Virtual_Display (Window2_Display,Pasteboard_ID)
	Call SMG$UnPaste_Virtual_Display (Line23MSG_Display,Pasteboard_ID)
	Call SMG$UnPaste_Virtual_Display (Line24MSG_Display,Pasteboard_ID)


	ReLoad = .TRUE.

	Return
	End

C--------------------------------------------------------------------
C	Do Single DCL command, when we must have the entire screen.
C	Used for "single" DCL commands Edit, More, etc.
C	Does NOT hold screen upon return.
C	Assumes that we won't know the state of file upon return,
C		so ReLoad is set automatically
C--------------------------------------------------------------------
	Subroutine Do_Single_DCL
	Integer*4 Saved_Display_ID

	Include 'Common.Dat'

C-------------------------------------------------------------------

1000	Format (A)                        
  
	If (.NOT.Have_DCL_Setup)  Call Setup_For_DCL
	If (.NOT.Have_SubProcess) then
		Call Create_SubProcess
	End If
                 

	Call SMG$Save_Physical_Screen (Pasteboard_ID,
	1	 Saved_Display_ID,1,24)
	Call SMG$Erase_Pasteboard (Pasteboard_ID)
	Call Lib$Wait (Wait_Time)

	Call SMG$Set_Cursor_Abs (Files_Display, TopLine+2, 1)

 	Write (Mbx_Lun,1000) CmdLine1
	Write (Mbx_Lun,1000) CmdLine2

	Doing_Command = .TRUE.
	Write (Mbx_Lun,1000) Exit_Com

	Write (Mbx_Lun,1000) '$'

C	Call Lib$Wait (Wait_Time)


	Call SMG$Erase_Pasteboard (Pasteboard_ID)

	Call SMG$Begin_Pasteboard_Update (Pasteboard_ID)

	Call SMG$Restore_Physical_Screen (Pasteboard_ID,
	1	 Saved_Display_ID)



	ReLoad = .TRUE.

	Doing_Command = .FALSE.

	Return
	End

C--------------------------------------------------------------------
C	Go out to DCL.  Come back when an "empty" CR is entered.
C--------------------------------------------------------------------
	Subroutine GoTo_DCL
	Implicit Integer*4 (A-Z)
	Integer*4 Max_Length
	Integer*2 Input_Length, K
	Character*255 Input

	Include 'Common.Dat'
	Data Max_Length /255/                   
C-------------------------------------------------------------------


	If (.NOT.Have_DCL_Setup)  Call Setup_For_DCL
	If (.NOT.Have_SubProcess) then
		Call Create_SubProcess
	End If


	Call SMG$Save_Physical_Screen (Pasteboard_ID,
	1	 Saved_Display_ID,1,24)
	Call SMG$Erase_Pasteboard (Pasteboard_ID)

	Call SMG$Set_Cursor_Abs (Files_Display, TopLine+2, 1)

	Doing_Command = .TRUE.

	
C 		Fix the terminal mode
	Call Fix_Spawned_Terminal

10	Call Lib$Get_Command (Input,%Descr('$ '),%Ref(Input_Length))

	If ((Input .NE. ' ').AND.(Input_Length.GT.0)) then

		If (.NOT.Have_SubProcess) Call Create_SubProcess

1000	Format (A)
 		Write (Mbx_Lun,1000) CmdLine1
		Write (Mbx_Lun,1000) CmdLine2

		Write (Mbx_Lun,1000) '$ '//Input(:Input_Length)


		If (.NOT.Have_SubProcess) Call Create_SubProcess

		Write (Mbx_Lun,1000) '$'

		Call Lib$Wait (Wait_Time)
		GoTo 10
	End If

C		In case the subprocess directory was changed..

	Call Str$Trim (%Descr(Current_Device)
	1		,%Descr(Current_Device),%Ref(K))
	Exit_Com = 'SET DEFAULT '//Current_Device(:K)//Current_Dir
	Call Do_Immediate_DCL
	
C 		Make sure the terminal mode is correct.
	Call Restore_Spawned_Terminal
	
	Call SMG$Erase_Pasteboard (Pasteboard_ID)

	Call SMG$Begin_Pasteboard_Update (Pasteboard_ID)

	Call SMG$Restore_Physical_Screen (Pasteboard_ID,
	1	 Saved_Display_ID)

	Doing_Command = .FALSE.


	ReLoad = .TRUE.

	Return
	End

C--------------------------------------------------------------------
C--------------------------------------------------------------------
	Subroutine Cancel_DCL

	Include 'Common.Dat'

C-------------------------------------------------------------------

	Doing_Command = .FALSE.

	If (Have_SubProcess) then
		Have_SubProcess = .FALSE.
		Call Sys$Delprc (%Ref(Process_ID))
	End If

	If (Have_DCL_Setup) then
		Close (Mbx_Lun)
		Have_DCL_Setup  = .FALSE.
	End If

	Return
	End

