From:	SMTP%"everhart@star.zko.dec.com" 19-SEP-1996 19:11:05.15
To:	EVERHART
CC:	
Subj:	dump-recall-buf.src

Date: Thu, 19 Sep 1996 14:46:35 -0400
Message-Id: <96091914463507@star.zko.dec.com>
From: everhart@star.zko.dec.com (Glenn C. Everhart 603 881 1497)
To: everhart@gce.com
Subject: dump-recall-buf.src
X-VMS-To: SMTP%"everhart@gce.com"

              <<< VAXAXP::NOTES$:[NOTES$LIBRARY]VMSNOTES.NOTE;1 >>>
               -< VAX and Alpha VMS - Digital Internal Use Only >-
================================================================================
Note 54.4  How to increase the number of commands saved by RECALL/ALL    4 of 11
DYPSS1::DYSERT "Barry - Custom Software Developmen" 322 lines   6-JAN-1995 10:29
                       -< Fixed so it works under V6.1 >-
--------------------------------------------------------------------------------
$ set = "set"
$ SET  symbol/scope = (noglobal,nolocal)/verb
$ DELE/symbol/local set
$ GOTO _after_introduction

 GET_RECALL_BUFFER.COM E1.0, (Get ENTIRE recall buffer and store in a file).
   Skip Morris, "SWSVAX::MORRIS", 6-Jun-90.

   Input parameters:
     P1: Filespec to store recalled commands [default to RECALL_BUFFER.TMP;].
     P2: Number of commands to recall [default to entire buffer].
     P3: Order to recall commands (FORWARD/REVERSE) [defaults FORWARD].

   Note: The ENTIRE recall buffer is returned (not just the last 20 commands),
     IN THE ORDER THEY WERE TYPED.  A "$" is also placed in front of each cmd.

   (This procedure is based upon ANALYZE.COM, which was derived from my
     original work on NETUPDATE.COM V1 (many, many years ago when Engineering
     ran the ENet.)  ANALYZE.COM is available in HACKERS notesfile note 1048.)

Edit History
---- -------
Chuck Newman            23 Nov 1993  Modify so that it will work on all OpenVMS
                                     VAX platforms.  Modifications to make it
                                     work on OpenVMS AXP have not been done, but
                                     should be straightforward.
                                     Also, I stripped out all the symbols that
                                     weren't required to get this command
                                     procedure to work (but might have been
                                     needed in related procedures).

$_after_introduction:
$ set noon
$ gosub initialize
$ gosub get_recall_buffer
$ gosub store_recall_buffer
$!
$ exit
$!
$! start of subroutine calls...
$initialize:
$ output_file = f$parse(p1,"recall_buffer.tmp;",f$envi("procedure"))
$ limit = f$integer(p2)
$ if f$edit(p2,"trim,uncomment") .eqs. "" then limit = -1
$ recall_forward = f$edit(p3,"trim,upcase") .nes. "REVERSE"
$!
$ version = f$getsyi("version")
$ major   = f$element(0, ".", version)
$ version = f$element(1, ".", version)
$ minor   = f$element(0, "-", version)
$ variant = f$element(1, "-", version)
$ version = major + "_" + minor + "_" + variant - "." - "-"
$ version = f$edit(version, "collapse")
$ save_mes = f$environment("message")
$ SET mess/nof/nos/noi/not
$ ON warning then GOTO _new_version
$ !
$ ! Skip's original version had a lot of symbols that didn't seem necessary
$ ! for the recall functionality.  I've stripped them out.
$ !
$ ! Try to go to a subroutine unique to this version of VMS
$ ! If it fails, it will go to _new_version
$ ! _new_version will teach this .COM about this versiof of VMS
$ ! When it returns, it will come back to the line after the GOSU
$ !
$ ! This won't work with OpenVMS AXP, where the symbols are found in 
$ ! sys$loadable_images:dcldef.stb and sys$loadable_images:sys$base_image.exe.
$ ! Making the modification for this shouldn't be too difficult.
$ !
$ GOSU _'version'
$ !
$ ON warning then CONTINUE
$ SET message'save_mes'
$ prc_addr = f$cvui(0,32,f$fao("!AD",4,ctl$ag_clidata+ppd$l_prc))
$ return
$!
$get_recall_buffer:
$! HA!!! If it can't be done in DCL then it's not worth doing!!!
$ recall_pointer = f$cvui(0,32,f$fao("!AD",4,prc_addr+prc_l_recallptr)) -
    - prc_addr - prc_g_commands
