Date: 23 Jul 1982 1117-PDT
From: SIM at SU-AI
To:   info-vax at SANDIA, h19-people
cc:   SIM at SU-AI
Re:   Reading Escape Sequences with VAX/VMS

   The following FORTRAN-77 subroutine allows VAX/VMS users to read escape
sequences.  This is useful for reading keypad and special function keys on
terminals, reported cursor positions, etc.  The subroutine sets then unsets
(using an exit handler) the terminal characteristic ESCAPE so that you don't
have too.
   To call ReadEscape from Pascal, declare it as follows:

       type StringTyp = packed array[1..?] of char;
       procedure ReadEscape( %STDESCR string : StringTyp;
                               var StrLen,EscLen : integer); FORTRAN;

   For those of you interested, I have also written routines for single
character input (using QIO reads in PASSALL mode with buffer length equal to
one), and several Heathkit H19 dependent routines:  one to display process
status, priority, terminal name, cpu time, image name, data and time, and
current default directory on the 25th line dynamically while running other
things; another to save everything you see on your screen, including graphics
characters, into a file which can then be edited, printed or typed out (VERY
HANDY!).                                                -Stuart McDonald

C       Subroutine ReadEscape
C       returns an input string terminated by a <CR> or any valid escape
C       sequence; StrLen is the number of characters before the terminator and
C       EscLen is the number of characters in the terminator.  The total
C       length of the inputed string is StrLen + EscLen.        -S.McD. 6/6/82

       function ReadEscape( string,StrLen,EscLen )
       implicit integer (a-z)
       character*(*) string
       integer ReadEscape,StrLen,EscLen

       character       sys$input*9/'SYS$INPUT'/,terminal*63
       external        io$_readvblk,io$_setmode,tt$m_escape,ToggleEsc
       logical         first/.true./
       integer         iosb*2(4)
       common          /stu_escape/cchan       ! common used by ToggleEsc
       save            first,func_code,chan

       if (first) then
                       ! Define ToggleEsc as an exit handler (see Users Guide)
           call userex(ToggleEsc)

                       ! Find lowest logical name translation of SYS$INPUT
           call trnlog(sys$input,terminal,name_len)            ! lowest log
           status = sys$assign( terminal, chan,, )             ! open terminal
               if (.not.status) call lib$stop( %VAL(status) )  ! check status
           cchan = chan                                        ! load common
           call ToggleEsc                                      ! allow esc seq

                       ! Ready function code for read of escape sequence
           func_code = %LOC(io$_readvblk)                      ! ordinary read
           first = .false.
       endif
                       ! Read in line and/or escape sequence
       status = sys$qiow( ,%VAL(chan),%VAL(func_code),iosb,,,
       1       %REF(string),%VAL(len(string)),,,,)     ! read esc seq
       if (.not.status) call lib$stop( %VAL(status) )  ! check status
       ReadEscape = iosb(1)                            ! rtn i/o stat
       StrLen = iosb(2)                        ! # chars before terminator
       EscLen = iosb(4)                        ! # chars in terminator
       return
       end
                               ! This came from "Prog. VMS in FORT/MAC",p.83
       subroutine trnlog( old_log,new_log,new_len )
       implicit        integer (a-z)
       byte            esc_null_int(2) /'1B'X,0/
       character*2     esc_null
       character*(*)   old_log,new_log
       external        ss$_notran
       equivalence     (esc_null,esc_null_int)
                               ! Translate name once
       status = sys$trnlog( old_log,new_len,new_log,,, )
       if (status.eq. %LOC(ss$_notran)) stop 'Logical name has no translation'
                               ! Repeat translation until unsuccessful
       do while (status.ne.%LOC(ss$_notran))
           old_log(1:new_len) = new_log
           status = sys$trnlog( old_log(1:new_len),new_len,new_log,,, )
       enddo
                               ! Check if process permanent file
       if (new_log(1:2).eq.esc_null) then
           new_log(1:new_len) = new_log(5:new_len)
           new_len = new_len - 4
       endif
       return
       end

       subroutine ToggleEsc    ! Toggles Escape Recognition for Terminals
       implicit        integer (a-z)
       integer         mode_buf(2)
       external        tt$m_escape,io$_setmode,io$_sensemode
       common          /stu_escape/chan        ! Channel passed in my common

       func_code = %LOC(io$_sensemode)         ! Get terminal characteristics
       status = sys$qiow( ,%VAL(chan),%VAL(func_code),,,,mode_buf,,,,,)
           if (.not.status) call lib$stop( %VAL(status) )      ! check status

       mode_buf(2) = mode_buf(2) .xor. %LOC(tt$m_escape)       ! toggle bits

       func_code = %LOC(io$_setmode)           ! Set terminal characteristics
       status = sys$qiow( ,%VAL(chan),%VAL(func_code),,,,mode_buf,,,,,)
           if (.not.status) call lib$stop( %VAL(status) )      ! check status

       return
       end