SELCOPY Coding Examples

Under the following headings are a selection of practical examples of SELCOPY Batch syntax. Please click on the headings to view.

For futher examples and help on other topics, please vist our FAQ page.

Simple File Copy

The simplest of functions you can perform with SELCOPY are file copies.

The following is a SELCOPY program which does this:


The above represent the minimum elements required for a SELCOPY program. One selection (READ) must cause input, and one selection (WRITE) must cause output.

In this case, SELCOPY will READ one logical record from file A and then copy it to file B. The READ/WRITE cycle is repeated until all of the records from file A are exhausted (i.e. end of file is reached) at which point, by default, SELCOPY will automatically terminate.

In addition to the control cards shown, a link must be provided between the filenames mentioned to SELCOPY (Files A & B in the above example) and the physical datasets to which they refer. These are:

  • DD statements for MVS users,
  • FILEDEF statements for CMS users, and
  • TLBL, DLBL, EXTENT and ASSGN statements for VSE users.

Alternatively, SELCOPY will dynamically allocate files using a dataset name provided either as a literal or from a position in its work area. e.g.

  WRITE B  DSN=44 AT 1001               CAT=UCAT1  VSAM

Select and Change

Almost as simple are SELCOPY's selection and modification capablities. For example:

  RD INFILE                    * Read a record
  IF POS 10 = 'CR'             * Select records with CR in col 10
    THEN PRINT STOPAFT=10      * and print only the first 10
    THEN WRITE CRFILE          * and write all of them to CRFILE
  IF POS ANY   = 'PICK ME'     * Scan whole rec for PICK ME
    THEN POS @ = 'PICKED '     * change it to PICKED
    THEN WRITE PKFILE          * and create a file of picked
    ELSE WRITE NOTPK           * plus file of not picked

Selection criteria can be as simple or as complex as required.

The above example illustrates use of IF/THEN/ELSE logic, but further conditions can be stipulated based on the result of a previous one with the use of THENIF/ELSEIF. Nesting can therefore easily be achieved in a structured and understandable manner.


For many applications, you will need more space than taken up by your file input record in order to store and manipulate data or counters, build new records etc...

For this purpose SELCOPY enables you to request a number of bytes which can be used as a sort of "scratch pad".

  RD INFILE      WORKLEN 300       * Read a record (say Lrecl=150) into POS 1
  IF POS 10  NE  POS 201  LEN 4    * Test for a change in Cost Centre.
    THEN MOVE  4 FR 10  TO 201     * Store in workarea for comparison.
    THEN PR      FR 201  L 4       * Print list of different Cost Centres.

In this example we read a file of records sorted by Cost Centre code, held in a 4 byte alpha-numeric field at position 10, and print out a list of each different code.

Variable to Fixed

Changing record formats is another example of the ease of coding SELCOPY control statements.

A Master file of customer records is kept on tape. Each record holds 40 bytes of fixed information for the customer in the first part of the record, and variable information at the end. The average record length is 600 bytes.

It is a requirement to produce a file containing only the fixed data, to reduce run times during small 'batch windows'. The abbreviated file is to be blocked to 32000 bytes.


Note that SELCOPY will automatically strip off the 4 bytes of control information when copying from variable to fixed length records.


Often, the information contained in files consists of data which is not readily printable - e.g. packed decimal, binary or hexadecimal fields.

SELCOPY will allow you to view parts of or whole records, areas of your work area, or indeed any of SELCOPY's special fields, in order to recognise non-character data. The normal printout produced by the PRINT commands in a SELCOPY program is basically geared to problem solving by programmers. You can however, easily produce reports for non-programming staff.

The SELCOPY reference manual contains several types of print format, three of which (Types MC,B & D), are illustrated below:-

Example: PRINT TYPE=MC (Mixed - predominantly char with hex)

    SELCOPY REL 9.8P AT CBL - Bridgend UK (Internal Only)                        (OS) VM/CMS=VM03      14.05 WED 09 DEC 1998    PAGE   1
  o -----------------------------------------------------                             --------------------------------------    -------- o

  o      1.  rd INDD                                                                                                                     o
         2.  print   type=mc    * Mixed - Char if printable, else Hex

  o                                                                                                                                      o
        INPUT   SEL SEL                                                                                                    1      RECORD
        RECNO   TOT ID.          1         2         3         4         5         6         7         8         9         0      LENGTH
  o     -----   --- --- ....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0      ------ o

            1     1   2 0Fred Bloggs,1Sunshine House,1Sunshine Street,0Sunny Village,0Sunny Valley,1Sunnington-on-Thames             96
  o                     D            0               1                F              E             5                                     o

            2     2   2 0Joe Bloggs,1Thunder Mountain,0Rain Town,0Snowy Creek,0Windy City,0Hail-on-Sea                               78
  o                     C           2                 B          D            C           C                                              o

  o SUMMARY..                                                                                                                            o
     SEL-ID      SELTOT      FILE     BLKSIZE  LRECL           FSIZE   CI    DSN
     ------      ------      ----     -------  -----           -----   --    ---
  o     1             2 READ INDD         96    96 U               2       SBR.TEST.A1                                                   o
        2             2

  o                                                                                                                                      o
             ** ** ** ** ** ** ** SELCOPY IS LICENSED BY COMPUTE (BRIDGEND) LTD  +44 (1656) 652222 & 656466 ** ** ** ** ** ** **
                                                      ** EXPIRY DATE -- 12 JUN 2001 **

