Answer to question 23

This little piece of code was not meant to contain only errors, but also to learn (or review) some interesting coding techniques.  By letting you analyze the procedure (play interpreter), we hope you learned even more than to read plain text.

These are the good techniques we included:

  1.  /* 3*/ Parse value translate(diag(8,'Q SET'),' ',','!!'15'X) ,
     /* 4*/       with  a b c d e emsg .
    

    The addition of the translate() function in the parse serves a specific purpose.  Let's have a look at a typical output of the CP QUERY SET command:

       MSG IUCV, WNG ON  , EMSG ON  , ACNT OFF, RUN OFF
       LINEDIT ON , TIMER OFF , ISAM OFF, ECMODE ON
       ASSIST OFF           , PAGEX OFF, AUTOPOLL OFF
       IMSG ON  , SMSG OFF , AFFINITY NONE   , NOTRAN OFF
       VMSAVE OFF, 370E OFF
       STBYPASS OFF   , STMULTI OFF   00/000
       MIH OFF , VMCONIO OFF , CPCONIO OFF , SVCACCL OFF , CONCEAL OFF
       MACHINE ESA, SVC76 CP, NOPDATA OFF, IOASSIST OFF
       CCWTRAN ON , 370ACCOM OFF
    

    This is probably one of the least appealing outputs produced by CP commands.  Throughout the VM Versions and Releases, elements were added or changed to this list.  In order to keep maximum compatibility, the keywords kept organized in this unordered way.

    Now, if we would simply use a parse like this one:

       parse value diag(8,'QUERY SET') with . 'EMSG' emsg ',' .
    

    then we would indeed be able to extract the value of EMSG.  But if we used this same template for the ECMODE value, we would have trouble:

    If we would code the parse as follows:

       parse value diag(8,'QUERY SET') with . 'EMSG' emsg .
    

    we may still have problems, as the value of EMSG cannot only be ON or OFF, but also IUCV (as it shows for MSG is in our example).  So, it means that the value of the emsg variable would become IUCV, as there is no space left before the comma.

    That is the reason why we code a translate() at line 3, to eliminate both the line-end characters and the commas so that the string we really will parse in statement 4 becomes:

       MSG IUCV  WNG ON    EMSG ON    ACNT OFF  RUN OFF
       LINEDIT ON   TIMER OFF   ISAM OFF  ECMODE ON
       ASSIST OFF             PAGEX OFF  AUTOPOLL OFF
       ...
    

  2. We already mentioned the technique to create a logical 0 or 1 value, ready for boolean comparisons.  Line 5 contains another example of this.  (emsg¬='OFF') sets the value to 1 if EMSG is not OFF, thus ON, and to 0 in the other case.  This has the advantage that you can code statements like the following:

       if emsg then do /* what's needed when EMSG is ON */
               else do /* what's needed when EMSG is OFF */
    

    Line 9 contains another example of this 'short if'.

    Remark that (emsg='ON') is not totally the same, as EMSG can also take the value IUCV...

  3. The use of abbrev() without a length parameter is OK:

        /*20*/      when abbrev(NO,w1) then exit
    

    The default length, when not specified, is equal to the length of the value you want to test.  Hence, the word must in this case completely match the keyword.  Also a null-string will match.  This technique can then used to provide a default value, as follows:

       parse upper linein answer .
       if abbrev('NO',answer) then do /* default answer given */
    

    If the user answers with a null-string, 'N', 'n', 'NO', 'No' or 'no', the condition will always be true.

On the other hand, the piece of coding contained a bunch of bad things:

  1. The worst one is of course the missing address command.  If we add it, then an EXEC would be required before the FILELIST commands on lines 21 and 22.
  2. Several variables are defined and never used, such as a b c d e and f in the parse instruction at line 4.  Idem dito for zero and nok.  The waste of storage and CPU may appear minimal, it is the reader of the program that has difficulties understanding the logic.
  3. The template for the parse at line 4 indeed contains a variable too much to position correctly on the EMSG value, but anyway we now know the parse should be written differently to become release independent...
  4. The line
       /*15*/    Parse upper pull answer
    

    would have been better with a parse upper external or linein() function.

  5. There is an extraneous parameter with at line 18:

       /*18*/    parse var anwser with w1 w2 w3 w4 .
    

    This keyword is valid (and needed) only for a parse value.

  6. Missing quotes around NO and FILELIST at line 22:

       /*22*/      when abbrev(FILELIST,w1,1) then 'FILELIST' w2 w3 w4
    
  7. The default answer can be solved via the select construct, so that

       /*17*/    if answer='' then answer='Y'
    

    can be eliminated.

Use the backward navigation button of your browser to return to the lesson.