[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference noted::hackers_v1

Title:-={ H A C K E R S }=-
Notice:Write locked - see NOTED::HACKERS
Moderator:DIEHRD::MORRIS
Created:Thu Feb 20 1986
Last Modified:Mon Aug 03 1992
Last Successful Update:Fri Jun 06 1997
Number of topics:680
Total number of notes:5456

410.0. "forcing input to a process" by AIWEST::MATTHEWS (San Diego, Ca. Fightertown, USA) Sat Feb 14 1987 00:41

	I brought this note over from the TOOLSHED notesfile. Figured you 
guys could help him.  

Hmmm...  I wonder what he wants this for???  8-|


>>>cameron


               <<< VNX::METOO$:[NOTES$LIBRARY]TOOLSHED.NOTE;2 >>>
                                 -< TOOLSHED >-
================================================================================
Note 433.0             wanted - force input on terminal               11 replies
TAV02::ISHAI                                          4 lines   5-JAN-1987 04:15
--------------------------------------------------------------------------------

    I am looking for a tool to force input on terminal (e.g writing
    to its type-ahead buffers from external process.
    
    						Thanks  ..AI..


T.RTitleUserPersonal
Name
DateLines
410.1FORCE for VMS V3SNO78C::CLARKEOvercome evil with good.Sun Feb 15 1987 22:4412
    I have such a program which worked for VMS V3. But somebody must
    have moved the terminal buffers since then. It would be great if
    someone has a V4 version, or can upgrade this one.
    
    The author is G. Davies. It requires CMKRNL and WORLD privs.
    
    sno78c::usersc_3:[clarke.goodies]force.mar	- the actual routine
    sno78c::usersc_3:[clarke.goodies]nasty.for	- a shell to make it
						    easier to use
    
    			Mat.   
    
410.2I can hear it coming8509::LASTOVICANorm LastovicaWed Feb 18 1987 00:553
    Not to be excited, but in a few days, I'll have a slick new version
    that is V4 compatable (among other things) of the code mentioned
    in .-1.  I'll post the results here.
410.3It was a long few days till I looked at itYALI::LASTOVICAStuck in a Lather-Rinse-Repeat loopSat Mar 28 1987 02:2817
    Ok Kids, here it is.  FORCE.MAR is much nicer and uses an internal
    routine to get the device UCB address and handles virtual terminals
    now (rather than the rude system crash that one used to get).  Other
    than that, the macro is about what it used to be.
    
    The BASIC code here (I call it F.BAS) is crude and gross, it is
    just the interface that I use.  No comments about the code, I hate
    it too.  Anyhow, after linking the two together, just enter the
    terminal name and then lines and lines of text.  Put a "^" in front
    of any character that you want to be a control character (like the
    old RSTS UT FORCE) and end a line with a "\" if you don't want a
    carriage return appended to the line.
    
    The first reply is the macro and the second is the basic.  The code
    here works just fine on my X4.6 and 4.5 systems, however, as typical,
    no promises.  Good luck, happy hacking and don't call me to look 
    at any crash dumps.  ;-)
410.4FORCE.MARYALI::LASTOVICAStuck in a Lather-Rinse-Repeat loopSat Mar 28 1987 02:29406
	.TITLE FORCE
	.IDENT "X01-020"
; 
;  ****************************************************************************
;  *									      *
;  *  COPYRIGHT (c) 1987                                                      *
;  *  BY DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS.			      *
;  * 								              *
;  *  THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND  COPIED  *
;  *  ONLY  IN  ACCORDANCE  WITH  THE  TERMS  OF  SUCH  LICENSE AND WITH THE  *
;  *  INCLUSION OF THE ABOVE COPYRIGHT NOTICE.  THIS SOFTWARE OR  ANY  OTHER  *
;  *  COPIES  THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY  *
;  *  OTHER PERSON.  NO TITLE TO AND OWNERSHIP OF  THE  SOFTWARE  IS  HEREBY  *
;  *  TRANSFERRED.							      *
;  * 									      *
;  *  THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE  WITHOUT  NOTICE  *
;  *  AND  SHOULD  NOT  BE  CONSTRUED  AS  A COMMITMENT BY DIGITAL EQUIPMENT  *
;  *  CORPORATION.							      *
;  * 									      *
;  *  DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR  RELIABILITY  OF  ITS  *
;  *  SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.		      *
;  *									      *
;  ****************************************************************************
;
; Facility:	Force input passed characters into a terminals typeahead 
;		buffer and from there into any outstanding read I/O requests.
;
; Abstract:	The particular terminals UCB is located from VMS's device 
;		tables. From there the typeahead buffer is located and 
;		the passed characters and inserted if there is room.
;		The terminal class driver routine TTY$PUTNEXTCHAR is used, 
;		this routine can be located from the UCB$L_TT_PUTNXT 
;		longword located in the UCB of the particular terminal device.
;		Since the class driver routine is used, much device
;		independence exists and all character codes are interpreted
;		including control sequences.
;
; Author:	G. Davies		20-Jan-1984
;		Concept stolen from a program "SPY" written by A. R. Fleig
;
; Modifications: 
;	18-Feb-1987	norm lastovica	csc/cs
;		Use IOC$SEARCHDEV to simplify finding the UCB.  Clean up
;	code further to make things simpler.  change little functionality.
;
; Notes:
;
;		CMKRNL and WORLD privileges are required.
;
; Calling standard:
;	Two parameters are needed, the first is the device name
;	passed by descriptor.  This needs to be the device name
;	or logical.  This will be passed to $GETDVI to return the
;	'real' terminal name.  This 'real' name string is passed to 
;	IOC$SEARCHDEV which will return the UCB and DDB addresses 
;	(though we only care about the UCB address here).
;
;	The second parameter is the string to be forced passed by
;	descriptor, it must be longer that zero characters but less than
;	or equal to 80 characters. If this is not true the status
;	SS$_BADPARAM will be returned.
;
;	The status of this routine is passed back in register zero.
;	Attempting to pass less or more than two parameters will 
;	return the status SS$_BADPARAM.
;
; Restrictions:	
;		It was found that if echo is set on the terminal
;	that is being forced to, the current read I/O if any
;	completes with the status SS$_TIMEOUT. This appears to
;	happen as soon as the first character forced to the terminal.
;	The following characters are forced without error. 
;		Fow example suposing the target terminal is at DCL
;	and the string "SH USERS" was forced.  The target terminal
;	would display the error "RMS-W-TMO, timeout" and then
;	display "H USERS" which would execute the HELP USERS command.
;	This only happened if there was an outstanding read I/O to
;	the terminal. For example if the target terminal was
;	executing a DCL WAIT command when the string above was
;	forced, on completion of the WAIT command the entire forced
;	string would echo and execute correctly. 
;		The application of this subprogram did not require
;	echo so before the force begin's the terminal is set to
;	noecho, and this is reversed afterwards. Note that the mode
;	or characteristics of the terminal are not changed but only
;	the current status of the current I/O request if any is
;	modified. So even with using the SET_ECHO and SET_NOECHO
;	routines, if there is no outstanding read I/O active on the
;	target terminal all characters echo correctly. 
;
; 17-Feb-1987
;		The current restriction seems to be that the first 
;	character is tossed when echo is not disabled.  However, 
;	the timeout message is not seen.  Initial investigation 
;	shows that the TTCHARI and TTCHARO routines do some strange 
;	things when doing echo and this could explain the missing characters.
;	The echo does not seem to happen real time anyhow, so there 
;	may be more going on here than meets the eye.  There are 
;	other entry points in the terminal driver code that may be 
;	usefull here...
; 

; 
; Include files:
;
	.LIBRARY	"SYS$LIBRARY:LIB.MLB"	;Use 'special' macro library
	.LINK		"sys$system:sys.stb"/se

	$DCDEF				;Device Characteristics
	$DDBDEF				;Device Data Block Offsets
	$IODEF				;I/O Function Codes
	$JPIDEF				;GETJPI definitions
	$TTDEF				;Terminal codes
	$TTYDEFS			;Terminal driver UCB extension offsets
	$UCBDEF				;Unit Control Block offsets
	$TTYMACS			;Terminal driver routines
	$DCDEF
	$DVIDEF
	
; Local storage.

	.PSECT	RWDATA, NOEXE, WRT, LONG

;
;	Remote terminal specification
;
RT_TERMINAL:
	.ASCII	/RT/

LOCK_DATA_START:		; page(s) from here to lock_data_end are	;-------+
				; locked into memory to prevent paging at		;
				; elevated IPL						;
											;	These
FORCE_LENGTH:	.WORD	0		; Length of string to force			;	bytes
FORCE_STRING:	.BLKB	80		; Buffer for string to force			;	are
FORCE_CHAR:	.BYTE	0		; Individual character to force for 		;	required
 					;  for each call to FORCE_INTO_TYPEAHEAD	;	to
 											;	be
UCBADR:		.BLKL	1		;UCB address of target terminal			;	locked
 											;
FORK_IPL:	.LONG	11		;IPL for terminal data access synchronisation	;
CURRENT_ECHO:	.BYTE	0		;Original state of echo/noecho indicator	;
					; for terminal line				;
DEVICE_NAME:	.BLKL	1		; points to the device name string desc		;
 											;
LOCK_DATA_END:									;-------+

;
; Control blocks to lock necessary pages in physical memory
;
LOCK_DATA:	.ADDRESS	LOCK_DATA_START
		.ADDRESS	LOCK_DATA_END

LOCK_CODE:	.ADDRESS	LOCK_CODE_START
		.ADDRESS	LOCK_CODE_END

;
; build a string descriptor for the physical device name.  $GETDVI will
; fill in the name length and the string.  We'll save room for 32 bytes
; of device name here.  Probably overkill, but not something that we'd
; want to risk!
;
real_name_desc:				; our descriptor
real_name_len:	.long			; resultant string length
		.address real_name_str	; pointer to the string 
real_name_str:	.blkb	32		; save room for 32 bytes of string

;
; Item list for getdvi system service
;
GETDVI_LIST:
	.WORD		4
	.WORD		DVI$_DEVCLASS
	.ADDRESS	DEVICE_CLASS		; check to be sure a terminal
	.LONG		0

	.word		32			; max string of 32 bytes back
	.word		dvi$_tt_phydevnam	; get the device name
	.address	real_name_str		; point to the string space
	.address	real_name_len		; put the returned length here

	.LONG		0			; end GETDVI item list

DEVICE_CLASS:					; save device class here
	.LONG		0
	
	.PSECT CODE, EXE, NOWRT, LONG

	.DEFAULT DISPLACEMENT, WORD

	.ENTRY	FORCE, ^M<R2, R3, R4, R5, R8, R9, R10, R11>
;
; Try and lock required data and code pages in memory
;
	$LKWSET_S	INADR=LOCK_DATA		; lock the data
	BLBS	R0,5$				; success??
	BRW	CRASH				; nope, error

5$:	$LKWSET_S	INADR=LOCK_CODE		; lock the code
	BLBS	R0,7$
	BRW	CRASH

;
; check the arguments to make sure there are 2 (ought to check for
; valid string descriptors to avoid damage later)
;
7$:	MOVL	(AP)+,R0			; Check number arguments
	CMPL	R0, #2				; must be 2
	BEQL	10$				; it is
	MOVL	#SS$_BADPARAM,R0		; it is not!
	BRW	CRASH				; complain

;
; save the device name address and get the device type and the physical
; device name from GETDVIW.  this allows logicals to be passed as well
; as virtual terminal names.
;
10$:	MOVL	(AP)+,R10			; Address of descriptor of terminal
	movl	r10,device_name			; save for later

15$:	$GETDVIW_S	EFN=#1,-
			DEVNAM=(R10),-
			ITMLST=GETDVI_LIST
	BLBS	R0,17$				; did the GETDVI go OK?
	BRW	CRASH				; not this time

;
; make sure the device requested is a terminal
;
17$:	CMPL	#DC$_TERM,DEVICE_CLASS		; is it a terminal??
	BEQL	CHECK_NOT_REMOTE		; yes
	MOVL	#SS$_DEVCMDERR,R0		; no, must be a mistake!!
	BRW	CRASH

;
; We cannot force to a remote terminal (but why??)
;
CHECK_NOT_REMOTE:
	MOVL	4(R10),R0			; Address of string
	MATCHC	#2,RT_TERMINAL,#4,(R0)		; Check for RT
	BNEQ	20$
	MOVL	#SS$_DEVCMDERR,R0		; was RT, no way!
	BRW	CRASH

20$:
;
; verify that the string passed is in bounds
;
	MOVL	(AP)+,R10			; Address of descriptor of force string
	TSTW	(R10)				; Check zero length
	BEQL	30$				; zero not allowed
	CMPW	(R10),#80			; Check too long
	BLEQ	40$				; it is OK

30$:	MOVL	#SS$_BADPARAM,R0		; can not do it
	BRW	CRASH				; get out with error

;
; move the string to our locked buffer
;
40$:	MOVW	(R10),FORCE_LENGTH		; Length of string
	MOVL	4(R10),R0			; Address of string
	MOVC3	FORCE_LENGTH,(R0),FORCE_STRING	; move passed string to buffer

;
; get the UCB address for the target terminal
;
50$:
test::
	$cmkrnl_s routin=search_unit	; determine the UCB address
	blbs	r0,90$			; did it work
	brw	crash			; nope.

90$:	MOVAL	FORCE_STRING,R10	; Address of string to force
	MOVZWL	FORCE_LENGTH,R9		; number of characters to force

;
; Set the terminal we are forcing at to noecho mode
;
	$CMKRNL_S	ROUTIN=SET_NO_ECHO
	BLBS	R0,COPY_LOOP
	BRW	CRASH

;
; Copy force string character by character into the terminal I/O 
; subsystem. Since many instructions may be executed to perform this
; action, and most processing is done at high IPL, one character is
; forced at a time so no latency problems are introduced when forcing
; long strings.
;
COPY_LOOP:
	MOVB	(R10)+,FORCE_CHAR	; move the next character
	$CMKRNL_S	ROUTIN=FORCE_INTO_TYPEAHEAD	; and send it
	BLBS	R0,100$
	BRW	CRASH

100$:	DECW	R9			; subtract one and go back
	BNEQ	copy_loop		; if they are not all moved

ALL_FORCED:
;
; Set terminal back to echo 
;
	$CMKRNL_S	ROUTIN=SET_ECHO
	BLBS	R0,10$
	BRW	CRASH

;
; Try and unlock pages previously tacked down
;
10$:	$ULWSET_S	INADR=LOCK_DATA
	BLBS	R0,20$
	BRW	CRASH

20$:	$ULWSET_S	INADR=LOCK_CODE
	BLBS	R0,30$
	BRW	CRASH

30$:	MOVL	#SS$_NORMAL,R0

CRASH:	RET


;
; Kernel mode routines.
;

LOCK_CODE_START:		; pages to be locked in memory start here,
				; end at lock_code_end

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Get UCB data.  Call IOC$SEARCHDEV passing the device name.  We will
; get back a UCB and DDB address in R1 and R2.  However, all we want is
; R1 (the UCB).  Save it in UCBADR for our caller.  See IOSUBPAGD.LIS
; for more information.
;

        .ENTRY	SEARCH_UNIT, ^M<R2, R3, R4, R5, R6, R7, R10, R11>

	moval	real_name_desc, r1	; get the device name descriptor
	
	DSBINT	FORK_IPL		; Raise IPL to lock the I/O database
	jsb	g^ioc$searchdev		; find the device
	ENBINT				; Reset IPL
	movl	r1,ucbadr		; save the UCB address
	ret				; status in R0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Set terminal driver status for this line to no echo by simply setting
; the bit in the state flag in the UCB.
;
        .ENTRY	SET_NO_ECHO, ^M<R2, R3, R4, R5, R6, R7, R10, R11>
	DSBINT	FORK_IPL		;Raise IPL
	MOVL	UCBADR,R5		;Unit control block address
	MOVAB	UCB$Q_TT_STATE(R5),R2	;Quadword of state bits 
	CLRB	CURRENT_ECHO		;Initialize our flag
	IF_STATE	NOECHO,10$	;Is noecho currently set - BR if so
	SET_STATE	NOECHO		;Set to noecho
	INCB	CURRENT_ECHO		; and set our flag

10$:	ENBINT				;Reset IPL
	MOVZWL	S^#SS$_NORMAL, R0	;Return with success
	RET

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Set terminal driver status for this line to original state of echo.
;
        .ENTRY	SET_ECHO, ^M<R2, R3, R4, R5, R6, R7, R10, R11>
	DSBINT	FORK_IPL		;Raise IPL
	MOVL	UCBADR,R5		;Unit control block address
	MOVAB	UCB$Q_TT_STATE(R5),R2	;Quadword of state bits 
	TSTB	CURRENT_ECHO		;Test whether echo was originally set
	BEQL	10$			;NO - so leave state as noecho
	CLR_STATE	NOECHO		;Set state to echo

10$:	ENBINT				;Reset IPL
	MOVZWL	S^#SS$_NORMAL, R0	;Return with success
	RET

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Force one character by using terminal class driver routine.  This will
; put the character into the typeahead buffer if there is one.  See
; TTCHARI.LIS in [TTDRVR] for more information.
;
        .ENTRY	FORCE_INTO_TYPEAHEAD, ^M<R2, R3, R4, R5, R6, R7, R10, R11>

	DSBINT	FORK_IPL		;Raise IPL.

	MOVL	UCBADR,R5		; Unit control block address
	MOVZBL	FORCE_CHAR,R3		; Character to force
	JSB	@UCB$L_TT_PUTNXT(R5)	; Prod terminal class driver for this
					; UCB

	ENBINT				;Reset IPL

	MOVZWL	S^#SS$_NORMAL, R0	;Return with success
	RET

LOCK_CODE_END:				; end of pages locked

	.END	
    
410.5F.BASYALI::LASTOVICAStuck in a Lather-Rinse-Repeat loopSat Mar 28 1987 02:3190
100	!
	! 	F . B A S
	!
	! using FORCE.MAR, force strings to other terminal's input buffer.
	! see the documentation in FORCE.MAR for more information.
	!
	! in the forced strings, a carat (^) preceeding another character will
	! cause the control character represented by the string to be passed
	! instead.  Unless the string is terminated by a backslash (\), the
	! string will be sent with a terminating carriage return (ascii 13,
	! control/M).  CNTL/Z at the prompt will exit the program.
	!
	external integer function force, lib$signal

	dim	s1%(80), s2%(80)

	Print "Force version 1"
	print
	linput "Terminal name: "; terminal$

	print
	print	"Each line will be sent with a terminating carriage return"
	print	"unless the line is terminated with a backslash ('\').  Any"
	print	"character preceeded by a carat ('^') will be sent as its"
	print	"control character ('^A' will be sent as a control/A)."
	print
	
	on error goto 200

	while 0<1
		linput s$
		j%=1%

		s$ = s$+chr$(13)	! put a <CR> at the end

		change s$ to s1%

		!
		! if a character is preceeded by "^", turn it into a control
		! character by trimming off bit 6 (after converting the 
		! character to upper case and verifying validity).  If the
		! last character is a "\" then don't pass a carriage return.
		!

		s1%(0%) = s1%(0%) - 2% if chr$(s1%(s1%(0%)-1%)) = "\" 
		
		!
		! this is gross code!!  blast through the string and handle the
		! control character substition.
		!

		for i%=1% to s1%(0)
			!
			! if the character is a carat, do some validity on
			! the next character.  If it is out of bounds, pass
			! both along as is.  If it is in bounds, make it the
			! corresponding control character by clearing bit 6.
			!
			if chr$(s1%(i%)) = "^" then
				x$ = edit$(chr$(s1%(i%+1%)),-1%)
				if x$ >= "A" and x$ <= "_" then
					s2%(j%) = ascii(x$) and 63%
					i%=i%+1%
				else
					s2%(j%) = s1%(i%)
					s2%(j%+1%) = s1%(i%+1%)
					j%=j%+1%
				end if
			else
				s2%(j%) = s1%(i%)
			end if
			j%=j%+1%
		next i%

		!
		! resultant string length is j% less 1 due to fenceposting
		!
		s2%(0%) = j%-1%
		change s2% to s$

		stat% = force(terminal$,s$)

		stat% = lib$signal(stat%) if (not stat% and 1%)
	next

200
	resume 201
201
	end
    
410.6Thanks.....IOSG::BAILEYPlug in \Turn on \Tune outWed Apr 08 1987 19:1118

Thanks  YALI::LASTOVICA, from your code I have fixed up a prog
that does the reverse, ie any OUTPUT to a terminal is echoed
to me, I replace the UCB$L_TT_GETNXT pointer so it points to my routine
(built in nonpaged pool) that JSB's to the 'real' routine, then
back in my code I build an AST to copy the outputed characters
to my process (prog) and then to the screen.

Using the SEE program in a subprocess and your FORCE in the parent
process you can drive any terminal from yours and see the results

(it may be a bit CPU intensive due to the number of AST's flying
around



Thanks  PEB
410.7CHAMBR::GUINEAUThu Apr 09 1987 12:1011

 FORCE is neat!,   Is SEE going to show up here?


 John





410.8Soon ?IOSG::BAILEYPlug in \Turn on \Tune outThu Apr 09 1987 13:367
Still a few loose ends to tidy up with SEE, should be able
to post it here in a few days (week?) depending on how much real work
I have to do  :-)


Peb
410.9Capture session to file with SEE??ISWSW::DOOLITTANPrimitive but effectiveThu Apr 09 1987 17:186
        Sounds trivial, but can SEE be used to capture part of
        an interactive session to a file, a la UNIX protocol (I
        think)?
        
        andy
        
410.10Here's one that does it all!UFP::MURPHYEuropean or African Swallow?Thu Apr 09 1987 19:401227
$!    I've got one that does both sides; it can capture both input and
$!    output. Extract this note and "@" it to compile and link.
$!    Usage: Run it. tell it what terminal.
$!    it will then slave your terminal to the other's output stream.
$!    if you type ^\ "input" mode is enabled; anything you type is
$!    forced to the other terminal's input stream. Another ^\ disables
$!    input mode. ^Z with input mode disabled will clean up and exit.
$!    **** WARNING: Don't point this to a RTxx device *****
$!    [unless you LIKE crashing systems].
$ CREATE TTYDEF.MAR
$ DECK/DOLLAR="%%"
 	.MACRO	$TTYDEF,$GBL		;
 	$DEFINI	TTY,$GBL
 $DEF	TTY$L_WB_FLINK	.BLKL
 $DEF	TTY$L_WB_BLINK	.BLKL
 $DEF	TTY$W_WB_SIZE	.BLKW
 $DEF	TTY$B_WB_TYPE	.BLKB
 $DEF	TTY$B_WB_FIPL	.BLKB
 $DEF	TTY$L_WB_FPC	.BLKL
 $DEF	TTY$L_WB_FR3	.BLKL
 $DEF	TTY$L_WB_FR4	.BLKL
 $DEF	TTY$L_WB_MAP	.BLKL
 $DEF	TTY$L_WB_NEXT	.BLKL
 $DEF	TTY$L_WB_END	.BLKL
 $DEF	TTY$L_WB_IRP	.BLKL
 $DEF	TTY$W_WB_STATUS	.BLKW
 $DEF	TTY$W_WB_BCNT	.BLKW
 $DEF	TTY$L_WB_RETADDR .BLKL
 $DEF	TTY$C_WB_HDRLEN
 $DEF	TTY$K_WB_HDRLEN
 $DEF	TTY$L_WB_DATA	.BLKL
 	$DEFEND	TTY,$GBL,DEF
 	.ENDM	$TTYDEF
	.MACRO	$TTYDEFS $GBL
	$UCBDEF
	$DEFINI	TTYDEFS,$GBL
			.BLKB	UCB$C_LENGTH
$DEF	UCB$Q_TT_STATE
			.BLKQ	1
$DEF	UCB$L_TT_MULTI
			.BLKL	1
$DEF	UCB$L_TT_RDUE
			.BLKL	1
$DEF	UCB$L_TT_RTIMOU
			.BLKL	1
$DEF	UCB$L_TT_CTRLY
			.BLKL	1
$DEF	UCB$L_TT_CTRLC
			.BLKL	1
$DEF	UCB$L_TT_OUTBAND
			.BLKL	1
$DEF	UCB$L_TT_BANDQUE
			.BLKL	1
$DEF	UCB$L_TT_TYPAHD
			.BLKL	1
$DEF	UCB$W_TT_INAHD
			.BLKW	1
$DEF	UCB$W_TT_HOLD
			.BLKW	1
	$VIELD	TTY,0,<-
		<TANK_CHAR,8,M>-
		<TANK_XOFF,1,M>-
		<TANK_XON,1,M>-
		<TANK_STOP,1,M>-
		<TANK_STOP2,1,M>-
		<TANK_HOLD,1,M>-
		<TANK_BURST,1,M>-
		>
$DEF	UCB$W_TT_CURSOR
			.BLKW	1
$DEF	UCB$B_TT_LINE
			.BLKB	1
$DEF	UCB$B_TT_LASTC
			.BLKB	1
$DEF	UCB$L_TT_DECHAR
			.BLKL	1
$DEF	UCB$L_TT_DECHA1
			.BLKL	1
$DEF	UCB$L_TT_WFLINK
			.BLKL	1
$DEF	UCB$L_TT_WBLINK
			.BLKL	1
$DEF	UCB$L_TT_WRTBUF
			.BLKL	1
$DEF	UCB$L_TT_GETNXT
			.BLKL	1
$DEF	UCB$L_TT_PUTNXT
			.BLKL	1
$DEF	UCB$L_TT_CLASS
			.BLKL	1
$DEF	UCB$L_TT_PORT
			.BLKL	1
$DEF	UCB$L_TT_OUTADR
			.BLKL	1
$DEF	UCB$W_TT_OUTLEN
			.BLKW	1
$DEF	UCB$B_TT_DS_RCV
			.BLKB	1
$DEF	UCB$B_TT_DS_TX
			.BLKB	1
$DEF	UCB$W_TT_DS_ST
			.BLKW	1
$DEF 	UCB$W_TT_DS_TIM
			.BLKW	1
$DEF	UCB$W_TT_SPEED
			.BLKW	1
	$VIELD	UCB,0,<-
		<TT_TSPEED,8,M>-
		<TT_RSPEED,8,M>-
		>
$DEF	UCB$B_TT_CRFILL
			.BLKB	1
$DEF	UCB$B_TT_LFFILL
			.BLKB	1
$DEF	UCB$B_TT_PARITY
			.BLKB	1
	$VIELD	UCB,3,<-
		<TT_LEN,2,M>-
		<TT_STOP,1,M>-
		<TT_PARTY,1,M>-
		<TT_ODD,1,M>-
		>
$DEF	UCB$B_TT_FILL
			.BLKB	1
$DEF	UCB$W_TT_DESPEE
			.BLKW	1
$DEF	UCB$B_TT_DECRF
			.BLKB	1
$DEF	UCB$B_TT_DELFF
			.BLKB	1
$DEF	UCB$B_TT_DEPARI
			.BLKB	1
$DEF	UCB$B_TT_DETYPE
			.BLKB	1
$DEF	UCB$W_TT_DESIZE
			.BLKW	1
			.BLKB
$DEF	UCB$B_TT_MAINT
			.BLKB	1
	$VIELD	UCB,0,<-
		<,7,>,-
		<TT_DSBL,1,M>-
		>
$DEF	UCB$L_TT_ALTDRV
			.BLKL	1
$DEF	UCB$L_TT_MAP
			.BLKL	1
$DEF	UCB$W_TT_ALTLEN
			.BLKW	1
$DEF	UCB$B_TT_ESC
			.BLKB	1
$DEF	UCB$B_TT_ESC_O
			.BLKB	1
$DEF	UCB$C_TT_LENGTH
$DEF	UCB$K_TT_LENGTH
	. = 0
$DEF	CLASS_GETNXT
			.BLKL	1
$DEF	CLASS_PUTNXT
			.BLKL	1
$DEF	CLASS_SETUP_UCB
			.BLKL	1
$DEF	CLASS_DS_TRAN
			.BLKL	1
$DEF	CLASS_DDT
			.BLKL	1
$DEF	CLASS_READERROR
			.BLKL	1
	. = 0
$DEF	PORT_STARTIO
			.BLKL	1
$DEF	PORT_DISCONNECT
			.BLKL	1
$DEF	PORT_SET_LINE
			.BLKL	1
$DEF	PORT_DS_SET
			.BLKL	1
$DEF	PORT_XON
			.BLKL	1
$DEF	PORT_XOFF
			.BLKL	1
$DEF	PORT_STOP
			.BLKL	1
$DEF	PORT_STOP2
			.BLKL	1
$DEF	PORT_ABORT
			.BLKL	1
$DEF	PORT_RESUME
			.BLKL	1
$DEF	PORT_SET_MODEM
			.BLKL	1
$DEF	PORT_START_DMA
			.BLKL	1
$DEF	PORT_MAINT
			.BLKL	1
	. = 0
$DEF	TTY$L_RB_NXT
			.BLKL	1
$DEF	TTY$L_RB_UVA
			.BLKL	1
$DEF	TTY$W_RB_SIZE
			.BLKW	1
			.BLKB	1
			.BLKB	1
$DEF	TTY$W_RB_ORGHOR
			.BLKW	1
$DEF	TTY$W_RB_TIMOS
			.BLKW	1
$DEF	TTY$L_RB_EXTEND
			.BLKL	1
$DEF	TTY$L_RB_DATA
			.BLKL	1
	. = 0

$DEF	TTY$L_TA_PUT
			.BLKL	1
$DEF	TTY$L_TA_GET
			.BLKL	1
$DEF	TTY$W_TA_SIZE
			.BLKW	1
$DEF	TTY$B_TA_TYPE
			.BLKB	1
			.BLKB	1
$DEF	TTY$L_TA_END
			.BLKL	1
$DEF	TTY$L_TA_DATA
			.BLKL	1
	$VIELD	TTY,0,<-
		<ST_CTRLS,,M>-
		<ST_FILL,,M>-
		<ST_CURSOR,,M>-
		<ST_SENDLF,,M>-
		<ST_MULTI,,M>-
		<ST_DMA,,M>-
		<ST_WRITE,,M>-
		<ST_BRDCST,,M>-
		<ST_EOL,,M>-
		<ST_CTRLR,,M>-
		<ST_READ,,M>-
		>
	$VIELD	TTY,0,<-
		<ST_CTRLO,,M>-
		<ST_DEL,,M>-
		<ST_PASALL,,M>-
		<ST_NOECHO,,M>-
		<ST_WRTALL,,M>-
		<ST_PROMPT,,M>-
		<ST_NOFLTR,,M>-
		<ST_ESC,,M>-
		<ST_BADESC,,M>-
		<ST_NL,,M>-
		<ST_REFRSH,,M>-
		<ST_ESCAPE,,M>-
		<ST_TYPFUL,,M>-
		<ST_SKIPLF,,M>-
		<ST_GETAHD,,M>-
		<ST_UNSOL,,M>-
		<ST_ESC_O,,M>-
		<ST_CTRLSP,,M>-
		<ST_WRAP,,M>-
		<ST_BRDP,,M>-
		<ST_DMAABO,,M>-
		<ST_OVRFLO,,M>-
		<ST_AUTOP,,M>-
		>
	$VIELD	TTY,0,<-
		<SX_CTRLS>-
		<SX_FILL>-
		<SX_CURSOR>-
		<SX_SENDLF>-
		<SX_MULTI>-
		<SX_DMA>-
		<SX_WRITE>-
		<SX_BRDCST>-
		<SX_EOL>-
		<SX_CTRLR>-
		<SX_READ>-
		>
	$VIELD	TTY,0,<-
		<A,32>-
		<SX_CTRLO>-
		<SX_DEL>-
		<SX_PASALL>-
		<SX_NOECHO>-
		<SX_WRTALL>-
		<SX_PROMPT>-
		<SX_NOFLTR>-
		<SX_ESC>-
		<SX_BADESC>-
		<SX_NL>-
		<SX_REFRSH>-
		<SX_ESCAPE>-
		<SX_TYPFUL>-
		<SX_SKIPLF>-
		<SX_GETAHD>-
		<SX_UNSOL>-
		<SX_ESC_O>-
		<SX_CTRLSP>-
		<SX_WRAP>-
		<SX_BRDP>-
		<SX_DMAABO>-
		<SX_OVRFLO>-
		<SX_AUTOP>-
		>
$EQULST TTY$C_,,0,1,<-
		<CTRLC,3>-
		<BELL,7>-
		<BS,8>-
		<TAB,9>-
		<LF,10>-
		<VT,11>-
		<FF,12>-
		<CR,13>-
		<CTRLO,15>-
		<CTRLQ,17>-
		>
$EQULST TTY$C_,,,1,<-
		<XON,17>-
		<CTRLR,18>-
		<CTRLS,19>-
		<XOFF,19>-
		<CTRLU,21>-
		<CTRLX,24>-
		<CTRLY,25>-
		<CTRLZ,26>-
		<ESCAPE,27>-
		<BLANK,32>-
		<DOLLAR,36>-
		>
$EQULST TTY$C_,,,1,<-
		<PLUS,43>-
		<ZERO,48>-
		<ONE,49>-
		<SCRIPT,96>-
		<LOWA,97>-
		<LOWZ,123>-
		<DELETE,127>-
		<NL,128>-
		>

$EQULST TTY$C_,,0,1,<-
		<MAXPAGLEN,255>-
		<MAXPAGWID,511>-
		<HIGHIPL,22>-
		>


$EQULST TTY$C_,,0,1,<-
		<FC_READ>-
		<FC_WRITE>-
		<FC_SETM>-
		<FC_SETC>-
		<FC_N_SET>-
		>

	$VIELD	TTY,0,<-
		<,3,M>-
		<CH_LOWER,,M>-
		<CH_SPEC,,M>-
		<CH_CTRL,,M>-
		<CH_CTRL3,,M>-
		<CH_CTRL2,,M>-
		>

$DEFEND	UCB
	$CRBDEF
crb$l_tt_modem		=	crb$l_timelink
crb$l_dz_modem		=	crb$l_duetime
crb$b_tt_timmask	=	crb$l_toutrout+3
crb$b_tt_ring		=	crb$l_toutrout
crb$b_tt_carrier	=	crb$l_toutrout+1
crb$b_tt_dtr		=	crb$l_toutrout+2
crb$b_tt_type		=	crb$b_type+1

IDB$B_TT_ENABLE		=	^X0E

	.ENDM	$TTYDEFS
	.MACRO	$TTYMACS

	.MACRO	GTSBITS	BITS,MODE,TARGET,BRANCH,?L1
	F=0
	Z0=3
	X0=0
	W0=0
	Z1=3
	X1=0
	W1=0
	.IRP	Y,<BITS>
	T=TTY$V_SX_'Y
	.IF	LE	32-T
	X1=T-32@-3
	.IF	LT	X1-Z1
	Z1=X1
	.ENDC
	W1=<TTY$M_ST_'Y>!W1
	.ENDC
	.IF	GT	32-T
	X0=T@-3
	.IF	LT	X0-Z0
	Z0=X0
	.ENDC
	W0=<TTY$M_ST_'Y>!W0
	.ENDC
	.ENDR
	.IF	NE	W0
	GTSBITS1 	Z0,W0,MODE,0
	.IF	NB	TARGET
	.IF	IDN	BRANCH,BEQL
	.IF	NE	W1
	F=1
	BNEQ	L1
	.IFF
	BEQL	TARGET
	.ENDC
	.ENDC
	.IF	DIF	BRANCH,BEQL
	BNEQ	TARGET
	.ENDC
	.ENDC
	.ENDC
	.IF	NE	W1
	GTSBITS1	Z1,W1,MODE,4
	.IF	NB	TARGET
	BRANCH	TARGET
	.ENDC
	.ENDC
	.IF	NE	F
L1:
	.ENDC
	.ENDM	GTSBITS


	.MACRO	GTSBITS1	Z,WX,MODE,BIAS
	WX=WX@-<Z*8>
	X=WX@-8
	.IF	EQ	X
	BI'MODE'B	#WX,BIAS+Z(R2)
	.IFF
	X=WX@-16
	.IF	EQ	X
	BI'MODE'W	#WX,BIAS+Z(R2)
	.IFF
	BI'MODE'L	#WX,BIAS+Z(R2)
	.ENDC
	.ENDC
	.ENDM	GTSBITS1

	.MACRO	SET_STATE	NAME
	GTSBITS	<NAME>,S
	.ENDM	SET_STATE

	.MACRO	CLR_STATE	NAME
	GTSBITS	<NAME>,C
	.ENDM	CLR_STATE

	.MACRO	IF_STATE	NAME,TARGET
	CNT = 0
	.IRP	Y,<NAME>
	CNT = CNT + 1
	.ENDR

	.IF EQUAL CNT - 1
	ONE_BIT	<NAME>,S,TARGET
	.IFF
	GTSBITS <NAME>,T,TARGET,BNEQ
	.ENDC
	.ENDM	IF_STATE


	.MACRO	IF_NOT_STATE	NAME,TARGET
	CNT = 0
	.IRP	Y,<NAME>
	CNT = CNT + 1
	.ENDR

	.IF EQUAL CNT - 1
	ONE_BIT	<NAME>,C,TARGET
	.IFF
	GTSBITS <NAME>,T,TARGET,BEQL
	.ENDC
	.ENDM	IF_NOT_STATE


	.MACRO	ONE_BIT	BIT,BRANCH,TARGET
	BB'BRANCH'	#TTY$V_SX_'BIT',(R2),'TARGET'
	.ENDM	ONE_BIT


	.MACRO	NOSET	BIT,?L1
	BBC	#TT2$V_'BIT',R1,L1
	BICL	#TT2$M_'BIT',R0
L1:
	.ENDM	NOSET

	.MACRO	NOCLEAR	BIT,?L1
	BBC	#TT2$V_'BIT',R1,L1
	BISL	#TT2$M_'BIT',R0
L1:
	.ENDM	NOCLEAR

	.MACRO	NOMOD	BIT,?L1
	BBC	#TT2$V_'BIT',R1,L1
	XORL2	#TT2$M_'BIT',R0
L1:
	.ENDM	NOMOD

	.MACRO	PRIV_TO_MOD	BIT,ERROR = NOPRIV_EXIT,?L1
	BBC	#TT2$V_'BIT',R1,L1
	BITL	#<<1@PRV$V_LOG_IO>!-
		<1@PRV$V_PHY_IO>>,-
		@IRP$L_ARB(R3)
	BNEQ	L1
	BRW	'ERROR'
L1:
	.ENDM	PRIV_TO_MOD

	.MACRO	$TTYMACS
	.ENDM	$TTYMACS

	.ENDM	$TTYMACS
	.MACRO	$TTYMODEM

	.MACRO	STO_TQE	OFFSET,SIZE,VALUE,BASE
$$$$$$	=	.
.	=	OFFSET+BASE
	.'SIZE	VALUE
.	=	$$$$$$
	.ENDM	STO_TQE



modem$b_st_onmask	=	0
modem$b_st_offmask	=	1
modem$w_st_timer	=	2
modem$w_st_routine	=	4
modem$c_st_length	=	6

modem$b_tran_type	=	0
modem$w_tran_nstate	=	2
modem$b_tran_offmask	=	4
modem$b_tran_onmask	=	5
modem$c_tran_length	=	6


modem$c_tran_time	=	1
modem$c_tran_dataset	=	0
modem$c_tran_end	=	2
modem$c_tran_dialtype	=	3
modem$c_tran_dz11	=	4
modem$c_tran_nomodem	=	5
modem$c_timer	=	4
modem$c_dataset =	3
modem$c_init	=	0
modem$c_shutdwn	=	1
modem$c_null	=	2

modem$m_enable =^x8000



	$VIELD	TIMCTRL,0,<-
		<CANCEL,,M>,-
		<ACTIVE,,M>,-
		>


	.ENDM	$TTYMODEM
%%
$ CREATE WATCH.MAR
$ DECK/DOLLAR=%%
		.TITLE	WATCH - Watch terminal output stream
		.LIBRARY	/TTYDEF/
		.LIBRARY	/SYS$LIBRARY:LIB/
		$IPLDEF				; Define IPL levels
		$TTYDEF				; Define term driver structures
		$TTYDEFS			;  ditto
		$TTYMDMDEF			; Define modem control signals
		$TTYVECDEF			; Define port/class vectors
		$TT2DEF				; Define terminal chars
		$SSDEF				; Define system service returns
		$DVIDEF				; GETDVI definitions
		$DYNDEF				; Dynamic memory struct types
		$FKBDEF				; Define fork block

		.PSECT	$DATA	RD, WRT, NOEXE, NOSHR, LONG

WAIT:		.BLKQ		1		; Flush timer quadword
TERM_IOSB:	.BLKQ		1		; Terminal output IOSB
INPUT_IOSB:	.BLKQ		1		; Terminal input IOSB
MBX_IOSB:	.BLKQ		1		; Mailbox IOSB
USER_IOSB:	.BLKQ		1		; User IOSB

TERM_CHARS:	.BLKL		3		; Terminal characteristics
ORIG_CHARS:	.BLKL		3		; Original characteristics

NAME_ARGS:	.LONG		3		; Arg list for find UCB routine
DESCR:		.BLKL		1		; Device name descr address
UCB:		.BLKL		1		; Returned UCB address
PUCB:		.BLKL		1		; Returned phys UCB address

SEND_ARGS:	.LONG		1		; Arg list for send char routine
SEND_CHAR:	.BLKL		1		; Character to send

TERM_EF:	.BLKL		1		; Terminal output EF
INPUT_EF:	.BLKL		1		; Terminal input EF
MBX_EF:		.BLKL		1		; Mailbox event flag
MBX_SIZE:	.LONG		512		; Size of terminal mailbox
MBX_QUO:	.LONG		2048		; Quota for terminal mailbox

T_NAME:		.LONG		64		; Descriptor for terminal name
		.ADDRESS	NAME_BUF

DVI_LIST:	.WORD		64		; GETDVI item list for
		.WORD		DVI$_DEVNAM	; Getting mailbox device name
		.ADDRESS	MBX_NAME
		.ADDRESS	MBX_DESC
		.LONG		0
		.LONG		0

MBX_DESC:	.BLKL		1		; Descriptor for data mailbox
		.ADDRESS	MBX_NAME	; Device name
MBX_NAME:	.BLKB		64

EXIT_BLOCK:	.BLKL		1		; Link
		.ADDRESS	EXIT_HANDLER	; Handler
		.LONG		1
		.ADDRESS	EXIT_CODE	; Exit reason
EXIT_CODE:	.BLKL		1

FLAGS:		.LONG		0		; Status flags
MBX_CHAN:	.BLKW		1		; Terminal Mailbox Channel
INPUT_CHAN:	.BLKW		1		; user input channel
USER_MBX:	.BLKW		1		; User input mailbox chan
		.ALIGN	LONG

NAME_BUF:	.BLKB		64		; Terminal name input buffer
MBX_BUF:	.BLKB		2048		; Mailbox buffer
INPUT_MBX_BUF:	.BLKB		512		; Buffer for term mailbox
INPUT_BUF:	.BLKB		80		; Input buffer
WHICH:		.ASCID		/What terminal:/
USER_TERM:	.ASCID		/SYS$COMMAND/	; User's terminal for output
TIMER:		.ASCID		/0 00:00:00.10/	; Wait for one tenth second
ENABLED:	.ASCID		/Input mode enabled - ^\ to disable/
DISABLED:	.ASCID		/Input mode disabled/

		.MACRO	STATUS ?L1
		BLBS	R0, L1
		$EXIT_S	R0
L1:
		.ENDM	STATUS

		.SBTTL	WATCH - Setup entry point

		.PSECT	$CODE	RD, NOWRT, SHR, EXE, LONG
		.ENTRY	WATCH, ^M<>

		$BINTIM_S	TIMBUF=TIMER,-		; Convert delay to
				TIMADR=WAIT		;  binary
		STATUS
;+
;	Assign a channel to the user's terminal with an
;	associated mailbox.
;-
		PUSHAL		USER_MBX		; Channel for user mailbox
		PUSHAL		INPUT_CHAN		; Channel for user term
		PUSHAL		MBX_SIZE		; And message size
		PUSHAL		MBX_QUO			; Quota
		PUSHAL		USER_TERM		; Device name
		CALLS		#5,G^LIB$ASN_WTH_MBX	; Assign the channel
		STATUS
;+
;	Get the user terminal characteristics
;-
		$QIOW_S		CHAN=INPUT_CHAN,-
				FUNC=#IO$_SENSEMODE,-
				P1=ORIG_CHARS, P2=#12
		STATUS
		MOVQ		ORIG_CHARS, TERM_CHARS	; Copy for mods
		MOVL		ORIG_CHARS+8, TERM_CHARS+8
;+
;	Allocate event flags
;-
		PUSHAL		MBX_EF			; Get the mailbox EF
		CALLS		#1,G^LIB$GET_EF
		STATUS
		PUSHAL		TERM_EF
		CALLS		#1,G^LIB$GET_EF
		STATUS
		PUSHAL		INPUT_EF
		CALLS		#1,G^LIB$GET_EF
		STATUS
;+
;	Create the data mailbox, and get it's UCB address
;-
		$CREMBX_S	CHAN=MBX_CHAN,-		; Create the mailbox
				MAXMSG=#2048
		STATUS
		$GETDVI_S	CHAN=MBX_CHAN,-		; Get the mailbox name
				ITMLST=DVI_LIST,-
				EFN=#1
		STATUS
		$WAITFR_S	EFN=#1
		STATUS
		MOVAL	MBX_DESC, DESCR		; Point to mailbox descriptor
		$CMKRNL_S	ROUTIN=FIND_UCB,-
				ARGLST=NAME_ARGS
		STATUS
		MOVL	UCB, MBX_UCB		; Point to mailbox UCB
;+
;	Get the name of the terminal to slave
;+
START:		PUSHAL	T_NAME			; Return length
		PUSHAL	WHICH			; Prompt
		PUSHAL	T_NAME			; Return buffer
		CALLS	#2, G^LIB$GET_COMMAND	; Get the terminal name
		STATUS
		MOVAL	NAME_BUF, R0		; Check for trailing colon
10$:		CMPB	(R0), #^A/:/		; Is it a colon?
		BEQL	30$			; Yup, all done
		CMPB	(R0), #^A/ /		; A space?
		BNEQ	20$			; Nope.
		MOVB	#^A/:/,(R0)		; Yes.. add colon.
		BRB	30$			; All done
20$:		INCL	R0			; Point to next
		BRB	10$			; Loop back
;+
;	Uppercase the string and find the UCB
;-
30$:		PUSHAL	T_NAME
		PUSHAL	T_NAME
		CALLS	#2, G^STR$UPCASE	; Upcase it
		MOVAL	T_NAME, DESCR		; Point kernel routine to arglist
		$CMKRNL_S	ROUTIN=FIND_UCB,-; Find the device UCB
				ARGLST=NAME_ARGS
		STATUS
		MOVL	UCB, TERM_UCB		; Store UCB for it
		TSTL	PUCB			; Is it virtual?
		BEQL	40$			; Nope.
		MOVL	PUCB, TERM_UCB		; Yes, use physical

40$:		CALLS	#0, G^SET_EXIT		; Declare the exit handler
;+
;	Set it to PASTHRU mode
;-
		BISL2		#TT2$M_PASTHRU, TERM_CHARS+8
		$QIOW_S		CHAN=INPUT_CHAN,-
				FUNC=#IO$_SETMODE,-
				P1=TERM_CHARS, P2=#12
		STATUS

;+
;	Load the magic code into nonpaged pool
;-
		$CMKRNL_S	ROUTIN=LOAD_CODE; Load the code and set hook
		STATUS
		BSBW	SETUP_TERM_AST		; Set up AST for terminal
		$SETIMR_S	DAYTIM=WAIT,-	; Set up the flush timer
				ASTADR=FLUSH
		STATUS
		CLRQ	-(SP)			; At top of screen..
		CALLS	#2, G^SCR$ERASE_PAGE	; Erase it
		STATUS
;+
;	Fall thru to begin reading the mailbox.
;-

		.SBTTL	MBX_READ - Read messages and echo
;+
;	Read and echo the mailbox message
;-
MBX_READ:	$QIOW_S		EFN=MBX_EF,-		; Read the mailbox
				CHAN=MBX_CHAN,-
				FUNC=#IO$_READVBLK,-
				IOSB=MBX_IOSB,-
				P1=MBX_BUF,P2=#2048
		STATUS					; Check QIO Status
		MOVZWL	MBX_IOSB, R0			; Check I/O status
		STATUS
		MOVZWL	MBX_IOSB+2, R1
		$QIOW_S		EFN=TERM_EF,-		; Write the text
				IOSB=TERM_IOSB,-
				CHAN=INPUT_CHAN,-
				FUNC=#IO$_WRITEVBLK,-
				P1=MBX_BUF, P2=R1
		STATUS
		MOVZWL	TERM_IOSB, R0
		STATUS
		BRW	MBX_READ			; Read another

;+
;	Exit handler setup
;-
		.ENTRY	SET_EXIT,^M<>
		$DCLEXH_S	DESBLK=EXIT_BLOCK ; Declare exit handler
		RET		

		.SBTTL	EXIT_HANDLER, Exit reset handler
		.ENTRY	EXIT_HANDLER,^M<>
		$QIOW_S		CHAN=INPUT_CHAN,-	; Reset the term
				FUNC=#IO$_SETMODE,-
				P1=ORIG_CHARS,-
				P2=#12
		$QIOW_S		EFN=TERM_EF,-		; Write the text
				CHAN=INPUT_CHAN,-
				FUNC=#IO$_WRITEVBLK,-
				P1=EXIT_MESSAGE, P2=#EXIT_SIZE
		MOVL	CODE_PTR, R0
		BEQL	10$
		MOVAL	RESET-KERNEL_CODE(R0), R0
		$CMKRNL_S	ROUTIN=(R0)		; Call fixup
		BLBC	R0, 20$
		$CMKRNL_S	ROUTIN=FREE_POOL	; Free pool
		BLBC	R0, 20$
10$:		MOVL	#SS$_NORMAL, R0
20$:		RET
EXIT_MESSAGE:	.ASCII	/Exiting.../
EXIT_SIZE = .-EXIT_MESSAGE

		.SBTTL	FLUSH - Flush the ring
		.ENTRY	FLUSH, ^M<>
		$SETIMR_S	DAYTIM=WAIT,-
				ASTADR=FLUSH
		STATUS
		MOVL	CODE_PTR, R0
		MOVAL	FLUSH_RING-KERNEL_CODE(R0), R0
		$CMKRNL_S	ROUTIN=(R0)		; Call the flusher
		STATUS
		RET

		.SBTTL	FIND_UCB - Locate the device UCB
;
;	This routine finds the address of the UCB for a specified
;	device.
;
;	Arguments:
;	DESCR	Address of device name descriptor
;	UCB	Return pointer to [virtual] UCB
;	PUCB	Return pointer to [physical] UCB, zero if none.
;
;	This routine executes in Kernel mode at elevated IPL
;
		.ENTRY	FIND_UCB,^M<R2,R3,R4,R5>
		CLRQ	8(AP)			; Clear UCB pointers
		MOVL	G^SCH$GL_CURPCB, R4	; Get current PCB pointer
		JSB	G^SCH$IOLOCKR		; Lock I/O database for read
		MOVL	4(AP), R1		; Point to device descr
		JSB	G^IOC$SEARCHDEV		; Search for device
		BLBC	R0, 10$			; Exit on failure
		MOVL	UCB$L_TL_PHYUCB(R1),12(AP) ; Return physical UCB
		MOVL	R1, 8(AP)		; Return UCB
		BBC	#DEV$V_DET, UCB$L_DEVCHAR2(R1),-
			10$			; Skip if not detached
		MOVL	#SS$_DEVOFFLINE, R0	; Say it's offline
10$:		PUSHL	R0			; Save status
		JSB	G^SCH$IOUNLOCK		; Unlock the I/O database
		POPL	R0
		RET				; And return

		.SBTTL	LOAD_CODE - Load hook code into pool

		.ENTRY	LOAD_CODE,^M<R2,R3,R4,R5>
		DSBINT	#IPL$_ASTDEL		; Stop process deletion
		MOVL	#KERN_SIZE, R1		; Size of pool to get
		JSB	G^EXE$ALONONPAGED	; Get the pool
		BLBS	R0, 10$			; Skip if OK
		ENBINT
		RET				; Can't get it!
10$:		MOVW	R1, CODE_SIZE		; Store size
		MOVL	R2, CODE_PTR		; Store pointer
		MOVC3	#KERN_SIZE,-
			KERNEL_CODE,-
			(R2)			; Store the code in the block
		MOVL	CODE_PTR, R0		; Point to code block
		MOVAL	SETUP-KERNEL_CODE(R0), R0 ; Get SETUP address
		JSB	(R0)			; Go to it
		ENBINT
		MOVL	#SS$_NORMAL, R0		; OK So far
		RET

		.SBTTL SETUP_TERM_AST - Setup the terminal mailbox AST
SETUP_TERM_AST:	$QIOW_S	CHAN=USER_MBX,-		; Using user's terminal mailbox
			FUNC=#IO$_SETMODE!IO$M_WRTATTN,- ; Write attention AST
			P1=TERM_AST		; AST routine
		STATUS
		RSB

		.ENTRY	TERM_AST, ^M<R2,R3>
		$QIOW_S		CHAN=USER_MBX,-
				IOSB=USER_IOSB,-
				FUNC=#IO$_READVBLK,-
				P1=INPUT_MBX_BUF,P2=#512
		STATUS
LOOP:		$QIOW_S	CHAN=INPUT_CHAN,-
			EFN=INPUT_EF,-
			FUNC=#IO$_READVBLK!IO$M_TIMED!IO$M_NOECHO,-
			IOSB=INPUT_IOSB,-
			P1=INPUT_BUF,-
			P2=#80,-
			P3=#0			; Zero second timeout
		STATUS
		MOVZWL	INPUT_IOSB, R0		; Check status
		CMPW	R0, #SS$_TIMEOUT	; Timed out?
		BEQL	10$			; Yup, that's OK.
		STATUS
10$:		MOVW	INPUT_IOSB+2, R2	; Get offset to terminator
		ADDW	INPUT_IOSB+6, R2	; Plus terminator size
		BNEQ	20$			; Something there
		BSBW	SETUP_TERM_AST		; Reset the AST
		RET				; Nothing there
20$:		MOVZWL	R2, R2			; Extend to word
		MOVAL	INPUT_BUF, R3		; And buffer pointer
30$:		MOVZBL	(R3)+, SEND_CHAR	; Get character
		CMPB	SEND_CHAR,#^A/\/-^A/@/	; ^\?
		BNEQ	50$			; Not the flag char
		BLBS	FLAGS, 40$		; If was set, clear it
		BISB	#1, FLAGS		; Set the flag
		PUSHAL	ENABLED			; Say input is enabled
		CALLS	#1,G^LIB$PUT_OUTPUT
		BRB	60$			; Try next char
40$:		BICB	#1, FLAGS		; Clear the input flag
		PUSHAL	DISABLED
		CALLS	#1,G^LIB$PUT_OUTPUT	; Say input disabled
50$:		BLBC	FLAGS, 60$		; Input mode disabled
		$CMKRNL_S	ROUTIN=SEND_ONE,ARGLST=SEND_ARGS
		STATUS
		BRB	70$			; Done character
60$:		CMPB	SEND_CHAR,#^A/Z/-^A/@/	; Control-Z?
		BNEQ	70$			; Nope, ignore it.
		$EXIT_S	#SS$_NORMAL		; Exit now.
70$:		SOBGTR	R2, 30$			; Loop back
		BRW	LOOP			; Any more input?
80$:		RET

		.SBTTL	SEND_ONE - Send a character to user terminal
		.ENTRY	SEND_ONE, ^M<R2, R3, R4, R5>
		MOVL	CODE_PTR, R0		; Point to code block
		MOVAL	SEND_IT-KERNEL_CODE(R0), R0 ; Get SEND CHARACTER address
		JSB	(R0)			; Call it
		RET

		.SBTTL	KERNEL_CODE
		.PSECT	LOADED	RD, WRT, PIC, NOSHR, EXE, PAGE
KERNEL_CODE:
FKB_LIST:	.BLKQ	1			; Fork block list
CODE_SIZE:	.BLKW	1			; Size
		.WORD	DYN$C_FRK		; Type
CODE_PTR:	.LONG	0			; Pointer to loaded code
TERM_UCB:	.LONG	0			; Terminal UCB
MBX_UCB:	.LONG	0			; Mailbox UCB
PORT_TABLE:	.BLKB	PORT_LENGTH		; Copied/munged port vector
CLASS_LENGTH = CLASSS_CLASS_DEF			; Hack since it's not there..
CLASS_TABLE:	.BLKB	CLASS_LENGTH		; Copied/munged class vector
PORT_START_VEC:	.LONG	0			; Gets original UCB PORT STARTIO
PORT_DS_VEC:	.LONG	0			; Gets original UCB PORT modem 
CLASS_GETNXT_VEC:.LONG	0			; Gets original UCB Class GETNXT
CLASS_PUTNXT_VEC:.LONG	0			; ... class driver put char
CLASS_DS_VEC:	.LONG	0			; ... class driver dataset trans
PORT_DIS_VEC:	.LONG	0			; ... port driver disconnect
CLASS_DIS_VEC:	.LONG	0			; ... class driver disconnect
SAVED_PORT:	.LONG	0			; Saved port driver pointer
SAVED_CLASS:	.LONG	0			; Saved class driver pointer
		.ALIGN	QUAD
FKB_COUNT = 20
FKB_1:
		.REPT	40
		.BLKQ	1			; Flink/Blink
		.WORD	FKB$K_LENGTH		; Size
		.BYTE	DYN$C_FRK		; Type
		.BYTE	6			; Fork IPL
		.BLKL	3			; FPC/FR3/FR4
		.ENDR
RING_SIZE = 1024				; Size of buffer
BUF_2:		.BLKB	RING_SIZE		; Fork level buffer
RING_BUFFER:	.BLKB	RING_SIZE		; Buffer for mailbox
RING_PTR:	.BLKL	1			; Pointer to data storage
RING_FREE:	.LONG	RING_SIZE		; Free in mailbox
WRITE_SIZE:	.BLKL	1			; Characters in alt buffer

		.SBTTL	SETUP - Set up hook
SETUP:		MOVAL	RING_BUFFER, RING_PTR	; Set up pointer to buffer
		MOVAL	FKB_LIST, FKB_LIST	; Set up queue header
		MOVL	FKB_LIST, FKB_LIST+4
		MOVAL	FKB_1, R0		; Set up FKB queue
		MOVL	#FKB_COUNT, R1		; Number of fork blocks
10$:		INSQUE	(R0), @FKB_LIST+4	; Insert onto queue at tail
		MOVAL	FKB$K_LENGTH(R0), R0	; Point to next
		SOBGTR	R1, 10$			; Do next
		MOVL	TERM_UCB, R2		; Get UCB pointer
		MOVL	UCB$L_TT_PORT(R2), R0	; Point to port vectors
		MOVL	R0, SAVED_PORT		; Save port vector pointer
		MOVAL	PORT_TABLE, R1		; Point to internal table
		PUSHR	#^M<R0,R1,R2,R3,R4,R5>	; Save across MOVC
		MOVC3	#PORT_LENGTH, (R0),(R1)	; Copy port vector to internal
		POPR	#^M<R0,R1,R2,R3,R4,R5>
		MOVL	PORT_STARTIO(R1),-	;
			PORT_START_VEC		; Save old port startio
		MOVAL	GRAB_STARTIO,-		;
			PORT_STARTIO(R1)	; Point to hook code
		MOVL	PORT_DS_SET(R0),-	;
			PORT_DS_VEC		; Save old port dataset vector
		MOVAL	GRAB_PORT_DS,-		;
			PORT_DS_SET(R1)		; Set new dataset transition
		MOVL	PORT_DISCONNECT(R0),-	; Save old port disconnect
			PORT_DIS_VEC		;
		MOVAL	GRAB_PORT_DIS,-		;
			PORT_DISCONNECT(R1)	;
		MOVL	UCB$L_TT_CLASS(R2), R0	; Point to class vectors
		MOVL	R0, SAVED_CLASS		; Save class table pointer
		MOVAL	CLASS_TABLE, R1		; Point to saved table
		PUSHR	#^M<R0,R1,R2,R3,R4,R5>	; Save registers
		MOVC3	#CLASS_LENGTH, (R0),(R1); Copy class vector
		POPR	#^M<R0,R1,R2,R3,R4,R5>	; Restore regs
		MOVL	CLASS_GETNXT(R0),-	; Save original getnxt vector
			CLASS_GETNXT_VEC	;
		MOVAL	GRAB_GETNXT,-		;
			CLASS_GETNXT(R1)	; Point to hook code
		MOVAL	GRAB_GETNXT,-		; Plus point UCB
			UCB$L_TT_GETNXT(R2)	;
		MOVL	CLASS_PUTNXT(R0),-
			CLASS_PUTNXT_VEC	; Save original PUTNXT vector
		MOVAL	GRAB_PUTNXT,-		; Set up copied class vector
			CLASS_PUTNXT(R1)
		MOVAL	GRAB_PUTNXT,-		; Plus device UCB
			UCB$L_TT_PUTNXT(R2)
		MOVL	CLASS_DS_TRAN(R0),-	; Save original dataset trans
			CLASS_DS_VEC		;
		MOVAL	GRAB_CLASS_DS,-		; Point to hook code
			CLASS_DS_TRAN(R1)	;
		MOVL	CLASS_DISCONNECT(R0),-	; Save class disconect
			CLASS_DIS_VEC		;
		MOVAL	GRAB_CLASS_DIS,-	; Point to hook code
			CLASS_DISCONNECT(R1)	;
		DSBINT				;;; Lock out interrupts
		MOVAL	CLASS_TABLE,-		;;; Point UCB to my class
			UCB$L_TT_CLASS(R2)	;;;   table copy
		MOVAL	PORT_TABLE,-		;;; Plus point to my port
			UCB$L_TT_PORT(R2)	;;;   table copy
		ENBINT				; Restore IPL
		RSB				; All done

		.SBTTL	GRAB_CLASS_DS - Hook to notice dataset hangups
GRAB_CLASS_DS:	BSBB	RESET_IT		;;; Remove hooks
		JMP	@CLASS_DS_VEC		;;; Call the class driver

		.SBTTL	GRAB_PORT_DS - Hook to notice dataset hangups
GRAB_PORT_DS:	BSBB	RESET_IT		;;; Remove hooks
		JMP	@PORT_DS_VEC		;;; Call the port driver

		.SBTTL	GRAB_PORT_DIS - Hook to notice disconnects
GRAB_PORT_DIS:	BSBB	RESET_IT		;;; Reset device
		JMP	@PORT_DIS_VEC		;;; Call port driver

		.SBTTL	GRAB_CLASS_DIS - Hook to notice disconnects
GRAB_CLASS_DIS:	BSBB	RESET_IT		;;; Reset device
		JMP	@CLASS_DIS_VEC		;;; Call class driver

RESET_IT:	MOVQ	R0, -(SP)		;;; Save registers
		CALLS	#0, RESET		;;; Reset terminal
		MOVQ	(SP)+, R0		;;; Restore...
		RSB				;;; And return

		.SBTTL	GRAB_STARTIO - Hook to send data to mbx
;+
;	This routine is called at device IPL to send
;	the data to the port driver. The value in R3 contains
;	the data; either a character or a pointer to a burst string.
;	(r2 contains the size.) An IPL 6 fork is created to send the data
;	to the mailbox.
;-
GRAB_STARTIO:	TSTL	R3			;;; Any work to do?
		BEQL	10$			;;; Nope, tell the startio.
		PUSHR	#^M<R0,R1,R2,R3,R4,R5>	;;; Store volatile regs
		BSBB	GET_DATA		;;; Get terminal data
		POPR	#^M<R0,R1,R2,R3,R4,R5>	;;; Restore registers
		TSTL	R3			;;; Reset condition codes
10$:		JMP	@PORT_START_VEC		;;; Call port routine

		.SBTTL	GRAB_GETNXT - Hook to send data to mbx
;+
;	This routine is called at device IPL to send
;	the data to the port driver. The value in R3 contains
;	the data; either a character or a pointer to a burst string.
;	(r2 contains the size.) An IPL 6 fork is created to send the data
;	to the mailbox.
;-
		.ENABLE LSB
GRAB_GETNXT:	JSB	@CLASS_GETNXT_VEC	;;; Call the class driver
10$:		TSTB	UCB$B_TT_OUTYPE(R5)	;;; Any work to do?
		BEQL	20$			;;; Nope.
		PUSHR	#^M<R0,R1,R2,R3,R4,R5>	;;; Store volatile regs
		BSBB	GET_DATA		;;; Check for data type...
		POPR	#^M<R0,R1,R2,R3,R4,R5>	;;; Restore regs
		TSTB	UCB$B_TT_OUTYPE(R5)	;;; Reset cond codes
20$:		RSB				;;; Return to caller

		.SBTTL	GRAB_PUTNXT
;+
;	This routine is used to grab echoes of input characters
;-
GRAB_PUTNXT:	JSB	@CLASS_PUTNXT_VEC	;;; Call the class driver
		BRB	10$			;;; Common code.
		.DISABLE LSB

		.SBTTL GET_DATA - Copy the output data to the buffer
;+
;	This routine copies the output data to the buffer.
;	When the buffer is full, DUMP_BUFFER is called
;	to output it to the mailbox.
;-
GET_DATA:	TSTL	R3			;;; Character or pointer?
		BLSS	20$			;;; Pointer
		MOVB	R3, @RING_PTR		;;; Copy to buffer
		INCL	RING_PTR		;;; And bump it
		DECL	RING_FREE		;;; Less this much free
		BGTR	10$			;;; Still room left
		BSBW	DUMP_BUFFER		;;; Dump the buffer
10$:		RSB				;;; Done sending message
;
;	Handle multi-byte messages
;
20$:		MOVZWL	R2, R2			;;; Size of message
		CMPL	R2, #RING_SIZE		;;; Is it too big?
		BLSS	30$			;;; Skip if not
		MOVL	#RING_SIZE, R2		;;; Limit to this size
30$:		CMPL	R2, RING_FREE		;;; Room for this one?
		BLEQ	40$			;;; Yup, add it in.
		MOVQ	R2,-(SP)		;;; Save R2 and R3
		BSBW	DUMP_BUFFER		;;; First, dump the buffer
		MOVQ	(SP)+, R2		;;; Restore R2 and R3
40$:		PUSHR	#^M<R0,R1,R2,R3,R4,R5>	;;; Store registers
		MOVC3	R2, (R3), @RING_PTR	;;; Move to buffer
		POPR	#^M<R0,R1,R2,R3,R4,R5>	;;; Restore registers
		ADDL	R2, RING_PTR		;;; Point to next byte
		SUBL	R2, RING_FREE		;;; Drop free counter
		RSB

		.SBTTL DUMP_BUFFER - Dump buffer to mailbox
;+
;	Routine to write the buffer to the mailbox.
;	First calls EXE$FORK to wait for IPL 6 interrupt;
;	Returns to caller to proceed until IPL drops.
;	Fork routine takes the text and writes it to the mailbox.
;-
DUMP_BUFFER:	SUBL3	RING_FREE, #RING_SIZE,-	;;; Free-original gives..
			WRITE_SIZE		;;;  Size to move
		MOVAL	RING_BUFFER, RING_PTR	;;; Reset pointer
		MOVL	#RING_SIZE,RING_FREE	;;; And free
		TSTL	WRITE_SIZE		;;; Anything to write?
		BLEQ	10$			;;; Nothing to do
		REMQUE	@FKB_LIST, R5		;;; Get a FKB to use
		BVS	10$			;;; No entry to get
		PUSHR	#^M<R0,R1,R2,R3,R4,R5>	;;; Save regs cross MOVC
		MOVC3	WRITE_SIZE, RING_BUFFER,-;;; Move # calculated from buffer
			BUF_2			;;; Move to mailbox write buffer
		POPR	#^M<R0,R1,R2,R3,R4,R5>	;;; Restore regs
		JSB	G^EXE$FORK		;;; Fork down
						;;; Return to caller at DIPL
;+
;	Following executed at FIPL (IPL 6) whenever things get
;	around to it
;-
		PUSHR	#^M<R0,R1,R2,R3,R4,R5>	; Save registers
		MOVAL	BUF_2, R4		; Address of buffer
		MOVL	WRITE_SIZE, R3		; Size of buffer
		MOVL	MBX_UCB, R5		; Get UCB Pointer
		JSB	G^EXE$WRTMAILBOX	; Write to mailbox
		POPR	#^M<R0,R1,R2,R3,R4,R5>	; Restore registers
		INSQUE	(R5), @FKB_LIST+4	; Insert back onto queue
10$:		RSB				; All done
		.SBTTL	RESET - Reset terminal UCB
		.ENTRY	RESET,^M<R2>
		MOVL	TERM_UCB, R2		; Point to terminal UCB
		BEQL	10$			; Skip if UCB gone
		DSBINT				;;; Disable interrupts
		MOVL	SAVED_PORT,-		;;; Restore port pointer
			UCB$L_TT_PORT(R2)	;;;   back to driver
		MOVL	SAVED_CLASS,-		;;; Restore class pointer
			UCB$L_TT_CLASS(R2)	;;;   back to driver
		MOVL	CLASS_GETNXT_VEC,-	;;; Restore UCB
			UCB$L_TT_GETNXT(R2)	;;;  getnxt pointer
		MOVL	CLASS_PUTNXT_VEC,-	;;;  putnxt pointer
			UCB$L_TT_PUTNXT(R2)	;;;
		ENBINT				; Restore IPL
		CLRL	TERM_UCB		; Clear UCB pointer
		MOVL	#SS$_NORMAL, R0		; All OK!
10$:		RET				; All done so far

		.SBTTL	FREE_POOL - Free nonpaged pool block
		.ENTRY	FREE_POOL,^M<R2,R3>
		DSBINT	#IPL$_ASTDEL		; Lock out deletion
		MOVL	CODE_PTR, R0		; Point to code
		JSB	G^EXE$DEANONPAGED	; Deallocate it
		ENBINT
		RET		

		.SBTTL FLUSH_RING - Kernel routine to flush ring buffer
		.ENTRY	FLUSH_RING, ^M<R2,R3,R4,R5>
		MOVL	#SS$_HANGUP, R0		; Assume hung up
		TSTL	TERM_UCB		; UCB There?
		BEQL	10$			; Nope, quit now.
		DSBINT	#21			;;; Lock down interrupts
		BSBW	DUMP_BUFFER		;;; Dump the buffer
		ENBINT				;;; Re-enable interrupts
		MOVL	#SS$_NORMAL, R0		; It's OK...
10$:		RET				; And return

		.SBTTL	SEND_IT - Send a character routine
SEND_IT:	MOVL	#SS$_HANGUP, R0		; Assume hung up
		MOVL	TERM_UCB, R5		; Get UCB pointer
		BEQL	30$			; Quit if none
		MOVL	4(AP), R3		; Get character
		DSBINT	#21			;;; Disable device ints
		JSB	@CLASS_PUTNXT_VEC	;;; Call putnext routine
		TSTB	UCB$B_TT_OUTYPE(R5)	;;; Check output type
		BEQL	10$			;;; None to do
		BSBW	GRAB_STARTIO		;;; Call the start I/O routine
10$:		ENBINT				; Enable interrupts
		MOVL	#SS$_NORMAL, R0		; Normal exit
30$:		RSB				; Done!

		KERN_SIZE = .-KERNEL_CODE	; Size of code to load
		.END	WATCH
%%
$ LIBRARY/MACRO/CREATE TTYDEF TTYDEF
$ MACRO WATCH
$ LINK WATCH,SYS$SYSTEM:SYS.STB/SELECTIVE
$ EXIT
410.11^\ doesnt workCOBRA::ROYThu May 07 1987 20:464
    
    	Cant seem to get input mode to work. ^\ doesnt do anything???
    	....
    
410.12Control or "^"USHS01::BLANDOReality, what a concept!Thu May 07 1987 22:524
    Most people use ^ to indicate the control key.  Did you type the
    characters "^" and "\", or Control "\"?
    
    FJBlando
410.13^ = CNTRL!COBRA::ROYMon May 11 1987 20:454
    
    	That's what I did wrong.. I typed ^ instead of cntrl....
    	thanks
    	Roy
410.14SCH$GL_CURPCB undefined in T5.0?FROST::W_PIPERbill piperFri Oct 23 1987 19:1917
    re: .10
    
    Under VMS V5, MACRO grumles about
    
%MACRO-W-GENWRN Raising IPL to #21 provides no multiprocessing...
    
    which is no big deal.  However, LINK says
    
%LINK-I-UDFSYM,	  SCH$GL_CURPCB
%LINK-W-USEUNDEF, undefined symbol SCH$GL_CURPCB
    
    And, of course, if you RUN WATCH anyway, all you get to watch
    is the system rebooting.
    
    Any idea what happened to the symbol?  Any quick fixes?
    
    -piper
410.15UFP::MURPHYRick MurphyFri Oct 23 1987 20:032
    Change it to CTL$GL_PCB.
    	-Rick
410.16Works greatCXJOAT::KERRISKFri Oct 23 1987 20:424
    	This Works great on V5. I have a fixed verion for V5 that inclyudes
    several other minor fixes. Drop me some mail If you want a copy.
    
    								Dennis
410.17Qualification of the use of CTL$GL_PCBVAXWRK::NEEDLEDoes VMS swim upstream to SPAWN?Fri Oct 23 1987 21:1212
Changing SCH$GL_CURPCB only solves part of the problem.  You also have
to be concerned with the issue that there may be more than one current
process.  If you are not on a multi-processing system, you don't have
to worry about it.  If you are, you should use the FIND_CPU_DATA Rx
macro and do a MOVL CPU$L_CURPCB(Rx),Ry.  You have to do this in kernel
mode above IPL 2.

CTL$GL_PCB is fine if you are in process context.

Jeff.

P.S.  WATCH.MAR is an exquisite piece of code.
410.18UFP::MURPHYRick MurphySat Oct 24 1987 00:499
    Re: .17 Thanks for the compliment!
    I looked at the code - it gets the current PCB pointer prior to
    calling SCH$IOLOCKR; it's scanning the I/O database for a UCB.
    There's probably a better way of doing this for V5, and it may be
    flat wrong. Let me know if WATCH runs, but it really needs to be
    checked out thoroughly. Specifically, don't use the TTYLIB macros
    that I supplied from V4; if the UCB definition changed, you're in
    big trouble..
  	-Rick
410.19Use the real ThingATDB2::KERRISKSat Oct 24 1987 03:005
    That was one of the things I fixed for V5. It now gets the correct
    TTYLIB stuff from sys$library before assembling. WATCH is a0 GREAT HACK!
    
    								Dennis
    									
410.20Software Artists still existOVDVAX::LENNIGDave, SWS, @CYO CincinnatiMon Oct 26 1987 15:227
    I have expressed this to several people in my office, 
    but yet to Rick directly...
    
    Rick, that code is a piece of art...
    
    With Admiration and Respect,
    	Dave
410.21UFP::MURPHYRick MurphyMon Oct 26 1987 20:063
    Re: .20
    Thank you.. it was fun, too!
    	-Rick
410.22GreaattCXJOAT::KERRISKSun Nov 01 1987 03:495
    	Fantastic!!  keep up the good work(fun)!!
    
    
    							Dennis
    
410.23I'm not a number, I am a free man.RDGCSS::ATTWOOLDo you speeka' my language ?Mon Nov 09 1987 11:286
    
    
    Great bit of code, Rick, but some people may feel disturbed if it fell into 
    the wrong hands.

    	Jka /?/
410.24UFP::MURPHYI'm not a hacker, but play one on TVMon Nov 09 1987 13:084
    If you give "the wrong hands" CMKRNL, you're in trouble already.
    Given CMKRNL, you can easily do the same thing with SDA.
    I just added a user interface ;-)
    	-Rick
