FLUC Record Interface

The record interface (access method) is based on the byte interface of FLUC. It allows sequential access in record form (length and data) to original data sets as is commonly used with file-I/O in the mainframe world (GET/PUT for COBOL or PL1). Local or remote access and all conversion options made available by FLAM can be used for reading and writing original data. For example, data sets encoded in EBCDIC IBM-1141 can be read transparently, even though the data comes from a member of a concatenated GZIP-file which is encrypted, Base64-encoded and located on a local disk or a remote system (Cloud/HOST/DMZ), with the actual plain text being encoded in UTF-16LE and delimited by 0x0D000A00.
 

The record interface is available for COBOL, PL1, C, Assembler and other programming languages in the form of separate load modules (FCROPN, FCRGET, FCRPUT, FCRCLS). All parameters are call-by-reference and there is no return value. Input strings are accepted either without null-termination by supplying an additional length parameter or as null-terminated string with the length parameter set to NULL. When a string is returned, the string is null-terminated and (additionally) the corresponding length field is set, allowing both kinds of string access. The external entry matches the module name (FCROPN), so that the load modules can be linked to the application statically or dynamically.

Generally, the record interface can be used to read any kind of dataset (PS, PDS, PDSE, VSAM, FB, VB with and without ASA resp. control character) on the host, or FLAMFILEs and can also (the main purpose of the interface) read formats from Windows or UNIX systems (including USS) in a record oriented way, translated, for example, into the desired character set. Among other things, this allows reading or writing a remote GZIP file with UTF-8 and delimiters on the host, even though the records with length and data are passed resp. returned in EBCDIC. The read is during this total indepentent of the kind and format of the file. In COBOL you must only know the file name for FCROPN(), to read normal host datasets (PS, PDS, VSAM, ...), member in FLAMFILEs, Windows text files or GZIP files coming from a UNIX systems.

The record interface converts texts (read.text()) to the system-specific character set unless another character set (z.B. ccsid='UTF-8') is supplied, so that the data can be compared to string constants, for example. In other words, the record interface provides a platform-neutral interface for accessing various kinds of file formats.

When reading records, one can decide between reading including ASA or machine control characters (RETAIN), ignoring them (DETACH (default)) or dealing with them like a printer would (RPLFFD=26 (replace form feed with a page size of 26 rows)), for example when processing an FBA or VBA file. For relative files, gaps can be retained as records or ignored. Furthermore, character conversion is also available. Trailing whitespace can be removed or converted to control characters and much more. Additionally, if a record is encountered that is longer than the available buffer, this is signalled with a special return code so that the complete record can be re-read with a larger buffer.

Additional you can also read or write FLAM5 elements like records in form of a certain struture with format.element(). In this case you can overload the default converter by a deticated converter for each element. This feature allows you to validate, collapse and or convert XML elements in programming language specific data types (e.g. picture clause in COBOL). If you know, the next data element must contain a decimal number as string, then you can convert this XML string to an integer value (PICTURE S9(8) COMP) for some calculations.

The record interface allows to decide freely how the data is read. However, in contrast to the byte interface, all data is accepted or returned in the form of records. The record interface is a specialization of the byte interface that always uses record formatting (format.record()).

Example

COBOL

