MainframeSupports
tip week 39/2006:

Some years ago I wrote a tip about how PL/1 is capable of reading almost any kind of file. Now it is time to reveal how to write almost any kind of file. In this context any kind of file is limited to controlling LRECL and BLKSIZE.

The following program copies data from DD name ANYFILE to a FB dataset with a LRECL of the same length as the first record read from ANYFILE. The dataset must be allocated to DD name FBFILE:

/* PLI - copy almost any dataset to FB */
writefb: PROC OPTIONS(MAIN);

DCL anyfile FILE RECORD SEQUENTIAL;
DCL anyfile_data CHAR(32767) VAR;
DCL anyfile_eof CHAR(1);

DCL fbfile FILE RECORD SEQUENTIAL OUTPUT
    ENV(FB RECSIZE(lrecl) BLKSIZE(blksize));
DCL fbfile_data CHAR(27998) VAR;
DCL space_data CHAR(27998) VAR;
DCL lrecl FIXED BIN(31) STATIC;
DCL blksize FIXED BIN(31) STATIC;

ON ENDFILE(anyfile) anyfile_eof = 'Y';
anyfile_eof = 'N';
lrecl = 80;
OPEN FILE(anyfile);
READ FILE(anyfile) INTO(anyfile_data);
IF anyfile_eof = 'N'
THEN DO;
  lrecl = min(length(anyfile_data), 27998);
  IF lrecl = 0
  THEN
    lrecl = 80;
END;
blksize = 27998 / lrecl;
blksize = lrecl * blksize;
space_data = repeat(' ', lrecl - 1);
OPEN FILE(fbfile);
DO WHILE(anyfile_eof = 'N');
  fbfile_data = substr(anyfile_data !! space_data, 1, lrecl);
  WRITE FILE(fbfile) FROM(fbfile_data);
  READ FILE(anyfile) INTO(anyfile_data);
END;
CLOSE FILE(fbfile);
CLOSE FILE(anyfile);

END writefb;

There is nothing more to it. Well a bit of explanation have to be done. The variables lrecl and blksize must be declared as FIXED BIN(31) STATIC. The declaration of the file variable must include option OUTPUT. When the output file is opened blksize must be a multiple of lrecl. You cannot use blksize = 0 inside PL/1. An important detail is that the calculation of blksize must be in two steps as shown. If you rewrite the calculation to a single statement like 27998 / lrecl * lrecl, it will always give the result 27998.

I use a CHAR VARYING when I write to fbfile. In this case the CHAR VARYING must have a length equal to lrecl because otherwise the program fails. I seriously consider to replace fbfile_data with a CONTROLLED variable with the length of lrecl, but I have not tried it so I do not know if it works.

Unfortunately PL/1 does not accept to substring a variable shorter than the substring length. That is why I have introduced space_data in order to ensure that this will never happen. If the length of anyfile_data is longer than lrecl then you will loose data. The program may need to be changed to determine lrecl in another way.

When you have seen the above example it should be easy for you to make a program that writes a VB dataset instead if that is what you need. Then you only need to consider what to do if the length of anyfile_data becomes greater than lrecl.

When you assign the DCB informations from inside PL/1 you must be aware that the existing DCB informations for the dataset are overwritten. On the other hand you only have to use DSN and SPACE on the DD statement when you allocate the dataset as DISP=(NEW,CATLG).

Previous tip in english        Sidste danske tip        Tip list