Wednesday, December 28, 2016

Calling a program in totally free RPG

call program in free format rog

Someone said to me that the reason that they will not use totally free RPG is they cannot call programs using it. In the earlier flavors of free format RPG they could just switch from free format to fixed to do the call, and return to free format afterwards.

  Var1 = 'Hello' ;
  Var2 = 1 ;
  Var3 = '' ;
C                   call      'OTHERPGM1'
C                   parm                    Var1
C                   parm                    Var2
C                   parm                    Var3
  if (Var3 = 'Y') ;

With totally free RPG once the **FREE compiler directive is placed in the code it is not possible to go back to fixed format after that. Therefore, the approach used above is not possible.

For some time there has been alternative method to call programs using, what I call, external program procedure calls. This method even predates free format definitions. But I am just going to discuss how to do this in totally free format.

In the declare procedure prototype definition, DCL-PR, there is a keyword I can use to indicate that this procedure is really an external program. This allows me to call the external program just like any procedure. Let me get straight to the code:

01  **free
02  ctl-opt option(*nodebugio:*srcstmt) ;
03  dcl-pr OtherPgm1 extpgm ;
04    Parm1 char(5) ;
05    Parm2 packed(3) ;
06    Parm3 char(1) ;
07  end-pr ;

08  dcl-s Var1 char(5) ;
09  dcl-s Var2 packed(3) ;
10  dcl-s Var3 char(1) ;

11  Var1 = 'Hello' ;
12  Var2 = 1 ;
13  Var3 = '' ;
14  OtherPgm1(Var1:Var2:Var3) ;
15  if (Var3 = 'Y') ;

Line 1: It is not totally free unless the **FREE in the first position of the source record.

Line 2: My standard control options I use in every program.

Lines 3 – 7: This is the procedure prototype definition for my external program.

Line 3: At the starting line of the procedure prototype definition, DCL-PR, line I give the name I want to call this procedure, and I have to use the EXTPGM keyword to denote that this is an external program. The program is called OTHERPGM1, therefore, my making the procedure name the same as the program's name I do not have to give the program name as part of the EXTPGM keyword. I will show an example of the program and procedure names being different later.

Lines 4 – 6: These are the three parameters that will be passed and returned to and from the external program. In this example I have given them names, which I normally don't do as I cannot use these as variable names later in the program.

Line 7: END-PR marks the end of the procedure prototype definition.

Lines 8 – 10: These are the definitions of the variables I will be using to pass and return from the procedure.

Lines 11 – 13: I am moving values into these variables.

Line 14: I do the call to the external program just as I would for any procedure.

Line 15: The external program can change the values in the parameter variables, that I can then use.

One advantage of using subprocedures is that I can define a procedure within it that remains "local", i.e. can only be used in the subprocedure it is defined it. If I am only going to call an external program from within a subprocedure I can define the procedure prototype with the subprocedure, rather than at the top of the program.

01  dcl-proc Procedure1 ;
02    dcl-pr OtherPgm1Returns extpgm('OTHERPGM1') ;
03      *n char(5) ;
04      *n packed(3) ;
05      *n char(1) ;
06    end-pr ;


07    OtherPgm1Returns(P1:P2:P3) ;
08  end-proc ;

Line 1: DCL-PROC marks the beginning of the subprocedure.

Lines 2 – 6: This is my procedure prototype definition.

Line 2: I am going to call the same program as before, but this time I am giving it a procedure name, OtherPgm1Returns, that is different from the program name. This is why I need to give the external program's name within the EXTPGM keyword.

Lines 3 – 5: This time I am not going to give the parameters names. I need to use *N to indicate that the name is null.

Line 6: END-PR marks the end of the procedure prototype definition.

Line 7: I call the procedure name as I did in the previous example.

Line 8: END-PR marks the end of the procedure.

If the program I am calling does not require parameters to be passed I can define a procedure prototype without any parameters, and call the procedure with no parameters.

01  dcl-pr OtherPgm2 extpgm ;
02  end-pr ;


03  OtherPgm2() ;

Regular readers have seen me do calls to the QCMDEXC API using a procedure.

