Use Cases

Below are a few common examples for the use of FLCL. This examples can be loaded in FLCC from the use case dialog.

Example 1

Display information for a file on Windows command shell.

C:> flcl info get.file=test.zip

Example 2

Show all supported CCSIDs on z/OS using a JCL batch job.

//FLCLINFO EXEC PGM=FLCL,REGION=0M,PARM='INFO GET.CCSIDS'
//STEPLIB  DD DSN=&SYSUID..FLAM.LOAD,DISP=SHR
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*

Example 3

Read a FLAMFILE and write it as record-oriented dataset on z/OS. This is the same as FLAM DECO of FLAM4. If you use FLAMFILE/FLAMIN and FLAMOUT as DD name, then the FILE specifications are not required. The DD name FLAMIN is the default for input files on z/OS. If FLAMOUT or FLAMFILE (only if it is a FLAMFILE) not allocated the default DSN (original name plus extension) is used if no file specification given. The default on other platforms would be the standard input or output stream, so you can use this to pipe the data streams.

//FLCLCONV EXEC PGM=FLCL,REGION=0M,PARM='CONV=DD:PARM'
//STEPLIB  DD DSN=&SYSUID..FLAM.LOAD,DISP=SHR
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//INPUT    DD DSN=&SYSUID..TEST.ADC,DISP=SHR
//OUTPUT   DD SYSOUT=*
//PARM     DD *
   READ.FLAM4(
      FILE='DD:INPUT'
   )
   WRITE.RECORD(
      FILE='DD:OUTPUT'
   )