Example: PRINT TYPE=B (Both char and hex)

    SELCOPY REL 9.8P AT CBL - Bridgend UK (Internal Only)                        (OS) VM/CMS=VM03      14.05 WED 09 DEC 1998    PAGE   1
  o -----------------------------------------------------                             --------------------------------------    -------- o

  o      1.  rd INDD                                                                                                                     o
         2.  print   type=b     * Both Char & Hex, Line 1-Char, 2-Zone, 3-Numeric.

  o                                                                                                                                      o
        INPUT   SEL SEL                                                                                                    1      RECORD
        RECNO   TOT ID.          1         2         3         4         5         6         7         8         9         0      LENGTH
  o     -----   --- --- ....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0      ------ o

            1     1   2  Fred Bloggs, Sunshine House, Sunshine Street, Sunny Village, Sunny Valley, Sunnington-on-Thames             96
  o                     0C9884C9988A61EA9A88984C9AA861EA9A88984EA988A60EA99A4E89988860EA99A4E8998A61EA99898A996996E8898A                 o

  o         2     2   2  Joe Bloggs, Thunder Mountain, Rain Town, Snowy Creek, Windy City, Hail-on-Sea                               78  o
  o                     ....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0             o

  o  SEL-ID      SELTOT      FILE     BLKSIZE  LRECL           FSIZE   CI    DSN                                                         o
     ------      ------      ----     -------  -----           -----   --    ---
        1             2 READ INDD         96    96 U               2       SBR.TEST.A1
  o     2             2                                                                                                                  o

  o          ** ** ** ** ** ** ** SELCOPY IS LICENSED BY COMPUTE (BRIDGEND) LTD  +44 (1656) 652222 & 656466 ** ** ** ** ** ** **         o
                                                      ** EXPIRY DATE -- 12 JUN 2001 **

Example: PRINT TYPE=D (Dump format)

    SELCOPY REL 9.8P AT CBL - Bridgend UK (Internal Only)                        (OS) VM/CMS=VM03      14.05 WED 09 DEC 1998    PAGE   1
  o -----------------------------------------------------                             --------------------------------------    -------- o

  o      1.  rd INDD                                                                                                                     o
         2.  print   type=d

  o                                                                                                                                      o
        INPUT   SEL SEL
        RECNO   TOT ID.
  o     -----   --- ---                                                                                                                  o
            1     1   2            96
      0000  0DC69985 8440C293 968787A2 6B10E2A4   95A28889 958540C8 96A4A285 6B11E2A4     *.Fred Bloggs,.Sunshine House,.Su*
  o   0020  95A28889 958540E2 A3998585 A36B0FE2   A49595A8 40E58993 93818785 6B0EE2A4     *nshine Street,.Sunny Village,.Su*             o
      0040  9595A840 E5819393 85A86B15 E2A49595   899587A3 96956096 9560E388 819485A2     *nny Valley,.Sunnington-on-Thames*
            2     2   2            78
  o   0000  0CD19685 40C29396 8787A26B 12E388A4   95848599 40D496A4 95A38189 956B0BD9     *.Joe Bloggs,.Thunder Mountain,.R*             o
      0020  81899540 E396A695 6B0DE295 96A6A840   C3998585 926B0CE6 899584A8 40C389A3     *ain Town,.Snowy Creek,.Windy Cit*
      0040  A86B0CC8 81899360 969560E2 8581                                               *y,.Hail-on-Sea                  *
  o                                                                                                                                      o
     SEL-ID      SELTOT      FILE     BLKSIZE  LRECL           FSIZE   CI    DSN
  o  ------      ------      ----     -------  -----           -----   --    ---                                                         o
        1             2 READ INDD         96    96 U               2       SBR.TEST.A1
        2             2
  o                                                                                                                                      o

             ** ** ** ** ** ** ** SELCOPY IS LICENSED BY COMPUTE (BRIDGEND) LTD  +44 (1656) 652222 & 656466 ** ** ** ** ** ** **
  o                                                   ** EXPIRY DATE -- 12 JUN 2001 **                                                   o

Use of GOTO

Where logic is required to bypass or repeat operations, the GOTO statement can be used.

The following example processes a tape file with a logical record length of 38, and block size of 3160. The file consists of two different types of records:

  • A header record, is always numeric in position 1 and 2.
  • A transaction record, always has 'Z' in position 1.

The file is in ascending sequence of header records, but many header records may have the same number in positions 1 and 2.

It is required to select only the header records containing '81' in position 1 and 2, together with their associated 'Z' records, writing them to tape with an output blksize of 380.

At the same time we require a print of all the '81' Header records that were selected.

  READ TAPE10   LRECL=38             * LRECL reqd for VSE only.
  IF POS 1 NE '81'
    THEN GOTO GET                    * Implicit label for 1st logical stmt.

  ==LOOP==                           ** Only '81' records drop through to here **
    IF POS 1 NE 'Z'
      THEN PRINT    STOPAFT=222      * Limit printing
    READ TAPE10                      * No need to repeat LRECL.
    IF POS 1 GT '81'                 * 'Z' is < '8'
    GOTO LOOP                        * Prevent automatic GOTO GET.
   =LOOPE=                           * Unref'd label. '=' for readability only

The THEN GOTO GET statement will cause looping around the first READ statement until we find a record with 81 in position 1. On finding it, control will drop through to LOOP, our main loop.

Because (for EBCDIC) "Z" is lower than numerics, checking position 1 for greater than "81" will never be satisfied by a transaction record. So we keep looping around until either we get End-of-file, or we find a record with 82 or more in position 1 and 2.


