Returning arbitrary binary data from RPG program

138 views Asked by At

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.

2

There are 2 answers

0
LppEdd On BEST ANSWER

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
8
Charles On

v5r1? Really?

Also note it's a bad idea to %alloc() data in the RPG program to pass back to JTOpen ...

You could have a PI that looks like

d PgmText         pi
d  outInfoPtr                       *   value
d  outInfoSize                  10i 0 const
d  pgmName                      10    const
d  pgmLibrary                   10    const

then use baased variables..

Another option would be to output the data to the IFS and the return the file name to JTOpen.

Lastly, if this is related to your debugger API question...why are you using an RPG wrapper? Just call the Debugger APIs directly from JTOpen.