$ if prc_c_cmdbufsiz .le. 512
$  then
$   recall_buffer1 = f$fao("!AD",prc_c_cmdbufsiz,prc_addr+prc_g_commands)
$   recall_buffer2 = ""
$  else
$   recall_buffer1 = f$fao("!AD",512,prc_addr+prc_g_commands)
$   recall_buffer2 = -
      f$fao("!AD",prc_c_cmdbufsiz-512,prc_addr+prc_g_commands+512)
$  endif
$ return
$!
$store_recall_buffer:
$ create 'output_file'
$   if .not. $status then exit $status.or.%x10000000
$ open/append outchan 'output_file'
$ ptr = recall_pointer				! find current start of buffer
$ wraparound = "false"
$ if recall_forward then gosub advance_past_null ! to go oldest command.
$loop:
$ if recall_forward				! move ptr past null separator
$  then
$   ptr = ptr + 1				! handle wraparound fwd
$   if ptr .ge. prc_c_cmdbufsiz
$    then
$      ptr = 0
$      wraparound = "true"
$    endif
$  else
$   ptr = ptr - 1				! handle wraparound reverse
$   if ptr .lt. 0
$    then
$      ptr = prc_c_cmdbufsiz-1
$      wraparound = "true"
$    endif
$  endif
$ if ptr .lt. 512				! get length of command
$   then len = f$cvui(ptr*8,8,recall_buffer1)
$   else len = f$cvui((ptr-512)*8,8,recall_buffer2)
$   endif
$ if (len .le. 0) .or. (limit .eq. 0)		! if zero then no more cmds.
$  then
$   close outchan
$   return
$  endif
$ limit = limit - 1
$ if wraparound then -				! sanity check with error rtn
    if (recall_forward .and. (ptr .gt. recall_pointer)) .or. -
    (.not. recall_forward .and. (ptr .lt. recall_pointer)) then return %x2
$ if recall_forward				! get start of cmd.
$  then
$   cmd = ptr + 1				!  is AFTER fwd char count
$   if cmd .ge. prc_c_cmdbufsiz then cmd = 0
$  else
$   cmd = ptr-len				!  is BEFORE reverse char cnt
$   if cmd .lt. 0 then cmd = prc_c_cmdbufsiz + cmd
$  endif
$ if cmd .lt. 512				! extract command line...
$   then cmd_line = f$extr(cmd,len,recall_buffer1)
$   else cmd_line = f$extr(cmd-512,len,recall_buffer2)
$   endif
$ if (cmd .lt. 512) .and. (cmd+len .ge. 512) -
    then cmd_line = cmd_line + f$extr(0,cmd+len+1-512,recall_buffer2)
$ if (cmd .ge. 512) .and. (cmd+len .ge. prc_c_cmdbufsiz) then cmd_line = -
    cmd_line + f$extr(0,len-(prc_c_cmdbufsiz-cmd),recall_buffer1)
