! %TITLE 'BYTESTREAM - BYTESTREAM FILE ACCESS UTILITY' MODULE usr_bytestream (IDENT = 'V001' ) = BEGIN !++ ! ! FACILITY: USR - USER WRITTEN UTILITIES ! ! ABSTRACT: This module contains all BYTESTREAM Utility routines. ! The goal of the BYTESTREAM utility is to make an ! input file look like a continuous byte stream. ! This is done by maintaining a current file context ! and buffered block input. ! ! ENVIRONMENT: VAX-11/VMS, Runs in USER mode, Unprivileged code, ! Non-reentrant due to saved file context. ! ! AUTHOR: Lost in the mists of time ! ! CREATED: A long time ago ! ! MODIFICATION ! HISTORY: ! ! !-- %SBTTL 'Declarations' !+ ! SWITCHES: !- SWITCHES ADDRESSING_MODE (EXTERNAL = GENERAL, NONEXTERNAL = WORD_RELATIVE); !+ ! LINKAGES: !- ! None. !+ ! TABLE OF CONTENTS: ! ! BYT_OPEN_FILE Start a new file context. ! BYT_CLOSE_FILE End the current file context. ! BYT_READ_BYTES Read the next set of consecutive bytes. ! BYT_SET_BYTEPOS Sets the current byte position. ! BYT_GET_BYTEPOS Gets the current byte position. ! BYT_GET_LENGTH Gets the current file's length. ! BYT_GET_PARAMS Gets a series of parameters. !- FORWARD ROUTINE byt_open_file, byt_close_file, byt_read_bytes, byt_set_bytepos, byt_get_bytepos, byt_get_length, byt_get_params; !+ ! INCLUDE FILES: ! ! LIB VMS Interface Definitions. ! USRLIB SERF User Definitions. !- LIBRARY 'SYS$LIBRARY:LIB'; LIBRARY 'USR_LIBRARY:USRLIB'; !+ ! MACROS: ! ! From USRLIB: ! ! _FACILITY_PSECT Declares a set of facility PSECTs. ! _STRING_DESC Declare a VMS standard string descriptor. !- !+ ! FIELDS: !- ! None. !+ ! STRUCTURES: !- ! None. !+ ! PSECTS: !- _facility_psect (usr_byt); !+ ! EQUATED SYMBOLS: ! ! BYT_K_BLOCKSIZE Input disk file block size. !- LITERAL byt_k_blocksize = 512; !+ ! OWN STORAGE: ! ! Input File Context : ! ! CONTEXT Current file context exists Boolean. ! RESULTBUF Resultant filename buffer. ! RESULT Resultant filename descriptor. ! EXPAND Expanded filename buffer. ! NAM Input file NAM. ! XAB Input file header characteristics XAB. ! FAB Input file FAB. ! BUFFER Input block buffer. ! RAB Input file RAB. ! ! Input File Position : ! ! NEXT_VBN Next virtual block to read. ! CURRENT_BYTE Current byte position within current VBN. ! ENDFILE End of file found Boolean. !- OWN context : INITIAL (0), resultbuf : VECTOR [nam$c_maxrss, BYTE], result : _string_desc (length = nam$c_maxrss, pointer = resultbuf), expandbuf : VECTOR [nam$c_maxrss, byte], nam : $nam ( ! esa = expandbuf, ! ess = nam$c_maxrss, ! rsa = resultbuf, ! rss = nam$c_maxrss ! ), ! xab : $xabfhc (), fab : $fab ( ! dnm = '.DVI', ! fac = , ! fop = , ! nam = nam, ! xab = xab ! ), ! buffer : VECTOR [byt_k_blocksize, BYTE], rab : $rab ( ! fab = fab, ! rac = , ! rop = , ! ubf = buffer, ! usz = byt_k_blocksize ! ); OWN next_vbn : INITIAL (0), current_byte : INITIAL (0), endfile : INITIAL (0); !+ ! BUILTIN DECLARATIONS: !- ! None. !+ ! EXTERNAL REFERENCES: !- ! None. %SBTTL 'Start a New Input File Context' GLOBAL ROUTINE byt_open_file (infile : REF _descriptor, infab : REF VECTOR [1, LONG]) = !++ ! ! FUNCTIONAL DESCRIPTION: ! ! This routine is used to establish a new input file context. The ! RMS context is maintained in the FAB, RAB, NAM, and XAB structures. ! The resultant (expanded) filename is pointed to by the RESULT ! descriptor and maintained in the RESULTBUF buffer. ! ! If any previous file context exists, it is ended with a call to ! byt_close_file. ! ! The current byte context variables are initialized such that the ! first call to BYT_READ_BYTES will read in the first VBN. All ! successive calls to BYT_READ_BYTES will then read sequentially. ! ! The calling routine is given access to the input file context by ! returning in INFAB the address of the input file FAB. ! ! CALLING SEQUENCE: ! ! STATUS.wlc.v = BYT_OPEN_FILE ( INFILE.rt.dx, INFAB.wa.r ) ! ! INPUT PARAMETERS: ! ! INFILE Address of a string descriptor pointing to ! the new input filename. ! ! OUTPUT PARAMETERS: ! ! INFAB Address of a longword where the file FAB ! context address will be returned. ! ! IMPLICIT INPUTS: ! ! CONTEXT Input file context exists Boolean. ! FAB Input file FAB. ! RAB Input file RAB. ! NAM Input file NAM. ! ! IMPLICIT OUTPUTS: ! ! FAB,RAB,NAM Describe new input file context. ! XAB Contains current file header characteristics. ! RESULT Contains input filename context. ! CONTEXT Set to true to indicate new input file context. ! NEXT_VBN Initialized to VBN 1. ! CURRENT_BYTE Initialized to byte 0. ! ENDFILE Initialized to false. ! ! COMPLETION STATUS: ! ! RMS$_NORMAL Normal successful completion. ! Any return from byt_close_file. ! Any return from $OPEN. ! Any return from $CONNECT. ! ! SIDE AFFECTS: ! ! Any previous file context is ended. ! !-- BEGIN !+ ! LOCAL STORAGE: ! ! STATUS Holds condition codes. !- LOCAL status; !+ ! If a previous file context exists then finish it. !- IF .context THEN IF NOT (status = byt_close_file ()) THEN RETURN .status; !+ ! Make the FAB point to the input filename and open the input file. ! Note that $OPEN alse performs a parse to fill in the NAM resultant ! string area, which will act as the filename context. The actual length ! of the resultant filename is obtained from the NAM. !- fab [fab$b_fns] = .infile [dsc$w_length]; fab [fab$l_fna] = .infile [dsc$a_pointer]; IF (status = $open (fab = fab)) THEN BEGIN result [dsc$w_length] = .nam [nam$b_rsl]; !+ ! Connect the record stream. If successful then set the context ! variable to true and return the FAB context. !- IF (status = $connect (rab = rab)) THEN BEGIN context = 1; infab [0] = fab; !+ ! The current byte context variables are initialized to force VBN 1 ! BYTE 0 as the first current byte position. !- next_vbn = 1; current_byte = 0; rab [rab$w_rsz] = 0; endfile = 0; END; END; !+ ! Return STATUS. Note that this is the NORMAL return from $CONNECT ! or an unsuccessful return from $OPEN or $CONNECT. !- .status END; ! End of routine BYT_OPEN_FILE %SBTTL 'End the Current File Context' GLOBAL ROUTINE byt_close_file = !++ ! ! FUNCTIONAL DESCRIPTION: ! ! This routine is used to terminate the current DVI input file context ! established by a previous call to BYT_OPEN_FILE. ! ! If a current file context does not exists, the routine just exits ! normally. ! ! CALLING SEQUENCE: ! ! STATUS.wlc.v = BYT_CLOSE_FILE () ! ! INPUT PARAMETERS: ! ! None. ! ! OUTPUT PARAMETERS: ! ! None. ! ! IMPLICIT INPUTS: ! ! CONTEXT Input file context exists Boolean. ! RAB Current file context RAB. ! FAB Current file context FAB. ! ! IMPLICIT OUTPUTS: ! ! CONTEXT Set to 0 to indicate no current file context. ! ! COMPLETION STATUS: ! ! RMS$_NORMAL Normal successful completion. ! Any return from $DISCONNECT. ! Any return from $CLOSE. ! ! SIDE AFFECTS: ! ! The current context record stream is disconnected and the input file ! is closed. ! !-- BEGIN !+ ! LOCAL STORAGE: ! ! STATUS Holds condition codes. Assume success. !- LOCAL status : INITIAL (rms$_normal); !+ ! Make sure that a current file context exists. If it does then ! disconnect the record stream, close the input file, and reset the ! context Boolean. !- IF .context THEN IF (status = $disconnect (rab = rab)) THEN IF (status = $close (fab = fab)) THEN context = 0; !+ ! Return STATUS. Note that this may be NORMAL or an unsuccessful ! return from any of the RMS calls. !- .status END; ! End of routine BYT_CLOSE_FILE %SBTTL 'Read the Next Set of Consecutive Bytes' GLOBAL ROUTINE byt_read_bytes (number, outbuf : REF VECTOR [, BYTE]) = !++ ! ! FUNCTIONAL DESCRIPTION: ! ! This routine is used to make the data from the input file look like ! a continuous byte stream. It will return the next NUMBER bytes in ! the stream in OUTBUF. ! ! The input file blocks are buffered. The current byte within the ! buffer is maintained and incremented as bytes are requested. If ! the current buffer is exhausted, then the next block is read in ! and the byte pointer reset. ! ! This routine will not return an end-of-file condition until all ! outstanding bytes have been passed from the $READ finding the ! condition. ! ! CALLING SEQUENCE: ! ! STATUS.wlc.v = BYT_READ_BYTES ( NUMBER.rlu.v, OUTBUF.wbu.r ) ! ! INPUT PARAMETERS: ! ! NUMBER Number of bytes to read. ! ! OUTPUT PARAMETERS: ! ! OUTBUF Address of the output byte buffer where ! NUMBER bytes will be returned. ! ! IMPLICIT INPUTS: ! ! NEXT_VBN Next VBN to read. ! CURRENT_BYTE Current byte within current VBN. ! BUFFER Input block buffer. ! ENDFILE End of file found Boolean. ! ! IMPLICIT OUTPUTS: ! ! NEXT_VBN Updated to next VBN if VBN's had to be read. ! CURRENT_BYTE Updated to next byte to read. ! BUFFER Contains a new block if one was read. ! ENDFILE Set if end-of-file encountered. ! ! COMPLETION STATUS: ! ! RMS$_NORMAL Normal successful completion. ! RMS$_EOF End of file. ! Any return from $READ. ! ! SIDE AFFECTS: ! ! - Implicit RMS NBP may be altered to point to next block if a new ! block was read. ! !-- BEGIN !+ ! LOCAL STORAGE: ! ! STATUS Holds condition codes. !- LOCAL status; !+ ! Loop for each requested byte. !- INCR i FROM 0 TO (.number - 1) BY 1 DO BEGIN !+ ! If the current block has been exhausted then get another one. !- WHILE .current_byte GEQU .rab [rab$w_rsz] DO !+ ! The following loop continues reading blocks until a non-empty ! one is found. If end-of-file is encountered, then the ENDFILE ! Boolean will be set. This causes the next loop entry to return ! with RMS$_EOF. !- BEGIN IF .endfile THEN RETURN rms$_eof; rab [rab$l_bkt] = .next_vbn; status = $read (rab = rab); IF NOT .status THEN IF .status EQLU rms$_eof THEN endfile = 1 ELSE RETURN .status; next_vbn = .next_vbn + 1; current_byte = 0; END; !+ ! Return the current byte and advance the pointer. !- outbuf [.i] = .buffer [.current_byte]; current_byte = .current_byte + 1; END; !+ ! The requested bytes have been returned. !- rms$_normal END; ! End of routine BYT_READ_BYTES %SBTTL 'Set the Current Byte Position' GLOBAL ROUTINE byt_set_bytepos (newpos) = !++ ! ! FUNCTIONAL DESCRIPTION: ! ! This routine is used to position the current byte context at an ! arbitrary byte in the file. Bytes are numbered starting at 0. ! ! If the target byte is found to be within the VBN currently in the ! buffer, then only the byte pointer will be updated. Otherwise, the ! VBN containing the target byte will be read from the file. ! ! CALLING SEQUENCE: ! ! STATUS.wlc.v = BYT_SET_BYTEPOS ( NEWPOS.rlu.v ) ! ! INPUT PARAMETERS: ! ! NEWPOS New current byte position. ! ! OUTPUT PARAMETERS: ! ! None. ! ! IMPLICIT INPUTS: ! ! None. ! ! IMPLICIT OUTPUTS: ! ! NEXT_VBN Points to next VBN after new VBN. ! CURRENT_BYTE Points to new current byte. ! BUFFER Contains VBN containing new current byte. ! RAB BKT points to VBN contained in BUFFER. ! RSZ contains size of VBN in BUFFER. ! ! COMPLETION STATUS: ! ! RMS$_NORMAL Normal successful completion. ! RMS$_EOF End of file. ! Any return from $READ. ! ! SIDE AFFECTS: ! ! None. ! !-- BEGIN !+ ! LOCAL STORAGE: ! ! STATUS Holds condition codes. !- LOCAL status; !+ ! Compute the VBN containing the target byte, and the target byte ! offset within that VBN. !- rab [rab$l_bkt] = .newpos/byt_k_blocksize + 1; current_byte = .newpos MOD byt_k_blocksize; !+ ! Read the target VBN if it is not the current one in the BUFFER. If an ! end-of-file occurs, then check to see if CURRENT_BYTE is within any ! outstanding bytes. !- IF .rab [rab$l_bkt] NEQU .next_vbn - 1 THEN IF NOT (status = $read (rab = rab)) THEN IF .status NEQU rms$_eof OR (.current_byte + 1) GTR .rab [rab$w_rsz ] THEN RETURN .status; !+ ! Update the next VBN pointer and return NORMAL. !- next_vbn = .rab [rab$l_bkt] + 1; rms$_normal END; ! End of routine BYT_SET_BYTEPOS %SBTTL 'Get the Current Byte Position' GLOBAL ROUTINE byt_get_bytepos (curpos : REF VECTOR [1, LONG]) = !++ ! ! FUNCTIONAL DESCRIPTION: ! ! This routine is used to return the current byte position (offset). ! Byte positions are numbered from 0 to N-1 where N = number of bytes ! in the file. ! ! CALLING SEQUENCE: ! ! STATUS.wlc.v = BYT_GET_BYTEPOS ( CURPOS.wlu.r ) ! ! INPUT PARAMETERS: ! ! None. ! ! OUTPUT PARAMETERS: ! ! CURPOS Address of a longword to receive the current ! byte position. ! ! IMPLICIT INPUTS: ! ! NEXT_VBN Next VBN to read. ! CURRENT_BYTE Current byte offset within current VBN. ! ! IMPLICIT OUTPUTS: ! ! None. ! ! COMPLETION STATUS: ! ! SS$_NORMAL Normal successful completion. ! ! SIDE AFFECTS: ! ! None. ! !-- BEGIN !+ ! If VBN = 1, then a block has not yet been read. Otherwise, ! compute the byte position. !- IF .next_vbn EQLU 1 THEN 0 ELSE (.next_vbn - 2)*byt_k_blocksize + .current_byte END; ! End of routine BYT_GET_BYTEPOS %SBTTL 'Get the Current Input File''s byte length' GLOBAL ROUTINE byt_get_length (length : REF VECTOR [1, LONG]) = !++ ! ! FUNCTIONAL DESCRIPTION: ! ! This routine obtains the byte length of the current input file from ! The end-of-file block and first-free-byte fields in the FHC XAB. ! ! CALLING SEQUENCE: ! ! STATUS.wlc.v = BYT_GET_LENGTH ( LENGTH.wlu.r ) ! ! INPUT PARAMETERS: ! ! None. ! ! OUTPUT PARAMETERS: ! ! LENGTH Address of a longword where the file's byte ! length will be returned. ! ! IMPLICIT INPUTS: ! ! XAB File header characteristics XAB for current ! input file. ! ! IMPLICIT OUTPUTS: ! ! None. ! ! COMPLETION STATUS: ! ! RMS$_NORMAL Normal successful completion. ! ! SIDE AFFECTS: ! ! None. ! !-- BEGIN (.xab [xab$l_ebk] - 1)*byt_k_blocksize + .xab [xab$w_ffb] END; ! End of routine BYT_GET_LENGTH %SBTTL 'Get a Series of Parameters' GLOBAL ROUTINE byt_get_params (prmlst) = !++ ! ! FUNCTIONAL DESCRIPTION: ! ! This routine is used to fetch a series of parameters from the input ! byte stream. ! ! The input arguments are grouped into pairs of two. The first in ! each pair specifies the number of bytes for the next parameter, and ! the second specifies the return longword address. ! ! Any number of parameters may be specified because the routine ! senses how may pairs exist from the first longword of the argument ! block. ! ! CALLING SEQUENCE: ! ! STATUS.wlc.v = BYT_GET_PARAMS ( P1SZ.rlu.v, PRM1.wlu.r, ... ) ! ! INPUT PARAMETERS: ! ! PnSZ Number of bytes in next parameter. ! ! OUTPUT PARAMETERS: ! ! PRMn Longword return location for next parameter. ! ! IMPLICIT INPUTS: ! ! CURRENT INPUT FILE CONTEXT ! ! IMPLICIT OUTPUTS: ! ! None. ! ! COMPLETION STATUS: ! ! Any return from BYT_READ_BYTES. ! ! SIDE AFFECTS: ! ! None. ! !-- BEGIN !+ ! BUILTINS: ! ! AP Access to argument pointer. !- BUILTIN AP; !+ ! LOCAL BINDS: ! ! ARGLST Name bound to argument list. !- BIND arglst = .AP : VECTOR [, LONG]; !+ ! LOCAL STORAGE: ! ! STATUS Holds condition codes. !- LOCAL status; !+ ! Process each parameter. This is done by reading the specified ! number of bytes from the input buffer and returning them in the ! associated return longword. Note that BYT_READ_BYTES insures ! that the bytes are packed in the proper order. !- INCR i FROM 1 TO .arglst [0] BY 2 DO BEGIN !+ ! Clear the return argument in case higher bytes are not used. !- (.arglst [.i + 1]) = 0; IF NOT (status = byt_read_bytes (.arglst [.i], .arglst [.i + 1])) THEN EXITLOOP; END; !+ ! Return STATUS. Note that this will be the return from the last ! successful or first unsuccessful call to BYT_READ_BYTES. !- .status END; ! End of routine BYT_GET_PARAMS END ! End of module USR_BYTESTREAM ELUDOM