How To Debug A Service Program Rpgle

Posted on  by 

The following example shows how to create a service program CVTTOHEX which converts character strings to their hexadecimal equivalent. Two parameters are passed to the service program:

  1. How To Debug A Service Program In Rpgle
  2. How To Debug In C
  1. a character field (InString) to be converted
  2. a character field (HexString) which will contain the 2-byte hexadecimal equivalent

The field HexString is used to contain the result of the conversion and also to indicate the length of the string to be converted. For example, if a character string of 30 characters is passed, but you are only interested in converting the first ten, you would pass a second parameter of 20 bytes (2 times 10). Based on the length of the passed fields, the service program determines the length to handle.

This shows the source for the service program.This shows the /COPY member containing the prototype for CvtToHex.

Re: Debugging the when we have a 'copy book' or 'service program' in RPGLE Copybooks: Compile the source with DBGVIEW > *LIST (or *all). SRVPGM: When in debug, press F14 and add the SRVPGM as required. Let me start with I do not have any issues with viewing the source while in debug with any of the RPGLE or CLLE programs using RDI or STRDBG, the issue only occurs when viewing code in a service program. The service program has been around for awhile and I can currently debug it.

The basic logic of the procedure contained within the service program is listed below:

  1. Operational descriptors are used to determine the length of the passed parameters.
  2. The length to be converted is determined: it is the lesser of the length of the character string, or one-half the length of the hex string field.
  3. Each character in the string is converted to a two-byte hexadecimal equivalent using the subroutine GetHex. Note that GetHex is coded as a subroutine rather than a subprocedure, in order to improve run-time performance. An EXSR operation runs much faster than a bound call, and in this example, GetHex is called many times.
  4. The procedure returns to its caller.

The service program makes use of operational descriptors, which is an ILE construct used when the precise nature of a passed parameter is not known ahead of time, in this case the length. The operational descriptors are created on a call to a procedure when you specify the operation extender (D) on the CALLB operation, or when OPDESC is specified on the prototype.

To use the operational descriptors, the service program must call the ILE bindable API,CEEDOD (Retrieve Operational Descriptor). This API requires certain parameters which must be defined for the CALLB operation. However, it is the last parameter which provides the information needed, namely, the length. For more information on operational descriptors, see “Using Operational Descriptors”.

Source for Service Program CvtToHex

Source for /COPY Member with Prototype for CvtToHex

When designing this service program, it was decided to make use of binder language to determine the interface, so that the program could be more easily updated at a later date. This shows the binder language needed to define the exports of the service program CVTTOHEX. This source is used in the EXPORT, SRCFILE and SRCMBR parameters of the CRTSRVPGM command.

The parameter SIGNATURE on STRPGMEXP identifies the interface that the service program will provide. In this case, the export identified in the binder language is the interface. Any program bound to CVTTOHEX will make use of this signature.

The binder language EXPORT statements identify the exports of the service program. You need one for each procedure whose exports you want to make available to the caller. In this case, the service program contains one module which contains one procedure. Hence, only one EXPORT statement is required.

Creating the Service Program

To create the service program CVTTOHEX, follow these steps:

  1. Create the module CVTTOHEX from the source, by entering: CRTRPGMOD
    MODULE(MYLIB/CVTTOHEX) SRCFILE(MYLIB/QRPGLESRC)
  2. Create the service program using the module CVTTOHEX and the binder language shown .

The last three parameters in the above command identify the exports which the service program will make available. In this case, it is based on the source found in the member CVTTOHEX in the file QSRVSRC in the library MYLIB.

Note that a binding directory is not required here because all modules needed to create the service program have been specified with the MODULE parameter.

How To Debug A Service Program In Rpgle

Debug

The service program CVTTOHEX will be created in the library MYLIB. It can be debugged using a statement view; this is determined by the default DBGVIEW parameter on the CRTRPGMOD command. No binder listing is produced.

Binding to a Program
To complete the example, we will create an ’application’ consisting of a program CVTHEXPGM which is bound to the service program. It uses a seven-character string which it passes to CVTTOHEX twice, once where the value of the hex string is 10 (that is, convert 5 characters) and again where the value is 14, that is, the actual length.

Note that the program CVTHEXPGM serves to show the use of the service program CVTTOHEX. In a real application the caller of CVTTOHEX would have another primary purpose other than testing CVTTOHEX. Furthermore, a service program would normally be used by many other programs, or many times by a few programs; otherwise the overhead of initial call does not justify making it into a service program.

To create the application follow these steps:

  1. Create the module from the source, by entering:
  2. CRTRPGMOD MODULE(MYLIB/CVTHEXPGM) SRCFILE(MYLIB/QRPGLESRC)

  3. Create the program by typing
  4. When CVTHEXPGM is created, it will include information regarding the interface it uses to interact with the service program. This is the same as reflected in the binder language for CVTTOHEX.

  5. Call the program, by typing:
    CALL CVTHEXPGM
