Newsgroups: vmsnet.internals
Subject: Current directory in prompt
From: don@zl2tnm.gen.nz
Date: 4 Oct 92 05:14:50 +1200
Organization: The Wolery


My "first" (well, first for several years) issue of VAX Pro arrived last 
week, and I finally got around to reading it.

Under "technical tip" is Nick de Smith's little DCL_DIRECTORY to copy 
the current directory into the prompt every second or so.

Fine, thinks I, but the timer isn't the best way to do things -- it burns 
cycles when not needed, and doesn't when it is (ie you can say SET 
DEFAULT [BLAH] and not see the new prompt until the next time you hit 
Return). 

So I came up with this version.  The actual setting the prompt code is 
Nick's, quite unmodified (although I have a few ideas as to improvements 
that could be made).  

What I do is re-vector SYS$SETDDIR to point to the code in P1 pool, so 
that after each call to $SETDDIR, the prompt is updated.

The only snag at the moment is that the routine runs in the access mode 
of the caller, which means it may or may not be able to fiddle the 
prompt.  Usually, it will run in supervisor mode (ie when called from 
DCL as a result of a SET DEFAULT command), but if a user mode program 
decides to change the default directory, the prompt won't be updated.

Anyone have a good solution to this problem?  (It's 5am and I'm off to 
bed!)

Don Stokes, ZL2TNM (DS555)                       don@zl2tnm.gen.nz (home)
Network Manager, Computing Services Centre           don@vuw.ac.nz (work)
Victoria University of Wellington, New Zealand             +64-4-495-5052

	.title PROMPT	Display current directory in prompt

;++
;
; This little ditty sets your prompt to the current directory every time
; the system service $SETDDIR is called from supervisor more or less (ie 
; whenever done from DCL).  
;
; This works by revectoring the $SETDDIR system service.  To do this we
; need to create virtual memory over the process system service entry point,
; set the page protection to something writable and tweak it.  Note that the
; acto of creating virtual memory also zeroes it, so we have to save the 
; page first and copy it back into the new memory.
;
; HERE BE DRAGONS:  By sheer luck, the $CRETVA and $SETPRT system service
; entry points do not occupy the same page as $SETDDIR ($SETPRT doesn't miss
; by much!), so we can get away with just copying the page, creating the new
; page and copying back.  Note also that the entry points are quadword 
; aligned, so _in_theory_ we shouldn't see any page boundary conditions.
;
; The code to change the prompt is lifted straight out of Nick de Smith's 
; DCL_DIRECTORY routine published in the Aug '92 VAX Pro.  The techniques
; used to revector system services are based on a part of the kernel mode
; portion of DBGSSISHR (SSIK.B32).  (DEBUG's SSIK stuff seems to be 
; compatible.)
;
; Obviously, this requires CMKRNL privilege to install itself, but once 
; loaded, requires no privilege to keep updating the prompt.
;
; Don Stokes <don@zl2tnm.gen.nz>			4-Oct-1992
;
;--


		.link "SYS$SYSTEM:SYS.STB"/selective_search
		.link "SYS$SYSTEM:DCLDEF.STB"/selective_search

		$PRTDEF
		$PSLDEF

code_start:	.blkl		; Location of code in P1 pool
pagetweak:	.blkl 2		; Virtual address of page containing SYS$SETDDIR

setprot:	$SETPRT inadr=pagetweak, acmode=PSL$C_KERNEL, prot=PRT$C_UW
resetprot:	$SETPRT inadr=pagetweak, acmode=PSL$C_KERNEL, prot=PRT$C_URKW
cretva:		$CRETVA inadr=pagetweak, acmode=PSL$C_KERNEL
				; Arglists for $CMKRNL calls (This means that
				; all kernel stuff goes straigt into the system
				; services -- me?  paranoid?

vectmp:		.blkb 512	; Temp storage while we tear the system service
				; vectors down and rebuild 'em.


;
; Mainline code -- install change prompt code and revector $SETDDIR to point
; to it.
;
	.entry prompt, ^M<>
		cmpl @#SYS$SETDDIR+2,#^x00278FBD; Check that $SETDDIR looks how
		beql 1$				; we expect, ie CHME #^x0027
		movl #SS$_ABORT, R0		; (This also checks that we
		ret				;  haven't already run)

1$:		$CMEXEC_S routin=install_code	; Install routine in P1 pool
						; Doesn't return anything useful

		bicl3 #^x000001FF, #SYS$SETDDIR, pagetweak
		movl pagetweak, pagetweak+4	; Calculate page address that
						; $SETDDIR lives in

		movc3 #512, @pagetweak, vectmp	; Save page to be mapped
		$CMKRNL_S routin=SYS$CRETVA, arglst=cretva
		blbc R0, 99$			; Create memory over the page
		$CMKRNL_S routin=SYS$SETPRT, arglst=setprot
		blbc R0, 99$			; Set page protection to UW
		movc3 #512, vectmp, @pagetweak	; Restore pages from saved copy

						; Point vector at our code in P1
		movw #^x9F17, @#SYS$SETDDIR+2	; JMP @#
		movl code_start,@#SYS$SETDDIR+4 ;       directory_code

		$CMKRNL_S routin=SYS$SETPRT, arglst=resetprot
		blbc R0, 99$			; Set page protection to URKW

		$CMEXEC_S routin=first_time	; Set the prompt now.

99$:		ret				; All done


;
; Code to install directory prompt stuff in P1 pool
;
	.entry install_code, ^m<>
		movl #directory_code_len, R1	; R1=length of allocated block
		jsb EXE$ALOP1PROC		; Get P1 pool
		movl R2, code_start		; Save address
		movc3 #directory_code_len, directory_code, (R2)
		ret				; Copy code into P1

;
; Stub to call local copy of directory prompt stuff so prompt is set before
; exit.
;
	.entry first_time, ^M<>			; Called in exec mode to set
		movl #1, R0			; the prompt for the first time
		brb skip_chme


;
; Routine to intercept $SETDDIR system service
;
directory_code:	chme #^x0027			; The real SYS$SETDDIR, we hope
skip_chme:					; Come here from first_time

		pushl R0			; Save return from real SETDDIR

		movpsl R0
		bbc #<PSL$V_CURMOD+1>, R0, 1$	; Don't do this unless we're
		bbs #<PSL$V_CURMOD>, R0, 999$	; in at least supervisor mode

1$:		pushr #^m<r2,r3,r4>		; Save regs

		moval @#CTL$AG_CLIDATA, R2	; Nick de Smith's code
		blequ 99$
		movl PPD$L_PRC(R2), R2
		blequ 99$

		movab @#PIO$GT_DDSTRING, R3
		movzbl (R3)+, R4
		cmpl R4, #PRC_S_PROMPT-1
		blssu 10$
		subl2 #PRC_S_PROMPT-1, R4
		addl2 R4, R3
		movl #PRC_S_PROMPT-1, R4

10$:		pushr #^m<r2,r3,r4,r5>
		movc3 R4, (R3), PRC_G_PROMPT(R2)
		popr #^m<r2,r3,r4,r5>
		addb3 #3+1, R4, PRC_B_PROMPTLEN(R2)
		movb #32, PRC_G_PROMPT(R2)[R4]

99$:		popr #^m<r2,r3,r4>		; Restore regs & exit
999$:		movl (SP)+, R0
		ret

directory_code_len = .-directory_code

	.end prompt