FLUC Record Interface
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.