.iif ndf rsx rsx = 1 ;Assume RSX11M .title $$getc Get characters ; ; The information in this document is subject to change ; without notice and should not be construed as a commitment ; by Digital Equipment Corporation or by DECUS. ; ; Neither Digital Equipment Corporation, DECUS, nor the authors ; assume any responsibility for the use or reliability of this ; document or the described software. ; ; Copyright (C) 1980, DECUS ; ; ; General permission to copy or modify, but not for profit, is ; hereby granted, provided that the above copyright notice is ; included and reference made to the fact that reproduction ; privileges were granted by DECUS. ; .ident /000005/ ; ;+ ; ; Internal ; ; Index Get characters (internal) ; ; Usage ; ; mov #iov,r4 ;r4 -> i/o vector ; call $$getc ;Get a character ; ; RSX: ; mov #iov,r4 ;r4 -> i/o vector ; mov #buffer,r0 ;r0 -> buffer ; mov buflen,r1 ;r1 := max. buffer size ; call $$get ;Get a record ; ; VF$EOF and/or VF$ERR are set on error or end of file. ; r0 := actual record length, -1 on error or end of file. ; ; Other registers preserved. ; ; RT11: ; mov #blknbr,r0 ;r0 := block to read ; call $$get ;Get a block ; ; VF$EOF and/or VF$ERR are set on error or end of file. ; r0 is zero if success, -1 on error or end of file. ; ; Other registers preserved. ; ; ; Description ; ; $$getc is the internal "get a byte" routine. The ; next byte in the indicated file is returned in r0. ; All other registers are preserved. ; ; $$get is the internal "get a record" routine. Note that ; the maximum record size (r1) is only needed on RSX. It is fixed ; at 512. bytes on RT11. ; ; If the file is defined as "stream" (the "n" flag was not set ; when the file was opened using fopen()), the end of the line ; will be represented by the newline (\n) character, and ; NULL's will be removed. ; ; Bugs ; ; In stream files in RT11, all carriage-returns are removed. ; It would be more correct to remove carriage-return from ; or sequences. ; ; RT11 uses .ttyin to read from the user command terminal. ; It would be more correct to use .gtline as this would allow ; indirect command file tracking. ; ;- ; ; Edit history ; 000001 18-Mar-80 MM Conversion for the newer library ; 000002 27-Mar-80 MM Merged libraries. ; 000003 14-May-80 MM Dropped NULLs from stream files. ; 000004 23-Jun-80 MM Flush stdout for RT11 ; 000005 27-Jun-80 MM No more C-bit hackery, RT11 $$get returns 0 if ok ; .if ne rsx ;02 .mcall GET$ .psect .prog. $$getc:: mov V$UGET(r4),r0 ;Is there an unget character ;04 bmi 10$ ;No mov #-1,V$UGET(r4) ;Make unget character go away return ; 10$: bit #VF$UBF,(r4) ;Is this an unbuffered stream beq 20$ ;No bis #VF$ERR,(r4) ;Yes, set error br geterr ; 20$: bit #VF$EOR,(r4) ;Any more stuff bne geterr ;Br if not 30$: dec V$BCNT(r4) ;Get a byte from the line bmi 40$ ;Br if none movb @V$BPTR(r4),r0 ;Grab it inc V$BPTR(r4) ;Fix pointer bic #177400,r0 ;Mask number to 8 bits return ; 40$: mov V$RBUF(r4),r0 ;Address of record buffer mov r0,V$BPTR(r4) ;Buffer address mov V$RBSZ(r4),r1 ;Size of record buffer call $$get ;Get record mov r0,V$BCNT(r4) ;Number of bytes in record bge 30$ ;Try again ;05 geterr: mov #-1,r0 ;Return EOF return ; ; ; ; Get record. ; r0 = buffer address. ; r1 = max record size. ; ; Sets IOV on EOF or error (IOV VF$EOF and/or VF$ERR set) ; Record length in r0 -- -1 if error ; $$get:: mov r0,-(sp) ;Save registers mov r1,-(sp) ; mov r2,-(sp) ; mov r3,-(sp) ; mov r0,r2 ;r2 -> buffer ; ; Note: the record buffer address is at 6(sp) ; ; Record devices. ; bit #VF$REC,(r4) ;Record device? beq 10$ ;Br if not ; ; Standard input/standard output ; magic on a tty. ; cmp r4,stdin ;Are we reading standard input? bne 10$ ;No bit #VF$TTY,(r4) ;Yes, is it a TTY? beq 10$ ;No mov stdout,r0 ;Is the standard output bit #VF$TTY,(r0) ;Also a TTY? beq 10$ ;No mov r4,-(sp) ;Yes, flush out the mov r0,r4 ;Standard output call $$flsh ;This is all in the mov (sp)+,r4 ;Prompting ; ; Read record ; 10$: mov r4,r0 ;R0 must point to FDB add #V$FDB,R0 ;Now it does GET$ r0,r2,r1 ;Get the record bcc 20$ ;No problem bis #VF$EOF,(R4) ;Trouble, force end of file cmpb #IE.EOF,F.ERR+V$FDB(R4) ;Was it end of file? beq getxit ;Yes, exit bis #VF$ERR,(R4) ;No, real trouble br getxit 20$: mov V$FDB+F.NRBD(R4),R0 ;R0 := actual byte count ; ; Clean up the record (thank's to RSX cleverness) ; Enter with R0 := actual byte count getfix: bit #VF$NOS,(r4) ;Stream file? bne getxit ;If not, don't do newline stuff. mov r0,r1 ;Copy actual byte count add r2,r1 ;R1 -> record end movb #12,(r1)+ ;tack on a line feed inc r0 ;Count it, too ; ; Erase CR from CR/LF and LF/CR sequences. ; R0 := actual byte count ; R1 -> input buffer end ; R2 -> input buffer current byte ; R3 -> output buffer current byte ; 6(SP) input buffer start (r0 at call to $get) ; mov r2,r3 ;Start of output record 10$: cmp r2,r1 ;At the end? bhis getxit ;Exit if so tstb (r2) ;Null? beq 30$ ;Skip it if so. cmpb (r2),#15 ;Carriage return? bne 20$ ;No, go copy it cmpb 1(r2),#12 ;Carriage return, is next LF? beq 30$ ;Yes, ignore carriage return cmpb r3,6(sp) ;At start of output line? blos 20$ ;Yes, keep carriage return cmpb -1(r3),#12 ;No, is previous LF? beq 30$ ;Yes, ignore Carriage return ; 20$: movb (r2)+,(r3)+ ;Copy the byte br 10$ ;And get another ; 30$: inc r2 ;Skip over this byte dec r0 ;Erase from count, too br 10$ ;And get another ; ; Exit from $$get ; getxit: mov (sp)+,r3 ;Restore mov (sp)+,r2 ;Registers mov (sp)+,r1 ;R3 - R1 tst (sp)+ ;Keep actual byte count bit #VF$EOR,(r4) ;Error or end of file? beq 10$ ;Neither, exit mov #-1,r0 ;Yes, signal error ;05 10$: return ;and exit .iff ;02+ .MCALL .TTYIN CR = 15 .psect .data. REAERR: .BYTE E$$EOF, E$$ERR, E$$FAT .psect .prog. ; ; Enter with r4 -> iov. ; Return, all registers preserved. ; $$GETC:: MOV V$UGET(R4),R0 ; Is there an unget character BMI GETBYT ; Nope MOV #-1,V$UGET(R4) ; Yes, not any more, though RTS PC ; Back to the caller GETBYT: cmp r4,stdin ;Are we reading standard input? ;04+ bne 10$ ;No bit #VF$TTY,(r4) ;Yes, is it a TTY? beq 10$ ;No mov stdout,r0 ;Is the standard output bit #VF$TTY,(r0) ;Also a TTY? beq 10$ ;No mov r4,-(sp) ;Yes, flush out the mov r0,r4 ;Standard output call $$flsh ;This is all in the mov (sp)+,r4 ;Prompting 10$: ;04- BIT #VF$TTY,(R4) ; Is it a tty? BEQ GETFIL ; Br if not .TTYIN ; R0 = input byte CMP R0,#32 ; see if byte is "^Z" (EOF) BEQ 20$ ; Return EOF if it is CMP R0,#3 ; See if byte is CTRL/C BNE GETDON ; return R0 if not ; 20$: CLR R0 ; Error code = 0 BR GETEOF ; CTRL/C = EOF ; ; Get a byte from a file ; GETFIL: MOV R1,-(SP) ; Save work register MOV R4,R1 ; R1 -> IOV ADD #V$BCNT,R1 ; R1 -> io_bcnt DEC (R1)+ ; remaining byte count BGE 20$ ; branch if buffer not empty MOV V$BNBR(R4),R0 ; Get block to read CALL $$GET ; Go get it. TST R0 ; Success if zero in r0 BEQ 10$ ; Go on if ok MOV (SP)+,R1 ; Nope, restore r1 RTS PC ; And exit ; 10$: DEC -2(R1) ; $$get sets byte count to 512. ; 20$: CLR R0 ; return a byte to caller BISB @(R1)+,R0 ; Make sure it's unsigned INC -(R1) ; bump nextp MOV (SP)+,R1 ; Restore R1 ; ; Hack CRLF if needed -- Note: all carriage returns are removed. ; GETDON: BIT #VF$NOS,(R4) ; Not a stream file? BNE 10$ ; Br if binary CMP R0,#CR ; Stream, carriage return? BEQ GETBYT ; Restart if so TST R0 ; Not , is it ? ;03 BEQ GETBYT ; Restart if so ;03 10$: RTS PC ; Return to the caller ; ; Get one block ; $$GET:: BIT #VF$TTY,(R4) ; we're called for the tty BNE 10$ ; we just exit. MOV R0,V$BNBR(R4) ; Fseek needs to refresh block number CLR -(SP) ; make an arg block for .READW MOV #256.,-(SP) ; so the next block can be read MOV R4,-(SP) ; Get address of ADD #V$BUFF,(SP) ; Block buffer MOV R0,-(SP) ; Add the block number MOV #10 * 400,-(SP) ; .READW function BISB V$LUN(R4),(SP) ; channel MOV SP,R0 ; R0 -> arg block EMT 375 ; .READW BCS 20$ ; branch if the read failed MOV R4,R0 ; Success, get another pointer ADD #V$BCNT,R0 ; R0 -> iov_bcnt MOV #512.,(R0)+ ; 512 bytes are now left in buffer CMP (SP)+,(SP)+ ; pop some of arg block MOV (SP)+,(R0)+ ; nextp INC (R0) ; bump blockno, it points to "next" CMP (SP)+,(SP)+ ; pop rest of arg block ; 10$: CLR R0 ; Success BIC #VF$BZY,(R4) ; Buffer non-busy RTS PC ; And exit 20$: ADD #5*2,SP ; Clear the stack on errors MOVB @#52,R0 ; Get the error code ; GETEOF: ; Enter with MOV ERR_CODE,R0/BR GETEOF BEQ 10$ ; Br if end of file BIS #VF$ERR,(R4) ; Set error bit 10$: BIS #VF$EOF,(R4) ; Always set eof bit MOVB REAERR(R0),$$FERR ; Save the error code MOV #-1,R0 ; Return EOF RTS PC ; And exit .endc ;02- .END