.TITLE FRMFIO ... format file I/O module .IDENT /061082/ .ENABL LC ; ; ; Written by Ray Di Marco ; 29-Apr-82. ; ; ;____________________________________________________________________________ ; ; This module is used by DBSMNG CUSPs to input chracaters from a format file. ; A format file is treated as a sequential ascii stream. Routines are provided ; to gain access to the file, input characters (one at a time) and to rewind ; the file prior to a new pass. The module entry points are ; ; FRMINT ... must be called to initialize the module. ; FRMINC ... returns the next character from the stream. ; FRMRST ... resets the file rewinding to the load point. ; FRMMRK ... moves the reset/rewind load point the current position. ; ; The FRMINT routine opens the file whose name is stored as an asciz string ; in the FRMNME buffer as the format file. The default name for the file is ; DK:FORMAT.FRM. The caller may change the name of the file to suit. ; ; The FRMINC routine returns a character in R0. If the EOF has been reached ; the C flag is set on exit. The routine also supports the following leading ; characters ; _ -> return exact ascii code of next character ; ^ -> mask out bits 7-5 of next character ; $ -> add 200!8 to next characters ascii code ; ; The EOF condition is assumed to occure upon detect of physical EOF, a ^Z in ; the stream or a . ; ; The FRMRST routine is called to rewind the stream. Normally it is reset by ; rewinding to Block 0, character 0. The user may setup the $$$FRM structure ; (by calling FRMMRK) so that the rewind point is moved to another position. ; ; .SBTTL Modifications ; ; 10-Oct-82 ; ; Number of changes made to support REPEAT BLOCKs and improve efficiency of ; module. Major change was repeat block handling. The sequence ; ; ^@C^@ ; ; where ^@ is a two letter sequence (ie an up-arrow followed by the @ symbol) ; and C is any valid 8 bit code (may be a normal character or one generated ; by the ^X or $X operators) is equivalent to repeating the sequence of ; characters between the ^@C and ^@ delimiters N times, where N is the ; ascii value of C. ; ; .SBTTL DECLARATIIONS ; ; .MCALL .PUSH,.POP ; stacking .MCALL .EXIT,.PRINT ; Error aborting .MCALL FILSPT ; file support ; FILSPT ; set up for file support ; ; .GLOBL FRMINT,FRMINC,FRMMRK,FRMRST ; entry points .GLOBL FRMNME ; important data structure ; ; .MACRO FATAL MES,?A,?B .PRINT #'B STATUS .EXIT B': .ASCII /'MES'/<15><12><'I-'@><200> .EVEN .ENDM FATAL ; ; .PSECT CODE ; open code section ; ------ ---- ; .SBTTL Routine - "FRMINT" ... initialization routine ; ; This routine is called to gain access to the format file. It ; attachs a FDB to the file, reads in the first blocks into memory ; and sets up various parameters. ; FRMINT: PURGE #FDBFRM ; ensure channel free BIS #F.NERR,FDB.FL(R5) ; disable error messages NAME STRING=#FRMNME,EXTENS=#^RFRM,ERROR=1000$ LOOKUP ERROR=1000$ ; Lookup File READ BLOCK=#0,ERROR=1000$,EOF=1000$ ; Read in file CLR FRMFLG ; Clear EOF marker CLR REPCNT ; Clear repeat counter MOV #FRMBUF,FRMPNT ; Reset fetch pointer MOV FDB.CP(R5),R0 ; R0 = number words read ASL R0 ; R0 = number bytes read MOV R0,FRMCNT ; number bytes in buffer MOV R0,$$$FRM ; set up rewind counter RETURN ; ALL DONE ; 1000$: FATAL ; ; .SBTTL Routine - "FRMINC" ... Return next Character ; ; Here to return next character from input stream. This code is responsible ; for compaction of "_X", "$X" and "^X" sequences and repeat blocks. ; ; ; Return next character in stream; watch out for special characters. ; FRMINC: CALL FRMINP ; R0 = next character BCS 700$ ; skip on physical EOF 100$: CMP R0,#<'Z-'@> ; logical EOF marker? BEQ 700$ ; yes -> 700$ 200$: CMP R0,#'_ ; Leadin Character? BEQ 1000$ ; yes -> 1000$ CMP R0,#'$ ; Leadin Character? BEQ 2000$ ; yes -> skip CMP R0,#'^ ; Leadin Character? BEQ 3000$ ; yes -> 300$ TST (PC)+ ; clear 'C' flag 700$: SEC ; set EOF flag 770$: RETURN ; all done ; ; ; return next character unconverted ; 1000$: CALL FRMINP ; R0 = next character RETURN ; return unconverted ; ; next character is to be returned as an escape code ; 2000$: CALL FRMINP ; R0 = next chracter BCS 700$ ; skip if hit EOF BIS #200,R0 ; translate to escape code RETURN ; all done ; ; translate next character to control code; watch out for ^@ ; 3000$: CALL FRMINP ; R0 = next chracter BCS 700$ ; skip if hit EOF BIC #^C37,R0 ; R0 = equivalent control code BNE 100$ ; done if not a ^@ ; ; ; Hit a ^@, which either marks the start or end of a repeat block. If ; REPCNT=0 then at start of a repeat block. If count non-zero then hit ; the end of the block, in which case decrement counter to see if must ; repeat again. If count zeros out then finished repeat operation and ; can skip over the ^@. ; TST REPCNT ; repeat count = 0? BEQ 3400$ ; yes -> setup repeat block DEC REPCNT ; repeat operation done? BEQ FRMINC ; yes -> ignore ^@ ; ; Have to perform a repeat block procedure; rewind input stream to ; start of block and loop for a character ; MOV #REPSAV,R0 ; R0 -> start of repeat block CALL RESTORE ; restore stream BR FRMINC ; get next character ; ; Have to setup a repeat block; next character is number of times must ; repeat. Setup REPCNT with repeat count and save file status in REPSAV ; so can rewind input stream to perform repeat operation. ; 3400$: CALL FRMINP ; R0 = next character BCS 770$ ; abort if EOF CALL 200$ ; translate if needed MOV R0,REPCNT ; save repeat count BEQ 3400$ ; ignore REPEAT 0 MOV #REPSAV,R0 ; R0 -> save area CALL SAVE ; save status BR FRMINC ; get next character ; .SBTTL Primitive - "FRMINP" ... inputs characters from file ; ; This routine returns next character from the file. It buffers the input ; in memory and reads in new blocks as needed. It will return with the 'C' ; flag set to indicate EOF; EOF is said to occure if a NULL byte is ; incountered or if an EOF error occures during a read operation. ; ; ; If FRMFLG is set have hit EOF; abort ; FRMINP: TST FRMFLG ; previously hit eof? BNE 7100$ ; yes -> abort ; ; Return next character in buffer. Have to check for buffer empty (in which ; case must read in another buffer from file) and for NULL in input stream. ; DEC FRMCNT ; taking one more byte BLT 1000$ ; skip if buffer empty MOVB @FRMPNT,R0 ; get character INC FRMPNT ; up pointer BIC #^C377,R0 ; mask unwanted bits BEQ 7000$ ; -> eof CLC ; clear fail RETURN ; EXIT ; ; Must read in more data from file; If reads ok reset count/pointer and ; restart operation. If cannot read must declare eith a hard error or an ; EOF condition. ; 1000$: .PUSH R5 ; save R5 MOV #FDBFRM,R5 ; R5 -> FDB ADD #2,FDB.BL(R5) ; update block number READ ERROR=7700$,EOF=1700$ ; Read in data MOV FDBFRM+FDB.CP,R0 ; R0 = number words read ASL R0 ; R0 = number bytes read BEQ 1700$ ; none read -> EOF MOV R0,FRMCNT ; setup number bytes cnt MOV #FRMBUF,FRMPNT ; reset pointer .POP R5 ; restore R5 BR FRMINP ; try again 1700$: BIS #F.NERR,FDB.FL(R5) ; re-disable error messages .POP R5 ; restore R5 ; ; ; If get an EOF error return a NULL in R0 and set C flag. Note that ; the FRMFLG must be set to disable further attempts to read data. ; 7000$: MOV #1,FRMFLG ; set eof marker 7100$: CLR R0 ; return a SEC ; ensure 'C' set RETURN ; exit ; 7700$: FATAL .SBTTL Routine - "FRMMRK" ... Marks restart point in file ; ; This routine may be called at any time to mark the input steams ; restart point; once FRMMRK is called FRMRST may be used at any ; time to rewind/reset the input stream. ; FRMMRK: .PUSH R0 ; save MOV #$$$FRM,R0 ; R0 -> rewind parameters CALL SAVE ; save file status .POP R0 ; restore RETURN ; exit ; ; .SBTTL Routine - "FRMRST" ... reset ascii stream ; ; This routine, when called, rewinds/resets the input stream to its ; start position (ie start of file or the stream position last time ; FRMMRK was called). ; FRMRST: .PUSH R0 ; save MOV #$$$FRM,R0 ; R0 -> save parameter block CALL RESTORE ; restore file .POP R0 ; restore CLR FRMFLG ; clear EOF flag CLR REPCNT ; clear repeat count RETURN ; all done ; ; .SBTTL Primitive - "SAVE" ... save file status in @R0 ; ; This routine is called with R0 pointing to a 3 word buffer; it stores ; information needed by RESTOR to restore the input to its present point. ; SAVE: MOV FRMCNT,(R0)+ ; save count MOV FRMPNT,(R0)+ ; save pointer MOV FDBFRM+FDB.BL,(R0)+ ; save block number RETURN ; all done ; ; .SBTTL Primitive - "RESTOR" ... restore file status from @R0 ; ; This routine is called with R0 pointing to a 3 word buffer (previosly ; setup by SAVE); it will restore the input stream to its position when ; SAVE was called. ; RESTOR: .PUSH R5 ; save R5 MOV (R0)+,FRMCNT ; number chars in buffer MOV (R0)+,FRMPNT ; setup pointer CMP (R0),FDBFRM+FDB.BL ; right block in memory? BEQ 700$ ; yes -> skip MOV (R0),FDBFRM+FDB.BL ; setup block number READ FDB=#FDBFRM,ERROR=1000$,EOF=1000$; read in right block 700$: CLR FRMFLG ; clear EOF marker .POP R5 ; restore R5 RETURN ; exit ; 1000$: FATAL .SBTTL Data Structures and Variables ; ; .PSECT FDB$$$ ; open special area ; ====== ====== ; ; REPCNT: .WORD 0 ; repeat count REPSAV: .WORD 0,0,0 ; repeat save buffer ; FDB NAME=FDBFRM,CHANNEL=14.,BUFFER=FRMBUF,SIZE=1000 FRMFLG: .WORD 0 ; <> 0 --> EOF FRMCNT: .WORD 0 ; Count of chars in buffer FRMPNT: .WORD FRMBUF ; Fetch pointer $$$FRM: .WORD 2000,FRMBUF,0 ; Initial rewind parameters FRMBUF: ; I/O buffer FRMNME: .ASCIZ /DK:FORMAT.FRM/ ; Selection format file default name .BLKB 2000-<.-FRMBUF> ; rest of buffer ; ; .END