$ write outchan "$ ",cmd_line
$ if recall_forward				! move ptr to next command
$   then ptr = ptr + 1 + len + 1		! dbbl length fields are:
$   else ptr = ptr - 1 - len - 1		!   command + 2 length fields
$   endif
$ if recall_forward				! handle wraparound of ptr
$  then
$   if ptr .ge. prc_c_cmdbufsiz			!   in forward direction
$    then
$      ptr = ptr - prc_c_cmdbufsiz
$      wraparound = "true"
$    endif
$  else
$   if ptr .lt. 0				!   in reverse direction
$    then
$      ptr = prc_c_cmdbufsiz + ptr
$      wraparound = "true"
$    endif
$  endif
$ goto loop
$!
$advance_past_null:				! this may take a while if the
$ ptr =  ptr + 1				!   buffer only has a few cmds
$   if ptr .eq. prc_c_cmdbufsiz then ptr = 0	! wraparound
$ if ptr .eq. recall_pointer then return	! wraparound sanity chk
$ if ptr .lt. 512				! get length of command
$   then len = f$cvui(ptr*8,8,recall_buffer1)
$   else len = f$cvui((ptr-512)*8,8,recall_buffer2)
$   endif
$ if len .ne. 0					! found the oldest cmd!!!
$  then
$   ptr = ptr - 1				! restore pointer
$   return
$  endif
$ goto advance_past_null

$_new_version:
$ WRIT sys$output "This is a new version of VMS for this command procedure"
$ WRIT sys$output "Please wait while it modifies itself with constants for this version of VMS"
$ pid = f$getjpi(0,"pid")
$ !
$ ! Look in sys$system:sys.stb for CTL$AG_CLIDATA
$ ! This could be done more compactly if I was certain that the format of 
$ ! ANALYZE wouldn't reorder its output.  I don't know that that's guaranteed,
$ ! so we'll make theh procedure of isolating its value a little loose.
$ !
$ ANAL/obj sys$system:sys.stb/out=sys$scratch:recall_analyze.'pid'
$ SEAR -
sys$scratch:recall_analyze.'pid'/out=sys$scratch:recall_search_1.'pid'/exa/win=(2,0) -
    CTL$AG_CLIDATA
$ SEAR sys$scratch:recall_search_1.'pid'/out=sys$scratch:recall_search_2.'pid' -
"version mask value:"/mat=nand
$ SEAR sys$scratch:recall_search_2.'pid'/out=sys$scratch:recall_search_3.'pid' -
"value:"
$ OPEN/read channel sys$scratch:recall_search_3.'pid'
$ READ channel line
$ CLOS channel
$ !
$ ! We should now have the line which contains the value of CTL$AG_CLIDATA.
$ !
$ ctl$ag_clidata = f$integer(f$edit(f$element(1, ":", f$element(0, "(", line)),"collapse"))
$ !
$ ! Clean up
$ !
$ DELE sys$scratch:recall_analyze.'pid';*,sys$scratch:recall_search_%.'pid';*
$ !
$ ! Look in sys$system:dcldef.stb for ppd$l_prc, prc_c_cmdbufsiz,
$ ! prc_g_commands, and prc_l_recallptr.
$ ! Same discussion as above about trying to be flexible.
$ !
$ ANAL/obj sys$system:dcldef.stb/out=sys$scratch:recall_analyze.'pid'
$ SEAR -
sys$scratch:recall_analyze.'pid'/out=sys$scratch:recall_search_1.'pid'/exa/win=(2,0) -
    PPD$L_PRC, PRC_C_CMDBUFSIZ, PRC_G_COMMANDS, PRC_L_RECALLPTR