The following example written in COBOL reads records from a GZIP file which is (after binary transfer) located in an XMIT.PDS on the host. It uses the character set auto detection and conversion to IBM-1141 encoded records. The original file was a text file from Windows in CP1252 with 0x0D0A as delimiter. However, since auto detection is used, the character set is not important here. The only thing important is that it is a text file with delimiters. It may happen that empty records ("\n\n") are detected. Due to COBOL requiring a minimum record length of 1, this special case must be handled appropriately. In this example, we just insert a space characters:

       IDENTIFICATION DIVISION.
       PROGRAM-ID.  SOFCRGET.
       AUTHOR.      LIMES DATENTECHNIK GMBH.
      *
      *           EXAMPLE FOR USING FLUC RECORD INTERFACE
      *
      *  SOFCRGET READS WITH THE FLUC-RECORD-INTERFACE A TEXT FILE. THE
      *           THE FILE CAN BE COMPRESSED (GZIP/BZIP2/XZ(LZMA)) OR
      *           NOT AND MUST BASED ON TEXT DELIMITER
      *
      *  DD-NAMES USED IN THIS EXAMPLE:
      *
      *    INPUT  THE FILE FLUC HAS TO READ
      *    OUTPUT OUR OUTPUT DATA SET
      *
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT      OUTDAT
           ASSIGN TO   S-OUTPUT
           ACCESS MODE IS SEQUENTIAL.
      *
       DATA DIVISION.
      *
       FILE SECTION.
       FD  OUTDAT  BLOCK CONTAINS 0 CHARACTERS
                   RECORDING MODE V
                   RECORD IS VARYING FROM 1 TO 2040 CHARACTERS
                          DEPENDING ON OUTLEN
                   LABEL  RECORD IS STANDARD.
       01  OUTDAT-RECORD.
           02 FILLER   PIC X(2040).
      *
       WORKING-STORAGE SECTION.
      *
       77  OUTLEN      PIC  9(5).
       77  OPERATION   PIC  X(6).
       77  MAXLEN      PIC  9(8)  COMP VALUE 2040.
      *
       01  FLUC-PARAMETER.
      *
      *  USED FOR ALL FLUC-CALLS
      *
           02 F-ID     PIC S9(8)  COMP.
           02 F-RETCO  PIC S9(8)  COMP.
              88 FLUCOK            VALUE  0.
              88 END-OF-FILE       VALUE  43.
      *
      *  USED FOR FLUC OPEN
      *
           02  F-FILELEN  PIC S9(8)  COMP VALUE 60.
           02  F-FILE     PIC X(60)  VALUE
               'READ.TEXT(FILE=''DD:INPUT'' RECLEN=2040)'.
           02  F-FORMLEN  PIC S9(8)  COMP SYNC VALUE 20.
           02  F-FORM     PIC X(20)  VALUE
               'CCSID=''1141'''.
           02  F-STATLEN  PIC S9(8)  COMP SYNC VALUE 512.
           02  F-STAT     PIC X(512) VALUE ' '.
      *
      *  USED FOR FLUC GET
      *
           02  F-INLEN   PIC S9(8) COMP.
      *
      *  USED FOR FLUC MSG
      *
           02  MSGRC     PIC S9(8) COMP.
           02  MSGLEN    PIC S9(8) COMP VALUE 800.
           02  MSGBUFF   PIC X(800) VALUE SPACES.
      *
      *  USED FOR FLUC CLS
      *
           02  C-DELETE  PIC S9(8) COMP VALUE 0.
           02  C-STATFMT PIC S9(8) COMP VALUE 1.
           02  C-STATLEN PIC S9(8) COMP VALUE 4096.
           02  C-STATBUF PIC X(4096) VALUE SPACES.
      /
       PROCEDURE DIVISION.
      *
       MAIN SECTION.
      *
       OPEN-OUTPUT-DATA.
      *
      *  OPEN DATA SET TO WRITE RECORDS
      *
           OPEN OUTPUT OUTDAT.
      *
       OPEN-FLUC.
      *
      *  CALL THE FLAM UNIVERSAL CONVERTER MODULE FOR OPEN
      *
           CALL  'FCROPN' USING F-ID, F-RETCO,
                                F-FILELEN, F-FILE,
                                F-FORMLEN, F-FORM,
                                F-STATLEN, F-STAT.
           IF  NOT FLUCOK
              THEN  MOVE 'OPEN' TO OPERATION
                    PERFORM FLUC-ERROR
                    GO TO CLOSE-DATA.

           DISPLAY F-STAT.

       READ-RECORD.
      *
      *  READ A RECORD WITH FLAM IN OUTPUT AREA
      *
           MOVE MAXLEN   TO  F-INLEN
      *
           CALL 'FCRGET' USING F-ID, F-RETCO,
                               F-INLEN, OUTDAT-RECORD.
      *
           IF  FLUCOK
             THEN  NEXT SENTENCE
             ELSE  IF  END-OF-FILE
                      THEN GO TO CLOSE-FLUC
                      ELSE MOVE 'GET' TO OPERATION
                           PERFORM FLUC-ERROR
                           GO TO CLOSE-FLUC.
      *
      *  DO WHAT YOU LIKE WITH THE RECORD
      *  .
      *  .
      *
       WRITE-RECORD.
      *
      *  WRITE THE CONVERTED RECORD
      *
           MOVE  F-INLEN  TO OUTLEN
           IF OUTLEN = 0 THEN
               MOVE 1   TO OUTLEN
               MOVE ' ' TO OUTDAT-RECORD
           END-IF
           WRITE OUTDAT-RECORD
      *
           GO TO READ-RECORD.
      *
       CLOSE-FLUC.
      *
      *  CLOSE TO FLUC
      *
           CALL 'FCRCLS' USING F-ID, F-RETCO, C-DELETE
                               C-STATFMT, C-STATLEN, C-STATBUF
           IF  NOT FLUCOK
             THEN MOVE 'CLOSE' TO OPERATION
                  PERFORM FLUC-ERROR.
       CLOSE-DATA.
      *
      *  CLOSE OUTPUT DATA
      *
           CLOSE  OUTDAT.
       MAIN-END.
           MOVE F-RETCO  TO RETURN-CODE
      *
      *  PRINT STATISTIC
      *
           DISPLAY 'READ-STATISTIC FROM FLUC'
           DISPLAY C-STATBUF

           STOP RUN.
      *
      * PRINT THE ERROR SITUATION
      *
       FLUC-ERROR SECTION.
       FLUC-ERROR-1.
           DISPLAY 'SOFCRGET: ERROR IN OPERATION ' OPERATION
           DISPLAY 'ERROR MESSAGE FROM FLUC:'
           MOVE F-RETCO  TO MSGRC
      *  GET THE ERROR MESSAGE
           CALL 'FCRMSG' USING MSGRC, F-RETCO, MSGLEN, MSGBUFF
           DISPLAY MSGBUFF.
       FLUC-ERROR-99.
           EXIT.