01  dcl-pr QCMDEXC extpgm ;
02    *n char(250) options(*varsize) const ;
03    *n packed(15:5) const ;
04  end-pr ;

05  dcl-s Command varchar(250) ;
06  dcl-s Length packed(15:5) ;

07  Command = 'CLRPFM QTEMP/WORKFILE' ;
08  QCMDEXC(Command:%len(%trimr(Command))) ;

09  Length = 25 ;
10  QCMDEXC('DLTDTAARA QTEMP/WRKDTAARA':Length) ;

11  QCMDEXC('DLTF QTEMP/WORKFILE':19) ;

In these examples the parameters in the procedure prototype definition have extra keywords on them. OPTIONS(*VARSIZE) mean that the string in the parameter is variable in length. CONST means that the value is passed to the external program, cannot be changed and returned to the calling program/procedure.

Why would I want that? As the examples shown on lines 7 – 11 I don't have to use a variable to pass a value to the external program. I can just pass the value. I tend to do this for two reasons:

  1. I don't have to define variables that will be used just once, as the parameters, when QCMDEXC is called.
  2. I think when I give the command I want to execute in the parameter it becomes obvious to myself at a later date, or to another, what I am doing.

It just a case of personal preference, I prefer to do it this way. If you don't then you don't have to.

in the examples I have shown when I have given a value in the EXTPGM it has been a value. But I can use a variable in the EXTPGM keyword, which allows me to call multiple different programs using one procedure prototype definition. Which is the same as using a variable name in the CALL operation code.

01  dcl-pr NextPgm extpgm(PgmName) ;
02  end-pr ;

03  dcl-s PgmName char(10) ;

04  PgmName = 'OTHERPGM2' ;
05       C                   call      PgmName
06  NextPgm() ;

07  PgmName = 'OTHERPGM3' ;
08  NextPgm() ;

line 1: This time the EXTPGMM contains a variable name, rather than a value.

Line 3: This is the variable that will contain the name of the program I want to call.

Line 4: First program I want to call is OTHERPGM2.

Line 5: If I was performing the call using fixed format it would look like this.

Line 6: When I call the procedure it calls the program's name that is in the variable PgmName.

Line 7: Change the name of the program in PgmName.

Line 8: This time when I call the procedure the program OTHERPGM3 is called.

 

I hope that this post, and the examples contained within, will convince the person I mentioned in the first paragraph, and anyone else who has used the same excuse, that it is possible to call a program in totally free RPG. Now there is no reason why they should not start coding using totally free format.

 

This article was written for IBM i 7.3, and will work for 7.1 TR11 and 7.2 TR3 and later too.