$ SEAR sys$scratch:recall_search_1.'pid'/out=sys$scratch:recall_search_2.'pid' -
"version mask value:"/mat=nand
$ !
$ SEAR -
sys$scratch:recall_search_2.'pid'/out=sys$scratch:recall_search_3.'pid'/exa/win=(1,0) PPD$L_PRC
$ SEAR sys$scratch:recall_search_3.'pid'/out=sys$scratch:recall_search_4.'pid' "value:"
$ OPEN/read channel sys$scratch:recall_search_4.'pid'
$ READ channel line
$ CLOS channel
$ !
$ ! We should now have the line which contains the value of PPD$L_PRC.
$ !
$ ppd$l_prc = f$integer(f$edit(f$element(1, ":", f$element(0, "(", line)),"collapse"))
$ SEAR -
sys$scratch:recall_search_2.'pid'/out=sys$scratch:recall_search_3.'pid'/exa/win=(1,0) PRC_C_CMDBUFSIZ
$ SEAR sys$scratch:recall_search_3.'pid'/out=sys$scratch:recall_search_4.'pid' "value:"
$ OPEN/read channel sys$scratch:recall_search_4.'pid'
$ READ channel line
$ CLOS channel
$ !
$ ! We should now have the line which contains the value of PRC_C_CMDBUFSIZ.
$ !
$ prc_c_cmdbufsiz = f$integer(f$edit(f$element(1, ":", f$element(0, "(", line)),"collapse"))
$ SEAR -
sys$scratch:recall_search_2.'pid'/out=sys$scratch:recall_search_3.'pid'/exa/win=(1,0) PRC_G_COMMANDS
$ SEAR sys$scratch:recall_search_3.'pid'/out=sys$scratch:recall_search_4.'pid' "value:"
$ OPEN/read channel sys$scratch:recall_search_4.'pid'
$ READ channel line
$ CLOS channel
$ !
$ ! We should now have the line which contains the value of PRC_G_COMMANDS.
$ !
$ prc_g_commands = f$integer(f$edit(f$element(1, ":", f$element(0, "(", line)),"collapse"))
$ SEAR -
sys$scratch:recall_search_2.'pid'/out=sys$scratch:recall_search_3.'pid'/exa/win=(1,0) PRC_L_RECALLPTR
$ SEAR sys$scratch:recall_search_3.'pid'/out=sys$scratch:recall_search_4.'pid' "value:"
$ OPEN/read channel sys$scratch:recall_search_4.'pid'
$ READ channel line
$ CLOS channel
$ !
$ ! We should now have the line which contains the value of PRC_L_RECALLPTR.
$ !
$ prc_l_recallptr = f$integer(f$edit(f$element(1, ":", f$element(0, "(", line)),"collapse"))
$ !
$ ! Clean up
$ !
$ DELE sys$scratch:recall_analyze.'pid';*,sys$scratch:recall_search_%.'pid';*
$ !
$ ! Now that we have the values we need, modify this command procedure so that 
$ ! it knows about this version of VMS
$ !
$ procedure = f$element(0, ";", f$parse(f$environment("procedure"),,,,"no_conceal") - "][")
$ OPEN/read input 'procedure'
$ OPEN/write output 'procedure'
$ COPY input output
$ CLOS input
$ WRIT output ""
$ WRIT output "$_", version, ":"
$ WRIT output "$ ctl$ag_clidata = ", ctl$ag_clidata
$ WRIT output "$ ppd$l_prc = ", ppd$l_prc
$ WRIT output "$ prc_l_recallptr = ", prc_l_recallptr
$ WRIT output "$ prc_g_commands = ", prc_g_commands
$ WRIT output "$ prc_c_cmdbufsiz = ", prc_c_cmdbufsiz
$ WRIT output "$ RETU"
$ WRIT output "$ EXIT"
$ CLOS output
$ RETU
$ EXIT

$_V5_3_:
$ ctl$ag_clidata = %x7ffe2a5c
$ ppd$l_prc = 8
$ prc_l_recallptr = 304
$ prc_g_commands = 309
$ prc_c_cmdbufsiz = 1025
$ RETU
$ EXIT

$_V5_4_2:
$ ctl$ag_clidata = %x7ffe2a5c
$ ppd$l_prc = 8
$ prc_l_recallptr = 304
$ prc_g_commands = 309
$ prc_c_cmdbufsiz = 1025
$ RETU
$ EXIT

$_V5_5_2:
$ ctl$ag_clidata = 2147363420
$ ppd$l_prc = 8
$ prc_l_recallptr = 384
$ prc_g_commands = 389
$ prc_c_cmdbufsiz = 1025
$ RETU
$ EXIT

$_V6_1_:
$ ctl$ag_clidata = 2147363420
$ ppd$l_prc = 8
$ prc_l_recallptr = 384
$ prc_g_commands = 389
$ prc_c_cmdbufsiz = 1025
$ RETU
$ EXIT
