Midrange News for the IBM i Community


Reference to Unpassed Parameter Published by: Bob Cozzi on 20 Sep 2011 view comments(1)
© 2011 Robert Cozzi, Jr. All rights reserved.

© Robert Cozzi, Jr. All rights reserved. Reproduction/Redistribution prohibited.
A midrangeNews.com Publication

UnPassed Parameters

We've all seen it "MCH3201 - Pointer not set for location referenced." We all know what it means: (1) There is a reference to unpassed parameter, (2) There's no recovery and (3) We better fix it quickly before someone realizes we are a bad programmer.

Do you remember when you first saw a Reference to an unpassed parameter error? It wasn't in RPG, it was in CL. The solution I choice to use was to become an expert on user-written CL commands. A CL command is nothing more than a description of a program's parameters. It has a prompter and syntax checker that lets you avoid passing the wrong information to a program--in addition you get to pass default values for parameters that the user doesn't really care about "this time".

UnPassed Parms in RPGIII

The *PARMS subfield on the PSDS (Program Status Data Structure) was used to determine the number of parameters passed to the RPGIII program. For example, if the program supports 3 parameters and the caller passed in only 2 parameters, the program would load, start running and as soon as the program "touched" that third parameter, bam! "RPG0221 - MYPGM 1400 referenced to a parameter not passed (C G S D F)."  

If you look at the low-level joblog messages, however, you will see the MCH0801 message was actually generated first. "MCH0801- Argument associated with external or internal parameter not passed."

To use *PARMS to avoid this kind of error, the PSDS data structure must be included in the RPGIII program. To do that, add the Input specifications for a Data Structure, and prefix the "DS" type with an "S" and include a subfield where the From/To column positions are *PARMS instead of real from/to columns. Then name the field anything you want. Naming it PARMS will be useful when migrating to RPGIV since %PARMS can then be easily substituted for the PARMS subfield. He is what it looks like in RPGIII:

     IPSDS       SDS
     I                                     *PARMS   PARMS
     IWORK        DS
     I                                        1  15 IP
     I I            '198.162.0.101'          16  30 DFTIP
     I                                       31  40 USRPRF
     I I            'QDFTOWN'                41  50 DFTUSR
     I                                       51  60 PWD
     I I            'ROSEBUD'                61  70 DFTPWD
     C                     MOVE *ON       *INLR
     C           *ENTRY    PLIST
     C                     PARM           RMTIP  15
     C                     PARM           USER   10
     C                     PARM           PASSWD 10
      /SPACE
     C           PARMS     IFGE 1
     C                     MOVELRMTIP     IP
     C                     ELSE
     C                     MOVELDFTIP     IP
     C                     ENDIF
     C           PARMS     IFGE 2
     C                     MOVELUSER      USRPRF
     C                     ELSE
     C                     MOVELDFTUSR    USRPRF
     C                     ENDIF
     C           PARMS     IFGE 3
     C                     MOVELPASSWD    PWD
     C                     ELSE
     C                     MOVELDFTPWD    PWD
     C                     ENDIF
     C                     RETRN 

UnPassed Parms in RPG IV

Moving to RPG IV, programmers quickly adopted the %PARMS() built-in function to check the number of parameters passed to the program. If 2 out of 3 parameters were passed, the program could avoid "touching" the third parameter. But if this precaution isn't taken, then RPG IV program generated the same type of error messages, but with different numbers.

In RPG IV, touching an unpassed parameter means "CEE9901 - Application error. MCH3601 unmonitored by MYPGM at statement 0000001800, instruction X'0000'." Looking at the low-level joblog shows that "MCH3601 - Pointer not set for location referenced." message.

Here is an example in RPG IV:

     D  rmtIP          S             15A                 
     D  IP             S             15A                 
     D  dftIP          S             15A                 
     D  user           S             10A                 
     D  usrprf         S             10A                 
     D  dftusr         S             10A   Inz('QDFTOWN')
     D  password       S             10A                 
     D  pwd            S             10A                 
     D  dftpwd         S             10A   Inz('ROSEBUD')
     C                   MOVE      *ON           *INLR   
     C     *ENTRY        PLIST                           
     C                   PARM                    RMTIP   
     C                   PARM                    USER    
     C                   PARM                    PASSWORD
      /free                                              
           if (%parms() >= 1);
              eval ip     = rmtip;     
           else;
              eval ip = dftip;
           endif;
           if (%parms() >= 2);
              eval usrprf = user;                           
           else;
              eval usrprf = dftusr;
           endif;
           if (%parms() >= 3);
              eval pwd    = password;
           else;
              eval pwd = dftpwd;
           endif;
               // Do something here 
           return;                  
      /end-free                     

Note that since RPG IV includes the %PARMS built-in function, there isn't much need for the legacy PSDS data structure any longer.

