Thursday, April 18, 2019

CA/ROSCOE LIBI Interface - Read Member Directly

When I joined GE in October 1989 I went from a TSO/ISPF environment to one that was using CA/ROSCOE. There were several challenges to overcome to adjust to the different environment. One distinct difference between TSO/ROSCOE is that ROSCOE libraries/members are stored in a proprietary format - they can not be accessed the same as a PDS (Partitioned Data Set) member by adding a DD (Data Definition) in your JCL. A ROSCOE member must be exported to a sequential file which can be cumbersome and completely unnecessary. After doing some research I found ROSCOE is delivered with User Library Interface (LIBI) macros. See CA/ROSCOE PDF.

Instead of incorporating these LIBI macros in each application program that needed to read a Roscoe Member I took a better approach & encapsulated them in an all-purpose subroutine. It can be accesses by Assembler, COBOL, Eazytrieve or any other language that supports Assembler Calls.

I named the new module GETROS since it's function is to "Get Roscoe Records". When you supply a Prefix (in my case "TD") and a library member name it will locate the member & upon each call return a single record. The GETROS routine should be placed within a simple loop that will end once an End-Of-File condition is returned (Basic instructions are included in the GETROS program header).

GETROS Code:

         TITLE 'GETROS - READ ROSCOE MEMBER INPUT CARDS // TONY DELIA'
***********************************************************************
*                                                                     *
*        MODULE:  GETROS.                                             *
*        AUTHOR:  TONY DELIA.                                         *
*          DATE:  01/03/1990.                                         *
*          DESC:  READ ROSCOE INPUT MEMBER (SIMILAR TO GETCARD).      *
*        FORMAT:  CALL   GETROS,(ROSAREA)                             *
*         PARMS:  ROSAREA CONSISTS OF THE FOLLOWING-                  *
*                                                                     *
*                 ROSAREA  DC    A(ROSEOF)       -END-OF-FILE ADDRESS *
*                 ROSABND  DC    A(ROSAB)        -ABEND ADDRESS       *
*                 ROSPFX   DC    CL2'XX'         -USER PREFIX         *
*                 ROSMEM   DC    CL8'XXXXXXXX'   -MEMBER NAME         *
*                 ROSREC   DC    CL256' '        -RECORD BUFFER AREA  *
*                                                                     *
*          NOTE:  IN THE EVENT OF AN ABEND, 'ROSREC' AREA IS FILLED   *
*                 WITH A 26-BYTE MESSAGE INDICATING CAUSE OF ABEND.   *
*                                                                     *
*                 IF NO EOF OR ABEND ADDRESS IS PROVIDED, ROSAREA     *
*                 AND ROSABND MUST BE SET TO ZERO.  WHEN EOF IS       *
*                 REACHED, ROSAREA = 'END*'. WHEN ABEND CONDITION,    *
*                 ROSABND = 'ABND'. THESE CAN BE TESTED FROM WITHIN   *
*                 THE CALLING PROGRAM.                                *
*                                                                     *
***********************************************************************
         EJECT
***********************************************************************
*        G  E  T  R  O  S           P  R  O  G  R  A  M               *
***********************************************************************
GETROS   CSECT                               BEGIN PROGRAM
         STM   14,12,12(13)                  SAVE REGISTERS
         LR    12,15                         LOAD PROGRAM ENTRY POINT
         USING GETROS,12                     SET UP BASE NUMBER 1
         L     11,BASE2                      LOAD BASE 2 ADDRESS
         USING GETROS+4096*1,11              SET UP BASE NUMBER 2
         L     10,BASE3                      LOAD BASE 3 ADDRESS
         USING GETROS+4096*2,10              SET UP BASE NUMBER 3
         ST    13,SAVE+4                     SAVE EXTERNAL SAVE AREA
         LR    14,13                         HOLD EXTERNAL ADDR IN R14
         LA    13,SAVE                       LOAD INTERNAL SAVE AREA
         ST    13,8(14)                      SAVE INTERNAL ADDRESS
         B     GO                            GO TO MAINLINE PROCESSING
