.title cvt ;++ ; ; CVT.MAR - Alters record structures of sequential files ; ; Author: Don Stokes 2-May-1989 ; ; This program allows the user to change the format of a sequential ; file. This is useful when using file serving packages which map ; files onto fixed or undefined format files, but are in reality using ; linefeeds, carriage returns or both to delimit records. ; ; The program works by creating a file of identical length to the ; original, copying all record information to the output file's FAB, ; and altering it according to the qualifiers specified. The file ; is then copied in block mode, regardless of the structure of either ; file. ; ; Syntax: ; CVT ; Qualifiers: ; /FORMAT={FIXED|STREAM|STREAM_CR|STREAM_LF|UNDEFINED|VARIABLE|VFC} ; /CARRIAGE_CONTROL={CARRIAGE_RETURN|FORTRAN|PRINT|NONE} ; /SIZE= ; /STREAM ; ; Note that a value for /SIZE is required if /FORMAT=FIXED is specified. ; Also, /CARRIAGE_CONTROL requires that /FORMAT=VFC be specified. This ; implies a two byte header. ; ; Modifications: ; 3/5/89/dcs added /STREAM qualifier to search automatically ; determine what type of stream file should be created. ; 8/5/89/dcs altered /STREAM to create a fixed length 512 byte record ; file if no crs or lfs are found. ; Also shorten the size of the block searched to 132 ; bytes to lessen the chances of non-text files appearing ; to be text files due to presence of cr or lf. ; ;-- ;+ ; Macros ;- ; ; Macro to check return status - calls SYS$EXIT if the low bit of R0 is clear. ; .macro STATUS ?L1 blbs R0, L1 $EXIT_S R0 L1: .endm STATUS ; ; Macro to get a value from the CLI. ; ENTITY is the label of the CLI entity to be read. ; RETDESC is the descriptor to return the string to. ; .macro CLI_GET_VALUE entity, retdesc pushal retdesc pushal entity calls #2, g^CLI$GET_VALUE STATUS .endm CLI_GET_VALUE ; ; Macro to determine if an entity is present. ; ENTITY is the CLI entity to look for. ; LABEL is the label to branch to if it is not present. ; .macro IF_CLI_NOT_PRESENT entity label, ?L1 pushal entity calls #1, g^CLI$PRESENT blbs R0, L1 brw label L1: .endm IF_CLI_NOT_PRESENT ; ; Macro to determine if an entity is not present. ; ENTITY is the CLI entity to look for. ; LABEL is the label to branch to if it is present. ; .macro IF_CLI_PRESENT entity label, ?L1 pushal entity calls #1, g^CLI$PRESENT blbc R0, L1 brw label L1: .endm IF_CLI_PRESENT ; ; Macro to call LIB$CVT_DX_DX to convert a string of one type top another. ; (Used to convert string to integer.) ; .macro LIB_CVT_DX_DX src dst pushal dst pushal src calls #2, g^LIB$CVT_DX_DX STATUS .endm LIB_CVT_DX_DX ; ; Macro to assign a value if a qualifier/keyword is present. ; ENTITY is the qualifier/keyword to look for. ; VALUE is the value to use if the strings match. ; DESTINATION is the destination of the VALUE parameter if the strings match. ; .macro IF_PRESENT entity value, destination, ?L1 IF_CLI_NOT_PRESENT entity L1 movb value, destination L1: .endm IF_PRESENT ; ; Macro to branch if a string contains a substring. ; SRCSTR contains the string to be searched. ; SUBSTR contains the string to search for. ; LABEL is the tabel to branch to if the search was successful. ; .macro IF_STR_POSITION srcstr, substr, label pushal substr pushal srcstr calls #2, g^STR$POSITION cmpl R0, #0 bneq label .endm IF_STR_POSITION ;+ ; Data structures ;- .psect data,wrt,noexe ; ; RMS control blocks ; infab: $fab fac = , - nam = innam inrab: $rab fab = infab, - bkt = 0, - ubf = rec_buff, - usz = rec_size innam: $nam rsa = inrsa, - rss = 255 inrsa: .blkb 256 outfab: $fab fac = , - dnm = , - nam = outnam outrab: $rab fab = outfab, - bkt = 0, - rbf = rec_buff outnam: $nam rlf = innam ; ; Record buffer - nice & large to speed transfers ; rec_size = 8192 rec_buff: .blkb rec_size ; ; Descriptor to record buffer for stream format search ; rec_buff_d: .blkw 1 .byte DSC$K_DTYPE_W .byte DSC$K_CLASS_S .long rec_buff ; ; Carriage return/line feed descriptors ; cr = 13 lf = 10 search_crlf: .ascid search_cr: .ascid search_lf: .ascid ; ; File name descriptors ; infiledesc: .long 80 .address infilebuf infilebuf: .blkb 80 outfiledesc: .long 80 .address outfilebuf outfilebuf: .blkb 80 ; ; Keyword/qualifier labels ; cli_infile: .ascid \INFILE\ cli_outfile: .ascid \OUTFILE\ cli_format: .ascid \FORMAT\ cli_size: .ascid \SIZE\ cli_carriage: .ascid \CARRIAGE_CONTROL\ cli_stream: .ascid \STREAM\ ; ; Keywords for /FORMAT qualifier ; fmt_fix: .ascid \FORMAT.FIXED\ fmt_stm: .ascid \FORMAT.STREAM\ fmt_stmcr: .ascid \FORMAT.STREAM_CR\ fmt_stmlf: .ascid \FORMAT.STREAM_LF\ fmt_udf: .ascid \FORMAT.UNDEFINED\ fmt_var: .ascid \FORMAT.VARIABLE\ fmt_vfc: .ascid \FORMAT.VFC\ ; ; Keywords for /CARRIAGE_CONTROL qualifier ; rat_cr: .ascid \CARRIAGE_CONTROL.CARRIAGE_RETURN\ rat_ftn: .ascid \CARRIAGE_CONTROL.FORTRAN\ rat_prn: .ascid \CARRIAGE_CONTROL.PRINT\ rat_none: .ascid \CARRIAGE_CONTROL.NONE\ ; ; Numeric buffer for /SIZE qualifier ; maxrecsiz_d: .word 2 .byte DSC$K_DTYPE_W .byte DSC$K_CLASS_S .long maxrecsiz maxrecsiz: .blkw 1 numbuff: .ascid \ \ ;+ ; Initialisation - sort out what we want to do ;- .psect code, nowrt, exe .entry cvt, ^M<> ; ; Get input and output file names. Point filename fields in FABs at them. ; CLI_GET_VALUE cli_infile, infiledesc CLI_GET_VALUE cli_outfile, outfiledesc movl #infilebuf, infab+fab$l_fna movb infiledesc, infab+fab$b_fns movl #outfilebuf, outfab+fab$l_fna movb outfiledesc, outfab+fab$b_fns ; ; Open input file. ; $open fab = infab ; Open input file STATUS $connect rab = inrab ; Connect block IO record stream STATUS ; ; Move useful info from input file FAB to output file FAB. ; movb infab+fab$b_rfm, outfab+fab$b_rfm movw infab+fab$w_mrs, outfab+fab$w_mrs movb infab+fab$b_rat, outfab+fab$b_rat movw infab+fab$w_deq, outfab+fab$w_deq movl infab+fab$l_fop, outfab+fab$l_fop movw infab+fab$w_gbc, outfab+fab$w_gbc movl infab+fab$l_alq, outfab+fab$l_alq ; ; If /FORMAT was specified, get its value. ; Set the RFM field in the output file FAB accordingly. ; IF_CLI_NOT_PRESENT cli_format, noformat IF_PRESENT fmt_fix, #fab$c_fix, outfab+fab$b_rfm IF_PRESENT fmt_stm, #fab$c_stm, outfab+fab$b_rfm IF_PRESENT fmt_stmcr, #fab$c_stmcr, outfab+fab$b_rfm IF_PRESENT fmt_stmlf, #fab$c_stmlf, outfab+fab$b_rfm IF_PRESENT fmt_udf, #fab$c_udf, outfab+fab$b_rfm IF_PRESENT fmt_var, #fab$c_var, outfab+fab$b_rfm IF_PRESENT fmt_vfc, #fab$c_vfc, outfab+fab$b_rfm ; ; If VFC was specified, then use a two byte header. ; IF_PRESENT fmt_vfc, #2, outfab+fab$b_fsz noformat: ; ; If the /CARRIAGE_CONTROL qualifier was specified then set the RAT ; field accordingly. Note that the FAB$M_BLK bit is preserved. ; IF_CLI_NOT_PRESENT cli_carriage, nocarriage IF_PRESENT rat_none, #0, R2 IF_PRESENT rat_cr, #fab$m_cr, R2 IF_PRESENT rat_ftn, #fab$m_ftn, R2 IF_PRESENT rat_prn, #fab$m_prn, R2 insv R2, #0, #3, outfab+fab$b_rat nocarriage: ; ; If the /SIZE qualifier was specified, get the record size. ; Note that /SIZE is required for fixed files. ; IF_CLI_NOT_PRESENT cli_size, nosize CLI_GET_VALUE cli_size, numbuff LIB_CVT_DX_DX numbuff, maxrecsiz_d movw maxrecsiz, outfab+fab$w_mrs nosize: ; ; Get first record in case we want to use intelligent stream formatting ; $read rab = inrab cmpl r0, #rms$_eof bneq 2$ brw done1 2$: STATUS ; ; If the /STREAM qualifier was specified, search the first 255 bytes ; in the block for a CRLF pair, a CR or LF, and set the format field to ; stream, stream_cr or stream_lf accordingly. If none of these characters ; were found, change the format to fixed length, with 512 byte records ( ; unless overridden by the /SIZE qualifier). ; IF_CLI_NOT_PRESENT cli_stream, nostream movw inrab+rab$w_rsz, rec_buff_d cmpw rec_buff_d, #132 bleq 1$ movw #132, rec_buff_d 1$: movb #fab$c_stm, outfab+fab$b_rfm IF_STR_POSITION rec_buff_d, search_crlf, nostream movb #fab$c_stmcr, outfab+fab$b_rfm IF_STR_POSITION rec_buff_d, search_cr, nostream movb #fab$c_stmlf, outfab+fab$b_rfm IF_STR_POSITION rec_buff_d, search_lf, nostream movb #fab$c_fix, outfab+fab$b_rfm IF_CLI_PRESENT cli_size, nostream movw #512, outfab+fab$w_mrs nostream: ; ; Create the output file. ; $create fab=outfab STATUS $connect rab = outrab STATUS ;+ ; Main loop - block reads & writes until EOF ;- ; ; Write the block to the output file. Note that we've already read on block. ; loop: movw inrab+rab$w_rsz, outrab+rab$w_rsz $write rab=outrab STATUS ; ; Read a block from the input file. ; Exit if at end of file. ; $read rab = inrab cmpl r0, #rms$_eof beql done STATUS brb loop ;+ ; Final cleanup - close files and exit ;- done: $close fab = outfab STATUS done1: $close fab = infab STATUS ret .end cvt