One more note; as of v7r1 the %PARMNUM built-in function was introduced. This built-in function allows you to specify the name of the parameter in place of the parameter's number. Therefore you can change the parameters sequence without the burden of having to adjust the Calc specs. This is very useful during the development phase of the program. It also allows you to quickly write this type of error/recovery routine without counting the parameters on your fingers. Here is the above example, re-written using the %PARMNUM built-in function:

     H DFTACTGRP(*NO)
     H OPTION(*SRCSTMT) ACTGRP(*NEW)
     DTESTNOPARM       PR                  EXTPGM('TESTNOPARM')
     D RMTIP                         15A
     D USER                          10A
     D PASSWORD                      10A
     DTESTNOPARM       PI
     D RMTIP                         15A
     D USER                          10A
     D PASSWORD                      10A
     D  IP             S             15A
     D  dftIP          S             15A
     D  usrprf         S             10A
     D  dftuser        S             10A   Inz('QDFTOWN')
     D  pwd            S             10A
     D  dftpwd         S             10A   Inz('ROSEBUD')

     C                   MOVE      *ON           *INLR
      /free
           if (%parms() >= %parmNum(rmtIP));
              ip = rmtIP;
           else;
              ip = dftIP;
           endif;
           if (%parms() >= %parmNum(user));
              usrprf = user;
           else;
              usrprf = dftUser;
           endif;
           if (%parms() >= %parmNum(password));
              pwd = password;
           else;
              pwd = dftPWD;
           endif;
               // Do something here
           return;
      /end-free 

 

UnPassed Parms in CL

As I mentioned, unpassed parameter errors were often handled with user-written CL commands. While that is the correct solution, it is not the only one. Around about 1985 IBM's Jim Sloan showed us all how to capture unpassed parameter error message in CL using a simple MONMSG statement. When message MCH3601 would be raised, you trap it and continue processing. Pretty cool! Here is an example:

 DFTPARMS:   PGM        PARM(&RMTIP &USER &PASSWORD)                
             DCL        VAR(&RMTIP) TYPE(*CHAR) LEN(15)   
             DCL        VAR(&USER) TYPE(*CHAR) LEN(10)    
             DCL        VAR(&PASSWORD) TYPE(*CHAR) LEN(10)    
                                                          
             DCL        VAR(&IP) TYPE(*CHAR) LEN(15)      
             DCL        VAR(&USRPRF) TYPE(*CHAR) LEN(10)  
             DCL        VAR(&PWD) TYPE(*CHAR) LEN(10)  
                                                          
             DCL        VAR(&DFTIP) TYPE(*CHAR) LEN(15) + 
                          VALUE('192.168.0.101')          
             DCL        VAR(&DFTUSR) TYPE(*CHAR) LEN(10) +
                          VALUE('QDFTOWN')                
             DCL        VAR(&DFTPWD) TYPE(*CHAR) LEN(10) +
                          VALUE('ROSEBUD')                
                                                          
             CHGVAR     VAR(&USRPRF) VALUE(&USER)         
             MONMSG     MSGID(MCH3601 MCH0801) EXEC(DO)           
                CHGVAR  VAR(&USRPRF) VALUE(&DFTUSR)       
             ENDDO
             CHGVAR     VAR(&PWD) VALUE(&PASSWORD)         
             MONMSG     MSGID(MCH3601 MCH0801) EXEC(DO)           
                CHGVAR  VAR(&PWD) VALUE(&DFTPWD)       
             ENDDO
             CHGVAR     VAR(&IP) VALUE(&RMTIP)                          
             MONMSG     MSGID(MCH3601 MCH0801) EXEC(DO)           
                CHGVAR  VAR(&IP) VALUE(&DFTIP)                          
             ENDDO                                                      
             FTPFILE RMTSYS(&IP) PUTGET(*GET) LCLFILE(&USRPRF/QXMLSRC) +
                       LCLMBR(CONFIG) USER(&USRPRF) PWD(&PWD)      
 ENDPGM:     ENDPGM

Strictly speaking, you probably don't need the MCH0801 monitor, but I like to be complete. If you want to be a bit lazy, you can probably monitor for just MCH0000 as monitoring is generic; that is any messages you monitor that end in 0 (zero) treat the zeros as a generic symbol, so MCH3600 monitors for all messages that begin with "MCH36" meaning MCH3600 through MCH36FF are trapped.

Pretty cool, huh?

Call Me

Bob Cozzi has been providing the solutions to midrange problems, in the form or articles and books since 1983. He is available for consulting/contract development or on-site RPG IV, SQL, and CGI/Web training. Currently many shops are contracting with Cozzi for 1 to 3 days of Q&A and consulting with their RPG staff. Your staff gets to ask real-world questions that apply to their unique development situations. To contact Cozzi, send an email to: bob at rpgworld.com

You can subscribe to RPG Report (we call it "follow") by visiting the RPG Report page on midrangeNews.com and then click the FOLLOW link in the table of contents for that page. To unsubscribe, simply click that same link. You must be signed up and signed in to midrangeNews.com to start following RPG Report.

Follow Bob Cozzi on Twitter

Return to midrangenews.com home page.
Sort Ascend | Descend

COMMENTS

(Sign in to Post a Comment)
Posted by: bobcozzi
Site Admin ****
Chicagoland
Comment on: RPG Report - 20 SEPT 2011
Posted: 12 years 6 months 24 days 13 hours 15 minutes ago

On V7R1 I've noticed that the CL MONMSG tip no longer works. I get a "Parms passed on call do not match those required by program" message. This the same message I remember getting decades ago. Perhaps v5r2 -> v5r4 had bugs in them that permitted this "feature" to work and now they've been corrected back to what it used to be. I personally prefer it to work as I saw it "working" on v5r2->v5r4 but whatever.