***********************************************************************
RETURN   EQU   *
         L     13,SAVE+4                     RESTORE EXTERNAL SAVE ADDR
         LM    14,12,12(13)                  RESTORE ORIGINAL REGISTERS
         BR    14                            BRANCH BACK TO CALLING PGM
***********************************************************************
SAVE     DC    18F'0'                        REGISTER PRESERVATION AREA
BASE2    DC    A(GETROS+4096*1)              BASE REGISTER 2 ADDRESS
BASE3    DC    A(GETROS+4096*2)              BASE REGISTER 3 ADDRESS
EODAD    DC    A(0)                          EOF RETURN ADDRESS
ABADDR   DC    A(0)                          ABEND RETURN ADDRESS
***********************************************************************
R0       EQU   0                             R0  USED BY LIBI MACRO
R15      EQU   15                            R15 USED BY LIBI MACRO
***********************************************************************
         EJECT
***********************************************************************
*        MAINLINE SECTION                                             *
***********************************************************************
GO       EQU   *
         PRINT NOGEN
         L     3,0(1)                        LOAD CALLING PGM PARMAREA
         USING XAREA,3                       USE XAREA DSECT
         LA    4,ROSPARM                     POINT TO ROSCOE PARM AREA
         USING LBPMDEF,4                     USE ROSCOE PARM DSECT
*
         BC    0,READ                        AFTER 1ST, GO TO READ
         OI    *-3,X'F0'                     SET BRANCH INSTRUCTION
*
         MVC   EODAD,XEODAD                  MOVE END-OF-FILE ADDRESS
         MVC   ABADDR,XABEND                 MOVE ABEND ADDRESS
         MVC   PFX,XPFX                      MOVE PREFIX TO SAVE AREA
         MVC   MEMBER,XMEM                   MOVE INPUT MEMBER NAME
         BAL   6,ROSINIT                     ROSCOE INITIALIZATION
         BAL   6,ROSFIND                     FIND ROSCOE MEMBER
READ     EQU   *
         BAL   6,ROSREAD                     READ ROSCOE MEMBER
         MVC   XREC,LBPMLINE                 MOVE RECORD TO TARGET
         B     RETURN                        RETURN TO CALLING PROGRAM
EOF      EQU   *
         BAL   6,ROSDONE                     WRAP UP ROSCOE FUNCTION
         L     13,SAVE+4                     RESTORE EXTERNAL SAVE ADDR
*
         MVC   XEODAD,=C'END*'               MOVE E-O-F LITERAL SWITCH
         L     6,EODAD                       LOAD EOF-ADDRESS
         LTR   6,6                           WAS EOF-ADDRESS PROVIDED??
         BZ    RETURN                        NO  - RETURN VIA R14
         MVC   12(4,13),EODAD                ALTER RETURN ADDRESS (EOF)
         B     RETURN                        RETURN TO CALLING PROGRAM
***********************************************************************
         EJECT
***********************************************************************
*        ROSCOE "LIBI" FUNCTIONS                                      *
***********************************************************************
*        INITIALIZE BATCH INTERFACE / ALLOCATE RESOURCES              *
***********************************************************************
         CNOP  0,4
ROSINIT  EQU   *
         LIBI  FUNC=INITX,LBRB=ROSLBRB
*
         LTR   15,15                         RETURN CODE = ZERO?
         BNZ   ERRINITX                      NO - ERROR ROUTINE
*
         LIBI  FUNC=ACTIVATE,LBRB=ROSLBRB,PARM=ROSPARM
*
         LTR   15,15                         RETURN CODE = ZERO?
         BNZ   ERRACTV                       NO - ERROR ROUTINE
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************
*        FIND <PFX>.<MEMBER> / ADD INDEX TO PARAMETER LIST            *
***********************************************************************
         CNOP  0,4
ROSFIND  EQU   *
         MVI   ROSPARM,X'00'                 HEX ZEROES 1ST BYTE
         MVC   ROSPARM+1(2),PFX              MOVE USER PREFIX
         MVI   ROSPARM+3,C' '                MOVE BLANK 4TH BYTE
         MVC   ROSPARM+4(8),MEMBER           MOVE DIRECTORY MEMBER
