Sunday, April 13, 2025

Manipulate REXX variables from a COBOL program

The IRXEXCOM variable access routine allows COBOL programs to manipulate REXX variables.
 
Documentation for IRXEXCOM  can be found at
https://www.ibm.com/docs/en/zos/2.4.0?topic=services-variable-access-routine-irxexcom
 
For COBOL program to manipulate REXX variables, it must be invoked by a REXX routine.
 
The REXX program presented below calls a COBOL program. This COBOL program retrieves the value of the REXX variable "LEREXX" and displays it. Subsequently, the COBOL program modifies the value of "LEREXX". When control returns to the REXX program, the updated value set by the COBOL program is visible in the REXX program.
 
 
REXX program
 
/* REXX */       
/* CODE FOR REXCOB PROGRAM */                
SAY "THIS IS FROM REXX "          
LEREXX = "VALUE IS SET IN REXX"   
SAY  'LEREXX: ' LEREXX            
SAY 'CALLING COBREXL..'           
"CALL *(COBREXL)"                 
SAY "RC : " RC                    
SAY "BACK FROM COBREXL"           
SAY  'LEREXX: ' LEREXX            
 
Run JCL for the REXX program
 
//STEP10   EXEC PGM=IKJEFT01               
//STEPLIB DD DISP=SHR,DSN=MY.COBOL.LOAD     
//SYSTSPRT DD SYSOUT=*                     
//SYSOUT   DD SYSOUT=*                     
//SYSTSIN  DD   *                          
 EX 'MY.REXX.PDS(REXCOB)'               
