![]() |
![]() HP OpenVMS Systemsask the wizard |
![]() |
The Question is: In July 1998, you answered a user's question relating to conversion of VFC format files to sequential variable files. Your answer read: ``COBOL uses VFC for files used with BEFORE or AFTER ADVANCING keywords, for files created by the report writer, and for files marked with GLOBAL or EXTERNAL. You might also be able to use FDL$CREATE to create the desired attributes, and then use OPEN EXTEND. If you have a software support contract, check on DSNlink or with the customer support center folks for a copy of the article "Example-COBOL Converting VFC Files To Seq. Variable On OpenVMS AXP".'' I do have a support contract, and I have searched DSNLink, and the CSC folks have searched their databases to no avail. Can you please e-mail me this article or give me a steer to a web link, etc. where I can obtain it? I have for many years used a COBOL program, CONVERT-VFC on VAXen to deal with this problem; unfortunately, it is broken on an Alpha machine - it aborts with an ACCVIO dump. Please help! The Answer is : The OpenVMS Wizard finds that other tools are typically better suited to this file format conversion task -- use of C or Macro32 code, or code that uses the DCL CONVERT utility, would likely be rather easier. The following (untested) example is likely close to what you need. This is DEC COBOL code -- the Wizard would not expect this to operate on VAX COBOL. $ CREATE FDLDEF.MAR .TITLE FDLDEF $FDLDEF GLOBAL .END $ MACRO FDLDEF $ COBOL SYS$INPUT/OBJECT=CONVERT_VFC PROGRAM: identification division. ******************************************************************************* * This program requires a MACRO program in order to link. The MACRO * program can be created to look like this (you can call it FDLDEF.MAR): * .TITLE FDLDEF * $FDLDEF GLOBAL * .END * The following commands can be used to compile and link the programs: * $ MACRO FDLDEF * $ COBOL CONVERT_VFC * $ LINK CONVERT_VFC,FDLDEF ************************ * Please note that this is a fairly detailed example. In an effort to * simplify things as much as possible, error checking and the anticipation * of contingencies has been kept to a minimum. Feel free to enhance this * aspect of this program once you understand the underlying concepts. ************************ * Also note that, with many devices, there is an implied line feed * pending prior to the *first* record being written. If you notice * that printed output from the converted file starts one line farther * down the page than expected, this could be the explanation. This * program converts the VFC information without giving consideration * to such external factors. * If you wish to suppress a line feed in the first record, evaluate * the prefix byte of the first record to see if there is a line feed * that is not necessary. If so, you can remove it. If not, there is * not much else you can do (at least from the perspective of this * program). ******************************************************************************* program-id. convert_vfc. environment division. configuration section. input-output section. file-control. select in_file assign to in_file organization sequential. select optional out_file assign to out_file organization sequential. * By default, RMS ignores (i.e. discard) the VFC bytes when reading * a VFC-formatted file. To override this, it is necessary to instruct * RMS to do otherwise. In COBOL, this can be accomplished by applying * print-control to the input file. This will cause RMS to reserve a * field in memory to hold the VFC bytes. The address of that field * will be placed into the RHB field of the RAB. i-o-control. apply print-control on in_file. data division. file section. fd in_file value of id is in_filename record varying from 1 to 255 depending on in_size. 01 in_rec. 03 in_data pic x(255). * Note that the size of the output record is set up to be greater * than the size of the input record. This is because the VFC * (carriage control) information is embedded into the output * record (thus increasing its size). fd out_file value of id is out_filename record varying from 1 to 765 depending on out_size. 01 out_rec. 03 out_data pic x(765). working-storage section. 01 variables. 05 stat pic s9(9) comp. 05 rab_address pic 9(9) comp. 05 rhb_address pic 9(9) comp. 05 vfc_address pic 9(9) comp. 05 in_filename pic x(255). 05 out_filename pic x(255). 05 vfc_switch pic x(7). 05 vfc_bytes. 10 prefix_byte pic x. 10 postfix_byte pic x. 05 record_number pic 9(9) comp. 05 work_string pic x(255). 05 work_string_len pic s9(4) comp. 05 total_size pic s9(4) comp. 05 bit7 pic s9(9) comp. 05 bit6 pic s9(9) comp. 05 bit5 pic s9(9) comp. 05 bit4 pic s9(9) comp. 05 bits0-6 pic s9(9) comp. 05 bits0-4 pic s9(9) comp. 05 in_size pic 9(4) comp. 05 out_size pic 9(4) comp. 05 prefix_data pic x(255). 05 prefix_size pic 9(4) comp. 05 postfix_data pic x(255). 05 postfix_size pic 9(4) comp. ** Constructs to emulate byte-sized integers... 05 work_num_long pic 9(9) comp. 05 work_num_bytes redefines work_num_long. 10 work_num_byte1 pic x. 10 filler pic x(3). 05 ext_size_word pic s9(4) comp. 05 ext_size_bytes redefines ext_size_word. 10 ext_size_byte1 pic x. 10 filler pic x. 05 ascii_c0_int pic s9(9) comp. 05 ascii_c0_txt redefines ascii_c0_int. 10 c0_char pic x. 10 filler pic x(3). 01 constants. 05 out_bufsize pic s9(4) comp value 765. 05 cr_char pic x value x"0D". 05 lf_char pic x value x"0A". 05 two pic 9(4) comp value 2. 05 four_w pic 9(4) comp value 4. 05 four pic 9(9) comp value 4. 05 five pic 9(9) comp value 5. 05 six pic 9(9) comp value 6. 05 seven pic 9(9) comp value 7. 05 pos0-4 pic 9(9) comp value 0. 05 pos0-6 pic 9(9) comp value 0. 01 flags. 05 eof_flag pic x. 88 eof value high-values. 01 external_constants. 05 rab$l_rhb pic s9(9) comp value external rab$l_rhb. 05 fdl$m_fdl_string pic 9(9) comp value external fdl$m_fdl_string. 01 fdl_string. 05 filler pic x(7) value "SYSTEM;". 05 filler pic x(32) value "SOURCE OpenVMS;". 05 filler pic x(5) value "FILE;". 05 filler pic x(35) value "ORGANIZATION sequential;". 05 filler pic x(7) value "RECORD;". 05 filler pic x(40) value "CARRIAGE_CONTROL none;". 05 filler pic x(33) value "FORMAT variable;". 05 filler pic x(26) value "SIZE 0;". procedure division. 0000-main. * Have the user enter the name of the input file and then open it... display "What is the name of the file to be converted? " no advancing. accept in_filename. open input in_file. * In order to evaluate the VFC bytes for each record, it is necessary * to determine where RMS puts them. The RAB$L_RHB field contains the * address of the field RMS sets up to hold the VFC byte values. So, * the next step is to isolate the RHB field and obtain the address it * contains. perform 0100-get-rhb-contents. * See what the user wants to name the output file... display "What do you want to name the output file? " no advancing. accept out_filename. * By default, COBOL-created files are typically of a VFC format. * Since we are converting *from* VFC, it would seem pointless to put * the results back into a VFC file. So, this program uses the * callable interface to FDL to pre-create a file with sequential, * variable attributes. This also provides a way to create the file * with no implied carriage control (since all the carriage control * information will be embedded in each record). We can then open * that existing, empty file and write the converted information to it. call "fdl$create" using by descriptor fdl_string out_filename omitted omitted omitted by reference fdl$m_fdl_string giving stat. if stat is failure call "lib$stop" using by value stat. * At this point an empty file exists (with the characteristics we want), * so open it EXTEND. open extend out_file. * Now that the files are open, read each record from the input file, * convert the VFC bytes, and write the converted result to the * output file. Note that the VFC information is translated and then * embedded into the record that is written to the file. perform 0200-read-infile. perform until eof move "PREFIX " to vfc_switch perform 0300-process-vfc move work_string (1:work_string_len) to prefix_data move work_string_len to prefix_size move "POSTFIX" to vfc_switch perform 0300-process-vfc move work_string (1:work_string_len) to postfix_data move work_string_len to postfix_size * At this point, the prefix information, the input record data, * and the postfix information have been formulated. All that * is left to do is piece them together in the output field and * write the resulting record to the output file. The only check * made at this point is to make sure the resulting string is not * too large for the output buffer. compute total_size = prefix_size + in_size + postfix_size end-compute if total_size > out_bufsize display " " display "Calculated record size greater than output buffer size..." display "...Record: " record_number with conversion display "...Data portion of record will be truncated to fit." compute in_size = in_size - (total_size - out_bufsize) end-compute end-if string prefix_data(1:prefix_size) delimited by size in_data(1:in_size) delimited by size postfix_data(1:postfix_size) delimited by size into out_data end-string compute out_size = prefix_size + in_size + postfix_size end-compute write out_rec perform 0200-read-infile end-perform. close out_file. close in_file. display " ". display "Records processed: " record_number with conversion. display " ". stop run. 0100-get-rhb-contents. * Determine where the RHB field in the RAB is and place the address * it contains into vfc_address. * The process of isolating the RHB field can be started by calling * DCOB$RMS_CURRENT_RAB. This returns the starting address of the * RAB. The RHB field can then be accessed by indexing into the RAB * structure (starting from the address retrieved) the appropriate * number of bytes. The symbolic constant RAB$L_RHB is used in this * example to represent that offset value. * Get the starting address of the RAB... call "dcob$rms_current_rab" giving rab_address. * Add the RHB offset value to the starting address to derive the * address of the RHB field... add rab$l_rhb to rab_address giving rhb_address. * Use LIB$MOVC3 to extract the address contained in the RHB field. * This is the address where the VFC information is written after * each read. call "lib$movc3" using by reference four_w by value rhb_address by reference vfc_address. 0200-read-infile. move spaces to in_rec out_rec prefix_data postfix_data vfc_bytes. move 0 to in_size out_size prefix_size postfix_size. read in_file at end set eof to true end-read. * Move the VFC bytes from the holding area (the address of which * we obtained from the RHB field of the RAB earlier) to a place * we can work with. if not eof add 1 to record_number call "lib$movc3" using by reference two by value vfc_address by reference vfc_bytes end-if. 0300-process-vfc. * Following is a table taken from the OpenVMS Record Management * Services Reference Manual. This table describes what the * different bit patterns of VFC bytes represent. Please note that * the prefix and postfix VFC bytes must be processed individually. * --------------------------------------------------------------------------- * Bit 7 Bit 6 Bit 5 Bit 4 Meaning * --------------------------------------------------------------------------- * 0 0 0 0 To specify no carriage control (NULL), * set bits 3 through 0 to 0. * 0 x x x Use bits 6 through 0 to specify a * count of new lines (line feed followed * by carriage return). * 1 0 0 x Output the ASCII C0 control character * specified by the configuration of bits * 4 through 0. * 1 0 1 x Reserved. * 1 1 0 0 Skip to the vertical format unit (VFU) * channel (1-16) specified by bits 3 * through 0. Devices that do not have * hardware VFUs translate these codes as * a 1-line advance. * 1 1 0 1 Reserved. * 1 1 1 0 Reserved. * Evaluate vfc_switch to determine if the prefix or postfix byte is to * be processed. move spaces to work_string. move 0 to work_string_len work_num_long. if vfc_switch equal "PREFIX " move prefix_byte to work_num_byte1 else move postfix_byte to work_num_byte1 end-if. * Evaluate the VFC byte of interest to determine what it means. * Load the appropriate information into the work area based on this * evaluation. In order to evaluate the meaning of the VFC byte, it * is necessary to examine it at a binary level. LIB$EXTZV is used * to help isolate the bits that need to be evaluated. Please note * that this program treats VFU references as a 1-line advance. * Reserved bit patterns are treated as Null carriage control. An * informational message is displayed if any of these bit patterns * are detected (the record *is* written). move 1 to ext_size_word. call "lib$extzv" using by reference seven by reference ext_size_byte1 by reference work_num_long giving bit7. call "lib$extzv" using by reference six by reference ext_size_byte1 by reference work_num_long giving bit6. call "lib$extzv" using by reference five by reference ext_size_byte1 by reference work_num_long giving bit5. call "lib$extzv" using by reference four by reference ext_size_byte1 by reference work_num_long giving bit4. move 5 to ext_size_word. call "lib$extzv" using by reference pos0-4 by reference ext_size_byte1 by reference work_num_long giving bits0-4. move 7 to ext_size_word. call "lib$extzv" using by reference pos0-6 by reference ext_size_byte1 by reference work_num_long giving bits0-6. evaluate bit7 when 0 evaluate bits0-6 when 0 * Null carriage control (00000000). move spaces to work_string move 0 to work_string_len when other * Bits 0-6 equal number of lf/cr's (0xxxyyyy). perform bits0-6 times move lf_char to work_string (work_string_len + 1 : 1) add 1 to work_string_len move cr_char to work_string (work_string_len + 1 : 1) add 1 to work_string_len end-perform end-evaluate when other evaluate bit6 when 0 evaluate bit5 when 0 * Bits 0-4 represent an ASCII C0 value (100xyyyy). move bits0-4 to ascii_c0_int move c0_char to work_string move 1 to work_string_len when other * Reserved (101xyyyy). display " " display "Reserved bit pattern detected (101x)..." display " ...Record: " record_number with conversion display " ...VFC byte: " vfc_switch display " ...Record will be written, but that " "VFC byte will be ignored." move spaces to work_string move 0 to work_string_len end-evaluate when other evaluate bit5 when 0 evaluate bit4 when 0 * VFU reference (1100yyyy). This program * treats these as a 1-line advance. display " " display "VFU bit pattern detected " "(1100)..." display " ...Record: " record_number with conversion display " ...VFC byte: " vfc_switch display " ...Record will be written, but " "that VFC byte will be treated " "as LF/CR." move lf_char to work_string (work_string_len + 1 : 1) add 1 to work_string_len move cr_char to work_string (work_string_len + 1 : 1) add 1 to work_string_len when other * Reserved (1101yyyy). display " " display "Reserved bit pattern " "detected (1101)..." display " ...Record: " record_number with conversion display " ...VFC byte: " vfc_switch display " ...Record will be written, but " "that VFC byte will be ignored." move spaces to work_string move 0 to work_string_len end-evaluate when other * Reserved (111xyyyy). display " " display "Reserved bit pattern detected (111x)..." display " ...Record: " record_number with conversion display " ...VFC byte: " vfc_switch display " ...Record will be written, but that " "VFC byte will be ignored." move spaces to work_string move 0 to work_string_len end-evaluate end-evaluate end-evaluate. end program convert_vfc. $ LINK CONVERT_VFC,FDLDEF
|