Displaying the attribute characters on your Green Screen

Tech tip courtesy of Douglas Handy

This tip appeared on the MIDRANGE-L list recently and, since there was significant interest at the November, 2004 general meeting, we asked Doug for permission to add it to our T & T pages. So here it is . . .

You may remember that, on the old 5251 workstations, there was a “test” switch that showed each attribute byte as its hexadecimal value.  There are a (very) few displays in use today that have that capability.  I can think of no PC-based emulators that can do it. Yet, it is a nice debugging tool when developing display panels. Well, now you can do it on ANY emulator – read on.

The 5250 data stream has information about things to display, how to allow input and other features.  Each field is introduced (and ended) by a position on the screen with an attribute.  These attribute bytes are hexadecimal values between x'20' and x'3F' and control what you see, how it looks and even whether or not you see it (e.g., non-display fields).  There are, therefore, 32 possible values and their interpretation by the display hardware/emulator depends upon whether you are in “color” or “good-old-green” mode.

The following table (from IBM's Information Center) shows the values and their meanings:

Hex

Limited Color

Full Color

20

Normal

Green

21

Reverse image

Green, reverse image

22

High intensity

White

23

High intensity, reverse image

White, reverse image

24

Underscore

Green, underscore

25

Underscore, reverse image

Green, underscore, reverse image

26

Underscore, high intensity

White, underscore

27

Nondisplay

Nondisplay

28

Blink

Red

29

Blink, reverse image

Red, reverse image

2A

Blink, high intensity

Red, high intensity

2B

Blink, high intensity, reverse image

Red, high intensity, reverse image

2C

Blink, underscore

Red, underscore

2D

Blink, underscore, reverse image

Red, underscore, reverse image

2E

Blink, underscore, high intensity

Red, underscore, blink

2F

Nondisplay

Nondisplay

30

Column separator

Turquoise, column separator

31

Reverse image, column separator

Turquoise, column separator, reverse image

32

High intensity, column separator

Yellow, column separator

33

High intensity, reverse image, column separator

White, reverse image, column separator

34

Underscore, column separator

Turquoise, underscore, column separator

35

Underscore, reverse image, column separator

Turquoise, underscore, reverse image, column separator

36

Underscore, high intensity, column separator

Yellow, underscore, column separator

37

Nondisplay

Nondisplay

38

Blink, column separator

Pink

39

Blink, reverse image, column separator

Pink, reverse image

3A

Blink, high intensity, column separator

Blue

3B

Blink, high intensity, reverse image, column separator

Blue, reverse image

3C

Blink, underscore, column separator

Pink, underscore

3D

Blink, underscore, reverse image, column separator

Pink, underscore, reverse image

3E

Blink, underscore, high intensity, column separator

Blue, underscore

3F

Nondisplay

Nondisplay

Here's the text of Doug's posting and the full code for the RPGLE program. Compile it at V5R1M0 or later because of the free-form calcs.  It works!

My solution was conceptually similar, but used DSM instead of USRDFN data streams. In addition, instead of clearing the unit and displaying the image as one output field, I leave the input fields intact and just overwrite the attribute bytes.  Then instead of simply waiting for an AID key and exiting, I loop while Enter is pressed, displaying the hex value of the cursor location until some other AID key is pressed (eg F3 or F12).

I wasn't sure I should put a 200 line source directly in a reply, but for the sake of comparison, here is a RPG alternative to the CL program.  Once upon a time I used USRDFN, but now consider DSM much more readable.

Here is my source, which I called DspDspAtr:

     H Option( *SrcStmt : *NoDebugIO )
     H DftActGrp( *No )
     H ActGrp( *Caller )
     H BndDir( 'QC2LE' )

      * Display display attributes

      * Use SETATNPGM DSPDSPATR then use ATTN key to invoke this program.
      * The current Screen will have all display attributes replaced by
      * a @ character.  Move the cursor and press Enter to have the hex
      * value of that position displayed.  Use any Fx key to exit.

      * Copyright 2004 Douglas Handy.
      * Permission is granted to distribute freely; all other rights
      * are reserved.

      * Stand-alone variables used
     D BegRow          S             10I 0
     D BegCol          S             10I 0
     D Rows            S             10I 0
     D Cols            S             10I 0
     D R               S             10I 0
     D C               S             10I 0
     D Hex             S              2

     D CmdBuf          S             10I 0
     D InpHnd          S             10I 0
     D BytRead         S             10I 0

     D ScrImg          S           3564
     D ScrImgPtr       S               *   Inz( *Null )
     D ScrBytePtr      S               *   Inz( *Null )
     D ScrByte         S              1    Based( ScrBytePtr )

     D InpDtaPtr       S               *   Inz( *Null )
     D InpDta          DS          3564    Based( InpDtaPtr )
     D  InpCsrRow                     3U 0
     D  InpCsrCol                     3U 0
     D  InpAID                        1

      * Convert character string to hex string (eg ABC to C1C2C3)
     D CvtToHex        PR                  ExtProc( 'cvthc' )
     D  Hex                        2048    Options( *Varsize )
     D  Char                       1024    Options( *Varsize )
     D  LenSrc                       10I 0 Value

      * Copy a block of memory (operands should not overlap)
     D memcpy          PR              *   ExtProc( '__memcpy' )
     D  Target                         *   Value
     D  Source                         *   Value
     D  Length                       10U 0 Value

      * Standard API error code DS
     D ApiErrCode      DS
     D  ErrBytPrv                     9B 0 Inz( %size( ApiErrCode ) )
     D  ErrBytAvl                     9B 0 Inz( 0 )
     D  ErrMsgID                      7
     D  ErrResv                       1
     D  ErrMsgDta                    80

      * Retrieve Screen dimensions of current mode (not capability).
     D RtvScrDim       PR            10I 0 ExtProc( 'QsnRtvScrDim' )
     D  Rows                         10I 0
     D  Cols                         10I 0
     D  EnvHnd                       10I 0 Options( *Omit ) Const
     D  ErrorDS                            Options( *Omit ) Like( ApiErrCode )

      * Clear buffer.
     D ClrBuf          PR            10I 0 ExtProc( 'QsnClrBuf' )
     D  CmdBuf                       10I 0 Options( *Omit ) Const
     D  ErrorDS                            Options( *Omit ) Like( ApiErrCode )

      * Create command buffer.
     D CrtCmdBuf       PR            10I 0 ExtProc( 'QsnCrtCmdBuf' )
     D  InitSize                     10I 0 Const
     D  IncrAmt                      10I 0 Options( *Omit ) Const
     D  MaxSize                      10I 0 Options( *Omit ) Const
     D  CmdBuf                       10I 0 Options( *Omit ) Const
     D  ErrorDS                            Options( *Omit ) Like( ApiErrCode )

      * Create input buffer.
     D CrtInpBuf       PR            10I 0 ExtProc( 'QsnCrtInpBuf' )
     D  InitSize                     10I 0 Const
     D  IncrAmt                      10I 0 Options( *Omit ) Const
     D  MaxSize                      10I 0 Options( *Omit ) Const
     D  InpBuf                       10I 0 Options( *Omit )
     D  ErrorDS                            Options( *Omit ) Like( ApiErrCode )

      * Delete buffer.
     D DltBuf          PR            10I 0 ExtProc( 'QsnDltBuf' )
     D  BufHnd                       10I 0 Const
     D  ErrorDS                            Options( *Omit ) Like( ApiErrCode )

      * Read Screen (without waiting for an AID key).
     D ReadScr         PR            10I 0 ExtProc( 'QsnReadScr' )
     D  NbrByt                       10I 0 Options( *Omit )
     D  InpBuf                       10I 0 Options( *Omit ) Const
     D  CmdBuf                       10I 0 Options( *Omit ) Const
     D  EnvHnd                       10I 0 Options( *Omit ) Const
     D  ErrorDS                            Options( *Omit ) Like( ApiErrCode )

      * Retrieve pointer to data in input buffer.
     D RtvDta          PR              *   ExtProc( 'QsnRtvDta' )
     D  InpBuf                       10I 0 Const
     D  InpDtaPtr                      *   Options( *Omit )
     D  ErrorDS                            Options( *Omit ) Like( ApiErrCode )

      * Read input fields.
     D ReadInp         PR            10I 0 ExtProc( 'QsnReadInp' )
     D  CCByte1                       1    Const
     D  CCByte2                       1    Const
     D  NbrFldByt                    10I 0 Options( *Omit )
     D  InpBuf                       10I 0 Options( *Omit ) Const
     D  CmdBuf                       10I 0 Options( *Omit ) Const
     D  EnvHnd                       10I 0 Options( *Omit ) Const
     D  ErrorDS                            Options( *Omit ) Like( ApiErrCode )

      * Get cursor address (does not wait for AID key).
     D GetCsrAdr       PR            10I 0 ExtProc( 'QsnGetCsrAdr' )
     D  CsrRow                       10I 0 Options( *Omit )
     D  CsrCol                       10I 0 Options( *Omit )
     D  EnvHnd                       10I 0 Options( *Omit ) Const
     D  ErrorDS                            Options( *Omit ) Like( ApiErrCode )

      * Set cursor address.
     D SetCsrAdr       PR            10I 0 ExtProc( 'QsnSetCsrAdr' )
     D  FldID                        10I 0 Options( *Omit ) Const
     D  CsrRow                       10I 0 Options( *Omit ) Const
     D  CsrCol                       10I 0 Options( *Omit ) Const
     D  CmdBuf                       10I 0 Options( *Omit ) Const
     D  EnvHnd                       10I 0 Options( *Omit ) Const
     D  ErrorDS                            Options( *Omit ) Like( ApiErrCode )

      * Write data.
     D WrtDta          PR            10I 0 ExtProc( 'QsnWrtDta' )
     D  Data                       3600    Const
     D  DataLen                      10I 0 Const
     D  FldID                        10I 0 Options( *Omit ) Const
     D  Row                          10I 0 Options( *Omit ) Const
     D  Col                          10I 0 Options( *Omit ) Const
     D  StrMonoAtr                    1    Options( *Omit ) Const
     D  EndMonoAtr                    1    Options( *Omit ) Const
     D  StrClrAtr                     1    Options( *Omit ) Const
     D  EndClrAtr                     1    Options( *Omit ) Const
     D  CmdBuf                       10I 0 Options( *Omit ) Const
     D  EnvHnd                       10I 0 Options( *Omit ) Const
     D  ErrorDS                            Options( *Omit ) Like( ApiErrCode )

     C/Free

       // Get display size and save current contents of Screen image
       RtvScrDim( Rows: Cols: *Omit: *Omit );
       GetCsrAdr( BegRow: BegCol: *Omit: *Omit );
       InpHnd     = CrtInpBuf( %size( ScrImg ): *Omit: *Omit: *Omit: *Omit );
       BytRead    = ReadScr( *Omit: InpHnd: *Omit: *Omit: *Omit );
       InpDtaPtr  = RtvDta( InpHnd: *Omit: *Omit );
       ScrImgPtr  = %addr( ScrImg );
       memcpy( ScrImgPtr : InpDtaPtr: BytRead );

       // Create command buffer with an output command to replace
       // each display attribute byte with a @ character, except
       // for the attribute at row/col 1,1 because overlaying it
       // affects at least some emulators
       CrtCmdBuf( 1024: 1024: 6192: CmdBuf: *Omit );
       ScrBytePtr = %addr( ScrImg );

       For R = 1 to Rows;
         For C = 1 to Cols;
           If ScrByte >= x'20' and ScrByte <= x'3F';
             If not ( R = 1 and C = 1 );
               WrtDta( '@': 1: 0: R: C: *Omit: *Omit: *Omit: *Omit:
                       CmdBuf: *Omit: *Omit );
             Endif;
           Endif;
           ScrBytePtr = ScrBytePtr + 1;
         Endfor;
       Endfor;

       // Output cmd buffer to display and wait for AID key
       SetCsrAdr( *Omit: BegRow: BegCol: CmdBuf: *Omit: *Omit );
       ReadInp( x'20': x'40': BytRead: InpHnd: CmdBuf: *Omit: *Omit );
       InpDtaPtr  = RtvDta( InpHnd: *Omit: *Omit );

       // Show hex contents of cursor position until Enter not pressed
       Dou InpAID <> x'F1';
         ClrBuf( CmdBuf: *Omit );
         ScrBytePtr = ScrImgPtr + ( ( InpCsrRow - 1 ) * Cols ) + InpCsrCol - 1;
         CvtToHex( Hex: ScrByte: 2 );
         WrtDta( Hex: 2: 0: Rows: Cols-1: x'22': *Omit: x'22': *Omit:
                 CmdBuf: *Omit: *Omit );
         SetCsrAdr( *Omit: InpCsrRow: InpCsrCol: CmdBuf: *Omit: *Omit );
         ReadInp( x'20': x'40': BytRead: InpHnd: CmdBuf: *Omit: *Omit );
         InpDtaPtr  = RtvDta( InpHnd: *Omit: *Omit );
       Enddo;

       // Delete DSM buffers and end program
       DltBuf( CmdBuf: *Omit );
       DltBuf( InpHnd: *Omit );
       *InLR = *On;
      /End-free