*
         LIBI  FUNC=FIND,LBRB=ROSLBRB,PARM=ROSPARM
*
         LTR   15,15                         RETURN CODE = ZERO?
         BNZ   ERRFIND                       NO - ERROR ROUTINE
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************
*        GET NEXT LOGICAL RECORD FROM LIBRARY MEMBER                  *
***********************************************************************
         CNOP  0,4
ROSREAD  EQU   *
         LIBI  FUNC=GET,LBRB=ROSLBRB,PARM=ROSPARM
*
         LTR   15,15                         RETURN CODE = ZERO?
         BZ    0(6)                          YES - BRANCH BAL/REGISTER
         CH    15,=H'4'                      RETURN CODE = 4?
         BNE   ERRGET                        NO  - ERROR ROUTINE
*
         CLI   ROSLBRB+(LBRBXRC-LBRB),LBRBXEOF     END FILE CONDITION?
         BNE   ERRGET                        NO  - ERROR ROUTINE
         B     EOF                           YES - END OF FILE
***********************************************************************
*        FREE LIBRARY RESOURCES / TERMINATE LIBI INTERFACE            *
***********************************************************************
ROSDONE  EQU   *
         LIBI  FUNC=FREE,LBRB=ROSLBRB
*
         LTR   15,15                         RETURN CODE = ZERO?
         BNZ   ERRFREE                       NO  - ERROR ROUTINE
*
         LIBI  FUNC=TERM,LBRB=ROSLBRB
*
         LTR   15,15                         RETURN CODE = ZERO?
         BNZ   ERRTERM                       NO  - ERROR ROUTINE
         BR    6                             BRANCH ON LINK REGISTER
***********************************************************************
         EJECT
***********************************************************************
*        ROSCOE ERROR ROUTINES                                        *
***********************************************************************
ERRINITX EQU   *
         MVC   XREC(26),AB111                MOVE ABEND MESSAGE 111
         B     ABENDIT                       GO TO ABEND ROUTINE
ERRACTV  EQU   *
         MVC   XREC(26),AB222                MOVE ABEND MESSAGE 222
         B     ABENDIT                       GO TO ABEND ROUTINE
ERRFIND  EQU   *
         MVC   AB333+14(2),PFX               MOVE PREFIX TO AB333
         MVC   AB333+17(8),MEMBER            MOVE MEMBER TO AB333
         MVC   XREC(26),AB333                MOVE ABEND MESSAGE 333
         B     ABENDIT                       GO TO ABEND ROUTINE
ERRGET   EQU   *
         MVC   AB444+14(2),PFX               MOVE PREFIX TO AB444
         MVC   AB444+17(8),MEMBER            MOVE MEMBER TO AB444
         MVC   XREC(26),AB444                MOVE ABEND MESSAGE 444
         B     ABENDIT                       GO TO ABEND ROUTINE
ERRFREE  EQU   *
         MVC   XREC(26),AB555                MOVE ABEND MESSAGE 555
         B     ABENDIT                       GO TO ABEND ROUTINE
ERRTERM  EQU   *
         MVC   XREC(26),AB666                MOVE ABEND MESSAGE 555
ABENDIT  EQU   *
         L     13,SAVE+4                     RESTORE EXTERNAL SAVE ADDR
         MVC   XABEND,=C'ABND'               MOVE ABEND LITERAL SWITCH
         L     6,ABADDR                      LOAD ABEND ADDRESS
         LTR   6,6                           WAS ABEND ADDR PROVIDED??
         BZ    RETURN                        NO  - RETURN VIA R14
         MVC   12(4,13),ABADDR               ALTER RETURN ADDRESS (AB)
         B     RETURN                        RETURN TO CALLING PROGRAM