Abap

During the process of making CVTHEXPGM ready to run, the system verifies that:

  • The service program CVTTOHEX in library MYLIB can be found
  • The public interface used by CVTHEXPGM when it was created is still valid at run time.

If either of the above is not true, then an error message is issued.

The output of CVTHEXPGM is shown below. (The input string is ’ABC123*’.)

Result14++++++
Result10++
C1C2C3F1F2 10 character output
C1C2C3F1F2F35C 14 character output

Source for Test Program CVTHEXPGM

Updating the Service Program
Because of the binder language, the service program could be updated and the program CVTHEXPGM would not have to be re-compiled. For example, there are two ways to add a new procedure to CVTTOHEX, depending on whether the new procedure goes into the existing module or into a new one.

To add a new procedure to an existing module, you would:

  1. Add the new procedure to the existing module.
  2. Recompile the changed module.
  3. Modify the binder language source to handle the interface associated with the new procedure. This would involve adding any new export statements following the existing ones.
  4. Recreate the service program using CRTSRVPGM.

To add a new procedure using a new module, you would:

  1. Create a module object for the new procedure.
  2. Modify the binder language source to handle the interface associated with the new procedure, as mentioned above.
  3. Bind the new module to service program CVTTOHEX by re-creating the service
    program.

With either method, new programs can access the new function. Since the old exports are in the same order they can still be used by the existing programs. Until it is necessary to also update the existing programs, they do not have to be re-compiled.

For more information on updating service programs, see ILE Concepts.

Sample Binder Listing
This shows a sample binder listing for the CVTHEXPGM. The listing is an example of a basic listing. For more information on binder listings, see “Using a Binder Listing”.

Basic Binder listing for CVTHEXPGM

Active5 years, 6 months ago

I am getting started with RPGLE and I am trying to determine if there is any way of just defining the parameters for the procedures in my service program once. I know I can put the prototypes inside a copy member (which I have done), but then I still have to put essentially the same code into the body of the procedure (the 'procedure interface').

My question is, is there some way of using the prototype to define the parameters in the procedure interface (or vice versa)?

Ideally, something like:

Prototype:

Procedure:

Well, ideally I would just be able to say 'use prototype' or something in the body of the procedure, or the compiler would find it on its own...

Am I misunderstanding how Prototypes and Procedure Interfaces need to be set up, or are they actually this repetitive when done correctly:

Prototype:

Procedure:

How to debug service start

How To Debug In C

Thanks for reading.

Sarah KempSarah Kemp
2,3802 gold badges15 silver badges27 bronze badges

3 Answers

On 7.1, if you are defining a sub-procedure in the same program you are using it, you don't need the prototype. You only need the prototype if you're consuming a sub-procedure from a service program or bound module (Don't bind modules to a program!)

I don't personally find the prototype burdensome to create. I copy the PI, change it to PR, put it into a /copy member and use it in many programs like this:

The only time I need to 'double define' is in the service program where the PI is located. A way to avoid most of that is to use conditional compilation. Here's an example:

qprotosrc(buildform)

qrpglesrc(mysrvpgm)

The first time the /copy is processed, it inserts the prototype - this is what you'd want for all your consumer programs. As part of processing, it defines buildform_proto. In your service program, you'd then put a second /copy. Because buildform_proto is defined, the compiler inserts the P...B and D...PI specs. You'd have to supply the procedure body and the P...E spec.

Buck CalabroBuck Calabro

IMHO, this is one of those things that seems useful, but serves no real purpose and in fact could lead to other problems.

It only saves you from having to copy & paste the parm list. But it's actually more keystrokes. I'm a big fan of 'Don't repeat yourself', but I don't see this as duplication but redundancy that increases error trapping. The compiler will let you know if there's a mismatch between PI and PR.

As I mention in my comment on Bucks post, you can run into problem with this. Assuming your include source has not just prototypes type other useful definitions, it's likely at some point you'll find an include file being included from multiple places. The fix for that is to simply have at the top of each include

Now no matter how many times it's pulled in the compiler will only see the definitions once.

Given that the compile will fail if it sees the same definitions multiple times, I think it's a good idea to not intentionally include the same source. Even if by playing games we can technically not include the same symbol definitions.

Additionally, consider templating your parms..

This allows callers to easily create a variable to use to pass to your procedure.

You might end up with the templates in a whole other include, for example STDTYPES or APPTYPES.

CharlesCharles
12.4k1 gold badge11 silver badges32 bronze badges

Many shops solve this by putting the parms in a copy book. The copy book is then used immediately after the Prototype (PR) D-spec line, and the Procedure Interface (PI) line.

WarrenTWarrenT

Not the answer you're looking for? Browse other questions tagged rpgle or ask your own question.

Coments are closed