To use a DD name at FCROPN is only an example in this case, to make the sample program direct useable as utility in a job (EXEC PGM=SCFCRGET). But normally the record interface are used with dataset or file (path) names (read.file='meine.datei.dat') where the dynamic allocation is done by FLAM. At this you can use the autodetection of the read procedure (read.auto()). Based on this you can read each kind of file in clear records in a transparent way, where only the file name must be known.

C

The following example is a simple C program which accepts the file and format strings for the read and write operation and copies the files using the record interface. Copying, however, is not the correct term in this context because any kinds of conversions can be performed by FLAM via the file strings. Insofar, this simple program exposes a major part of the functionality of FLUC, but with any conversions always being performed on records.

/**
 * @file   SCFCRCPY.c
 * @brief  Sample program in C to copy files via the FLUC record interface
 * @author limes datentechnik gmbh
 ******************************************************************************/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include"FLCRECLB.h"

/**
 * This test program takes four parameters to convert files via the
 * FLUC record interface.
 *
 * @param  argc must be 5
 * @param  argv contains the strings for FCROPN
 * @return 8=parameter error
 *         6=open file error
 *         4=read write error
 *         2=close error
 *         0=Success
 */
int main(int argc, char * argv[])
{
   void*                   pvRed;
   void*                   pvWrt;
   static char             acBuf[65536];
   char                    acSta[2048];
   int                     siLn1,siLn2,siLen,siSta;
   int                     siRtc,siHlp,siWat,siDep,i;
   int                     siDel=1;

   char*                   h;
   char*                   a[5];

   if (argc==2) { // parse HOST parameter string
      i=2; a[0]=argv[0]; a[1]=argv[1];
      h=strchr(a[1],',');
      if (h!=NULL) { h[0]=0x00; a[2]=h+1; i++; }
      h=strchr(a[2],',');
      if (h!=NULL) { h[0]=0x00; a[3]=h+1; i++; }
      h=strchr(a[3],',');
      if (h!=NULL) { h[0]=0x00; a[4]=h+1; i++; }
      argc=i; argv=a;
   }

   siDep=1;
   if (argc!=5) {
      fprintf(stderr,"Parameter count (%d) not correct!\n",argc);
      fprintf(stderr,"Given parameters:\n");
      for (i=0;i<argc;i++) fprintf(stderr,"--> P%2.2d(%s)\n",i,argv[i]);
      fprintf(stderr,"Required parameters:\n");
      fprintf(stderr,"%s \"read file string\" \"read format string\""
         " \"write file string\" \"write format string\"\n",argv[0]);
      siWat=FCR_READ_FILE; siLen=sizeof(acBuf); siHlp=0;
      FCRSYN(&siRtc,&siWat,&siDep,&siHlp,NULL,&siLen,acBuf);
      fprintf(stderr,"READ FILE STRING   : \"%s\"\n",acBuf);
      siWat=FCR_READ_FORMAT;  siLen=sizeof(acBuf); siHlp=0;
      FCRSYN(&siRtc,&siWat,&siDep,&siHlp,NULL,&siLen,acBuf);
      fprintf(stderr,"READ FORMAT STRING : \"%s\"\n",acBuf);
      siWat=FCR_WRITE_FILE;   siLen=sizeof(acBuf); siHlp=0;
      FCRSYN(&siRtc,&siWat,&siDep,&siHlp,NULL,&siLen,acBuf);
      fprintf(stderr,"WRITE FILE STRING  : \"%s\"\n",acBuf);
      siWat=FCR_WRITE_FORMAT; siLen=sizeof(acBuf); siHlp=0;
      FCRSYN(&siRtc,&siWat,&siDep,&siHlp,NULL,&siLen,acBuf);
      fprintf(stderr,"WRITE FORMAT STRING: \"%s\"\n",acBuf);
      exit(8);
   }

   siLn1=strlen(argv[1]); siLn2=strlen(argv[2]); siSta=sizeof(acSta);
   FCROPN(&pvRed,&siRtc,&siLn1,argv[1],&siLn2,argv[2],&siSta,acSta);
   if (pvRed==NULL) {
      fprintf(stderr,"Open file for read operation failed!\n");
      fprintf(stderr,"FCROPN(&pvRed,%d,%d,\"%s\",%d,\"%s\");\n\n",
              siRtc,siLn1,argv[1],siLn2,argv[2]);
      siLen=sizeof(acBuf);
      FCRMSG(&siHlp,&siRtc,&siLen,acBuf);
      fprintf(stderr,"ERRMSG:\n%s\n\n",acBuf);
      siLen=sizeof(acBuf);
      FCRTRC(&siHlp,&siRtc,&siLen,acBuf);
      fprintf(stderr,"ERRTRC:\n%s\n"  ,acBuf);
      exit(6);
   }

   /*Use zero terminated strings*/
   FCROPN(&pvWrt,&siRtc,NULL,argv[3],NULL,argv[4],&siSta,acSta);
   if (pvWrt==NULL) {
      fprintf(stderr,"Open file for write operation failed!\n");
      fprintf(stderr,"FCROPN(&pvWrt,%d,%d,\"%s\",%d,\"%s\");\n\n",
              siRtc,siLn1,argv[3],siLn2,argv[4]);
      siLen=sizeof(acBuf);
      FCRMSG(&siHlp,&siRtc,&siLen,acBuf);
      fprintf(stderr,"ERRMSG:\n%s\n\n",acBuf);
      siLen=sizeof(acBuf); FCRTRC(&siHlp,&siRtc,&siLen,acBuf);
      fprintf(stderr,"ERRTRC:\n%s\n"  ,acBuf);
      FCRCLS(&pvRed,NULL,NULL,NULL,NULL,NULL);
      exit(6);
   }

   for (siLen=sizeof(acBuf),FCRGET(&pvRed,&siRtc,&siLen,acBuf); siRtc==0;
        siLen=sizeof(acBuf),FCRGET(&pvRed,&siRtc,&siLen,acBuf)) {
      FCRPUT(&pvWrt,&siRtc,&siLen,acBuf);
      if (siRtc) {
         fprintf(stderr,"Write data to file failed!\n");
         fprintf(stderr,"FCRPUT(&pvWrt,%d,%d,acBuf);\n\n",
                 siRtc,siLen);
         siLen=sizeof(acBuf);
         FCRMSG(&siHlp,&siRtc,&siLen,acBuf);
         fprintf(stderr,"ERRMSG:\n%s\n\n",acBuf);
         siLen=sizeof(acBuf);
         FCRTRC(&siHlp,&siRtc,&siLen,acBuf);
         fprintf(stderr,"ERRTRC:\n%s\n"  ,acBuf);
         FCRCLS(&pvRed,NULL,NULL,NULL,NULL,NULL);
         FCRCLS(&pvWrt,NULL,NULL,NULL,NULL,NULL);
         exit(4);
      }
   }
   if (siRtc!=FLMRTC_OK && siRtc!=FLMRTC_EOF) {
      fprintf(stderr,"Read data from file failed!\n");
      fprintf(stderr,"FCRGET(&pvRed,%d,%d,acBuf);\n\n",
              siRtc,(int)sizeof(acBuf));
      siLen=sizeof(acBuf);
      FCRMSG(&siHlp,&siRtc,&siLen,acBuf);
      fprintf(stderr,"ERRMSG:\n%s\n\n",acBuf);
      siLen=sizeof(acBuf);
      FCRTRC(&siHlp,&siRtc,&siLen,acBuf);
      fprintf(stderr,"ERRTRC:\n%s\n"  ,acBuf);
      FCRCLS(&pvRed,NULL,NULL,NULL,NULL,NULL);
      FCRCLS(&pvWrt,NULL,NULL,NULL,NULL,NULL);
      exit(4);
   }

   siLen=sizeof(acBuf);
   FCRCLS(&pvWrt,&siRtc,&siDel,NULL,&siLen,acBuf);
   if (siRtc) {
      fprintf(stderr,"Close file for write operation failed!\n");
      fprintf(stderr,"FCRCLS(&pvWrt,%d);\n\n",siRtc);
      siLen=sizeof(acBuf);
      FCRMSG(&siHlp,&siRtc,&siLen,acBuf);
      fprintf(stderr,"ERRMSG:\n%s\n\n",acBuf);
      siLen=sizeof(acBuf);
      FCRTRC(&siHlp,&siRtc,&siLen,acBuf);
      fprintf(stderr,"ERRTRC:\n%s\n"  ,acBuf);
      FCRCLS(&pvRed,NULL,NULL,NULL,NULL,NULL);
      exit(2);
   } else {
      fprintf(stderr,"Statistic for FCROPN(\"%s\",\"%s\")\n",argv[3],argv[4]);
      fprintf(stderr,"%s",acBuf);
   }

   siLen=sizeof(acBuf);
   FCRCLS(&pvRed,&siRtc,&siDel,NULL,&siLen,acBuf);
   if (siRtc) {
      fprintf(stderr,"Close file for read operation failed!\n");
      fprintf(stderr,"FCRCLS(&pvRed,%d);\n\n",siRtc);
      siLen=sizeof(acBuf);
      FCRMSG(&siHlp,&siRtc,&siLen,acBuf);
      fprintf(stderr,"ERRMSG:\n%s\n\n",acBuf);
      siLen=sizeof(acBuf);
      FCRTRC(&siHlp,&siRtc,&siLen,acBuf);
      fprintf(stderr,"ERRTRC:\n%s\n"  ,acBuf);
      exit(2);
   } else {
      fprintf(stderr,"Statistic for FCROPN(\"%s\",\"%s\")\n",argv[1],argv[2]);
      fprintf(stderr,"%s",acBuf);
   }

   exit(0);
}

/**********************************************************************/

For additional information please refer to the interface specification in the Download area.