/*                                         
 
 
 
Below is the COBOL program
 
VARNAME1V refers to the name of the "REXX" variable to be manipulated.
VARNAME1L refers to the length of the "REXX" variable name.
 
VARVALUE1V refers to the value of the "REXX" variable.
VARVALUE1L refers to length of the "REXX" variable value.
 
SHVBLOCK is the communication area used by IRXEXCOM routine.
 
Function code such "fetch", "store" need to be populated in the SHVCODE of SHVBLOCK before the IRXEXCOM routine call.
 
       ID DIVISION.
       PROGRAM-ID.  COBREXL.
       ENVIRONMENT DIVISION.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
 
      *****************************************************
      * SHARED VARIABLE REQUEST BLOCK
      *****************************************************
       01 SHVBLOCK.
      * CHAIN POINTER TO NEXT SHVBLOCK
          02 SHVNEXT         USAGE POINTER.
      * USED DURING "FETCH NEXT"
      * CONTAINS LENGTH OF BUFFER
      * POINTED TO BY SHVNAMA
          02 SHVUSER         PIC S9(9) BINARY.
          02 SHVCODES.
      * FUNCTION CODE - INDICATES TYPE
             03 SHVCODE      PIC A.
      * RETURN CODES
             03 SHVRET       PIC X.
      * RESERVED (SHOULD BE 0)
          02 PIC             X(2).
      * LENGTH OF FETCH VALUE BUFFER
          02 SHVBUFL         PIC S9(9) BINARY.
      * ADDRESS OF VARIABLE NAME
          02 SHVNAMA         USAGE POINTER.
      * LENGTH OF VARIABLE NAME
      * (SET ON FETCH)
          02 SHVNAML         PIC S9(9) BINARY .
      * ADDRESS OF VALUE BUFFER
          02 SHVVALA         USAGE POINTER.
      * LENGTH OF VALUE BUFFER
          02 SHVVALL         PIC S9(9) BINARY .
 
      * LENGTH OF SHVBLOCK
       77 SHVBLEN            PIC 9(9) BINARY VALUE IS 32.
 
      *******************************************************
      * SHARED VARIABLE REQUEST BLOCK - FUNCTION CODES
      *******************************************************
      * SET VARIABLE FROM GIVEN VALUE
       77 SHVSTORE           PIC A VALUE IS 'S'.
      * COPY VALUE OF VARIABLE TO BUFFER
       77 SHVFETCH           PIC A VALUE IS 'F'.
      * DROP VARIABLE
       77 SHVDROPV           PIC A VALUE IS 'D'.
      * SYMBOLIC NAME SET VARIABLE
       77 SHVSYSET           PIC A VALUE IS 's'.
      * SYMBOLIC NAME FETCH VARIABLE
       77 SHVSYFET           PIC A VALUE IS 'f'.
      * SYMBOLIC NAME DROP VARIABLE
       77 SHVSYDRO           PIC A VALUE IS 'd'.
      * FETCH NEXT VARIABLE
       77 SHVNEXTV           PIC A VALUE IS 'N'.
      * FETCH PRIVATE INFORMATION
       77 SHVPRIV            PIC A VALUE IS 'P'.
 
      **********************************************************
      * SHARED VARIABLE REQUEST BLOCK - RETURN CODES (SHVRET)
      **********************************************************
      * EXECUTION WAS OK
       77 SHVCLEAN           PIC X VALUE IS X'00'.
      * VARIABLE DID NOT EXIST
       77 SHVNEWV            PIC X VALUE IS X'01'.
      * LAST VARIABLE TRANSFERRED ("N")
       77 SHVLVAR            PIC X VALUE IS X'02'.
      * TRUNCATION OCCURRED FOR "FETCH"
       77 SHVTRUNC           PIC X VALUE IS X'04'.
      * INVALID VARIABLE NAME
       77 SHVBADN            PIC X VALUE IS X'08'.
      * INVALID VALUE SPECIFIED
       77 SHVBADV            PIC X VALUE IS X'10'.
      * INVALID FUNCTION CODE (SHVCODE)
       77 SHVBADF            PIC X VALUE IS X'80'.
 
       77 REXXRTN            PIC X(8) VALUE "IRXEXCOM".
       77 REXXRC             PIC S9(9) BINARY.
       77 REXXRTNRC          PIC S9(9) BINARY.
       77 SHVRETB            PIC S9(9) BINARY.
 
       77 NULADDR            PIC 9(9)  BINARY VALUE 0.
 
       01 VARNAME1.
          02 VARNAME1L       PIC 999 VALUE 6.
          02 VARNAME1V       PIC X(250) VALUE 'LEREXX'.
 
       01 VARVALUE1.
          02 VARVALUE1L      PIC 999.
          02 VARVALUE1V      PIC X(250).
 
       PROCEDURE DIVISION.
 
           PERFORM INIT-AREA
           MOVE 250        TO SHVBUFL OF SHVBLOCK.
      * FETCH (DIRECT NOT SYMBOLIC) THE VARIABLE
           MOVE SHVFETCH TO SHVCODE OF SHVBLOCK.
           PERFORM INVOKE-IRXEXCOM
           DISPLAY 'FETCHING LEREXX FROM COBOL: '
           DISPLAY 'LEREXX: ' VARVALUE1V
      * STORE (DIRECT NOT SYMBOLIC) THE VARIABLE
           MOVE 20         TO SHVVALL OF SHVBLOCK.
           MOVE 'VALUE SET IN COBOL..' TO VARVALUE1V
           MOVE SHVSTORE TO SHVCODE OF SHVBLOCK.
           PERFORM INVOKE-IRXEXCOM
           STOP RUN.
 
       INIT-AREA.
 
           INITIALIZE SHVBLOCK REPLACING ALPHANUMERIC BY X'00'.
      * THE VARIABLE NAME
           SET SHVNAMA OF SHVBLOCK TO ADDRESS OF VARNAME1V.
           MOVE VARNAME1L TO SHVNAML OF SHVBLOCK.
      * THE VARIABLE VALUE
           SET SHVVALA OF SHVBLOCK TO ADDRESS OF VARVALUE1V.
 
       INVOKE-IRXEXCOM.
      * CALL THE REXX SERVICE AS A SUBPROGRAM TO SET THE
      * shared variable
           CALL REXXRTN USING REXXRTN ,
           OMITTED , OMITTED ,
           SHVBLOCK ,
           NULADDR , REXXRC
           Returning REXXRTNRC.
      *
           MOVE SHVRET TO SHVRETB
           DISPLAY "REXX RC IS " REXXRC ","
           " IRXEXCOM RC IS " REXXRTNRC ","
           " SHVRET IS " SHVRETB "." .
 
             
 
Output of the REXX routine
 
******************************** Top of Data ***********************************
ACF0C038 ACF2 LOGONID ATTRIBUTES HAVE REPLACED DEFAULT USER ATTRIBUTES         
READY                                                                          
 EX 'MY.REXX.PDS(REXCOB)'                                                   
THIS IS FROM REXX                                                              
LEREXX:  VALUE IS SET IN REXX                                                  
CALLING COBREXL..                                                              
RC :  0                                                                        
BACK FROM COBREXL                                                              
LEREXX:  VALUE SET IN COBOL..                                                  
READY                                                                          
END                                                                            
 ******************************* Bottom of Data ********************************
 
Output of the COBOL program
 
******************************** Top of Data ***********************************
REXX RC IS 000000000, IRXEXCOM RC IS 000000000, SHVRET IS 000000000.           
FETCHING LEREXX FROM COBOL:                                                    
LEREXX: VALUE IS SET IN REXX                                                   
                                                                               
                                                                               
REXX RC IS 000000000, IRXEXCOM RC IS 000000000, SHVRET IS 000000000.           
 ******************************* Bottom of Data ********************************
 
 

Saturday, April 12, 2025

Regular expressions or pattern matching with ISPF FIND, CHANGE, and EXCLUDE commands

A Regular Expression (or Regex) is a pattern (or filter) that describes a set of strings that matches the pattern.

Following documentation is copied from https://www.ibm.com/docs/en/zos/3.1.0?topic=string-regular-expressions-string1
 
A regular expression in a FIND, CHANGE, or EXCLUDE command allows you to search for a string matching a basic or extended regular expression. Note that The ‘replacement’ string for the CHANGE command cannot be specified as a regular expression.
 
Regular expression is specified as a quoted string preceded or followed by the letter “r”
For example, FIND r'l[ai]ne' word, will find the words lane and line
 
ISPF uses the IBM® C regcomp() — Compile regular expression and regexec() — Execute compiled regular expression functions to compile and execute a regular expression specified with a FIND, CHANGE, or EXCLUDE command. These are supported by the C runtime library and the C runtime library must be available.
 
ISPF queries the host code page defined for your TN3270 session. If the code page is one of the following:
 
 00037   00871   01123   01156
 00273   00875   01140   01157
 00277   00924   01141   01158
 00278   00930   01142   01160
 00280   00933   01143   01165
 00284   00935   01144   01364
 00285   00937   01145   01371
 00290   00939   01146   01388
 00297   01025   01147   01390
 00424   01026   01148   01399
 00425   01027   01149   04971
 00500   01047   01153   05123
 00838   01112   01154   08482
 00870   01122   01155   12712
 
ISPF uses the IBM C setlocale function with LC_ALL to set the corresponding C locale. This is done so that the special symbols (such as square brackets) within the regular expression are correctly interpreted when the regcomp function is used to compile the regular expression.
 
If the TN3270 code page is not one of the listed code pages then the default C locale is used when compiling the regular expression. If a regular expression is encountered on a FIND, CHANGE, or EXCLUDE command that is specified in an Edit macro that is called from a batch Edit session (where no terminal is attached), code page 1047 is used.
 
To see the code page for your ISPF session, you can check the value of your ISPF profile variable "ZTERMCID"
 
The simplest form of regular expression is a string of characters with no special meaning.
 
The following characters do have a special meaning; they are used to form extended regular expressions:
 
 

Symbol

Description

. (period)

The period symbol matches any one character except the terminal newline character.

For example, the regular expression d.g matches “dig”, “dug”, and “dog”, but not “dg”, though it matches “dgg”.

* (asterisk)

The asterisk symbol matches zero or more instances of the previous character.

For example, the regular expression he*ath matches “hath” and “heath” and (if it exists) “heeath”.

? (question mark)

The question mark symbol matches zero or one instance of the previous character.

For example, the regular expression behaviou?r matches “behaviour” and “behavior”.

+ (plus)

The plus symbol matches one or more instances of the previous character.

For example, the regular expression south+ern matches “southern” and “southhern”, but not “soutern”. (If you also wanted a match for “soutern”, use south*ern as the regular expression.) 

| (vertical bar)

The vertical bar symbol acts as an OR operator and matches the values to the left and right of the vertical bar.

For example, the regular expression Jack|Jill matches “Jack” and “Jill”.

\ (backslash)

The backslash symbol acts as an escape sequence. Use it when you want search for a regular expression symbol. The backslash character immediately precedes the symbol in the expression.

For example, the regular expression a.\+.b matches the string “a + b”. 

[string]

A string within square brackets matches any one of the characters in string.

For example, the regular expression d[iu]g matches “dig” and “dug”, but not “dog”. 

[character-character]

The hyphen symbol, within square brackets, means through. It fills in the intervening characters according to the current collating sequence. For example, [a-z] can be equivalent to [abc...xyz] or, with a different collating sequence, it can be equivalent to [aAbBcC...xXyYzZ].

For example, the regular expression m[a-z]p matches “map” and “mop”, but not “m9p”, since 9 is not in the range a to z. 

[^string]

The caret symbol, when the first character inside square brackets, negates the following characters within the square brackets.

For example, the regular expression d[^iu]g matches “dog”, but not “dig” or “dug”. 

{m} {m,u} {m,}

Integer values enclosed in {} indicate the number of times to apply the preceding regular expression. m is the minimum number, and u is the maximum number. {m} indicates an exact number of times to apply the regular expression. {m,u} indicates a range of instances. {m,} indicates that there is a minimum, but no maximum.

For example:

·       m[eaiy]{2}n matches “main”, “mien” and “mean”, but it does not match “man”, because there is only one instance of the letters in the square brackets. Nor does it match “mayan”, because this has three instances of the letters in the square brackets.

·       [0-9][a-z]{2,3}[0-9] matches “7ab5” and “4abc3”, but not “7b5”, nor “4abcd3”.

·       [0-9][a-z]{2,}[0-9] matches “4ab3”, “4abc3”, “4abcd3”, and so on, but not “4a3”. 

(expression)

Used to group parts of the expression into sub-expressions. This can be used to limit an operator to a sub-expression.

For example, the regular expression z/OS.((1\.1[0-3])|(2\.[1-2])) matches “z/OS® 1.13” and “z/OS 2.1”. 

 
Note: You can use the ] (right square bracket) alone within a pair of square brackets, but only if it immediately follows either the opening left square bracket or if it immediately follows [^. For example: []-] matches the ] and - characters.

ISPF Scroll more than 9999 lines

 Starting from z/OS 2.1, when issuing a scrolling command, a scroll amount of up to 9,999,999 can be entered in the primary input field. 'Scroll' fields on ISPF panels(which is located on the right hand side) continue to be limited to values up to 9999.

Example is given below. Key in "down 9999999" in the "Command" line and hit enter key in the BROWSE/VIEW/EDIT panels. Or You can Key in "9999999" and hit PF8 key. This will scroll the screen to 9999999 lines 

   Menu  Utilities  Compilers  Help                                             
 sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
 BROWSE    MY.BIG.FILE                              Line 0000000000 Col 001 080 
 Command ===> down 9999999                                      Scroll ===> CSR  
********************************* Top of Data **********************************
line no 1                                                                       
line no 2                 
line no 3                 
line no 4                 
line no 5                 
line no 6

   Menu  Utilities  Compilers  Help                                             
 sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss
 BROWSE    MY.BIG.FILE                              Line 0009999999 Col 001 080 
 Command ===>                                                   Scroll ===> CSR  
********************************* Top of Data **********************************
line no 9999999                                                       
line no 10000000           
line no 10000001                 
line no 10000002                 
line no 10000003          
line no 10000004

ZXSMIN and ZXSMAX are system profile variables containing the minimum and maximum scroll values as defined in the ISPF configuration table. Can be in the range of 0 to 9999999. When the value is entered in the scroll field the user is limited to entering a 4-digit value but when the value is entered in the command field it can be any value between ZXSMIN and ZXSMAX (inclusive).

If "down 9999999" command throws "Invalid scroll amount", then it implies ZXSMAX system profile variable is set to "9999" in the ISPF configuration table.

Tuesday, April 1, 2025

Utility to expand all copybooks in a COBOL program


IBM supplied program called ISRLEMX can be used to expand all the copybooks in a COBOL program. The documentation of the utility can be found at https://www.ibm.com/docs/en/zos/2.4.0?topic=4-member-expansion-isrlemx
 
Please note that this utility has some restrictions. It can be found at
https://www.ibm.com/docs/en/zos/2.4.0?topic=isrlemx-restrictions-member-expansion-member-parts-lists
 
It does not expand INCLUDE statements in a COBOL program.
 
Below is a sample Job step to expand the program called “PROGNAME”. You should concatenate both COPY library and SOURCE library under ISRLCODE ddname.  
 
//STEP10   EXEC PGM=ISRLEMX,                          
// PARM=('COB,PROGNAME,B,N,E,4, ,00,ENU,4,7',         
//      '1,/,VIO')                                    
//*                                                   
//ISRLMSG DD SYSOUT=*                                 
//SYSPRINT DD SYSOUT=*                                
//SYSOUT   DD SYSOUT=*                                
//ISRLXREF DD SYSOUT=*                                
//ISRLCODE DD DISP=SHR,DSN=MY.COPYLIB             
//         DD DISP=SHR,DSN=MY.SOURCE.PDS
//ISRLEXPD DD DSN=EXPANDED.SOURCE.FILE,               
//         DISP=(,CATLG,DELETE),                      
//         DCB=(LRECL=80,RECFM=FB),                   
//         SPACE=(CYL,(50,50),RLSE)                   
//*    
                                                

SUPERC - Display lines preceding and following the search line found to be listed

When you invoke ISRSUPC(SUPERC) to search for strings, by default, it will display only matching lines.

If you want to display the lines preceding and following the search line found to be listed, then you can use LPSF process option in the PARM card of SUPERC. The default value is 6.

The count can be changed by using the LPSFV process statement. This allows a count range of 1 to 50 lines.

In the below example, "LPSFV 2" option, lists up to 2 lines before and after the line found.

//SEARCH  EXEC PGM=ISRSUPC,                       
//            PARM=(SRCHCMP,LPSF,NOSUMS,          
//            'ANYC')                             
//NEWDD  DD DISP=SHR,DSN=MY.SEARCH.PDS
//OUTDD  DD SYSOUT=*                  
//SYSIN  DD *                         
SRCHFOR 'WS-PGM1XXXU-XXXCLE-UPDATE'   
LPSFV 2                               
/*                                    
 
Output of the above step
 
1  ISRSUPC   -   MVS/PDF FILE/LINE/WORD/BYTE/SFOR COMPARE UTILITY- ISPF FOR z/OS           LINE-#  SOURCE SECTION                    SRCH DSN: MY.SEARCH.PDS 
                                                                       
                                                                       
  MEMBER01 CONCAT#(9)       ----------- STRING(S) FOUND ----------------
                                                                       
                                                                       
       *  010500*=======================================================
       *  010600 01 WS-SQLCODE                      PIC ----9.         
     110  010700 01 WS-PGM1XXXU-XXXCLE-UPDATE       PIC X(8) VALUE 'A01U
       *  010800 01 WS-RECS-READ                    PIC 9(08).         
       *  010900 01 WS-RECS-POSTED                  PIC 9(08).         
        

Explanation for JOIN statement in SORT JOINKEYS application

If you don't specify a JOIN statement for a JOINKEYS application, only paired records from F1 and F2 are kept and processed by the main task as the joined records. This is known as an inner join.
 
You can change which records are kept and processed by the main task as the joined records by specifying a JOIN statement. You must specify the UNPAIRED operand. The F1, F2 and ONLY operands are optional. The JOIN operands you specify indicate the joined records to be kept and processed by the main task as follows:
 
JOIN UNPAIRED,F1,F2 or JOIN UNPAIRED
Unpaired records from F1 and F2 as well as paired records. This is known as a full outer join.
 
JOIN UNPAIRED,F1
Unpaired records from F1 as well as paired records. This is known as a left outer join.
 
JOIN UNPAIRED,F2
Unpaired records from F2 as well as paired records. This is known as a right outer join.
 
JOIN UNPAIRED,F1,F2,ONLY or JOIN UNPAIRED,ONLY
Unpaired records from F1 and F2.
 
JOIN UNPAIRED,F1,ONLY
Unpaired records from F1.
 
JOIN UNPAIRED,F2,ONLY
Unpaired records from F2.
 
Examples are given below for each of the above JOIN cases.
 
//STEP01   EXEC PGM=SORT                
//SORTJNF1 DD *                         
001 FILE 1                              
002 FILE 1                              
//SORTJNF2 DD *                         
001 FILE 2                              
003 FILE 2                              
//SORTOUT  DD SYSOUT=*                  
//SYSOUT   DD SYSOUT=*                  
//SYSIN    DD *                         
 OPTION COPY                            
 JOINKEYS FILES=F1,FIELDS=(1,3,CH,A)    
 JOINKEYS FILES=F2,FIELDS=(1,3,CH,A)    
 REFORMAT FIELDS=(F1:1,10,F2:1,10,?)    
 JOIN UNPAIRED,F1,F2                    
/*                                      
 
Output of the above step
001 FILE 1001 FILE 2B
002 FILE 1          1
          003 FILE 22

 
//STEP02   EXEC PGM=SORT               
//SORTJNF1 DD *                        
001 FILE 1                             
002 FILE 1                             
//SORTJNF2 DD *                        
001 FILE 2                             
003 FILE 2                             
//SORTOUT  DD SYSOUT=*                 
//SYSOUT   DD SYSOUT=*                 
//SYSIN    DD *                        
 OPTION COPY                           
 JOINKEYS FILES=F1,FIELDS=(1,3,CH,A)   
 JOINKEYS FILES=F2,FIELDS=(1,3,CH,A)   
 REFORMAT FIELDS=(F1:1,10,F2:1,10,?)   
 JOIN UNPAIRED,F1                      
/*                                     
 
Output of the above step
001 FILE 1001 FILE 2B
002 FILE 1          1

 
//STEP03   EXEC PGM=SORT                
//SORTJNF1 DD *                         
001 FILE 1                              
002 FILE 1                              
//SORTJNF2 DD *                         
001 FILE 2                              
003 FILE 2                              
//SORTOUT  DD SYSOUT=*                  
//SYSOUT   DD SYSOUT=*                  
//SYSIN    DD *                         
 OPTION COPY                            
 JOINKEYS FILES=F1,FIELDS=(1,3,CH,A)    
 JOINKEYS FILES=F2,FIELDS=(1,3,CH,A)    
 REFORMAT FIELDS=(F1:1,10,F2:1,10,?)    
 JOIN UNPAIRED,F2                       
/*                                      
 
Output of the above step
001 FILE 1001 FILE 2B
          003 FILE 22

 
//STEP04   EXEC PGM=SORT               
//SORTJNF1 DD *                        
001 FILE 1                             
002 FILE 1                             
//SORTJNF2 DD *                        
001 FILE 2                             
003 FILE 2                             
//SORTOUT  DD SYSOUT=*                 
//SYSOUT   DD SYSOUT=*                 
//SYSIN    DD *                        
 OPTION COPY                           
 JOINKEYS FILES=F1,FIELDS=(1,3,CH,A)   
 JOINKEYS FILES=F2,FIELDS=(1,3,CH,A)   
 REFORMAT FIELDS=(F1:1,10,F2:1,10,?)   
 JOIN UNPAIRED,F1,F2,ONLY              
/*                                     
 
Output of the above step
002 FILE 1          1
          003 FILE 22

 
//STEP05   EXEC PGM=SORT              
//SORTJNF1 DD *                       
001 FILE 1                            
002 FILE 1                            
//SORTJNF2 DD *                       
001 FILE 2                            
003 FILE 2                            
//SORTOUT  DD SYSOUT=*                
//SYSOUT   DD SYSOUT=*                
//SYSIN    DD *                       
 OPTION COPY                          
 JOINKEYS FILES=F1,FIELDS=(1,3,CH,A)  
 JOINKEYS FILES=F2,FIELDS=(1,3,CH,A)  
 REFORMAT FIELDS=(F1:1,10,?)          
 JOIN UNPAIRED,F1,ONLY                
/*                                    
 
Output of the above step
002 FILE 11 

 
//STEP06   EXEC PGM=SORT               
//SORTJNF1 DD *                        
001 FILE 1                             
002 FILE 1                             
//SORTJNF2 DD *                        
001 FILE 2                             
003 FILE 2                             
//SORTOUT  DD SYSOUT=*                 
//SYSOUT   DD SYSOUT=*                 
//SYSIN    DD *                        
 OPTION COPY                           
 JOINKEYS FILES=F1,FIELDS=(1,3,CH,A)   
 JOINKEYS FILES=F2,FIELDS=(1,3,CH,A)   
 REFORMAT FIELDS=(F2:1,10,?)           
 JOIN UNPAIRED,F2,ONLY                 
/*                                     
//*
 
Output of the above step
003 FILE 22