18 comments:

  1. ILE-RPG brought unprecedented superiority and sophistication to the computer programming. It brought advanced features to handle many aspects of business logic and the ability to connect with many other languages. It’s a truly amazing programming language – easy to code and easy to interpret.

    Unfortunately, one of my previous supervisors continuously discouraged me from and relentlessly harassed me for using the advanced features of this beautiful language simply because he could neither comprehend nor adapt to the evolving nature of ILE-RPG and the advanced features of embedded SQL. He preferred to live in the stone age and hated me for not joining him. But I never gave up. I love ILE-RPG and SQL.

    ReplyDelete
    Replies
    1. I think we all have managers/supervisors/colleagues who are that way. I regularly have "battles" with others over using the newer versions of RPG.

      Delete
    2. Jay - I feel your pain. About seven years ago I began working at a company with over 6,000 active RPG II (not RPG III) programs. By taking an evolutionary approach (rather than a revolutionary approach) I was able to introduce LE features, Dynamic SQL, and advanced screen design. Today we have 61 RPG II programs remaining, and a much happier staff. There is still much to do but by taking small steps we are getting there.

      Delete
    3. Although I do like free ile-rpg there is nothing sophisticated or unprecendented in it. Free ile rpg is just a C compiler with some make up thrown on top , the makeup being the data structures constructs and the packed decimal for bcd arithmetic. Don't get me wrong I do like free ile-rpg but...no Object orientation? In XXI century? Let's face it, free ile-rpg is an old lady with some make up. It's a fine looking old lady, certainly, and we all love her, but there is nothing new or umprecedented in it. The compiler is a one pass compiler, that is it does one read of your source (that's why you need "prototypes" just like C) you generate "MODULES" (.OBJ files in c) and you need "Service Programs" (DLLs), nothing new, and in fact all these ammenities could be found in my clipper compiler from the 80/90.
      Certainly I've expected better from IBM , semicolon to terminate lines not statements? booohhh, need to declare prototype? My time is expensive computer time it's not (not in XXI century at least) booooh, no object orientation? boooh.
      I'm not a rpg hater, in fact I do love RPG, but what is true is true and the shinning new free rpg is still an old language by any meassure you go on it.
      And yes, I've been on the platform since V2R1 and I'm still seeing new programs being written in RPG III.

      Delete
  2. free format is awesome!! utilize modules, service programs, binder language, XML, SOAP, webservices.

    ReplyDelete
    Replies
    1. Is it easy to learn these technologies? I'm a free format RPG programmer and
      i just landed a job and i will be working with these technologies you mentionned and im nervous.

      Delete
  3. Excellent and useful post explaining different ways of calling a program in free format!!!!Keep going ILE.

    ReplyDelete
  4. A note to the Punch-Card Hold-outs. Totally Free does not work on the discontinued System 36/38/AS400. You have to be using this century's powerful OS called "IBM i 7.2/7.3", not OS/400 5.4.

    ReplyDelete
  5. If you are not expecting to return values from the called program then follow the example of QCMDEXC.

    If you are expecting to return values then move those values to the variables, and then call the procedure.

    ReplyDelete
  6. how do people think about embedding free format stuff in an old converted OPM program? I try to put new stuff in a subr that is all free but stay with C specs in the original code.

    ReplyDelete
  7. The Old fashioned CALL is selfdocumentary, the new is not.

    Example:

    C call 'ZIPINFO'
    C parm 12312 ZI_ZipCod 5 0
    C parm 45000 ZI_YearSalary 7 0
    C parm 35 ZI_Age 3 0
    C parm 'M' ZI_Gender 1
    C ZipCount parm 0 ZI_RrnCnt 9 0

    This is selfdocumentary.

    Here how it looks in Free:

    ZIPINFO(12312:45000:35:M:ZipCount)

    How do i know what all this parameters are? I need to look on the prototype and count the position of the parameters. It returns me back to SYSTEM36 OCL where i needed to count the commas (,,,) to know what is the passed parameter. When we swithced to AS400, it was a big relief Parameter Have a name. Especially commands. Are we going backwards again?

    ReplyDelete
    Replies
    1. The easy solution is to define those parms as variables with INZ value, and then pass the variable names instead of constants. Actually you were doing the same in fixed format, but in the free format decided to cut the defining of variables and pass the constants directly.

      Delete
    2. I see the danger with that is I would have to search to see if value within the variable is changed in another part of the program/subprocedure.

      Delete
  8. Simon--

    Thank you for your blog work. It is a go-to resource for me.

    rp

    ReplyDelete
  9. A question.. If I needed to call another RPG program for example as shown below.. where runcmd is the Prototype name for QCMDEXEC, would this be considered as a bad practice?

    Cmd = 'CALL PGM(MF194R00B) PARM(''HF'' ''30'' ''031'' ''FS'' ''10'')';
    RunCmd(Cmd:%len(%trim(Cmd)));



    ReplyDelete
  10. Hi Simon. As always, your article is very good. I have a problem: I want to call a "dynamic" program with a return parameter. Working Full ILE works very well, but with OPM I can't find a way to tell it to return a value.
    I know well that I can use the value of the variables that I used as input parameters, but I would have liked it to work like value-return programa(parm1 : parm2 : parm3);

    ReplyDelete
    Replies
    1. If you are calling an OPM program you have to think with that mind set.

      The OPM program places the variables it wants to return into the same variables you passed it. You need to look at those.

      I never add any of the extra keywords, like CONST, to the parameters when I call an OPM. Just keep it as simple as you can.

      Delete

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.