From:	CRDGW2::CRDGW2::MRGATE::"SMTP::CRVAX.SRI.COM::RELAY-INFO-VAX" 12-DEC-1989 11:56
To:	MRGATE::"ARISIA::EVERHART"
Subj:	Retrieve, part 4 of 5

Received: From NAC.NO by GIZMO.SRI.COM with TCP; Tue, 12 DEC 89 07:27:00 PDT
Received: from runix.runit.sintef.no by nac.no (5.61++/1.15) with SMTP 
	id AA14304; Tue, 12 Dec 89 16:24:48 +0100
Received: by runix.runit.sintef.no (norunix.EARN) (1.2/7.8)
	id AA19861;  Tue, 12 Dec 89 16:25:31 +0100
Date: 12 Dec 89 16:24 +0100
From: Jo Torsmyr <j_torsmyr%avh.unit.uninett@nac.no>
To: info-vax@kl.sri.com
Message-Id: <230*j_torsmyr@avh.unit.uninett>
Subject: Retrieve, part 4 of 5

+-+-+-+ Beginning of part 4 +-+-+-+
X`009`009to display the next command.
X`009`009If ArrayP is equal to LogEndPointer, DownArrowEnd is set. This
X`009`009is done because when the Up-arrow key is pressed, we want to
X`009`009display the previous command even if ArrayP is equal to
X`009`009LogEndPointer. If you press the Down-arrow key when ArrayP is
X`009`009equal to LogEndPointer, the current initialstring is zeroed out.
X
X`009  RETURN: Terminates the lineediting and returns the command string.
X
X
X      FORMAL PARAMETERS:`032
X      `032
X`009  IniStr - The initialization string, that is, the commandstring
X`009`009   found in the recallbuffer which matched the searchstring.
X`009  Prompt - The string containing the DCL prompt.
X`009  ArrayP - The pointer to the recallbuffer.
X`009  DstStr - The command which is to be executed in DCL.
X      `032
X      IMPLICIT INPUTS:
X      `032
X`009  LogEndPointer and RecallArray.`009 `032
X      `032
X      IMPLICIT OUTPUTS:
X      `032
X`009  NONE
X      `032
X      ROUTINE VALUE:
X      `032
X`009  NONE
X      `032
X      SIDE EFFECTS:
X      `032
X`009  NONE
X      `125
X  `032
X    CONST
X      (* Carriage Return specification, see I/O User's Part I, 8-37 *)
X      (* The Postfix byte is used. Bit 7 is set to signal the single *)
X      (* ASCII control character specified by the configuration of *)
X      (* bits 0 to 4 (13 i.e. carriage return) *)
X      CR_Spec`009    = 128 + 13 ;
V      (* Read with prompt, use extended to provide additional functionality.
X *)
X      IO_Function   = IO$_ReadPrompt + IO$M_Extend ;
X    TYPE
X      (* The itemlist read descriptor as described in the *)
X      (* I/O User's Part I, 8-29. *)
X      ItemType`009    = RECORD
X`009`009`009Buffer_Length,
X`009`009`009Item_Code`009: $UWORD ;
X`009`009`009Addr_Or_Data,
X`009`009`009Return_Address`009: UNSIGNED ;
X`009`009      END (* of RECORD ItemType *) ;
X      TermSetType   = PACKED ARRAY [1..16] OF CHAR ;
X
X      (* IOSB contents for itemlist read function as described in *)
X      (* I/O User's Part I, 8-49. *)
X      IO_Status_Block`009= [UNSAFE, QUAD]
X`009`009`009  RECORD
X`009`009`009    Status,
X`009`009`009    OffSet_To_Terminator`009: $UWORD ;
X`009`009`009    Terminator_Character,
X`009`009`009    Reserved,
X`009`009`009    Terminator_Length,
X`009`009`009    Cursor_Position_From_EOLN`009: $UBYTE ;
X`009`009`009  END (* of RECORD IO_Status_Block *) ;
X      ItemList`009    = ARRAY [1..4] OF ItemType ;
X`009`009`009
X    VAR
X      (* Bufferpointer used when recalling next command *)
X      DummyP`009    : BufferInt ;
X      ClearLine,`009`009    (* Escape sequence to erase a line *)
X      Buffer`009    : VarCmdType ;  (* Varying string buffer *)
X      (* Itemlist describing the read function options *)
X      ReadItems`009    : ItemList ;
X      QIO_IO_Status : IO_Status_Block ;`009(* $QioW I/O status block *)
X      IO_Channel    : $UWORD ;`009`009(* Terminal channel *)
X      LocalIniStr,`009`009    (* Local initialization string for $QioW *)
X      LocalPromptStr,`009`009`009(* Local prompt string for $QioW *)
X      (* Received string from $QioW *)
X      ReceiveStr    : PACKED ARRAY [1..MaxCmdLen] OF CHAR ;
X      TerminatorSet : TermSetType ; (* Read function terminatorset *)
X      DownArrowEnd,`009`009(* At start of buffer due to Down-arrow key *)
X      Exit`009    : BOOLEAN ;`009(* Termination marker *)
X   `032
X
X  PROCEDURE Set_Terminator (VAR TermSet : TermSetType ; TermCode : INTEGER) ;
X  `032
X      `123
X      FUNCTIONAL DESCRIPTION:`032
X      `032
X`009  Set_Terminator sets a read function terminator.
X`009  The terminator set is described in I/O User's Part I, 8-28:
X
X`009  The long form is used. A mask size of 16 bytes allows all seven-bit
X`009  ASCII characters to be used as terminators. The format of the
X`009  string is interpreted as follows:
X
X`009  Terminator mask:
X
X`009  1. byte`009  2. byte ...`009`009`009    ... 16 byte
X
X`009  0 1 2 3 4 5 6 7 8 9 ...`009`009`009`009`009127
X`009  -----------------------------------------------------------------
V`009  `124 `124 `124 `124 `124 `124 `124 `124 `124 `124 `124 `124 `124 `124 `
X124 `124 `124 `124 `124 ...`009       ...  `124 `124 `124 `124
X`009  -----------------------------------------------------------------
X
X`009  16 bytes = 16 * 8 = 128 bits
X`009  When a bit is set, the character with ASCII-value = Bit-nr. is a
X`009  terminator. Otherwise, the character isn't a terminator.
X
X`009  Example of how to set a terminator (R):
X
X`009  R has ASCII-value 82.
X`009  Byte-nr`009`009= 82 DIV 8 + 1 = 11
X`009  Bit-nr in Byte`009= 82 MOD 8`009= 2
X`009  Byte-value`009`009= 2 ** Bit-nr in Byte
X      `032
X      FORMAL PARAMETERS:`032
X      `032
X`009  TermSet - The terminator set.
X`009  TermCode - The ordinal value of the terminator character to be
X`009`009     added to the terminatorset.
X      `032
X      IMPLICIT INPUTS:
X      `032
X`009  NONE
X      `032
X      IMPLICIT OUTPUTS:
X      `032
X`009  NONE
X      `032
X      ROUTINE VALUE:
X      `032
X`009  NONE
X      `032
X      SIDE EFFECTS:
X      `032
X`009  NONE
X      `125
X  `032
X    BEGIN
X      TermSet[(TermCode DIV 8) + 1] :=`032
X      Chr (Ord (TermSet[(TermCode DIV 8) + 1]) + 2 ** (TermCode MOD 8)) ;
X  END (* of PROCEDURE Set_Terminator *) ;
X
X
X    BEGIN (* of PROCEDURE LineEditor *)
X      (* Sequence to delete the content of the current cursor line *)
X      ClearLine`009:= Chr (27) + '[2K' ;
X      Exit`009:= FALSE ;
X      (* DownArrowEnd is TRUE when the Down-arrow key has reached the last *)
X      (* command in the buffer => ArrayP = LogEndPointer *)
X      DownArrowEnd := FALSE ;
X
X      TerminatorSet`009:= Zero ;
X
X      (* Set the desired terminators *)
X      Set_Terminator (TerminatorSet, 27) ;  (* ESC (Down = Esc [ B) *)
X      Set_Terminator (TerminatorSet, 2) ;   (* Ctrl-B/Up *)
X      Set_Terminator (TerminatorSet, 13) ;  (* Return *)
X
X      (* Disable the recall feature & allow escape sequences *)
X      ReadItems[1].Buffer_Length    := 0 ;
X      ReadItems[1].Item_Code`009    := Trm$_Modifiers ;
V      ReadItems[1].Addr_Or_Data`009    := Trm$M_Tm_NoRecall + Trm$M_Tm_Escape
X ;
X      ReadItems[1].Return_Address   := 0 ;
X
X      (* Assign the terminators *)
X      ReadItems[2].Buffer_Length    := Size (TerminatorSet)  ;
X      ReadItems[2].Item_Code`009    := Trm$_Term ;
X      ReadItems[2].Addr_Or_Data`009    := IAddress (TerminatorSet) ;
X      ReadItems[2].Return_Address   := 0 ;
X
X      (* Assign a prompt *)
X      ReadV (PromptStr, LocalPromptStr) ;
X      ReadItems[3].Buffer_Length    := PromptStr.Length ;
X      ReadItems[3].Item_Code`009    := Trm$_Prompt ;
X      ReadItems[3].Addr_Or_Data`009    := IAddress (LocalPromptStr) ;
X      ReadItems[3].Return_Address   := 0 ;
X
X      (* Assign an inistring *)
X      ReadItems[4].Item_Code`009    := Trm$_IniStrng ;
X      ReadItems[4].Addr_Or_Data`009    := IAddress (LocalIniStr) ;
X      ReadItems[4].Return_Address   := 0 ;
X
X      $Assign (Terminal, IO_Channel) ;`009`009(* Assign terminal channel *)
X
X      REPEAT
X`009ReadV (IniStr, LocalIniStr) ;
X`009ReadItems[4].Buffer_Length  := IniStr.Length ;
X
X`009ReceiveStr := Zero ;
X`009$QioW (Chan := IO_Channel,`009    (* Channel *)
X`009       Func := IO_Function,`009    (* Function *)
X`009       IOSB := QIO_IO_Status,`009    (* IO status *)
X`009       P1   := ReceiveStr,`009    (* Receive buffer *)
X`009       P2   := MaxCmdLen,`009    (* Receive length *)
X`009       P5   := IAddress (ReadItems),(* Itemlist address *)
X`009       P6   := Size (ItemList)) ;   (* Itemlist size in bytes *)
X
X`009(* Now check the terminator *)
X`009CASE QIO_IO_Status.Terminator_Character OF
X(* UP *)     2  : IF NOT (ArrayP = LogEndPointer) OR DownArrowEnd THEN
X`009`009     BEGIN
X`009`009       IF DownArrowEnd THEN
X`009`009`009  DownArrowEnd := FALSE ;
X`009`009       IF NOT (RecallArray[Inc (ArrayP, -1)] = Null) THEN
X`009`009`009  GetPrevCommand (IniStr, ArrayP)
X`009`009       ELSE
X`009`009`009  Inc (ArrayP, 1) ;
X`009`009     END ;
X(* RETURN *) 13 : Exit := TRUE ;
X(* DOWN *)   27 : BEGIN
X`009`009    WriteV (Buffer, ReceiveStr) ;
X`009`009    IF SubStr (Buffer, QIO_IO_Status.Offset_To_Terminator + 2,
X`009`009`009       QIO_IO_Status.Terminator_Length - 1) = '[B' THEN
X`009`009       IF NOT (ArrayP = LogEndPointer) THEN
X`009`009`009  BEGIN
X`009`009`009    (* Position ArrayP to length *)
X`009`009`009    Inc (ArrayP, 1) ;
X`009`009`009    (* ArrayP now points to the next NULL byte *)
X`009`009`009    Inc (ArrayP, Ord (RecallArray[ArrayP]) + 2) ;
X`009`009`009    IF NOT (ArrayP = LogEndPointer) THEN
X`009`009`009       BEGIN
X`009`009`009`009 DummyP := ArrayP ;
X`009`009`009`009 (* DummyP points to the leading length byte *)
X`009`009`009`009 DummyP := Inc (DummyP, 1) ;
X`009`009`009`009 GetNextCommand (IniStr, DummyP) ;
X`009`009`009       END (* of IF *)
X`009`009`009    ELSE
X`009`009`009       BEGIN
X`009`009`009`009 IniStr`009`009:= Zero ;
X`009`009`009`009 DownArrowEnd`009:= TRUE ;
X`009`009`009       END (* of ELSE *) ;
X`009`009`009  END (* of IF *)
X`009`009       ELSE
X`009`009`009  BEGIN
X`009`009`009    IniStr`009    := Zero ;
X`009`009`009    DownArrowEnd    := TRUE ;
X`009`009`009  END (* of ELSE *) ;
X`009     END ;
X`009END (* of CASE *) ;
X
X`009IF NOT Exit THEN (* => Clear current line *)
X`009   $QioW (Chan  := IO_Channel,`009`009`009    (* Channel *)
X`009`009  Func  := IO$_WriteVBlk + IO$M_NoFormat,   (* Function *)
X`009`009  P1    := ClearLine.Body,`009(* Write string *)
X`009`009  P2    := ClearLine.Length,`009(* Write length *)
X`009`009  P4    := CR_Spec * (2 ** 24)) ;  (* Carriage return control *)
X      UNTIL Exit ;
X
X      $DAssgn (IO_Channel) ;`009`009`009(* Deassign terminal channel *)
X      WriteV (DstStr, ReceiveStr) ;`009`009(* Return the string read *)
X      (* Strip off terminator from string *)
X      DstStr := SubStr (DstStr, 1, QIO_IO_Status.Offset_To_Terminator) ;
X  END (* of PROCEDURE LineEditor *) ;
X
X
X  PROCEDURE RecallCmd ;
X  `032
X      `123
X      FUNCTIONAL DESCRIPTION:`032
X      `032
X`009  RecallCmd retrieves a command. The command is specified by a number
X`009  or a character string which is tried to be matched. You specify a
X`009  number larger than 255, then the actual value is your value MOD 255.
X`009  If the command string is ommited, the first command in the buffer is
X`009  returned.
X
X      `032
X      FORMAL PARAMETERS:`032
X      `032
X`009  NONE
X      `032
X      IMPLICIT INPUTS:
X      `032
X`009  RecallArray and LogEndPointer.
X      `032
X      IMPLICIT OUTPUTS:
X      `032
X`009  NONE
X      `032
X      ROUTINE VALUE:
X      `032
X`009  NONE
X      `032
X      SIDE EFFECTS:
X      `032
X`009  NONE
X      `125
X  `032
X    VAR
X      (* Local bufferpointer used to step through the recallbuffer *)
X      LogP`009    : BufferInt ;
X      RecCmd,`009`009`009    (* The command string to search for *)
V      RecBuffer`009    : VarCmdType ;  (* Command string from the recallbuffe
Xr *)
X      CmdNr,`009`009`009    (* Current recalled command *)
V      RecNr`009    : $UBYTE ;`009    (* Command number to recall from buffer
X *)
X
X
X  PROCEDURE Read_Exec_Cmd (RecBuf : VarCmdType ;
X`009`009`009   ArrayP : BufferInt) ;
X  `032
X      `123
X      FUNCTIONAL DESCRIPTION:`032
X      `032
X`009  Read_Exec_Cmd calls LineEditor to get a commandstring and executes
X`009  it by means of Lib$Do_Command, which also terminates the program
X`009  execution. The commandstring is inserted into the recallbuffer
X`009  before the program terminates.
X
X      `032
X      FORMAL PARAMETERS:`032
X      `032
X`009  RecBuf - The commandstring found in the recallbuffer which matched
X`009`009   the searchstring.
X`009  ArrayP - The pointer to the recallbuffer.
X      `032
X      IMPLICIT INPUTS:
X      `032
X`009  LogEndPointer.
X      `032
X      IMPLICIT OUTPUTS:
X      `032
X`009  NONE
X      `032
X      ROUTINE VALUE:
X      `032
X`009  NONE
X      `032
X      SIDE EFFECTS:
X      `032
X`009  NONE
X      `125
X  `032
X    VAR
X      LastCmd,`009`009`009`009(* Last command in buffer *)
X      DoStr,`009`009`009`009(* DCL command to execute *)
X      Prompt`009`009: VarCmdType ;`009(* DCL prompt *)
X    BEGIN
X      Get_DCL_Prompt (Prompt) ;
X
X      (* Call LineEditor to get the string to execute *)
X      LineEditor (RecBuf, Prompt, ArrayP, DoStr) ;
X
X      IF NOT (DoStr.Length = 0) THEN (* Do we have something to insert? *)
X`009 BEGIN
X`009   (* Retrieve last command... *)
X`009   ArrayP := LogEndPointer ;
X`009   Inc (ArrayP, -1) ;
X`009   GetPrevCommand (LastCmd, ArrayP) ;
X`009   IF NOT (Str$Case_Blind_Compare (DoStr, LastCmd) = 0) THEN
X`009      BEGIN
X`009`009(* GlobalCmd is used in InsRetrCmd *)
X`009`009GlobalCmd := DoStr ;
X`009`009$CmExec (%IMMED InsRetrCmd) ; (* Insert new command *)
X`009      END (* of IF *) ;
X`009   (* Execute choosen commandstring and exit program... *)
X`009   Lib$Do_Command (DoStr) ;
X`009 END (* of IF *) ;
X  END (* of PROCEDURE Read_Exec_Cmd *) ;
X
X
X    BEGIN (* of PROCEDURE RecallCmd *)
X      LogP := LogEndPointer ;
X      (* We have some commands... *)
X      IF NOT (RecallArray[Inc (LogP, -1)] = Null) THEN
X`009 BEGIN
X`009   Cli$Get_Value (Cli$_Par1, RecCmd) ;
X`009   (* Recall using a number? *)
X`009   ReadV (RecCmd, RecNr, Error := Continue) ;
X`009   IF (StatusV = Pas$K_InvSynInt) THEN (* No, search for string... *)
X`009      BEGIN
X`009`009(* Search... *)
X`009`009REPEAT
X`009`009  GetPrevCommand (RecBuffer, LogP) ;
X`009`009UNTIL MatchStr (RecBuffer, RecCmd)  OR`009(* Command found *)
X`009`009      (* Position LogP to the trailing length byte *)
X`009`009      (RecallArray[Inc (LogP, -1)] = Null) ; (* No more cmds *)
X
X`009`009(* Found...? *)
X`009`009IF MatchStr (RecBuffer, RecCmd) THEN
X`009`009   (* LogP points to the trailing length, must point to NULL. *)
X`009`009   Read_Exec_Cmd (RecBuffer, Inc (LogP, 1))
X`009`009ELSE (* => Command RecCmd not found... *)
X`009`009   Lib$Signal (RETR_CmdNoFou, 1, %STDESCR (RecCmd)) ;
X`009      END (* of IF *)
X`009   ELSE (* Search by number... *)
X`009      BEGIN
X`009`009(* Skip the number of commands specified by RecNr *)
X`009`009SkipCommands (LogP, CmdNr, RecNr) ;
X`009`009(* Found...? *)
X`009`009IF NOT (RecallArray[LogP] = Null) AND (CmdNr = RecNr) THEN
X`009`009   BEGIN
X`009`009     (* Extract the command found *)
X`009`009     GetPrevCommand (RecBuffer, LogP) ;
X`009`009     Read_Exec_Cmd (RecBuffer, LogP) ;
X`009`009   END (* of IF *)
X`009`009ELSE (* => Command number RecNr not found... *)
X`009`009   Lib$Signal (RETR_CmdNumNoFou, 1, RecNr) ;
X`009      END (* of ELSE *)
X`009 END (* of IF *)
X      ELSE (* => No commands in the recallbuffer *)
X`009 Lib$Signal (RETR_NoComFou) ;
X  END (* of PROCEDURE RecallCmd *) ;
X
X
X  PROCEDURE ListCmds ;
X  `032
X      `123
X      FUNCTIONAL DESCRIPTION:`032
X      `032
X`009  ListCmds lists the commands specified by the START and END values.
X`009  If no values are given, all commands are listed to the current
-+-+-+-+-+ End of part 4 +-+-+-+-+-