***********************************************************************
AB111    DC    CL26'FUNC=INITX                '
AB222    DC    CL26'FUNC=ACTIVATE             '
AB333    DC    CL26'FUNC=FIND    (XX.XXXXXXXX)'
AB444    DC    CL26'FUNC=GET     (XX.XXXXXXXX)'
AB555    DC    CL26'FUNC=FREE                 '
AB666    DC    CL26'FUNC=TERM                 '
***********************************************************************
         EJECT
***********************************************************************
*        WORKING STORAGE                                              *
***********************************************************************
         LTORG
***********************************************************************
ROSLBRB  DC    8F'0'                         ROSCOE LIBI FULLWORDS
ROSPARM  DC    265C' '                       ROSCOE PARM AREA
PFX      DC    CL2'XX'                       ROSCOE LIBRARY PREFIX
MEMBER   DC    CL8'XXXXXXXX'                 ROSCOE LIBRARY MEMBER
***********************************************************************
         LBRB
         LBPMDEF
***********************************************************************
XAREA    DSECT
XEODAD   DS    F                             END-OF-FILE ADDRESS
XABEND   DS    F                             ABEND ADDRESS
XPFX     DS    CL2                           USER PREFIX
XMEM     DS    CL8                           MEMBER NAME
XREC     DS    CL256                         TARGET RECORD AREA
***********************************************************************
         END   GETROS


To validate my GETROS load module I created several Calling Programs - one in Assembler, COBOL & Eazytrieve. Unfortunately I no longer possess many of my older programs including the Eazytrieve version. I lost a lot of brilliant work between 1985 and the early 1990's simply due to lack of reliable storage media. Faulty 5.25 inch disks as well as a totally useless magnetic tape reel (with no tape drive to read it) contributed greatly to the loss... but not everything was gone. Below are the Assembler & COBOL versions (COBOL & Easytrieve are very similar).

Calling Program - Assembler Test - GETROSX:

The READ Loop executes the call as follows: CALL  GETROS,(ROSAREA).
No explicit exit from the loop is required since the ROSAREA defintion contains the EOF Address as well as the ABEND address. GETROS will branch to the appropriate address.

        TITLE 'GETROSX - GETROS SUBROUTINE TESTING // TONY DELIA'
***********************************************************************
*                                                                     *
*        MODULE:  GETROSX.                                            *
*        AUTHOR:  TONY DELIA.                                         *
*          DATE:  01/03/1990.                                         *
*          DESC:  TEST 'GETROS' ROSCOE INPUT READER.                  *
*          NOTE:  PREFIX/MEMBER PASSED VIA JCL EXEC PARM.             *
*                                                                     *
***********************************************************************
         EJECT
***********************************************************************
*        G  E  T  R  O  S  X        P  R  O  G  R  A  M               *
***********************************************************************
GETROSX  SETUP REGS=(12,11,10)               BEGIN PROGRAM
***********************************************************************
*        MAINLINE SECTION                                             *
***********************************************************************
         PRINT NOGEN
         L     3,0(1)                        LOAD 'EXEC' PARM ADDRESS
         MVC   PFX,2(3)                      SAVE PREFIX PARAMETER
         MVC   MEMBER,5(3)                   SAVE MEMBER PARAMETER
         MVC   PRT,PRT-1                     CLEAR PRINT LINE
         BAL   6,W8B                         PRINT - PAGE EJECT
***********************************************************************
READ     EQU   *
         CALL  GETROS,(ROSAREA)              READ ROSCOE INPUT
         MVC   PRT,RECORD                    MOVE ROSCOE RECORD TO PRT
         BAL   6,W09                         PRINT - SPACE 1 LINE
         B     READ                          READ NEXT RECORD
***********************************************************************
EOF      EQU   *
         BAL   6,WXX                         CLOSE PRINT FILE
         B     RETURN                        EXIT PROGRAM
***********************************************************************
*        ABEND ROUTINE                                                *
***********************************************************************
ABENDIT  EQU   *
         MVC   PRT,PRT-1                     CLEAR PRINT LINE
         BAL   6,W8B                         PRINT - PAGE EJECT
         MVC   PRT+1(26),ABTITLE             MOVE TITLE LINE
         BAL   6,W19                         PRINT - SPACE 3 LINES
         MVC   PRT+1(26),RECORD              MOVE ABEND MESSAGE
         BAL   6,W09                         PRINT - SPACE 1 LINE
         BAL   6,WXX                         CLOSE PRINT FILE
         ABEND 111                           ISSUE ABEND NO. 111
