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:
/* 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 ...
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...
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:
/*15*/ Parse upper pull answer
would have been better with a parse upper external or linein() function.
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.
Missing quotes around NO and FILELIST at line 22:
/*22*/ when abbrev(FILELIST,w1,1) then 'FILELIST' w2 w3 w4
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.