Storing data on disk is extremely inefficient when the data consists of many embedded blanks and other duplicated characters. To avoid this inefficiency, the COMPRESS/EXPAND facility has been introduced, allowing compression before writing, and expansion back to the full record size after reading a compressed record.

  READ BIGFILE    NORDW   WORKLEN=2222                * Ignore the 4-byte RDW.
  COMPRESS FR 1  TO 1001                              * Compress LRECL bytes.
  WR TAPEFIL     FR 1001  RECFM=VB   B=32000 L=4096   * Write Back-up.

Input File Concatenation

The CAT statement:

Concatenation of input files is beneficial to MVS, VSE and CMS users, as any type of file may be concatenated. e.g. a sequential disk file, a VSAM file, a Card reader file, a Library Directory file, and even a VTOC file. No restrictions on record format, record length or blocksize.

CAT Example:

    CAT DBAAAA00  DL1 SEG=DBAAAA01    * A DL1 data base.
    CAT LIB2DD  DIR                   * A PDS directory.
    CAT TAPE10                        * A magnetic tape.
  WRITE BIGFIL                        * Your reqd RECFM etc.

CAT Example for VSE:

An example for VSE users is to read a standard MVS labelled tape containing 2 logical data sets, processing everything (all 6 physical data sets) as data by reading the tape as unlabelled using NL, No Label. An MVS data set on tape consists of 3 sections, each one terminated by a Tape Mark which denotes physical EOF (End-of-File) for a VSE unlabelled tape.

  • The 1st section contains two 80-byte Header records for the data set, and on the 1st data set on the tape volume this section will also contain one 80-byte Volume label preceding the HDR records.
  • The 2nd section contains the data records for the data set which may be of any length up to 32760 bytes.
  • The 3rd section contains two 80-byte Trailer records for the data set.

Thus the 2 data sets constitute 6 unlabelled VSE files, which we will read as one file using the CAT statement. Note that TLBL cards are not required for unlabelled tapes.

  // ASSGN SYS010,X'280'
  // ASSGN SYS011 etc up to SYS015, all to the same drive.

    READ TAPE10   NL                CLOSE=NORWD  B=80     RECFM U
     CAT TAPE15   NL   OPEN=NORWD                B=80     RECFM U

    IF LRECL = 80                                          * Check length of current record.
      THEN IF P 2 = 'VOL'  !OR P 2 = 'HDR' !OR P 2 = 'TRL'
        THEN PRINT   TYPE M                                * Statistics info.
        THEN GG                                            * GOTO GET if reqd.
    WRITE BIGFIL  RECFM U  LRECL 32760                     * Make a Disk copy.

CAT Example for MVS:

An example for MVS users is to concatenate several associated files of different types. e.g. A RECFM=FB unlabelled tape file, a RECFM=VB file and a VSAM ESDS on different disk types. This mixture of files cannot be concatenated using JCL.

Assuming DD statements for TAPE1, DISK1, DISK2, SYSPRINT and SYSIN:

  READ TAPE1   RECFM=FB   L=46   INTO 11   WORKLEN 222
   CAT DISK1                             * Recfm, Blksize & Lrecl known to system.
   CAT DISK2   ESDS                      * Must identify as VSAM ESDS
  IF IN 1 !THEN MOVE 8 FR FNAME   TO 1   * Current filename.

  IF POS 11 = 'CUST'                     * Test pos 1 of inp rec.
    THEN LRECL = L+10                    * Allow for filename
    THEN PRINT                           * Print Customers only.

Directory and Data

CMS and VSE users may access directory and data records for generic groups of files and MVS users may access all members of single or concatenated PDSs, using the DIRDATA input facility.

CMS and MVS users may also Update-in-place, but for VSE an update file must be written out and used subsequently as input to a LIBR step.

For Data records SELCOPY's INCOUNT value is reset to 1 on reading the first data record from each library member or CMS file. For Directory records the INCOUNT value is simply increased by 1 to reflect the count of library members or CMS files. Directory and Data records are distinguishable using the IF DIR/IF DATA syntax.

MVS Summary of PDS Members:

A PDS contains a large number of CLISTs and REXX procedures which conventionally contain within the 1st 10 records a timestamp, level number and a short description of their purpose and call parameters. We will create a compendium of the descriptive text, spacing 2 lines between each member.

  NOPRINT                         * Suppress print of ctl cards etc.
  READ INPDS    DIRDATA           * Read all PDS members.

  IF DIR                          * If it's a Dir record.
    THEN SPACE 2                  * Print 2 blank lines.
    THEN PR   TYPE=M              * Use Mixed print for binary recstats.
    THEN GOTO GET                 * Means go to 1st logical statement.

  IF INCOUNT <= 10                * Select 1st 10 DATA recs
    THEN PRINT                    * Use default TYPE=N
    ELSE FLAG EOMEMB              * Force to read next member.

CMS Generic Update:

An EXEC procedure becomes outdated and is replaced by another with a different name. All other EXEC's which call this need therefore to be updated to call the new name.

  READ '* EXEC *'    DIRDATA      * Read all EXEC files.

  IF DIR                          * If it's a Dir record.
  AND POS 77 NE 'R/W'             * Can't update if disk is read-only.
    THEN FLAG EODISK              * Indicate End of Disk
    THEN GOTO GET                 * Bypass rest of disk.

  IF POS ANY    = 'EXEC ABC'      * Name of old EXEC.
    THEN POS @  = 'EXEC XYZ'      * Change name
    THEN UPDATE '* EXEC *'        * and update the file.

The above could easily be improved so that it prints the name of each file modified, and the names of the read-only files left unchanged.

VSE Library Generic Backup

