Trailing-Edge
-
PDP-10 Archives
-
integ_tools_tops20_v7_30-apr-86_dumper
-
tools/10backup_v2_1/bio.mar
There are 5 other files named bio.mar in the archive. Click here to see a list.
.title BIO 10BACKUP IO Routines
.ident 'BIO v2.1'
;
;
; This module is part of 10BACKUP - a program to read DECsystem-10
; BACKUP tapes in INTERCHANGE mode on a VAX.
;
; The routines in this module do the tape input and the file output
; under control of the other modules.
;
; The source modules that make up the 10BACKUP program are:-
;
; 10BACKUP.BAS the main line program.
; BIO.MAR contains tape and file IO routines.
; BUR.MAR is a set of macro utility routines.
; C36.MAR contains 36 bit conversion routines.
; BMS.MSG contains the error message definitions.
; 10BACKUP.RNH Runoff input to build the help library.
;
;
; The first BIO routines are for tape input:-
;
; On tape initialization the tape device is checked to see if
; it is a foreign mounted tape. If it is the QIO's are used for
; all I/O otherwise RMS is called. This enables the program to
; work efficiently with tape devices and yet be able to take its
; input from a file if necessary.
;
; When QIO's are used a number of buffers are set up to allow the
; program to buffer its input. This seems to work OK although the
; program tends to be CPU bound on our overloaded system.
;
; The routines for tape input are:-
;
; bio_tape_init To initialize tape access.
; bio_tape_skip To skip over tape marks (end of tape files).
; bio_tape_rewind To rewind the tape to the beginning.
; bio_tape_close To finish accessing the tape.
; bio_tape_free_buff To free current buffer for further read aheads.
; bio_tape_read To read a tape block.
;
; It is possible that some of these routines may be useful to someone
; else setting up another program which has to read from tapes as well.
;
;
;
$dvidef
;
buffers = 4 ;Number of buffers to use.
max_reclen = 2720 ;Maximum block length.
;
;
.psect buffer,abs,quad ;Layout of a single buffer.
;
bufque: .blkq 1 ;Buffer que entry.
bufsts: .blkl 1 ;Buffer status code.
buflen: .blkl 1 ;Buffer data length.
bufdat: .blkb max_reclen ;Buffer data area.
.align quad
bufsiz:
;
;
;
.psect data_ro,pic,shr,nowrt,noexe,long
;
tape_itmlst:
.word 4,dvi$_devclass ;Item code and length.
.address tape_devclass ;Item buffer address.
.long 0 ;No return length address.
.word 4,dvi$_devchar ;Item code and length.
.address tape_devchar ;Item buffer address.
.long 0 ;No return length address.
.long 0 ;End of item list.
;
;
;
.psect data,rd,wrt,quad
;
.align quad
tape_que: .address tape_que,tape_que ;Input queue header.
proc_que: .address proc_que,proc_que ;Process queue header.
tape_mode: .long 0 ;Mode of input.
tape_buffer: .long 0 ;Current process buffer.
tape_enable: .long 0 ;Flag indicating reads may continue.
tape_working: .long 0 ;Flag indicating read in operation.
tape_mark: .long 0 ;Tape mark seen flag.
tape_devclass: .long 0 ;Class of input device.
tape_devchar: .long 0 ;Characteristics of input device.
tape_chan: .blkw 1 ;Input QIO channel.
tape_iosb: .blkq 1 ;Input QIO status block.
tape_qio: $qio efn=5, -
chan=0, -
func=io$_readlblk, -
iosb=tape_iosb, -
astadr=tape_ast, -
p1=0, -
p2=max_reclen ;QIO parameters for block read.
;
;
.align quad
tape_buffers: .blkb buffers * bufsiz ;Allocate QIO buffer pool.
;
;
tape_fab: $fab ;FAB for RMS input.
tape_rab: $rab fab=tape_fab, -
rop=rah, -
usz=max_reclen, -
ubf=tape_buffers ;RAB for RMS input.
;
;
;
;
;
; Initialize tape device ready for access.
; Check whether to use RMS or QIO's and then open the file
; or assign a channel to the device and get everything ready
; for reads.
;
; Called via: status_code = BIO_TAPE_INIT( DEVICE )
;
.psect $code,pic,shr,nowrt,long
;
.entry bio_tape_init,^M<R2,R3,R4>
movl 4(AP),R2 ;Get address device name.
$getdviw_s efn=#1, -
devnam=(R2), -
itmlst=tape_itmlst, -
iosb=tape_iosb ;See if device name is valid.
blbc R0,10$ ;No, assume we use RMS.
blbc tape_iosb,10$ ;If error in info assume RMS.
cmpl tape_devclass,#dc$_tape ;Is the device a tape?
bneq 10$ ;No, go use RMS.
bbc #dev$v_for,tape_devchar,10$ ;Use RMS unless mounted Foreign.
brb 50$ ;Alright, go use QIOs.
;
;
10$: movb #1,tape_mode ;Remember we are using RMS I/O.
movb (R2),fab$b_fns+tape_fab ;Set file name length.
movl 4(R2),fab$l_fna+tape_fab ;Set file name address.
$open fab=tape_fab ;Open the input file.
blbc R0,20$ ;Check for errors.
$connect rab=tape_rab ;Connect input record stream.
20$: brw 90$ ;All finished.
;
;
50$: clrb tape_mode ;Remember we are using QIO's.
$assign_s devnam=(R2), -
chan=tape_chan ;Assign a channel to the device.
blbc R0,90$ ;Check for errors.
movzwl tape_chan,tape_qio+qio$_chan ;Put channel in QIO block.
movab proc_que,proc_que ;Initialise process queue.
movab proc_que,proc_que+4
movab tape_que,tape_que ;Initialise input queue.
movab tape_que,tape_que+4
movzbl #buffers,R4 ;Set up buffer counter.
movab tape_buffers,R3 ;Set up buffer address.
60$: insque (R3),tape_que ;Put buffer into read queue.
addl #bufsiz,R3 ;Point to next buffer.
sobgtr R4,60$ ;Do all buffers.
clrl tape_buffer ;There is no current buffer.
clrl tape_mark ;No tape marks seen.
clrl tape_working ;Nothing happening yet.
movzbl #1,tape_enable ;Enable tape reads.
;
;
90$: ret ;Return to caller with status.
;
;
;
;
;
; Skip over tape tape marks.
;
; Called via: status_code = BIO_TAPE_SKIP( COUNT )
;
.psect $code,pic,shr,nowrt,long
;
.entry bio_tape_skip,^M<R2,R3,R4>
movzbl #ss$_normal,R0 ;Assume normal status.
movl @4(AP),R3 ;Get skip count.
bneq 10$ ;Skip unless zero.
brw 90$ ;Assume we are finished if zero.
10$: blbc tape_mode,50$ ;Go use QIOs if appropriate.
;
;
20$: $get rab=tape_rab ;Get a record.
blbc R0,30$ ;Finished if errors.
tstw rab$w_rsz+tape_rab ;Does record have a length?
bgtr 20$ ;Yes, go get another.
sobgtr R3,20$ ;Skip each file.
30$: brb 90$ ;All finished.
;
;
50$: bsbw tape_stop ;Ensure all I/O has stopped.
60$: remque @proc_que,R4 ;Get address of buffer.
bvs 70$ ;Got a buffer?
insque (R4),tape_que ;Yes, put into input queue.
movl bufsts(R4),R0 ;Get error status.
blbc R0,70$ ;Check for errors.
tstl buflen(R4) ;Tape mark?
bneq 60$ ;No, go look in next buffer.
decl R3 ;Decrement skip count.
bneq 60$ ;Have we finished skipping?
brb 90$ ;Already skipped to the right place.
;
70$: $qiow_s efn=#1, -
chan=tape_chan, -
func=#io$_skipfile, -
iosb=tape_iosb, -
p1=(R3) ;Ask the driver to do the skip.
cmpl R0,#ss$_endofvolume ;Did driver hit end of volume.
bneq 75$ ;No, go test skip direction.
movl #rms$_eof,R0 ;Indicate end of volume.
brb 90$ ;All finished.
;
75$: clrl tape_mark ;Assume we skipped to before a tape mark.
tstl R3 ;Check direction of skip.
blss 80$ ;Was a skip backwards.
movb #1,tape_mark ;Remember positioned after tape mark.
80$: movb #1,tape_enable ;Enable further tape reads.
;
;
90$: ret ;Return to caller with status.
;
;
;
;
;
;
; Rewind tape.
;
; Called via: status_code = BIO_TAPE_REWIND
;
.psect $code,pic,shr,nowrt,long
;
.entry bio_tape_rewind,^M<R2,R3,R4>
blbc tape_mode,50$ ;Go use QIOs if appropriate.
;
;
$rewind rab=tape_rab ;Rewind the record stream.
blbc R0,90$ ;Finish if errors.
movl rab$l_sts+tape_rab,R0 ;Get status.
brb 90$ ;All finished.
;
;
50$: bsbw tape_abort ;Abort current I/O stream.
$qiow_s efn=#1, -
chan=tape_chan, -
func=#io$_rewind!io$m_nowait, -
iosb=tape_iosb ;Rewind the tape.
bsbw chkerr ;Check for errors.
movb #1,tape_enable ;Enable further tape reads.
clrb tape_mark ;No tape mark (yet).
;
;
90$: ret ;Return to caller with status.
;
;
;
;
;
;
;
; Finish with the tape.
;
; Called via: status_code = BIO_TAPE_CLOSE
;
.psect $code,pic,shr,nowrt,long
;
.entry bio_tape_close,^M<R2,R3,R4>
blbc tape_mode,50$ ;Go use QIOs if appropriate.
;
;
$close fab=tape_fab ;Close the tape file.
brb 90$ ;All finished.
;
;
50$: bsbw tape_abort ;Abort current I/O stream.
$dassgn_s chan=tape_chan ;Deassign tape channel.
;
;
90$: ret ;Return to caller with status.
;
;
;
;
;
;
; Release current QIO buffer for further read aheads.
; If there is no current buffer then no problem.
; If we don't get called then still no problem
; (the next read will get release the buffer anyway).
;
; Called via: CALL BIO_TAPE_FREE_BUFF
;
.psect $code,pic,shr,nowrt,long
;
.entry bio_tape_free_buff,^M<>
blbs tape_mode,50$ ;Does not apply while using RMS.
movl tape_buffer,R1 ;Get address of current buffer.
beql 50$ ;If none then skip.
insque (R1),@tape_que ;Put buffer into input que.
clrl tape_buffer ;No current buffer now.
;
50$: ret ;Return to caller.
;
;
;
;
;
;
; Read a block from the tape.
;
; Called via: status_code = BIO_TAPE_READ( BLOCK_LENGTH, BLOCK_ADDRESS )
;
.psect $code,pic,shr,nowrt,long
;
.entry bio_tape_read,^M<R2,R3,R4>
blbc tape_mode,50$ ;Go use QIOs if appropriate.
;
;
$get rab=tape_rab ;Get a record from the input stream.
blbc R0,10$ ;Finish if errors.
movl fab$l_sts+tape_fab,R0 ;Get final status.
movzwl rab$w_rsz+tape_rab,@4(AP) ;Pass back record length.
movl rab$l_ubf+tape_rab,@8(AP) ;Pass back data address.
10$: brb 90$ ;All finished.
;
;
50$: movl tape_buffer,R1 ;Get address of current buffer.
beql 60$ ;If none then skip.
insque (R1),@tape_que ;Put buffer into input que.
clrl tape_buffer ;No current buffer now.
60$: blbs tape_working,70$ ;Is tape already working?
blbs tape_enable,65$ ;Is the tape enabled for reads.
movab proc_que,R0 ;Get address of process queue.
cmpl proc_que,R0 ;Is the process queue empty?
bneq 70$ ;No, do not restart reads yet.
movb #1,tape_enable ;Enable further reads.
65$: movb #1,tape_working ;Mark tape as working.
bsbw tape_start ;Initialise tape reads.
70$: remque @proc_que,R4 ;Get address of buffer to process.
bvc 80$ ;Got a buffer?
$waitfr_s efn=#5 ;Wait for a tape read to finish.
bsbw chkerr ;Check for errors.
brb 70$ ;Try getting a buffer now.
;
80$: movl R4,tape_buffer ;Remember the buffer address.
movl bufsts(R4),R0 ;Pass back status code.
movl buflen(R4),@4(AP) ;Pass back record length.
movab bufdat(R4),@8(AP) ;Pass back data address.
;
;
90$: ret ;Return to caller with status.
;
;
;
;
; This is the QIO ast routine which is called at the completion
; of every QIO. If possible it sets another QIO going to read
; into the next input buffer before it finishes.
;
.entry tape_ast,^M<R4> ;Input AST routine.
movzwl tape_iosb,R0 ;Get QIO status.
movzwl tape_iosb+2,R1 ;Get QIO length.
blbs R0,20$ ;Skip on if no errors.
cmpw R0,#ss$_endoffile ;Tape mark detected?
beql 10$ ;Yes, go deal with it.
cmpw R0,#ss$_endoftape ;Block read ok past tape end?
bneq 20$ ;No, some other problem.
movzbl #ss$_normal,R0 ;Ignore being past tape marker.
brb 20$ ;Continue business as usual.
10$: clrl R1 ;Zero bytes for tape mark.
movl #rms$_eof,R0 ;Assume end of tape.
blbs tape_mark,30$ ;Done if second tape mark.
movzbl #ss$_normal,R0 ;Only first tape mark.
movb #1,tape_mark ;Remember the tape mark.
brb 30$ ;Have handled the tape mark.
20$: clrb tape_mark ;No tape mark this read.
;
30$: remque @tape_que,R4 ;Remove entry from read queue.
movl R0,bufsts(R4) ;Save status.
movl R1,buflen(R4) ;Save data length.
insque (R4),@proc_que+4 ;Put buffer into process queue.
;
blbc R0,40$ ;Error on last read?
blbc tape_enable,50$ ;Someone wants us to stop?
bsbb tape_start ;Initialise another read.
brb 70$ ;All done.
;
40$: clrb tape_enable ;Disable further reads.
50$: clrb tape_working ;Remember we have stopped.
;
70$: ret ;Resume whatever.
;
;
;
; This is an internal subroutine to start a QIO if an input
; buffer is available for it.
;
tape_start:
movl tape_que,R1 ;Find first free input buffer.
movab tape_que,R0 ;Get header address.
cmpl R1,R0 ;Is input queue empty?
beql 40$ ;Yes, give up.
movab bufdat(R1),tape_qio+qio$_p1;Set up address of buffer.
$qio_g tape_qio ;Issue an input QIO.
bsbw chkerr ;Check for errors.
brb 50$ ;All finished.
40$: clrb tape_working ;Cannot do a read.
50$: rsb ;Return to caller.
;
;
;
; This is an internal routine to abort the current I/O stream.
; It stops current I/O and then releases all the process buffers.
;
tape_abort:
bsbb tape_stop ;Ensure I/O is stopped.
10$: remque @proc_que,R4 ;Get address of a process buffer.
bvs 20$ ;Got a buffer?
insque (R4),tape_que ;Put all buffers into input queue.
brb 10$ ;Release all buffers.
20$: rsb ;Return to caller.
;
;
;
; This is an internal routine to stop tape I/O. It disables the
; read enable flag and then waits for I/O to stop.
;
tape_stop:
clrb tape_enable ;Turn off tape I/O.
10$: blbc tape_working,20$ ;Tape still reading?
$waitfr_s efn=#5 ;Wait for a tape read to finish.
bsbw chkerr ;Check for errors.
brb 10$ ;Try again.
20$: movl tape_buffer,R4 ;Get address of current buffer.
beql 30$ ;Skip if none.
insque (R4),tape_que ;Put buffer into input queue.
clrl tape_buffer ;No current buffer now.
30$: rsb ;Return to caller.
;
;
;
; This is our old faithful error checking routine. It checks the
; status code in R0 for errors and if found reports it by calling
; BUR_CHKERR.
;
chkerr:
blbc R0,10$ ;Check error status.
rsb ;All OK, simply exit.
10$: pushl R0 ;Error status.
pushal (SP) ;Point to the status.
calls #1,G^BUR_CHKERR ;Deal with the error.
movl (SP)+,R0 ;Recover the error status.
rsb ;Exit after the error.
;
;
;
.page
;
;
;
; This is the code to get the next tape volume ready for access. If
; the job is a batch job accessing a tape device then we ask the
; operator via OPCOM to load the next tape volume into the same
; device. For other jobs we call LIB$GET_INPUT to find out what to
; use as the next device.
;
;
;
; The NEXT_VOLUME routine asks the user or operator to ready the
; next tape volume for reading.
;
; Called via: status_code = BIO_NEXT_VOLUME( TAPE_STATUS, OPERATOR_REPLY )
;
; The possible values for tape_status are:-
; -1 tape device is not open
; 0 tape device is ready for normal access
; 1 reserved
; 2 retryable read error detected
; 3 fatal (or unknown) error detected
; 4 reached end of tape
;
;
;
;
$opcdef
$jpidef
;
;
.psect data_ro,pic,shr,nowrt,noexe,long
;
tape_nvl_prompt:.ascid 'Please ready the next 10BACKUP tape volume: '
tape_req_head: .byte opc$l_ms_text ;Header length.
.long <<opc$m_nm_cluster!opc$m_nm_tapes>@8>!opc$_rq_rqst
.long 0 ;Request header.
tape_request: .ascid '!ACPlease ready the next 10BACKUP tape volume on !AD for read access'
;
.psect data,rd,wrt,quad
;
tape_modlst:
.word 4,jpi$_mode ;Item code and length.
.long 0 ;Item buffer address (unknown).
.long 0 ;Return length address (none).
.long 0 ;End of item list.
;
tape_namlst:
.word 64,dvi$_devnam ;Item code and length.
.long 0 ;Item buffer address (unknown).
.long 0 ;Return length address (unknown).
.long 0 ;End of item list.
;
.psect nvl_local,abs ;Local storage on stack.
;
nvl_mode: .blkl 1 ;Process mode.
nvl_devtxt: .blkb 64 ;Device name text.
nvl_devlen: .blkl 1 ;Length of device text.
nvl_reqtxt: .blkb 255 ;Request text.
nvl_reqbuf: .blkq 1 ;Descriptor for request.
nvl_mbxchn: .blkw 1 ;Reply mailbox channel.
nvl_iosb: .blkq 1 ;Reply mailbox IOSB.
nvl_reptxt: .blkb 255 ;Reply text.
nvl_loclen:
;
.psect $code,pic,shr,nowrt,long
;
.entry bio_next_volume,^M<R2,R3,R4,R5,R6,R9>
subl #nvl_loclen,SP ;Make local storage.
movl SP,R9 ;Remember where it is.
;
blbs tape_mode,10$ ;If RMS IO ask user for next volume.
;
clrb tape_mark ;Set no tape mark.
movab nvl_mode(R9),tape_modlst+4 ;Set up buffer pointer.
$getjpiw_s efn=#1, -
itmlst=tape_modlst ;Find out what mode we are in.
bsbw chkerr ;Check for errors.
cmpl nvl_mode(R9),#jpi$k_interactive ;Is this job interactive?
bneq 50$ ;No, go and ask operator for next volume.
;
;
; Since this is an interactive job or we are using RMS I/O then
; we assume that the name of the next volume can be gotten from
; the user or the command procedure via lib$get_input.
;
10$: calls #0,bio_tape_rewind ;First we rewind the present volume.
blbc R0,40$ ;Give up if errors.
;
movl 8(AP),R2 ;Get address of operator reply string.
;
20$: pushab tape_nvl_prompt ;Prompt to use.
pushl R2 ;Where to put reply.
calls #2,G^LIB$GET_INPUT ;Get reply from user.
blbc R0,40$ ;Give up if errors.
;
tstw (R2) ;Check if we were given data.
bneq 25$ ;Yes, go open new volume.
;
tstl @4(AP) ;Check if there is a current volume.
blss 20$ ;No, reask user for volume name.
brb 40$ ;Assume we will use the current volume.
;
25$: tstl @4(AP) ;Check if we still have a current volume.
blss 30$ ;No, just go open new volume.
calls #0,G^bio_tape_close ;Close old volume.
mnegl #1,@4(AP) ;Remember it is closed.
;
30$: pushl R2 ;Name for next volume.
calls #1,g^bio_tape_init ;Open up the next volume.
blbs R0,40$ ;If OK go ahead and use it.
;
pushl R0 ;Put status code on stack.
pushab (SP) ;Point to it.
calls #1,g^bur_wrtmsg ;Write an error message.
movl (SP)+,R0 ;Get status code back.
brb 20$ ;Go try again.
;
40$: brw 90$ ;Have finished setting up next volume.
;
;
; We come here to send a request to the operator via OPCOM so that
; he will mount the next volume in the tape drive for our BATCH job.
;
50$: $qiow_s efn=#1, -
chan=tape_chan, -
func=#io$_rewindoff!io$m_nowait, -
iosb=tape_iosb ;Unload the tape.
blbc R0,40$ ;Check for errors.
movb #1,tape_enable ;Enable further tape reads.
;
movab nvl_devtxt(R9),tape_namlst+4 ;Set up buffer pointer.
movab nvl_devlen(R9),tape_namlst+8 ;Set up return length.
$getdviw_s efn=#1, -
chan=tape_chan, -
itmlst=tape_namlst ;Find device name.
bsbw chkerr ;Check for errors.
;
movl #255,nvl_reqbuf(R9) ;Set initial request length.
movab nvl_reqtxt(R9),nvl_reqbuf+4(R9) ;Set request address.
;
pushab nvl_devtxt(R9) ;Device text arg.
movzwl nvl_devlen(R9),-(SP) ;Device len arg.
pushab tape_req_head ;Header arg.
pushaq nvl_reqbuf(R9) ;Output descriptor arg.
pushal nvl_reqbuf(R9) ;Where to put output length.
pushaq tape_request ;Control string arg.
calls #6,G^sys$fao ;Format the request buffer.
bsbw chkerr ;Check for errors.
;
$crembx_s chan=nvl_mbxchn(R9), -
maxmsg=#255, -
promsk=#^XFF00 ;Make a mailbox for the reply.
bsbw chkerr ;Check for errors.
$sndopr_s msgbuf=nvl_reqbuf(R9), -
chan=nvl_mbxchn(R9) ;Send the request to operator.
bsbw chkerr ;Check for errors.
$qiow_s efn=#1, -
chan=nvl_mbxchn(R9), -
func=#io$_readlblk, -
iosb=nvl_iosb(R9), -
p1=nvl_reptxt(R9), -
p2=#255 ;Get reply from operator.
bsbw chkerr ;Check for errors.
movzwl nvl_iosb(R9),R0 ;Get reply IO status.
bsbw chkerr ;Check for errors.
$dassgn_s chan=nvl_mbxchn(R9) ;Deassign mailbox channel.
bsbw chkerr ;Check for errors.
;
movzwl nvl_iosb+2(R9),R0 ;Get length of reply.
subl #8,R0 ;Adjust for reply text only.
bgeq 60$ ;Check if length is OK.
clrl R0 ;Don't let string length be negative.
60$: movab nvl_reptxt+8(R9),R1 ;Point to reply text.
movl 8(AP),R2 ;Destination descriptor.
jsb G^LIB$SCOPY_R_DX6 ;Pass back string.
bsbw chkerr ;Check for errors.
movzwl nvl_reptxt+opc$w_ms_status(R9),R0 ;Get operator status.
;
;
90$: ret ;Return with status.
;
;
;
.page
;
;
; The rest of the routines in this module are for calling RMS to
; write out the output files being restored.
;
; The three routines are:-
; bio_file_init To open up the output file.
; bio_file_write To write the current buffer to the output file.
; bio_file_close To close the output file.
;
;
;
.psect data,rd,wrt,quad
;
.align quad
bio_file_maxlen == 32763 ;Maximum size of file record.
bio_file_buflen:: .long 0 ;Length of file record.
bio_file_buffer:: .blkb bio_file_maxlen ;Allocate buffer storage.
;
.align quad
file_fab: $fab rat=<CR> ;FAB for RMS file.
file_rab: $rab fab=file_fab, -
rbf=bio_file_buffer, -
rop=wbh ;RAB for RMS file.
;
;
; The following are the routines to write the restored files.
;
; Initialize output file for writing.
;
; Called via: CALL BIO_FILE_INIT( FILE_NAME, DEFAULT_NAME )
;
.psect $code,pic,shr,nowrt,long
;
.entry bio_file_init,^M<>
movl 4(AP),R1 ;Get address of file name.
movb (R1),fab$b_fns+file_fab ;Set file name length.
movl 4(R1),fab$l_fna+file_fab ;Set file name address.
movl 8(AP),R1 ;Get address of default name.
movb (R1),fab$b_dns+file_fab ;Set default name length.
movl 4(R1),fab$l_dna+file_fab ;Set default name address.
$create fab=file_fab ;Open the file file.
bsbw chkerr ;Check for errors.
$connect rab=file_rab ;Connect file record stream.
bsbw chkerr ;Check for errors.
clrl bio_file_buflen ;No data in buffer yet.
ret ;Return to caller with status.
;
;
; Write a file record.
;
; Called via: CALL BIO_FILE_WRITE
;
.psect $code,pic,shr,nowrt,long
;
.entry bio_file_write,^M<>
movw bio_file_buflen,rab$w_rsz+file_rab ;Set length of file record.
$put rab=file_rab ;Write a record.
bsbw chkerr ;Check for errors.
clrl bio_file_buflen ;Reset the file length.
ret ;Return to caller.
;
;
; Close the output file.
;
; Called via: CALL BIO_FILE_CLOSE
;
.psect $code,pic,shr,nowrt,long
;
.entry bio_file_close,^M<>
tstl bio_file_buflen ;Is there still data in buffer?
beql 10$ ;No, don't need write.
calls #0,G^bio_file_write ;Write the data then.
10$: $close fab=file_fab ;Close the data file.
bsbw chkerr ;Check for errors.
ret ;Return to caller.
;
;
;
.end