/*

Example 4

Read a member from a FLAMFILE and write it as record oriented dataset on z/OS with character conversion from CP1252 to IBM1141 (same as the job above but with dynamic allocation).

//FLCLCONV EXEC PGM=FLCL,REGION=0M,PARM='CONV=DD:PARM'
//STEPLIB  DD DSN=&SYSUID..FLAM.LOAD,DISP=SHR
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//PARM     DD *
&1140;
   READ.FLAM4(
      FILE='~.TEST.ADC'
      MEMBER=MEMBERNAME
      CCSID=1252
   )
   WRITE.RECORD(
      FILE=STREAM
      CCSID=IBM-1141
   )
/*

Be aware that tilde (abbreviation for '<SYSUID>') is a character with different code points in EBCDIC. The environment variable LANG or the corresponding system variables must be defined to the CCSID used to build the in line control statements so that CLP can interpret this correctly else you can define the CCSID used for this CLP string like in the example above.

Example 5

Read a record-oriented dataset on z/OS and write it to two targets at the same time.

  1. As password-encrypted FLAMFILE on z/OS using static allocation with default DD names FLAMIN and FLAMFILE/FLAMOUT.
  2. As password-encrypted PGP file to a ZIP archive (FLAMOUT). The ZIP file is an encrypted backup of the host dataset containing length fields in front of each record and all relevant DCBs in the ZIP member header.

The password for both instances is specified in a file (which is written inline for better understanding of the example). There is no parameter file assigned to the CONV command. In this case the default DD name 'FLAMPAR' are used.

The next example shows how you can reconstruct the stored host dataset from the ZIP archive.

//FLCLCONV EXEC PGM=FLCL,REGION=0M,PARM='CONV'
//STEPLIB  DD DSN=&SYSUID..FLAM.LOAD,DISP=SHR
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//FLAMIN   DD DSN=&SYSUID..TEST.DAT,DISP=SHR
//FLAMFILE DD DSN=&SYSUID..TEST.ADC,DISP=NEW
//FLAMOUT  DD DSN=&SYSUID..TEST.ZIP,DISP=NEW
//PASSFILE DD *
e'Password'
/*
//FLAMPAR  DD *
   READ.RECORD()
   WRITE.FLAM(pass=f'DD:PASSFILE')
   WRITE.RECORD(encr.pgp(pass=f'DD:PASSFILE') archive.zip())
/*

The password is defined to use EBCDIC encoding as binary interpretation. With an 'a' you can ensure ASCII but normally we recommend to use 'x' for an hexadecimal string.

Example 6

Read the PGP encrypted host dataset from the ZIP archive and reconstruct it with the original name and DCB parameter.

//FLCLCONV EXEC PGM=FLCL,REGION=0M,PARM='CONV'
//STEPLIB  DD DSN=&SYSUID..FLAM.LOAD,DISP=SHR
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//FLAMIN   DD DSN=&SYSUID..TEST.ZIP,DISP=SHR
//PASSFILE DD *
e'Password'
/*
//FLAMPAR  DD *
   READ.RECORD(decode decr.pgp(pass=f'DD:PASSFILE'))
   WRITE.RECORD()
/*

Example 7

Read a text file on windows and write EBCDIC records to a FLAMFILE for a German z/OS.

C:> flcl conv "read.text(file=test.txt) write.flam(file=test.adc ccsid=1141)"

Example 8

Read a remote text file from a windows system (its a GZIP stream in the home directory) and write it on z/OS to a record oriented dataset in EBCDIC(1047).

//FLCLCONV EXEC PGM=FLCL,REGION=0M,PARM='CONV=DD:PARM'
//STEPLIB  DD DSN=&SYSUID..FLAM.LOAD,DISP=SHR
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//PARM     DD *
   READ.TEXT(
      FILE=ssh://<cuser>@winserver/test.gz
      CCSID=1252
   )
   WRITE.RECORD(
      FILE=<SYSUID>.OUTPUT.DAT
      CCSID=1047
   )
/*

Example 9

Write a record oriented host dataset as text in UTF-8 to a PGP file (signed and encrypted), which will be stored as ASCII-armor encoded member in a remote ZIP archive on a UNIX system and convert the member name to a path name.

//FLCLCONV EXEC PGM=FLCL,REGION=0M,PARM='CONV=DD:PARM'
//STEPLIB  DD DSN=&SYSUID..FLAM.LOAD,DISP=SHR
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//STDENV   DD *
LANG=de_DE.IBM-1141
HOME=/u/hugo
USER=hugo
ENVID=T
/*
//PARM     DD *
   READ.RECORD(
      FILE=~.TEST.XMIT(MYTEXT)
      CCSID=1141
   )
   WRITE.TEXT(
      FILE=ssh://<cuser>@unix.server.com/out.zip
      CCSID=UTF-8
      encrypt.pgp(userid='receiver.name' signid='my.name' armor())
      archive.zip(member='[member].txt')
   )
/*

If the input output name mapping with square brackets used, then the CCSID for the correct interpretation of the CLP string must be defined (same for tilde). The '@' in the URL is also a character with different code points. In this case FLAM supports also the ampersand as separation between the user and the server, to prevent the requirement to know the CCSID used for correct interpretation. In the example above the DD name STDENV are used to define the most important environment variables required to run FLAM commands.

Example 10

Read all XML files from ZIP archive on UNIX in UTF-8 and convert it to a FLAM archive for z/OS in EBCDIC. XML in a FLAMFILE is record-oriented and pretty printed by default.

$ flcl conv "read.xml(file=test.zip/?*.xml)
             write.flam(file=test.adc member=<CUSER>.XMLPDS([base]) ccsid=1141)"

Example 11

Compare the content of a BZIP file with the content of a FLAMFILE text record by text record with suppression of trailing whitespace on a UNIX system.

$ flcl diff "read.text(file=test.bz ccsid=Latin-1 SUPTWS)
             compare.text(file=test.adc ccsid=1141 SUPTWS)"

Example 12

Write and read a FLAMFILE on UNIX with piping (DECO is default).

$ cat test.txt | flcl flam comp | flcl flam

Example 13

OpenPGP key management and encryption using the PGP key ring implementation of libfkm5 on a UNIX system (PGPRING is the default function of libfkm5 library on non IBM platforms. For example, on z/OS, PGPCCA is the default function and with z/OSv2r2 no additional FKM5 parameters are required. This means that the same will work on z/OS with ICSF except that SETENV as first step is not required).

$ flcl setenv FL_DEFAULT_PGPRNGPARA="pub='~/.pgp/pubrng.pgp',sec='~/.pgp/secrng.pgp',pass=f'~/.pgp/keyring.pwd'"
$ flcl key "gen.pgp(user='<cuser>')"
$ flcl key "exp.pgp(user='<cuser>' file=~/mykey.pgp)"
$ flcl key "imp.pgp(file=~/max.pgp kidver=12B738)"
$ flcl conv "read.binary(file='message.txt')
             write.binary(file='message.pgp' encrypt.pgp(userid['Max','<cuser>'] signid='<cuser>'))"
$ flcl conv "read.binary(file='message.pgp' deco)
             write.binary(file='message.out')"

Example 14

Use SSH in interactive mode to read a remote ZIP file from a Windows server, convert the character set and write all members (/?*) as remote gzip files to a Unix server (not in interactive mode (URL used)) and delete all members from the ZIP archive (remove) and the empty archive itself. The interactive mode (enabled by hostkeycheck=ask) allows FLCL to require user input instead of failing, e.g. if the SSH host is unknown and must be granted trust manually.

C:> flcl conv read.text(net.ssh(hostkeycheck=ask,
                                user='<cuser>',
                                host='winserver')
                        file='test.zip/?*' remove ccsid=1251)
       write.text(file=ssh://<cuser>@unixserver/[name].gz
                  ccsid='UTF-8' comp.gzip())

Example 15

Convert a FB dataset with 2 columns to a CSV text file without a headline. The first column is a whitespace-padded name in EBCDIC (local character set) with up to 32 bytes. The second column is a 4 byte packed BCD number with the age of the person. The string should be collapsed (remove leading, trailing and repeated whitespace) for the CSV file, which will be written in the local character encoding (EBCDIC).

//FLCLCONV EXEC PGM=FLCL,REGION=0M,PARM='XCNV=DD:PARM'
//STEPLIB  DD DSN=&SYSUID..FLAM.LOAD,DISP=SHR
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//PARM     DD *
   INPUT(SAV.FIL(FIO.REC(NAME='DD:FBINP')
                 FMT.TAB(FORMAT=FIX ROW='DD:FBROW')))
   OUTPUT(SAV.FIL(FMT.TAB(FORMAT=CSV DEFAULTS(NOHDLN))
                  FIO.REC(NAME='DD:CSVOUT')))
/*
//FBROW    DD *
 NAME='my.fb.record'
 COLUMN(
     NAME='name'
     TYPE.STRING(CHRSET(WHITESPACE=COLLAPSE))
     MAXLEN=32
 )
 COLUMN(
     NAME='age'
     TYPE.INTEGER(FORMAT.BCD(TYPE=PACKED))
     MAXLEN=4
 )
/*

Example 16

Binary copy of a file per SSH to a remote system, with checksum calculation over the local original file as pre-process and over the copied remote file as post process and a final post-processing which compares the check sums. This could be used for example to realize a receipt for a data transfer.

flcl xcnv
   input(save.file(
      fio.blk(file=wrtorg.bin
              pre(command='sha1sum [copy]'
                  stdout=wrtorg.local.sha1))
   ))
   output(save.file(
      fio.blk(file=ssh://<USER>:limes@tests.limes.de/wrtorg.bin
              post(command='sha1sum [copy]'
                  stdout=wrtorg.remote.sha1))
      post(command='diff wrtorg.local.sha1 wrtorg.remote.sha1'
          stdout=log)))

Example 17

Binary copy of a file per SSH to an IBM mainframe system with a post-processing which copies the file in a MVS data set and removes the copied file from USS on success.

flcl xcnv
 input(save.file(fio.blk(file=wrtorg.bin)))
 output(save.file(
  fio.blk(file=ssh://<USER>:limes@zos22/wrtorg.bin
  postpro(command='cp -B [copy] "//TEST.XMIT([base])"')
  postpro(command='rm [copy]' on=success))))

Example 18

Sometimes it is required to copy some directories from USS and/or a remote system to one (or more) PDS(E) on MVS. The following example is a job step that is part of FLAM5 license generation. This step copies assembler macros from three USS directories (IBM1140) to a PDSE on MVS which is required to assemble the license module. The library is newly created every time (RENEW (removes the DSN and re-allocates the library with DISP=NEW)). No preceding IEFBR14 step is required to delete the output dataset first. The example does something similar to what OGETX does, but with FLAM the input files could also be in UTF-8 on another system, if you use a URL and/or members in a ZIP archive and/or PGP encrypted.

//COPYMAC  EXEC PGM=FLCL,PARM='CONV=DD:PARM',REGION=0M
//STEPLIB  DD DSN=LIMES.FLAM.LOAD,DISP=SHR
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//PARM     DD *
READ.TEXT(FILE='/u/<cuser>/git/FL5/HASMMAC/*.mac'
          FILE='/u/<cuser>/git/FL5/HASMMAC/ZOS/*.mac'
          FILE='/u/<cuser>/git/FL5/HASMMAC/COLUMBUS/*.mac'
          CCSID=1140)
WRITE.RECORD(FILE='<SYSUID>.LICORDER.HASMMAC([base])'
             FALLOC(ORGA=LIB RECF=FB RECL=80
                    SPACE(PRIMARY=1 SECONDARY=1)
                    RENEW)
             CCSID=1140)
MESSAGE(MINIMAL)
/*

Example 19

This example is also used in our build, test and deploy automation and use the SYSOUT allocation of a mail writer on z/OS to send an email if anything is ready with the converted log as attached GZIP file.

//FLCLMAIL EXEC PGM=FLCL,REGION=0M,PARM='CONV'
//STEPLIB  DD DSN=&SYSUID..AUTH.LOAD,DISP=SHR
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//FLAMPAR  DD *
read.record(file='<SYSUID>.SCLM.FITSTOUT.*' ccsid=1141)
write.text(method=unix ccsid='UTF-8' file='[copy].gz'
  FALLOC(SYSOUT(FORMAT.MAIL(
    FROM='<SYSNAME>@zos.limes.de'
    TO='system@flam.de')))
  COMPRESS.GZIP())
/*

By default the CLASS='A' and the WRITER='CSSMTP' are used and additional it is possible to redirect the request with a remote workstation specification and a destination user ID to another LPAR.

Example 20

To encrypt a backup with OpenSSL-ENC.

flcl xcnv "input(save.file(fio.blk(file='wrtorg.bin' frcblk)))
           output(save.file(
                  cnv.edc(KDF=PBKDF2 ALGO=AES MODE=CBC KEYLEN=KL256
                          PASS=a'123456789012345678901234567890')
                  fio.blk(file='wrtorg.bin.enc')))"

Example 21

To decrypt an OpenSSL-ENC backup

flcl xcnv "input(save.file(fio.blk(file='wrtorg.bin.enc' frcblk)
                           cnv.edc(KDF=PBKDF2 ALGO=AES MODE=CBC KEYLEN=KL256
                                   PASS=a'123456789012345678901234567890')))
           output(save.file(fio.blk(file='wrtorg.bin')))"

Example 22

Find datasets containing a certain pattern.

//FIND     EXEC PGM=FLCL,PARM='CONV',REGION=0M
//STEPLIB  DD DSN=LIMES.FLAM.LOAD,DISP=SHR
//SYSOUT   DD SYSOUT=*
//SYSPRINT DD SYSOUT=*
//FLAMPAR  DD *
READ.TEXT(FILE='HLQ.**' SUPTWS
          CCSID=DEFAULT CHRMODE=SUBSTITUTE
          REGEXP(PATTERN='^find$' NOCASE IGNREC))
WRITE.TEXT(FILE=DUMMY CCSID=LOCAL CHRMODE=SUBSTITUTE)
DIR(LINK ALIAS HIDDEN RECURSIVE ARCHIVE)
MESSAGE(MATCH,SOURCE)
/*

This example searches for the record with content 'find' in all datasets (PS/PO/VSAM) under the high level qualifier 'HLQ' (not case sensitive). A log message with the match count and the filename of each match is written to the log. The datasets can be record-oriented, with length fields in front of each record or with delimiter after each record. The datasets can be encoded, encrypted, compressed and/or in clear form. The search term is specified as regular expression. The output with the records found are written to the trash, but can also be written to SYSPRINT (FILE=STREAM) or to any other dataset (FILE='HLG.MY.FINDS').