This example will backup all payroll associated PROCEDURE and PHASE members from a VSE Library to a single tape file.

  READ LIB1.SUB.PAY.*  DIRDATA    * Read all payroll files.

  IF DIR                          * If it's a Dir record.
   THENIF POS ANY = 'PHASE'       * Further selection.
   OR     POS ANY = 'PROC'
       THEN DUMMY                 * Do nothing.
       ELSE FLAG EOMEMB           * Indicate End of Member.
       THEN GOTO GET              * Will bypass data rec's.

  WR TAPEFIL    RECFM=VB LRECL=4096 BLKSIZE=32000  * Copy to tape.

Back-up VSAM


Back-up 6 small VSAM files to a single tape volume without the usual multi-file volume difficulties and dangers.


Use SELCOPY to prefix a one-byte file identifier to each record and write all files to the same tape file, one after the other. Write RECFM=V output, blocked to device capacity, 32760. The overhead of 5 bytes for each record (4 for RDW and 1 for File Id) is more than compensated by the large blocksize. Use of NORDW on the restore suppresses the RDW from the input area. Omitting JCL for defining files, the SELCOPY control cards are below.


SELCOPY treats lower case as upper case unless in 'quotes', the Exclamation Mark is a Line End Character, and valid abbreviations used are:

  rd read    w worklen   fr from   l lrecl     b  blksize   t  then
  pr print   p pos       ty type   s stopaft   li elseif    ti thenif

VSAM is specified throughout for simplicity, but the same principle works for any file. RECFM, LRECL and BLKSIZE would be needed for VSE, but not for MVS and CMS as the operating system supplies this, as does VSAM.

  equ LMAX   4000                        * Maximum record length.
  read F1  ksds   into 102   w=LMAX+110  * GS009 DOC *
   cat F2  esds                          * INTO effective on all CAT's.
   cat F3  ksds                          * 2nd char of filename used as identifier.
   cat F4  esds
   cat F5  rrds
   cat F6  vsam                          * More CAT statements can be added.

  move 1 fr fname+1 to 101               * Set File Identifier (2nd char of filename).
  lrecl = L+1                            * Add 1 to record length of current record.
  wr TAPE10  recfm=v  b=32760  fr=101
  do PRINTIT                             * Print sample of data backed up.
  goto get                               * GET is implicit label - 1st ctl stmt.

  ==PRINTIT== * Subrtn only coded for additional info on printer *
    if p 6  ne  p 101  len 1             * same File Id No?
      t p 1 = 'File x --- started.'  s 1
      t move 1 fr 101 to 6               * Save File Id No.
      t space 2  !t pr l 30              * Print file id msg.
    if p 101 = '1' !t pr fr 101 ty=b s=3 * Print 1st 3 recs, Both char+hex.
    li p 101 = '2' !t pr fr 101 ty=b s=3 * and the same for F2
    li p 101 = '3' !t pr fr 101 ty=b s=3 * and F3
    li p 101 = '4' !t pr fr 101 ty=b s=3 * etc.
    li p 101 = '5' !t pr fr 101 ty=b s=3
    li p 101 = '6' !t pr fr 101 ty=b s=3
   =ret=                                 * Return to statement following DO PRINTIT.

Restore All Files:
  rd TAPE10   recfm v    nordw    blksize=32760
  lrecl = L-1                            * Reduce record length.
  if p 1 = '1' !t wr F1   ksds   fr 2
  li p 1 = '2' !t wr F2   ksds   fr 2
  li p 1 = '3' !t wr F3   esds   fr 2
  li p 1 = '4' !t wr F4   esds   fr 2
  li p 1 = '5' !t wr F5   rrds   fr 2
  li p 1 = '6' !t wr F6   vsam   fr 2

Restore Just One File:
  rd TAPE10   recfm v    nordw    blksize=32760
  if p 1 lt '3' !t goto get    * GET is implicit label - 1st ctl stmt.
  if p 1 gt '3' !t eoj         * Force eoj when finished with file 3.
  lrecl = L-1
  write F3   esds   fr 2

Match the contents of 2 files

A file of JCL statements, OLDJCL, needs modification to numerous DSN fields, all of which are on the first line of the DD card. The file REPJCL contains just DD cards which are in any sequence, and any match of any DD name in OLDJCL must be substituted with the appropriate record from REPJCL. Other records are to remain unchanged, and the file NEWJCL is to be created.

SELCOPY treats lower case as upper case unless in 'quotes', the Exclamation Mark is a Line End Character, and the following abbreviations are used:

 w worklen     p pos     l lrecl     t then     fr from     wr write

  //               MSGCLASS=X,MSGLEVEL=(1,1)
  //SYSIN     DD *

   option         w=80000                  * Large workarea.
   equ ARRAY         4001                  * Store area for REPJCL recs.
   equ ARRAYEND     79900                  * End of array.

   @ = ARRAY                               * Set @ ptr to start of array.

  ==LOOP1==     * Once only * Read whole of Base Data Set into an array.
    read REPJCL   into @                  * Read into array elem.
    if eof REPJCL
      then @END = @                       * Save ptr to end of array.
      then goto LOOP1E                    * Go read 2nd file.

    @ = @+80                              * Add 80 to @ ptr.
    if @ > ARRAYEND                       * If array is full.
      then goto cancel
    goto LOOP1
   =LOOP1E=             * LOOP1 end *

  ==LOOP2==     *(Main Loop)*
    read OLDJCL                           * Read 2nd input file.
    if eof OLDJCL      !t eoj             * Go to successfull End-of-Job.

                   * Match this OLDJCL record against all REPJCL records
                   * using substitute record for output where appropriate.
    if p ARRAY+2,@END  =  8 at 3  step=80 * Scan for DDNAME match.
      then wr NEWJCL   fr @-2             * If same DD, use Substitute.
      else wr NEWJCL   fr 1               * Write out orig record.
    goto LOOP2                            * To read next record.
   =LOOP2E=             * LOOP2 end * (Unreferenced label.)