***********************************************************************
ABTITLE  DC    CL26'GETROS: READ UTILITY ABEND'
***********************************************************************
         EJECT
***********************************************************************
*        WORKING STORAGE                                              *
***********************************************************************
         TPRNT
         LTORG
***********************************************************************
ROSAREA  DC    A(EOF)
ROSABND  DC    A(ABENDIT)
PFX      DC    CL2'**'
MEMBER   DC    CL8'********'
RECORD   DC    CL256' '
***********************************************************************
         END   GETROSX



Calling Program - COBOL Test - GETROSY:

In the COBOL test program the ROSCOE records are read within the ROS-LOOP using this call: CALL 'GETROS' USING ROSAREA. The address fullwords for End-Of-File & Abend Routine are set to zero. The GETROS load module detects this & passes a code of 'EOF*' or 'ABND' instead of branching to an address. The conditions are then 'explicitly' tested & handled appropriately.

      ******************************************************************
      *                                                                *
      *     MODULE:  GETROSY.CBL                                       *
      *     AUTHOR:  TONY DELIA.                                       *
      *       DATE:  01/30/1990.                                       *
      *       DESC:  TEST 'GETROS' ROSCOE INPUT READER.                *
      *                                                                *
      ******************************************************************
       INSTALLATION.  TRANSPORT INTERNATIONAL POOL.
      *
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT FILOT ASSIGN TO UT-S-FILOT.
      *
       DATA DIVISION.
       FILE SECTION.
       FD  FILOT
                   RECORD CONTAINS 132 CHARACTERS
                   RECORDING MODE IS F
                   LABEL RECORDS ARE STANDARD
                   DATA RECORD IS OUT-RECORD.
       01  OUT-RECORD                    PIC X(132).
      *
       WORKING-STORAGE SECTION.
      *
       01  ROSAREA SYNC.
           05  ROSEOF                    PIC 9(8) COMP SYNC.
           05  ROSEOF-X REDEFINES ROSEOF PIC X(4).
           05  ROSAB                     PIC 9(8) COMP SYNC.
           05  ROSAB-X  REDEFINES ROSAB  PIC X(4).
           05  ROSPFX                    PIC X(2).
           05  ROSMEM                    PIC X(8).
           05  ROSREC                    PIC X(256).
      *
       PROCEDURE DIVISION.
      *
           OPEN OUTPUT FILOT.
           MOVE 'TD'       TO ROSPFX.
           MOVE 'ZZZZZPRT' TO ROSMEM.
      *****************************************************************
      *    READ ROSCOE MEMBER / LOOP UNTIL END-OF-FILE                *
      *****************************************************************
       ROS-LOOP.
           CALL 'GETROS' USING ROSAREA.
           IF ROSEOF-X = 'END*' GO TO END-OF-JOB.
           IF ROSAB-X  = 'ABND' GO TO ABEND-JOB.
           MOVE ROSREC TO OUT-RECORD.
           WRITE OUT-RECORD.
           GO TO ROS-LOOP.
      *****************************************************************
      *    ABEND DETECTED                                             *
      *****************************************************************
       ABEND-JOB.
           MOVE ROSREC TO OUT-RECORD.
           WRITE OUT-RECORD.
      *****************************************************************
      *    END OF JOB                                                 *
      *****************************************************************
       END-OF-JOB.
           CLOSE FILOT.
           STOP RUN.
      *****************************************************************
      *    END OF PROGRAM                                             *
      *****************************************************************


A pretty simple exercise but it ultimately saved countless hours as well as system resources. I was able to directly access the data I needed without the trouble of exporting, creating new datasets & constantly refreshing them as the data changed. The old adage is true, "If you want something done right you have to do it yourself".

This blog post brings back some great memories...