Search code examples
ibm-midrangerpglejtopen

Returning arbitrary binary data from RPG program


Let's say I have this program interface

d PgmText         pi
d  outInfo                   65535
d  pgmName                      10    const
d  pgmLibrary                   10    const

I'm calling it through JTOpen, which then reads the data assigned to the input/output parameter outInfo. The issue is that the %alloc-ated data exceeds the maximum dimension of outInfo.

Thus, what should I do? E.g. I could pass an AS400ByteArray as ProgramParameter.PASS_BY_REFERENCE, but then what do I do in the RPG code?

N.B. it must be compatible with V5R1.


Solution

  • It seems the best possible choice is the User Space.

    For example, let's say we need to extract the source code from a *PGM object, which we'll then read from JTOpen. To accomplish that, we write the following RPG program, which given a *PGM qualified path and a *USRSPC qualified path, writes to that User Space.

    From the JVM layer, simply ProgramCall this RPG program, and then read with a UserSpace.

     h dftactgrp(*no)
    
      **
      * This program writes to a UserSpace with the following layout:
      *
      * Total lines number     | CHAR(10)
      * [for every line]
      *   Sequence number      | CHAR(6)
      *   Last edit date       | CHAR(6)
      *   Source line          | CHAR(*)  (lineLength - 12)
      *
      * @author Edoardo Luppi
      **
    
     d PgmText         pr                  extpgm('PGMTEXT')
     d  qProgramName                 20    const
     d  qUsrspcName                  20    const
     d  lineLength                   10i 0 const
    
     d PgmText         pi
     d  qProgramName                 20    const
     d  qUsrspcName                  20    const
     d  lineLength                   10i 0 const
    
      * Internal procedures
     d startSourceDebug...
     d                 pr
    
     d retrieveTextViewNumber...
     d                 pr            10i 0
    
     d retrieveViewId...
     d                 pr            10i 0
     d   viewNumber                  10i 0 value
    
     d writeLinesToUserSpace...
     d                 pr
     d   viewId                      10i 0 value
    
      /copy qcopysrc,qusrspc
      /copy qcopysrc,qdebug
    
     d errorCode       ds                  qualified
     d  bytesProvided                10i 0 inz(%size(errorCode))
     d  bytesAvailable...
     d                               10i 0 inz
     d  exceptionId                   7
     d                                1
     d  exceptionData               512
    
      * QteRetrieveModuleViews
     d vewl0100        ds                  qualified
     d  bsReturned                   10i 0 inz
     d  bsAvailable                  10i 0 inz
     d  numOfElements                10i 0 inz
    
     d vewl0100Element...
     d                 ds                  qualified based(vewl0100ElementPtr)
     d  moduleName                   10
     d  viewType                     10
     d  compilerId                   20
     d  mainIndicator                10
     d  viewTimestamp                13
     d  viewDescription...
     d                               50
     d                                3
     d  viewNumber                   10i 0
     d  numberOfViews                10i 0
    
     d vewl0100ElementPtr...
     d                 s               *
    
      * QteRetrieveViewText
     d textViewStruct  ds                  qualified
     d  bsReturned                   10i 0 inz
     d  bsAvailable                  10i 0 inz
     d  numOfElements                10i 0 inz
     d  lineLength                   10i 0 inz
    
     d textViewStructElement...
     d                 ds                  qualified based(textViewElementPtr)
     d  sequenceNum                  12
     d  sourceLine                  500
    
     d textViewElementPtr...
     d                 s               *
    
      * Common variables
     d viewId          s             10i 0 inz
     d numOfLines      s             10i 0 inz
     d returnedLib     s             10    inz
     d viewTimestamp   s             13    inz
     d receiverVar     s          32000    inz
     d textViewNumber  s              3i 0 inz
     d programName     s             10    inz
      /free
    
       programName = %subst(qProgramName:1:10);
    
       startSourceDebug();
       textViewNumber = retrieveTextViewNumber();
    
       if (textViewNumber >= 0);
         viewId = retrieveViewId(textViewNumber);
         writeLinesToUserSpace(viewId);
       endif;
    
       return;
    
      /end-free
    
      **
      * Start the debug session and register the program-stop handler exit program.
      **
     p startSourceDebug...
     p                 b
      * Program-stop handler exit program path
     d PSHEP           c                   'PGMSTOPHDLMYLIB     '
      /free
    
       reset errorCode;
       QteStartSourceDebug(PSHEP:errorCode);
    
      /end-free
     p                 e
    
      **
      * Find the *TEXT debug view's number.
      **
     p retrieveTextViewNumber...
     p                 b
     d                 pi            10i 0
     d i               s             10i 0 inz
      /free
    
       reset errorCode;
    
       QteRetrieveModuleViews(
         receiverVar:
         %size(receiverVar):
         'VEWL0100':
         qProgramName:
         '*PGM':
         programName:
         returnedLib:
         errorCode
       );
    
       vewl0100 = receiverVar;
       i = 0;
    
       dow (i < vewl0100.numOfElements);
         // 124 is the length of an element of the VEWL0100 structure
         vewl0100ElementPtr = %addr(receiverVar) + 12 + (i * 124);
    
         // We are interested in the *TEXT view only, which contains
         // sequence numbers and their associated source lines
         if (vewl0100Element.viewType = '*TEXT');
           return vewl0100Element.viewNumber;
         endif;
    
         i += 1;
       enddo;
    
       // No *TEXT view found.
       return -1;
    
      /end-free
     p                 e
    
      **
      * Get the debug View ID given its number.
      **
     p retrieveViewId...
     p                 b
     d                 pi            10i 0
     d   viewNumber                  10i 0 value
    
     d viewId          s             10i 0 inz
      /free
    
       reset errorCode;
    
       QteRegisterDebugView(
         viewId:
         numOfLines:
         returnedLib:
         viewTimeStamp:
         qProgramName:
         '*PGM':
         programName:
         textViewNumber:
         errorCode
       );
    
       return viewId;
    
      /end-free
     p                 e
    
      **
      * Writes every line of the program's source, which has a fixed width,
      * sequentially to the User Space.
      **
     p writeLinesToUserSpace...
     p                 b
     d                 pi
     d   viewId                      10i 0 value
    
     d data            s            999    inz
     d startLineNumber...
     d                 s             10i 0 inz(1)
     d linesPerPass    s             10i 0 inz
     d firstPass       s               n   inz(*on)
     d lineNumber      s             10i 0 inz
     d i               s             10i 0 inz
      /free
    
       dow firstPass or textViewStruct.bsReturned < textViewStruct.bsAvailable;
         reset errorCode;
         reset receiverVar;
    
         QteRetrieveViewText(
           receiverVar:
           %size(receiverVar):
           viewId:
           startLineNumber:
           linesPerPass:
           lineLength:
           errorCode
         );
    
         firstPass = *off;
         textViewStruct = receiverVar;
    
         if (textViewStruct.bsReturned < textViewStruct.bsAvailable);
           startLineNumber += textViewStruct.numOfElements;
           linesPerPass = 1000;
         endif;
    
         i = 0;
    
         dow (i < textViewStruct.numOfElements);
           // The length of an occurrence depends on lineLength
           textViewElementPtr = %addr(receiverVar) + 16 + (i * lineLength);
           data = textViewStructElement.sequenceNum +
                  %subst(textViewStructElement.sourceLine:1:lineLength - 12);
    
           Quschgus(
             qUsrspcName:
             10 + (lineNumber * lineLength + 1):
             lineLength:
             %subst(data:1:lineLength):
             '0':
             errorCode
           );
    
           lineNumber += 1;
           i += 1;
         enddo;
       enddo;
    
       Quschgus(qUsrspcName:1:10:%char(lineNumber):'0':errorCode);
    
      /end-free
     p                 e