; ~!eee edi03.mac ; ~r taco. .TITLE bEDI03 .IDENT /X01.B/ .NLIST BEX .ENABL LC ; ; EDITOR (TEMP FILE VERSION) ; ; VERSION X01.b ; ; DAVID G. CONROY 10-APR-78 ; ; modified by eric b. levy to allow for gigantic files ; (this version should only be used when necessary) ; ; ; The seek pointer was 15bits (15-1) and 1bit (0) ; disk wd addr global-bit ; ; this module modified that to be: ; ; ; x xxx xxx xxx xxb bbg ; ; where the x's are the disk address, The b's are the byte number ; with 5 zeros assumed to be on the right (this technique is similar ; to the pdp-11 memory management sceme). The g is the global bit ; and when used to compute the disk address is always zeroed. ;. ; This makes it necessary to store the text strings on 64 byte ; boundaries and thus makes for larger temp files and slower ; access to text. However, it successfully read 20,000 lines of ; assembly text before it ran out of temp file space. I think ; That it will handle 1.8 million bytes in the temp file. Remember ; that every operation that requires newly formed text (even ; a substitute cmd) adds that text to the end of the buffer. This ; means that inserting 1 char on every line in a 10000 line file ; is equivalent to reading the file twice. ; .GLOBL APPEND .GLOBL GETTY .GLOBL DELETE .GLOBL READIN .GLOBL READN2 .GLOBL FILE .GLOBL GETLIN .GLOBL PUTLIN .GLOBL FDB .GLOBL TMP .GLOBL TPTR .MCALL CALL .MCALL CALLR .MCALL RETURN .MCALL OPEN$R .MCALL CLOSE$ .MCALL GET$S .MCALL PUT$S .MCALL READ$ .MCALL WRITE$ .MCALL WAIT$ .MCALL FDBDF$ .MCALL NMBLK$ .MCALL FDAT$A .MCALL FDOP$A .MCALL FDRC$A .MCALL FSRSZ$ .MCALL CSI$ .MCALL CSI$1 .MCALL CSI$2 .mcall qiow$,dir$ FSRSZ$ 1 CSI$ ; ; EQUIVALENCES ; BUFFER HEADER ; BLOCK = 0 ;BLOCK NUMBER UPD = 2 ;UPDATE FLAG BUFFER = 4 ;START OF 512 BYTE BUFFER exsize=100. ;extend size crsize=100. ;create size (of temp file) ; ; LOCAL DATA ; rattr: qiow$ io.rat,2,7,,,,<0,alist> ;read attributes alist: .byte -2,2 ;read protection of input file .word protec ;and put it here mes1: .asciz /Line to long - truncating line # / .even $byte: .word 0 $block: .word 0 FC: .BLKW 1 ;COUNT FOR READIN FP: .BLKW 1 ;POINTER FOR READIN FNR: .BLKW 1 ;NUMBER OF LINES FOR READIN CSI: .BLKB C.SIZE ;CSI WORK BLOCK FDB: FDBDF$ ;FILE I/O FDB FDAT$A R.VAR,FD.CR FDOP$A 2,CSI+C.DSDS,DFNB TMP: FDBDF$ ;TEMP FILE FDB FDAT$A R.FIX,,512.,-crsize,-exsize ;IS THIS REQUIRED? (yes) FDRC$A FD.RWM FDOP$A 3 DFNB: NMBLK$ ,,,SY ;DEFAULT FILENAME BLOCK ; ; THESE CELLS ARE USED BY THE TEMPFILE ROUTINES. ; $tptr:: TPTR: .WORD 0 ;NEXT TEMP FILE BYTE. IBUF: .WORD -1 ;BUFFER 1 .WORD 0 ; .BLKB 512. ; OBUF: .WORD -1 ;BUFFER 2 .WORD 0 ; .BLKB 512. ; BIOVBN: .WORD 0,0 ;VIRTUAL BLOCK NUMBER BIOS: .BLKW 2 ;STATUS BLOCK ;+ ; ** APPEND - APPEND TEXT ; ; INPUTS: ; R4=ADDRESS OF ROUTINE TO CALL TO GET LINES ; R5=ADDRESS TO APPEND AFTER ; ; USES: ; ALL ;- APPEND: MOV R5,DOT ;RESET '.' AT THE BEGINNING 10$: CALL (R4) ;GET A LINE BCS 50$ ;BR IF NONE AVAILABLE 15$: MOV TOP,R1 ;TEST IF ROOM FOR A LINE SUB #2,R1 ; CMP DOL,R1 ; BLO 20$ ;WE HAVE ROOM call morecore ;allocate more memory br 15$ ;try again 20$: CALL PUTLIN ;SAVE THE LINE IN THE TEMP FILE MOV R0,R2 ;SAVE SEEK POINTER ADD #2,DOL ;FIX '$' MOV DOL,R0 ;SET UP TO FIX TEXT POINTERS MOV R0,R1 ; ADD #2,R1 ; ADD #2,DOT ; 30$: CMP R0,DOT ;MAKE ROOM FOR NEW LINE BLOS 40$ ; MOV -(R0),-(R1) ; BR 30$ ; 40$: MOV R2,@DOT ;STORE NEW LINE SEEK ADDRESS BR 10$ ;GO AGAIN 50$: RETURN ;FINIS ;+ ; ** GETTY - GET LINES FROM THE TTY ; ; THIS ROUTINE READS A LINE FROM THE TTY AND STUFFS IT INTO THE LINE ; BUFFER. IT RETURNS WITH THE C BIT SET ON EOF, WHICH IS JUST A LINE ; CONSISTING OF A SINGLE '.'. ; IT ALSO CHECKS FOR GLOBAL EOF AND MAKES SURE THE END OF FILE GETS ; RETURNED AT THE RIGHT TIME. ; ; OUTPUTS: ; LBUF1=THE LINE ; C=0 IF ALL OK ; C=1 IF NO MORE LINES ; ; USES: ; R0, R1 ;- GETTY: MOV #LBUF1,R1 ;GET POINTER TO LINE BUFFER CALL GETC ;GET CHARACTER FROM THE TTY CMP R0,#EOF ;GLOBAL EOF BNE 20$ ;NO SEC ;YES, RETURN TEXT EOF BR 50$ ; 10$: CALL GETC ;GET A CHARACTER CMP R0,#EOF ;MAP EOF TO NEWLINE BNE 20$ ; MOV #NL,R0 ; 20$: CMP R1,#LBUF1+LBS-1 ;WILL IT FIT BHIS 30$ ;NO, IGNORE MOVB R0,(R1)+ ; 30$: CMP R0,#NL ;CONTINUE UNTIL NEWLINE BNE 10$ ; CLRB (R1) ;MAKE LINE ASCIZ CMP R1,#LBUF1+2 ;SEE IF TEXT EOF BHI 40$ ; CMPB LBUF1,#'. ; BNE 40$ ; SEC ;WE HAVE EOF BR 50$ ; 40$: CLC ;WE HAVE A LINE 50$: RETURN ;FINIS ;+ ; ** DELETE - DELETE TEXT FROM BUFFER ; ; INPUTS: ; ADR1=FIRST LINE TO DELETE ; ADR2=LAST LINE TO DELETE ; ; USES: ; ALL ;- DELETE: MOV ADR1,R0 ;GET POINTER TO THE START MOV ADR2,R1 ;GET POINTER JUST PAST THE END TST (R1)+ ; 10$: CMP R1,DOL ;SCRUNCH BHI 20$ ; MOV (R1)+,(R0)+ ; BR 10$ ; 20$: TST -(R0) ;RESET LAST LINE MOV R0,DOL ; MOV ADR1,DOT ;SET DOT JUST PAST THE DELETION CMP DOT,DOL ;UNLESS ITS OUT OF THE BUFFER BLOS 30$ ; MOV DOL,DOT ;WHEN YOU SET IT TO THE LAST LINE 30$: RETURN ; ;+ ; ** READIN - READ FROM A FILE ; ; THIS ROUTINE IS USED BY STARTUP, THE E COMMAND AND THE R COMMAND TO ; READ TEXT FROM A FILE. IT OPENS THE FILE, DOES THE APPEND AND PUTS ; OUT THE COUNT (IF NOT IN A GLOBAL) ALL BY ITSELF. ; ; INPUTS: ; R5=WHERE TO APPEND ; ; OUTPUTS: ; FN=THE FILE NAME (FOR E COMMAND) ; ; USES: ; ALL ;- READIN: CALL FILE ;GET FILE NAME READN2: OPEN$R #FDB ;OPEN IT FOR READING Bcc 5$ ;?8 ON OPEN ERRORS jmp ERR8 ;?8 ON OPEN ERRORS 5$: dir$ #rattr ;get protection of file into 'protec' CLR FNR ;INITIALISE CLR FC ; MOV #20$,R4 ;ROUTINE CALL APPEND ;APPEND THE TEXT TST GUPTR ;IN A GLOBAL BNE 10$ ;YES, DON'T PRINT COUNT MOV FNR,R1 ;OUTPUT RECORD COUNT CALL TTYNUM ; CALL TTYNL ; 10$: RETURN ;FINIS ; ; FOR REASONS BEYOND THE UNDERSTANDING OF MEAGER MORTALS, THERE ARE ; MANY TYPES OF ASCII FILES. ONE OF THEM HAS IMBEDDED SLEWS. OUTPUT ; OF A PIP /LI SWITCH IS ONE OF THESE. THIS ROUTINE TRIES TO INPUT ; THESE FILES CORRECTLY. ; ; YES, IT IS STUPID. ; 20$: MOV #LBUF1,R1 ;GET POINTER TO LINE BUFFER 30$: CALL 70$ ;GET A CHARACTER BCS 40$ ;BR IF NONE TO GET CMP R1,#LBUF1+LBS-2 ;DOES IT FIT Blo 35$ ;yes movb r0,(r1)+ ;store current and terminate line mov #nl,r0 ; 35$: MOVB R0,(R1)+ ;SAVE THE CHARACTER CMP R0,#NL ;CONTINUE UNTIL NEWLINE BNE 30$ ; 40$: CMP R1,#LBUF1 ;DID I GET ANYTHING BEQ 50$ ;NO, EOF INC FNR ;COUNT UP A LINE CLRB (R1) ;MAKE ASCIZ CLC ;GOOD RETURN BR 60$ ; 50$: SEC ;EOF RETURN 60$: RETURN ; 70$: DEC FC ;ANY CHARACTERS IN BUFFER BPL 90$ ;BR IF YES GET$S #FDB,#LBUF2,#LBS-1 ;READ A LINE FROM THE FILE Bcc 75$ ;ERROR, MAYBE EOF cmpb f.err(r0),#-40. ;is it record length error bne 100$ ;no, not recoverable then mov r0,-(sp) ;save mov r1,-(sp) ;save mov #mes1,r0 ;addr of message call ttystr ;write it out mov dot,r1 ;compute the sub zero,r1 ;line number asr r1 ;and put inc r1 call ttynum ;it out also call ttynl ;new line output mov (sp)+,r1 ;restore mov (sp)+,r0 ;restore mov #lbs-2,f.nrbd(r0) ;set to longest length 75$: MOV F.NRBD(R0),R0 ;GET RECORD SIZE call nonull ;change all nulls to 177's BITB #FD.CR!FD.FTN,FDB+F.RATT ;DO WE NEED TO ADD NEWLINE BEQ 80$ ;NO MOVB #NL,LBUF2(R0) ;APPEND THE NEWLINE INC R0 ; 80$: MOV R0,FC ;SET COUNT MOV #LBUF2,FP ;SET POINTER BR 70$ ; 90$: MOVB @FP,R0 ;GET CHARACTER FROM BUFFER INC FP ; ;; BIC #177600,R0 ;MAKE 7 BIT CMP R0,#CR ;DELETE CARRIAGE RETURNS BEQ 70$ ; CLC ;GOOD RETURN BR 110$ ; 100$: CMPB F.ERR(R0),#IE.EOF ;END OF FILE BNE ERR10 ;NO CLOSE$ ;CLOSE THE FILE SEC ;EOF RETURN 110$: RETURN ; ERR10: mov f.err+fdb,-(sp) ;save error code CLOSE$ #fdb ;CLOSE THE FILE mov (sp)+,f.err+fdb ;restore for o? reporting MOV #10.,R1 ;GIVE ERROR JMP ERROR ; ERR8: MOV #8.,R1 ;FILE ACCESS ERRORS JMP ERROR ; ;+ ; ** FILE - ACCESS A FILE ; ; THIS ROUTINE GETS A FILE NAME AND SETS UP THE DSPT IN THE CSI WORK ; BLOCK. THE FILE IS NOT OPENED. ; IT ALSO SAVES THE FILE NAME IN A BUFFER SO THAT THE E COMMAND CAN ; COPY THE FILE NAME INTO THE SAVED FILE NAME BUFFER. ; ; OUTPUTS: ; FN=FILE NAME STRING ; ; USES: ; R0, R1 ;- FILE: CALL GETC ;MAKE FIRST CHAR AFTER CMD A BLANK (SAFETY) CMP R0,#' ;THIS MEANS EX OR RXXX IS NO GOOD BEQ 10$ cmp r0,#nl ;new line ok bne 5$ mov #r0,peek ;put back whatever it was br 10$ 5$: MOV #2,R1 ;ERROR 2, BAD COMMAND JMP ERROR ;AND GET OUT 10$: CALL GETC ;GET THE FILE NAME CMP R0,#' ; BEQ 10$ ; MOV #FN,R1 ;POINT AT FILE NAME BUFFER 20$: CMP R0,#NL ;STOP ON NL OR EOF BEQ 30$ ; CMP R0,#EOF ; BEQ 30$ ; CMP R1,#FN+FNS-1 ;DOES IT FIT BHIS ERR8 ;NO CMP R0,#'a ;IS THE CHARACTER LOWER CASE BLO 22$ ;NO CMP R0,#'z ;PERHAPS BHI 22$ ;NO SUB #' ,R0 ;MAP FOR V02 22$: MOVB R0,(R1)+ ;SAVE IT CALL GETC ;GO FOR MORE BR 20$ ; 30$: CMP R1,#FN ;IS THERE A NAME AT ALL BHI 50$ ;YES TSTB SFN ;SAVED NAME BEQ ERR8 ;NO MOV #SFN,R0 ;YES, USE IT 40$: MOVB (R0)+,(R1)+ ; BNE 40$ ; DEC R1 ; 50$: CLRB (R1) ;INSURE NAME IS ASCIZ MOV #CSI,R0 ;CHOP UP COMMAND LINE SUB #FN,R1 ;SET DESCRIPTOR IN CSI BLOCK MOV R1,C.CMLD(R0) ; MOV #FN,C.CMLD+2(R0); CSI$1 ;SYNTAX CHECK BCS ERR8 ;ERROR CSI$2 ,OUTPUT ;BUILD DSPT BCS ERR8 ;ERROR RETURN ;DONE ;+ ; ** GETLIN - GET LINE FROM TEMPFILE ; ; THIS ROUTINE READS A LINE OF TEXT FROM THE TEMPFILE. THE STARTING ; LOCATION OF THE LINE IS SPECIFIED; THE END OF THE LINE IS MARKED ; BY A NULL BYTE. ; ; INPUTS: ; R0=SEEK ADDRESS. ; ; USES: ; NONE ;- GETLIN: MOV R4,-(SP) ;SAVE REGISTERS MOV R3,-(SP) ; MOV R2,-(SP) ; MOV R1,-(SP) ; MOV R0,-(SP) ; call expand mov $byte,r2 mov $block,r1 CALL GETBLK ;YANK FIRST BLOCK MOV #LBUF1,R4 ;POINT AT BUFFER 10$: CALL GETB ;GET BYTE MOVB R0,(R4)+ ;SAVE IN THE BUFFER AND BNE 10$ ;CONTINUE UNTIL NULL BYTE MOV (SP)+,R0 ;RETURN MOV (SP)+,R1 ; MOV (SP)+,R2 ; MOV (SP)+,R3 ; MOV (SP)+,R4 ; RETURN ; ; ; GET BYTE. ; R1=BLOCK NUMBER (NEXT BLOCK) ; R2=BYTE NUMBER ; R3=BUFFER POINTER ; GETB: CMP R2,#1000 ;GOT ALL THE BYTES IN THIS BLOCK BLO 10$ ;NOT YET CALL GETBLK ;READ IN A BLOCK AND CLR R2 ;START AT BYTE 0 10$: MOV R2,R0 ;PICK UP THE BYTE ADD R3,R0 ; ADD #BUFFER,R0 ; INC R2 ;NEXT CHARACTER. MOVB (R0),R0 ; RETURN ;RETURN ;+ ; ** PUTLIN - PUT LINE ONTO TEMPFILE ; ; INPUTS: ; LBUF1=ASCIZ LINE TO PUT OUT ; ; OUTPUTS: ; R0=SEEK ADDRESS OF THE LINE ;- PUTLIN: MOV R4,-(SP) ;SAVE REGISTERS MOV R3,-(SP) ; MOV R2,-(SP) ; MOV R1,-(SP) ; MOV TPTR,R1 ;GET SEEK ADDRESS MOV R1,-(SP) ;FOR EVENTUAL RETURN mov #lbuf1,r0 10$: tstb (r0)+ ;get line len bne 10$ sub #lbuf1,r0 add #77,r0 bic #77,r0 ;round up to 64 byte boundary call newptr mov r1,tptr ;set up new pointer for next time mov (sp),r0 ;get the old ptr again call expand mov $block,r1 mov $byte,r2 beq 30$ ;skip if beg of block CALL GETPUT ;READ OLD BLOCK IN BR 40$ ; 30$: CALL GETMTY ;GET EMPTY BLOCK ; ; COPY THE LINE TO THE FILE. ; 40$: MOV #LBUF1,R4 ;POINT AT THE LINE 50$: MOVB (R4)+,R0 ;COPY TO THE FILE BEQ 60$ ;DONE CALL 70$ ; BR 50$ ; 60$: CALL 70$ ;PUT OUT THE FINAL NULL MOV (SP)+,R0 ;RETURN SEEK ADDRESS MOV (SP)+,R1 ; MOV (SP)+,R2 ; MOV (SP)+,R3 ; MOV (SP)+,R4 ; RETURN ; ; ; PUT BYTE. ; R0=BYTE R1=BLOCK NUMBER R2=BYTE NUMBER R3=BUFFER ; 70$: MOV R0,-(SP) ;SAVE CHARACTER CMP R2,#1000 ;FULL BLOCK BLO 80$ ;NO INC R1 ;YES, GET NEW EMPTY BLOCK CALL GETMTY ; CLR R2 ;AND GO BACK TO BYTE 0 80$: MOV R2,R0 ;COMPUTE LOCATION OF THE BYTE ADD R3,R0 ; ADD #BUFFER,R0 ; INC R2 ; MOVB (SP)+,(R0) ;STORE THE BYTE DOWN RETURN ;DONE ;+ ; ** GETBLK - GET BLOCK FOR READING ; ; INPUTS: ; R1=DESIRED BLOCK ; ; OUTPUTS: ; R1=OLD R1+1 (NEXT BLOCK) ; R3=BUFFER POINTER ; ; USES: ; R0 ;- GETBLK: MOV #OBUF,R3 ;TRY OUTPUT BLOCK BUFFER CMP R1,BLOCK(R3) ;MATCH BEQ 10$ ;FOUND IT MOV #IBUF,R3 ;TRY INPUT BLOCK BUFFER CMP R1,BLOCK(R3) ;MATCH BEQ 10$ ;FOUND IT CALL BREAD ;READ IN BLOCK 10$: INC R1 ;PREPARE FOR NEXT READ RETURN ; ;+ ; ** GETPUT - GET BLOCK FOR WRITING ; ; INPUTS: ; R1=DESIRED BLOCK ; ; OUTPUTS: ; R3=BUFFER POINTER ; ; USES: ; R0 ;- GETPUT: MOV #IBUF,R3 ;TRY INPUT BUFFER CMP R1,BLOCK(R3) ;MATCH BEQ 10$ ;YES MOV #OBUF,R3 ;TRY OUTPUT BUFFER CMP R1,BLOCK(R3) ;MATCH BEQ 10$ ;YES CALL BREAD ;READ IN THE BLOCK 10$: INC UPD(R3) ;SET UPDATED FLAG RETURN ;DONE ;+ ; ** GETMTY - GET AN EMPTY BLOCK ; ; INPUTS: ; R1=BLOCK NUMBER TO STORE IN HEADER ; ; OUTPUTS: ; R3=BUFFER POINTER ; ; USES: ; R0 ;- GETMTY: MOV #IBUF,R3 ;TRY INPUT BUFFER CMP R1,BLOCK(R3) ;MATCH BEQ 10$ ;YES MOV #OBUF,R3 ;TRY OUTPUT BUFFER CMP R1,BLOCK(R3) ;MATCH BEQ 10$ ;YES CALL BWRITE ;WRITE OUT OLD OBUF MOV R1,BLOCK(R3) ;RESET BLOCK NUMBER 10$: INC UPD(R3) ;SET UPDATE FLAG AND RETURN ;RETURN ;+ ; ** BREAD - READ TEMPFILE ; ; INPUTS: ; R1=BLOCK NUMBER ; R3=BUFFER TO USE ; ; USES: ; R0 ;- BREAD: CALL BWRITE ;WRITE OUT IF UPDATED MOV R1,BLOCK(R3) ;RESET BLOCK NUMBER CLR UPD(R3) ;RESET UPDATE FLAG MOV R1,BIOVBN+2 ;GET RSX BLOCK NUMBER INC BIOVBN+2 ; ADD #BUFFER,R3 ;GET ACTUAL BUFFER ADDRESS READ$ #TMP,R3,#512.,#BIOVBN,,#BIOS ;READ TEMPFILE WAIT$ ; CMPB BIOS,#IS.SUC ;WAS THE READ GOOD BNE BERROR ;NO SUB #BUFFER,R3 ;FIX BUFFER ADDRESS RETURN ; ;+ ; ** BWRITE - WRITE TEMPFILE ; ; INPUTS: ; R3=BUFFER POINTER ; ; USES: ; R0 ;- BWRITE: TST UPD(R3) ;NEED TO WRITE BEQ 10$ ;NO MOV BLOCK(R3),BIOVBN+2 ;GET RSX BLOCK NUMBER INC BIOVBN+2 ; ADD #BUFFER,R3 ;GET ACTUAL BUFFER ADDRESS WRITE$ #TMP,R3,#512.,#BIOVBN,,#BIOS ;WRITE TEMPFILE WAIT$ ; CMPB BIOS,#IS.SUC ;WAS THE WRITE GOOD BNE BERROR ;NO SUB #BUFFER,R3 ;FIX ADDRESS OF BUFFER CLR UPD(R3) ;CLEAR UPDATE FLAG 10$: RETURN ;DONE ;+ ; ** BERROR - TEMPFILE I/O ERROR ; ; ALL TEMPFILE I/O ERRORS COME HERE. SOMEDAY SOME CLEVER RECOVERY ; SCHEME MAY BE ADDED. ;- BERROR: MOV #-1,BLOCK-BUFFER(R3) ;BAD BLOCK NUMBER CLR UPD-BUFFER(R3) ;NO UPDATE MOV #12.,R1 ;?12 JMP ERROR ; ;+ ; ; expand - expands a 16 bit pointer into a byte number ; and a block number ; input ; r0=seek address ; output ; $byte=byte number ; $block=block number ;- expand: mov r0,-(sp) mov r1,-(sp) mov r2,-(sp) mov r0,r1 ;byte mov r0,r2 ;block bic #177761,r1 ash #5,r1 mov r1,$byte ;output byte number clc ror r2 asr r2 asr r2 asr r2 mov r2,$block ;output block number mov (sp)+,r2 mov (sp)+,r1 mov (sp)+,r0 rts pc ;+ ; ; newptr - build new seek address or jmp to error ; ; input r0=length of string (rounded up to 64. byte boundary) ; r1=old pointer ; ; output ; r1=new pointer if ok ; else jmp to error with code 12. ;- newptr: mov r0,-(sp) clc ror r0 ror r0 ror r0 ror r0 ror r0 bic #174000,r0 ;clean up the shift right 5 operation add r0,r1 bcc 10$ ;skip if no overflow mov #12.,r1 ;temp file overflow (super big file) jmp error 10$: mov (sp)+,r0 rts pc .END