In the above SELCOPY control cards, use is made of both the standard @ pointer and a user @ pointer which for convenience we have chosen to call @END.

The @ ptr is invaluable in giving a fixed reference point to a previously undefined position in your work area. It can be set either explictly by the assignment @ = 20 for instance, or implicitly by a successful range test. e.g. IF P 20 30 = ABC STEP=1 where STEP indicates the increment over the range for each subsequent compare. (STEP=1 is actually the default and needn't be coded)

Offsets may be obtained by coding @+n or @-n, where n is the offset required.

VM/CMS update


A very large CMS library needs modification to the directory date to force reorganisation.

Record 1 of the file holds the Directory record number as a 2 byte binary field at position 38. In the Directory record, position 107 contains a date in YYMMDD format which must change to set the Day number to zero. The year is 95, so we can verify this before the update.

XEDIT says it's too large.
EXECIO says the lrecl is greater than 256.
COPY says insufficient disk space - and anyway it takes too long.


SELCOPY will fix it!

Just key it in:

  l lib1 usrlib b ( alloc
  LIB1     USRLIB   B1 F       8192       8200      16400
  IF P 107 '95'

    THEN P 111 '00'
    THEN LOG   FR 101   LEN 50   TYPE B
     RECNO RECNO ID.            1         2         3         4         5
     ----- ----- ---   ....,....0....,....0....,....0....,....0....,....0
  0      2     1   5         950700  USRLIB      Q       w     48

Or write an EXEC:

  * NEWDAY EXEC * +++ LEVEL 002 +++ 94/04/21 17:07:32 +++
  * Alters library's directory date to force REORG.

    read LIB                         * Read 1st record.
    read LIB   rec 2 at 38 ty b      * Read specific record
    if  p 1 = '--- KEY/REC NOT FOUND ---'
      then log '+++ DIR POINTER INVALID +++'
      then goto cancel
    if  p 107 ones '000000'          * Date will be numeric.
    and p 107  ge '75'  le 2 at date * Check for valid Year.
    and p 109  ge '01'  le '12'      * Check for valid Month.
    and p 111  ge '01'  le '31'      * Check for valid Day.
      then p 111 = '00'              * All OK - Zeroise Day No
      then update lib                * Rewrite record to disk.
      then print type b              * Print whole record, both char and hex.
      then eoj

      else log '+++ EXISTING DATE INVALID +++'
      then goto cancel

DB2 Table Columns

SYSIBM.SYSCOLUMNS is the DB2 table which describes every column of every table within a DB2 SubSystem. For our example we'll list from it a few columns of interest for a specified table and use the CHAR option to return all information in displayable character format.

  read F1  tab=SYSIBM.SYSCOLUMNS  char                              \
         where="TBNAME='TYPE_TEST'"                                 \

  print                                     * Print the row.

The code for this SQL operation is quite long, so we have used the SELCOPY statement continuation feature. The continuation character is a backslash (\) as the last character of a control statement.

The following is output from the above control cards with a subroutine added which generates column headings by analysing the SQL Descriptor Area using the SELCOPY positional keyword SQLDA.

    SELCOPY REL 9.80 AT CBL-VMPS31 MVS 5.2.2                                          OS JOB=P390A     13.47 WED 14 MAY 1997    PAGE   1
  o ----------------------------------------                                          --------------------------------------    -------- o

  o          ** CBL.SSC.CTL(DB2SBR2) ***        L=101 +++ 97/05/14 13:47:19 (P390A)                                                      o

                           * Demonstrate Table Column listing.
  o                                                                                                                                      o
               equ hd 1001
               opt  w 2222
  o                                                                                                                                      o
               rd  f1   tab=sysibm.syscolumns  char                              \
                        fmt='name,TBNAME,TBCREATOR,COLNO,COLTYPE,LENGTH,SCALE'   \
  o                   where="TBNAME='TYPE_TEST'"                                 \                                                       o

         1.           order='colno'
  o                                                                                                                                      o
         2.    do heading   stopaft=1

  o      3.    print                                     * Print the row.                                                                o
         4.    goto get

  o                                                                                                                                      o

  o            -------                                                                                                                   o
         5.    @n    = 2 at sqlda+14  type=b       * Number of cols in use.
         6.    @sqlv = sqlda+16                    * Point to 1st var.
  o      7.    pos uxatptr = 4 at @sqlv+4          * Sets @ -> 1st  col in workarea.                                                     o
         8.    @1stc = @                           * Keep as @1stc.

  o           =loop=                                                                                                                     o
         9.    pos uxatptr = 4 at @sqlv+4          * Sets @ -> this col in workarea.
  o     10.    pos hd+@-@1stc-1     = '|'                                                                                                o
        11.    pos hd+@-@1stc-1+100 = '|'
        12.    pos hd+@-@1stc   = 18 at @sqlv+14
  o                                                                                                                                      o

               if @n > 1
  o     13.                then @n=@n-1                                                                                                  o
        14.                                then @sqlv=@sqlv+44
        15.                                                      then goto loop
  o                                                                                                                                      o

        16.    pr fr hd
  o     17.                tran Lrecl at hd+100 ' '  '-'                                                                                 o
        18.                                                pr fr hd+100
        19.   =ret=
  o                                                                                                                                      o

        INPUT   SEL SEL                                                                                                    1      RECORD
  o     RECNO   TOT ID.          1         2         3         4         5         6         7         8         9         0      LENGTH o
        -----   --- --- ....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0....,....0      ------
            1     1  16 NAME              |TBNAME            |TBCREATO|COLNO |COLTYPE |LENGTH|SCALE                                  76
  o         1     1  18 ------------------|------------------|--------|------|--------|------|------                                 76  o
            1     1   3 TTINT             |TYPE_TEST         |P390    |     1|INTEGER |     4|     0                                 76
            2     2   3 TTSINT            |TYPE_TEST         |P390    |     2|SMALLINT|     2|     0                                 76
  o         3     3   3 TTDEC             |TYPE_TEST         |P390    |     3|DECIMAL |     7|     2                                 76  o
            4     4   3 TTCHAR            |TYPE_TEST         |P390    |     4|CHAR    |     8|     0                                 76
            5     5   3 TTVCHAR           |TYPE_TEST         |P390    |     5|VARCHAR |    30|     0                                 76
  o         6     6   3 TTFLOAT           |TYPE_TEST         |P390    |     6|FLOAT   |     8|     0                                 76  o
            7     7   3 TTREAL            |TYPE_TEST         |P390    |     7|FLOAT   |     4|     0                                 76
  o                                                                                                                                      o
     SEL-ID      SELTOT      FILE     BLKSIZE  LRECL           FSIZE   CI    DSN
  o  ------      ------      ----     -------  -----           -----   --    ---                                                         o
        1             7 READ F1                 76 U               7
        2             1
  o     3----4        7                                                                                                                  o
        5----8        1
        9---12        7
  o    13---15        6                                                                                                                  o
       16---19        1

  o                                                                                                                                      o
             ** ** ** ** ** ** ** SELCOPY IS LICENSED BY COMPUTE (BRIDGEND) LTD  +44 (1656) 652222 & 656466 ** ** ** ** ** ** **
                                                      ** EXPIRY DATE -- 12 JUN 2001 **

The following special arguments for the SELCOPY POS keyword are supported:

POS SQLCA Refers to the SQL Communication Area.
POS SQLDA Refers to the SQL Descriptor Area.
POS SQLMA Refers to the SQL Message Area.

IMS/DL1 Database

We will print a sample of a DL1/IMS Data Base, together with Segment names and Level numbers, restricting the print to the first 50 segments.

For clarity, we will space a line on the print every time we hit a Root Segment which is identified by a Level number of 01 in the PCB feedback area.

Fields in DL1's PCB may be referenced using SELCOPY's positional keywords:

Keyword Description Length Type
POS PCB Database Name 8 Char
POS PCB+8 Seg Level 2 ZonedDec
POS PCB+10 Status Code 2 Char
POS STATUS Synonym for PCB+10    
POS PCB+12 Processing Options 4 Char
POS PCB+16 Reserved 4  
POS PCB+20 Segment Name 8 Char
POS SEG Synonym for PCB+20    
POS PCB+28 Length of Key 4 Binary
POS PCB+32 No of Sensitive Segs 2 Binary
POS PCB +36 Key Feedback Area Var Char

We will use a work area (automatically initialised to blanks by SELCOPY) which is larger than the largest record, and read segments (records) into position 101.

But segments shorter than 100 bytes may have residual data still in the work area from the last segment. This must be cleared with blanks before printing.

POS LRECL in SELCOPY refers to the last byte of the current input record assuming it was read into position 1, but in our case, we read our record into a position 100 bytes further on, so LRECL+100 is the last byte of the current record. It is therefore position LRECL+101 which needs to be blanked. L+101 is a valid abbreviation.

After moving in the Segment Name and Level no to the front of the work area, we will print it, restricting the print length to 200 and spacing one line first if we have a root segment to print. In spite of the restriction of L=200 on the PRINT command, it is still the true segment length of each individual segment which is printed on the right hand side of the SELCOPY report.

The Status Code is not checked because EOF is handled automatically by SELCOPY as well as any major error conditions.

SELCOPY Control Cards

  read DBNAME   DL1   into 101   w 2222  * Work area length 2222.

  pos L+101,200 = ' '                    * Blank out residual data.
  move 2   fr pcb+8   to 1               * Segment Level No.
  move 8   fr seg     to 10              * Segment Name.

  if pos pcb+8 = '01'                    * Is it a Root Segment?
    t space 1                            * Extra blank line.
    t p 20 = '*=* ROOT SEGMENT OF DB xxxxxxxx *=*'
    t move 8   fr pcb   to 43            * Data Base name.
    else pos 20,80 = ' '

  print   L 200   s 50                   * First 50 segs, length 100.

  • SELCOPY treats lower case as upper case unless in 'quotes'. Some common abbreviations are:

  rd read    w worklen   fr from   l lrecl     b  blksize    t  then
  pr print   p pos       ty type   s stopaft   li elseif     ti thenif

Change "t space 1 " to " t line 1 " to force a new page. You could also display the Processing Options. Use POS PCB+12.

Usage under TSO

The following live example illustrates use from TSO's READY message, using the S CLIST (provided on the distribution tape) to invoke SELCOPY, taking its control cards from parameter 1.

Using the command 'S TERM', the CLIST allocates both SYSIN and SYSPRINT to the user's terminal. This type of invocation is ideal for one-off jobs to investigate, for instance, the layout of files, or for simple fixes as shown in the following example.

We wish to read all members of a PDS with the dataset name, 'userid.ABCD', which happens to contain JCL. Where the JCL calls the program IEWL, replace it with a call to the program XXXX. This, of course, is not a real program name but serves as an example.


   s      term
   rd A dsn=abcd dirdata upd!if p any = 'IEWL'!t p @ = 'XXXX'!t upd A!t pr

   SELCOPY REL 9.8P AT CBL - Bridgend UK (Internal Only)

                                      IF P ANY = 'IEWL'
        2.                                              T P @ = 'XXXX'
        3.                                                             T UPD A
        4.                                                                     T PR

       INPUT   SEL SEL
       RECNO   TOT ID.          1         2         3         4         5         6
       -----   --- --- ....,....0....,....0....,....0....,....0....,....0....,....0..
          77     1   4 //LNK      EXEC PGM=XXXX,REGION=500K,
          76     2   4 //LNK      EXEC PGM=XXXX,REGION=500K,
          35     3   4 //LNK      EXEC PGM=XXXX,REGION=500K,
          35     4   4 //LNK      EXEC PGM=XXXX,REGION=500K,

    SEL-ID      SELTOT      FILE     BLKSIZE  LRECL           FSIZE   CI    DSN
    ------      ------      ----     -------  -----           -----   --    ---
       1           320 READ A         23440    80 FB              4       P390B.ABCD
       2             4
       3             4 UPD  A         23440    80 FB              4       P390B.ABCD
       4             4

            ** ** ** ** ** ** ** SELCOPY IS LICENSED BY COMPUTE (BRIDGEND) LTD  +44 (
                                                    ** EXPIRY DATE -- 12 JUN 2001 **)

The above example is perfectly good for a controlled example, but has certain short-comings if we consider changing a more commonly used string.

  1. There is no check to ensure that we don't update directory records.
  2. Only the first occurence of the string within each record will be modified.

An easier and better (in that it eliminates the deficiencies above) way to achieve the same update would be to use a REXX exec called SCANPDS, which is also provided on the SELCOPY distribution tape.

It's syntax is: SCANPDS ddname string1 string2

ddname is the ALLOC for the input PDS
string1 is the string to scan for
string2 if provided is used to overwrite string1, wherever found, and update that PDS member record.

For our example we would key in: SCANPDS abcd IEWL XXXX

Dynamic Allocation

MVS, VSE and CMS datasets may be processed without a DD, DLBL or FILEDEF statement by providing the full dataset name on the SELCOPY I/O command, either as a literal or as a field in the workarea giving a variable data set name.

Dynamic allocation has a variety of uses in all environments. A simple application for MVS is shown below, which uses SELCOPY to copy selected members of a PDS to another new PDS. For this example, we will select members with '96' anywhere in the member name.

    read  PDSINP  dsn='CBL.PDS.SSPDSC'   dirdata   into 101  worklen 33333
                                  * Read directory record and data
                                  * records for each PDS member.

    if dir                        * If it's a PDS directory record
      then do  SELECTION          * then selectively open a new output memb.
      else write PDSOUT   fr 101  * Copy record to the output member.

    goto get

  ==SELECTION==        ** Process the PDS directory records **
    if pos 101,107 = '96'  * Select if '96' appears anywhere in the name.
      then pos   1,44  =  'CBL.PDS.SSPDSC.Y96'   stopaft 1 * Output DSN.
      then pos  45     =  '(12345678)'           stopaft 1 * Append the
      then pos  46     =    8 at 101                       * memb name.
      then open   PDSOUT      dsn = 44+10 at 1   * CLOSE is automatic.

      else flag eomemb   * Suppress the OPEN for this input member.


Programming Notes

  1. SELCOPY tolerates blanks padding the variable DSN up to 44 bytes and blanks padding the member name up to 8 bytes.
  2. The SELCOPY feature, DIRDATA, is used to read all DIRectory and DATA records from the PDS, opening each member in turn, provided FLAG EOMEMB has not been set.

    DIRDATA input for MVS returns the directory record for each member, followed by its data records. (For VSE and CMS, the directory records are reformatted by SELCOPY.) PDS member selection may then be based on any combination of information held in the directory record. e.g. member name, userid, timestamps, record count/file size, authorisation code.

  3. Although not illustrated above, at the same time, using a few additional statements, the output member name could have been changed to rationalize it so that the '96' falls in a fixed position.

SELCOPY for Microsoft Windows

The following SELCOPY/WNT job will generate and dynamically execute File Transfer Program commands to SEND a generic group of files to your mainframe.

Although this example uses an MVS Partitioned Data Set to receive the PC files it could easily be modified for any environment and any FTP command.


Occurrences of %1, %2 and %3 in the control card syntax refer to the parameters passed to SELCOPY/WNT on the invoking command line.

    equ pdsname       1
    equ dirrec      101

    option      w 32760

    do init stopaft=1                 * Initialise once only.

    rd %1     dir     into dirrec     * Read a directory rec into pos 101.

    pos  dirrec-1+38    = ' '              * Blank out the '.'
    pos  @fn            = 9 at dirrec-1+30 * fn followed by a blank.
    if p @fn,@fn+9      = ' '              * Bound to get one.
      then pos @,@fn+10 = ")'"

    pos  dirrec-1+60-5  = 'send '
    if lrecl < 80
      then pos dirrec+lrecl,dirrec+80 = ' '
      then lrecl = 80                          * Keep it neat.
    pos  dirrec+lrecl   = pos 1,@fn+22

    log           fr dirrec-1+60-5,dirrec+lrecl-1+@fn+22-1
    system        fr dirrec-1+60-5,dirrec+lrecl-1+@fn+22-1
  * wr ssftp.cmd  fr dirrec-1+60-5,dirrec+lrecl-1+@fn+22-1 * To run in OS/2.

  ==init==              ** Initialisation sub-routine **
    pos  pdsname+3    = %2   !lower 1 at pdsname+3   * The emulator session.
    pos  pdsname+3+1  = ":'"                         * x:
    pos  pdsname+3+3  = %3                           *
    if p pdsname+3,pdsname+99 = ' '                  * Scan for blank.
      then @fn   = @+1

    lower from pos pdsname+3,@fn                     * Lower case the dsn.
    pos @fn-1 = "(ABCDEFGH)'  ascii crlf"    * etc


Assuming that the above control cards are stored in the file d:\cbl\SSFTP.ctl, then keying in at the DOS prompt

  selcopy <d:\cbl\SSFTP.ctl    c:\dos\*.BAS   C   CBL.FTPTEST

could generate and execute the following FTP commands:

  send c:\dos\GORILLA.BAS    c:'cbl.ftptest(GORILLA)'   ascii crlf
  send c:\dos\MONEY.BAS      c:'cbl.ftptest(MONEY)'     ascii crlf
  send c:\dos\NIBBLES.BAS    c:'cbl.ftptest(NIBBLES)'   ascii crlf
  send c:\dos\REMLINE.BAS    c:'cbl.ftptest(REMLINE)'   ascii crlf

The command line may seem a little long winded, in which case it would be worthwhile setting up a BAT file: e.g.

  :** h:\cg\SSFTP.BAT kkk             L=101 --- 97/06/19 11:24:32    (P22)

  : Format: ssftp      fileid_with_wildcard    emulator_session   mvs_pds_dsn
  :   e.g.  ssftp           C:\CBL\*.T*               B          CBL.SELC980.DM

  selcopy <d:\cbl\ssftp.ctl     %1                    %2              %3

Compress/Expand Comma Separated Variable (CSV) Data

The following job illustrates use of EXPAND and COMPRESS for CSV data.

Input CSV records are read into position 1 of the workarea and expanded so that all comma separated fields are copied to contiguous, fixed 30 byte fields beginning at position 201.

The expanded fields are printed (datawidth 30) before being re-compressed into a CSV format where hash (#) is used to delimit fields (instead of comma) and all non-numeric fields are enclosed in apostrophes (').

  * Expand/Compress CSV example.
  * Note: The LRECL value is automatically updated to be the length of the
  *       expanded or compressed data following an EXPAND or COMPRESS operation.
  *       Hence, PRINT FROM x, requires no length. (Prints LRECL bytes by default).

    opt worklen=2222   pagedepth=99999  datawidth=30

    read CARD   fill

    if incount > 1
      then print "------------------------------"
      then space 3

    print        "*** --------------------------"
    print  from   1                   * The original (compressed) CSV data.
    space 1

  * Expand to fixed length 30 byte fields.
  * Note that each comma separated source field must be <= 30 bytes.

    expand    Lrecl at   1    to    600 at 201    dlm=','   enc='"'       flen 30

    print  from 201                   * The expanded CSV data.
    space 1

  * Re-Compress using "#" to delimit fields (instead of commas) and enclose all
  * non-numeric fields in single quotes.

    compress  600   at 201    to    200 at 801    dlm='#'   enc="'"  str  flen 30

    print  from 801                   * The re-compressed CSV data.

  10010001,Mrs,Gaye,Sample,0,Mrs Sample,"""Uppingdene House""",Barham,,,,CANTERBURY,Kent,CT4 6QD,United Kingdom,C
  10010002,Mr,Edward,McSample,10,Mr Edward S McSample,23 Sycamore Drive,,,,,AYLESFORD,Kent,ME20 7LB,United Kingdom,C
  10010003,Ms,Lisa,Sample,"""""",Ms Lisa Sample,14 St. Stephen's Road,,,,,CANTERBURY,Kent,CT2 7HT,United Kingdom,C
  10010004,Mrs,Glynis,Sample,',Mrs Sample,"Railway Cottage, Sandland",Chipstead,,,,SEVENOAKS,Kent,TN13 2SP,United Kingdom,C
  10010005,Mrs,Patricia,Sample,,Mrs Sample,Barbican House,St. Stephen's Way,,,,FOLKESTONE,Kent,CT20 3RD,United Kingdom,C
  10010006,Mrs,Jennifer,Sample,,Mrs Sample,2 Court Cottages,Flete Road,Manston,,,MARGATE,Kent,CT9 4LP,United Kingdom,C02
  10010007,Mrs,Elizabeth,Sample,,Mrs Sample,5 Hever Place,,,,,CANTERBURY,Kent,,United Kingdom,C
  10010008,Mr,Christopher,Sample,,Mr Christopher J Sample,12 Croft Way,,,,,SEVENOAKS,Kent,TN13 2JX,United Kingdom,C
  10010009,Mrs,Adriana,Sample-Sample,,Mrs Sample-Sample,19 Westway,Pembury,,,,TUNBRIDGE WELLS,,TN2 7EX,United Kingdom,C
  10010010,Mrs,Sally,Sample,xxx,Mrs Sample,Woodstock',Pelham Gardens,xxx,xxx,xxx,FOLKESTONE,xxx,CT20 2LF,United Kingdom,C
  10010011,Mrs,Susan,Sample,,Mrs Sample,Colleton House,101 North Road,,,,,Kent,CT21 4AS,United Kingdom,C