410.25WATCH is great!SRFSUP::LONGOBob LongoTue Nov 10 1987 20:458
    Rick:
    
    Fantastic!  Reminds me of what we used to be able to do on TOPS-20.
    Now if I could only figure out (per your previous note) how to force
    input to a process with SDA.  I have heard of hacking SDA to allow
    deposits, or were you referring to reading someone's input?
    
    -Bob
410.26UFP::MURPHYI'm not a hacker, but play one on TVTue Nov 10 1987 23:517
    You use SDA to watch. Someone smarter than me could probably figure
    out how to force input using DELTA..
    
    This reminds me of some code I watch someone write once for TSS-8
    that did the same thing. I use that to write a utility to
    simultaneously log in 24 users. Great system exerciser!
    	-Rick
410.27WATCH a WT device?WJG::GUINEAUW. John GuineauThu Nov 12 1987 11:087

Watch doesn't seem to work on WT devices (VAXstation windows).
It doesn't crash, but no input is reflected and input mode does not
force to the other terminal.

JOhn 
410.28UFP::MURPHYI'm not a hacker, but play one on TVThu Nov 12 1987 17:214
    Re: .27
    I've never tried it, but Jon Callas told me it wouldn't work.
    However, if you're on the VAXstation, you can just look, not WATCH.
    	-Rick	:-)
410.29WJG::GUINEAUW. John GuineauFri Nov 13 1987 11:236



Not if your on a remote terminal wondering what someone is doing on your 
VAXstation! :-)
410.30ERIS::CALLASI like to put things on top of thingsFri Nov 13 1987 14:473
    Easy solution for that -- crash the system and look through the dump! 
    
    	Jon