; ; ************************** ; * * ; * CO-ED: * ; * * ; * A Ripsoft Product * ; * * ; * ( C ) * ; * * ; ************************** ; TRUE * %0 FALSE * %1 BBC * TRUE SYSTEM * FALSE [ SYSTEM COED ORG $C000 ] [ BBC COED ORG $1900 ] ; (In the explanations below, 'upper' and 'lower' correspond to ; the notion of a file as a long sheet of paper laid out in front ; of you - not as the addresses where the file is stored.) ; As a first approximation, this editor can be considered to ; work on files entirely in store. The file is stored as two parts: ; the top part being all the text to the left and above the cursor, ; and the bottom part being the text to the right of and below the ; cursor. Moving around the file consists of copying text across ; the gap between the two parts. The overhead of this technique is ; far outweighed by the simplicity of insertion and deletion it ; offers. ; In fact, the file is not necessarily completely in store: ; if the file fits in the space available, then all is well; if not, ; then the ends of the top and bottom parts (the ends farthest from ; the gap) are slaved to disc. This is transparent to all but a little ; of the editor code, as it is implemented 'behind the scenes'. ; There are various pointers to places in the file image. ; These are explained below. ; FBEG - the start of the file (inclusive) ; FEND - the end of the file (exclusive) ; LBEG - the start of the current line (inclusive) ; LEND - the end of the current line (points to the CR at the end) ; FP - the File Pointer. - the character under the cursor ; PP - the Previous Pointer - the last character in the ; top part of the file (exclusive) ; SBEG - the start of real memory ; SLIM - the end of real memory ; (SBEG and SLIM correspond roughly to FBEG and FEND) ; The actual implementation of slaving to disc is as follows: ; When the size of the file increases such that one of the two parts, ; (say the top part) is too large for memory and has to be expelled, ; it is written to disk on a push-down stack of fixed length blocks. ; (These blocks do not correspond in any way to lines, or other file ; structures - they are merely convenient sizes to write to disk.) ; The pointers to all positions in the top part of the file are ; then moved back by the blocksize. E.g. PP becomes PP - 256. ; The file thus appears to have moved up in memory by 256 locations. ; The part of the file starting at FBEG is actually on disc, but ; appears to be in memory. FBEG therefor points to the location ; 256 bytes before SBEG - the real start of store. ; Now, when an access is made which passes SBEG in the upward ; direction, it is trapped by the 'behind the scenes' routines, ; which move the top part of the file back down again and read in ; the appropriate block from file. The pointers are also relocated. ; It may help to explain the pointers graphically: ; ; O N E CR T W . . . O CR N E X T CR . . CR L A S T CR ; | | | | | | ; F L P F L F ; B B P P E E ; E E N N ; G G D D ; ; ; To cut down the number of unseen tests for data on disc, ; everything between LBEG and LEND is always assumed to be in store. ; The code is arranged so that only LBEG and LEND creep past the ; store-limit boundaries - and so the slaving tests therefor only ; need to compare LBEG with SBEG and LEND with SLIM. PP and FP ; never need to be checked as they are always between LBEG and LEND. ; ; (The extra s are for bouncing off when scanning ; through data looking for line starts/ends when the cursor ; is at the beginning or the end of the file. Their use will ; be more obvious later on...) ; ; ; ; +---------------------------------+ ; FBEG -> | | ; | <- 256 bytes -> +------------+ ; +--------------------+ <- SBEG | ; | | ; | | ; LBEG -> | +----------------+ ; +----------------+ PP + ; ; {GAP} ; ; + FP +-----------+ ; +----------------+ CR| <- LEND ; | | ; | CR| ; +---------------------------------+ <- FEND, SLIM ; ; Similarly SLIM works with FEND as SBEG does with FBEG ; (Because the two ends of the file are not synchronised, there ; are two files to which data is slaved - one for data popping up ; from the top of the file, and one for data dropping down off ; the bottom. Both are implemented as push down stacks with the ; unit size being one block {currently pitched at 256 bytes}) [ BBC OSWRCH * $FFEE OSRDCH * $FFE0 OSFIND * $FFCE OSBGET * $FFD7 OSBYTE * $FFF4 ] [ SYSTEM OSWRCH * $FFF4 OSRDCH * $FFE3 OSFIND * $FFCE OSBGET * $FFD4 ] Gap * %512 Blocksize * %256 XMin * %0 XMax * %79 YMin * %0 YMax * %31 ^ $20 ; Base of Page-0 variables [ BBC HIMEM # %2 ] PP # %2 FP # %2 LBEG # %2 LEND # %2 FBEG # %2 FEND # %2 SBEG # %2 SLIM # %2 VBEG # %2 VLIM # %2 CURRENT # %2 PAGE # %2 Vgap # %1 PTR # %2 RETN # %2 SWITCH # %2 X # %2 Y # %2 XX # %2 YY # %2 ScrollOneShot # %1 TEMP # %1 SYM # %1 INFILE # %1 ; Input file ID DPEND # %1 ; Data Pending flag JSR Init GETCHAR JSR DispPage JSR OSRDCH CMPIM %13 BEQ RETURN CMPIM %127 BEQ RUBOUT CMPIM %128 BCC DATAVAL CMPIM %144 BCC VAL CMPIM %160 BCC SHIFTVAL CMPIM %176 BCC CONTROLVAL JSR PSTR = "***Illegal input",%0 JMP VAL DATAVAL JSR AddChar JMP GETCHAR VAL ANDIM %15 ; Subtract 128 TAX LDAAX SWILOW STA SWITCH LDAAX SWIHIGH STA SWITCH + %1 JMI SWITCH SHIFTVAL CONTROLVAL ;for now... ANDIM %15 TAX LDAAX LOSHITABLE STA SWITCH LDAAX HISHITABLE STA SWITCH + %1 JMI SWITCH RETURN JSR InsUp ;For now... JMP GETCHAR RUBOUT JSR DelLeft ;For now... JMP GETCHAR IR LdaIM %32 Sta SYM Jsr InsRight JMP GETCHAR IL LdaIM %32 Sta SYM Jsr InsLeft JMP GETCHAR DL Jsr DelRight JMP GETCHAR DR Jsr DelLeft ;I know... JMP GETCHAR IU Jsr InsUp JMP GETCHAR ID Jsr InsDown JMP GETCHAR DD Jsr DelDown JMP GETCHAR DU Jsr DelUp JMP GETCHAR RR RL JMP GETCHAR RU RD JMP GETCHAR ST JMP GETCHAR RT JMP GETCHAR NP JMP GETCHAR GP JMP GETCHAR EM RM JSR GETPAGE ;re-initialise Jsr CLEARSCREEN Jsr DispPage ;TEMP JMP GETCHAR AB JSR PSTR = "Basic",%13,%10,%0 RTS TA STA CTA LdaIM %32 Sta SYM Jsr InsLeft Jsr InsLeft Jsr InsLeft JMP GETCHAR CO SCO CCO JMP GETCHAR LE SLE CLE Jsr MovLeft JMP GETCHAR RI SRI CRI Jsr MovRight JMP GETCHAR SDO CDO LdaIM %0 Sta ScrollOneShot DO Jsr MovDown JMP GETCHAR SUP CUP LdaIM %0 Sta ScrollOneShot UP Jsr MovUp JMP GETCHAR CLEARSCREEN LDAIM %12 JMP OSWRCH AddChar Sta SYM JMP InsLeft ;{And return to GETCHAR} ; DEFAULT EFFECTS FOR UNSHIFTED FN-KEYS SWILOW = IR = DL = IU = DD = RR = RU = ST = RT = EM = AB = TA = CO = LE = RI = DO = UP SWIHIGH = IR/ = DL/ = IU/ = DD/ = RR/ = RU/ = ST/ = RT/ = EM/ = AB/ = TA/ = CO/ = LE/ = RI/ = DO/ = UP/ ; SHIFTED FUN KEYS LOSHITABLE = IL = DR = ID = DU = RL = RD = NP = GP = RM = AB = STA = SCO = SLE = SRI = SDO = SUP HISHITABLE = IL/ = DR/ = ID/ = DU/ = RL/ = RD/ = NP/ = GP/ = RM/ = AB/ = STA/ = SCO/ = SLE/ = SRI/ = SDO/ = SUP/ ; Procedure ReadLine ; { Fill line with text from PP onwards.} ; {Initially, LBEG = PP} ; repeat ; Sym = GET ; exit if Sym = eot ; if Sym = cr then begin ; FP = FP - 1 ; Byte (FP) = cr ; LEND = FP ; LSTAR ; return ; end ; Byte (PP) = Sym ; PP = PP + 1 ; MakeSpace ; until false ; DataPending = false ; end RDLine Lda DPEND Bne RDret RDagain Ldy INFILE Jsr OSBGET Bcs RDeot CmpIM %4 Beq RDeot CmpIM %13 Bne RDskip PHA Jsr DecFP PLA Jsr StoreFP Jsr SetLEND Jmp Left RDskip JSR StorePP Jsr IncPP Jsr MakSpace Jmp RDagain RDeot LdaIM %1 {False} Sta DPEND RDret Rts ; Procedure DeleteLeft (Sym) ; { ERASE THE CHARACTER TO THE LEFT OF THE CURSOR } ; return if PP = LBEG ; PP = PP - 1 ; end DelLeft Jsr TestLBEG ; return if ; PP = LBEG Jmp DecPP ; PP = PP - 1 ;Rts ; Procedure DeleteRight (Sym) ; { ERASE THE CHARACTER UNDER THE CURSOR } ; return if FP = LEND ; FP = FP + 1 ; end DelRight Jsr TestLEND ; return if ; FP = LEND Jmp IncFP ; FP = FP + 1 ;Rts ; Procedure InsertLeft (Sym) ; { INSERT A CHARACTER TO THE LEFT OF ; THE CURSOR, AND MOVE RIGHT } ; Byte (PP) = Sym ; PP = PP + 1 ; MakeSpace ; End InsLeft Lda Sym ; @PP = Sym Jsr StorePP Jsr IncPP ; PP = PP + 1 Jmp MakSpace ; MakeSpace ;Rts ; Procedure InsertRight (Sym) ; { INSERT A CHARACTER UNDER THE CURSOR, ; PUSHING THE REMAINING TEXT TO THE RIGHT } ; FP = FP - 1 ; MakeSpace ; Byte (FP) = Sym ; end InsRight Jsr DecFP ; FP = FP-1 Jsr MakSpace ; MakeSpace Lda Sym ; @FP = Sym Jmp StoreFP ;Rts ; Procedure MoveRight ; { MOVE THE CURSOR RIGHT ONE CHARACTER } ; return if FP = LEND ; Byte (PP) = Byte (FP) ; PP = PP + 1 ; FP = FP + 1 ; end MovRight Jsr TestLEND ; return if FP = LEND Jmp ToPP ; @PP = @FP ; PP = PP + 1 ; FP = FP + 1 ;Rts ; Procedure MoveLeft ; { MOVE THE CURSOR LEFT ONE CHARACTER } ; return if PP = LBEG ; PP = PP - 1 ; FP = FP - 1 ; Byte (FP) = Byte (PP) ; end MovLeft Jsr TestLBEG ; return if LBEG = PP Jmp ToFP ; @FP = @PP ; PP = PP - 1 ; FP = FP - 1 ;Rts ; Procedure InsertUp ; { MOVE THE CURRENT LINE, AND ALL THOSE ABOVE, ; UP BY ONE - LEAVING THE CURRENT LINE BLANK } ; RSTAR ; Byte (PP) = cr ; PP = PP + 1 ; MakeSpace ; LBEG = PP ; VBEG down ; end InsUp Jsr Right ; RSTAR LdaIM %13 ; @PP = cr Jsr StorePP Jsr IncPP ; PP = PP + 1 Jsr SetLBEG ; LBEG = PP Jsr MakSpace Inc Vgap Jmp VBdown ;Rts ; Procedure InsertDown ; { MOVE THE CURRENT LINE, AND ALL THOSE BELOW, ; DOWN BY ONE - LEAVING THE CURRENT LINE BLANK } ; LSTAR ; FP = FP - 1 ; MakeSpace ; Byte (FP) = cr ; LEND = FP ; VLIM up ; end InsDown Jsr Left ; LSTAR Jsr DecFP ; FP = FP - 1 Jsr MakSpace LdaIM %13 ; @FP = cr Jsr StoreFP Jsr SetLEND ; LEND = FP Inc Vgap Jmp VLup ;Rts ; Procedure DeleteDown ; { DELETE THE CURRENT LINE, AND LEAVE ; THE CURSOR ON THE LINE ABOVE } ; if LBEG = FBEG then DeleteUP and return ; FP = LEND ; PP = LBEG - 1 ; LBEG = PP ; LBEG = LBEG - 1 until Byte (LBEG) = cr ; LBEG = LBEG + 1 ; VBEG up ; end DelDown Lda LBEG ; if LBEG = FBEG Cmp FBEG Bne Skip11 Lda LBEG + %1 Cmp FBEG + %1 Beq DelUP ; then DeleteUp ;Rts ; and return Skip11 Jsr SetFP ; FP = LEND Jsr SetPP ; PP = LBEG Jsr DecPP ; - 1 Jsr NewLBEG ; grope LBEG Dec Vgap Jmp VBup ;Rts ; Procedure DeleteUp ; { DELETE THE CURRENT LINE, AND LEAVE THE ; CURSOR ON THE LINE BELOW } ; return if LEND = FEND ; PP = LBEG ; FP = LEND + 1 ; LEND = FP ; LEND = LEND + 1 while Byte (LEND) <> cr ; VLIM down ; end ; needs readline call??? DelUp Jsr TestFEND ; return if LEND = FEND Jsr SetPP ; PP = LBEG Jsr SetFP ; FP = LEND Jsr IncFP ; + 1 LDA FEND CMP FP BNE DU1 LDA FEND + %1 CMP FEND + %1 BNE DU1 JSR RDLine INC Vgap ;===DITTO=== DU1 Jsr NewLEND ; grope LEND Jsr VLdown DEC Vgap Rts ; Procedure LSTAR ; { GO TO THE LEFT HAND SIDE OF THE ; CURRENT LINE } ; while PP <> LBEG do ; ToFP { PP = PP - 1 } ; { FP = FP - 1 } ; { Byte (FP) = Byte (PP) } ; end ; end Leftagain ; Leftagain: Jsr ToFP ; PP = PP - 1 ; FP = FP - 1 ; @FP = @PP Left ; procedure LSTAR Lda LBEG ; if PP <> LBEG then Cmp PP ; goto Leftagain Bne Leftagain Lda LBEG + %1 Cmp PP + %1 Bne Leftagain Rts ; end ; Procedure RSTAR ; { GO TO THE RIGHT HAND SIDE OF THE ; CURRENT LINE } ; while FP <> LEND do ; ToPP { Byte (PP) = Byte (FP) } ; { PP = PP + 1 } ; { FP = FP + 1 } ; end ; end Rightagain ; Rightagain: Jsr ToPP ; @PP = @FP ; PP = PP + 1 ; FP = FP + 1 Right ; procedure RSTAR Lda LEND ; if FP <> LEND then Cmp FP ; goto Rightagain Bne Rightagain Lda LEND + %1 Cmp FP + %1 Bne Rightagain Rts ; end ; Procedure MoveUp ; { MOVE THE CURSOR TO THE RIGHT HAND SIDE OF ; THE LINE ABOVE } ; return if LBEG = FBEG ;****BALLS - ORDER WRONG... **** ; if Scrolling then begin ; VLIM up ; VBEG up ; end ; if LBEG = VBEG then begin ; VLIM up {*** Order ***} ; VBEG up ; end {Won't scroll twice because VBEG will be on line above} ; LSTAR ; PP = PP - 1 ; FP = FP - 1 ; Byte (FP) = Byte (PP) {=cr} ; LEND = FP ; LBEG = PP ; LBEG = LBEG - 1 until Byte (LBEG) = cr ; LBEG = LBEG + 1 ; end MovUp ; procedure MoveUp Jsr TestFBEG ; return if LBEG = FBEG Lda VBEG Cmp LBEG Bne MVU10 Lda VBEG + %1 Cmp LBEG + %1 Bne MVU10 LdaIM %0 Sta ScrollOneShot MVU10 Jsr Left ; LSTAR Jsr ToFP ; PP = PP - 1 ; FP = FP - 1 ; @FP = @PP {cr} Jsr SetLEND ; LEND = FP Jsr NewLBEG ; grope LBEG Lda ScrollOneShot Bne MVUdone Jsr VBup Inc ScrollOneShot ;WAS 0 (Always) MVUdone RTS ; Procedure MoveDown ; { MOVE THE CURSOR TO THE LEFT HAND SIDE ; OF THE LINE BELOW } ; return if LEND = FEND ; if Scrolling then begin ; VBEG down ; VLIM down ; end ; if LEND = VLIM then begin ; VBEG down {Similar comments as for MoveUp} ; VLIM down ; end ; RSTAR ; Byte (PP) = Byte (FP) ; PP = PP + 1 ; FP = FP + 1 ; LBEG = PP ; if FP = FEND and DataPending then ReadLine ; LEND = FP ; LEND = LEND + 1 while Byte (LEND) <> cr ; end MovDown ; procedure MoveDown Jsr TestFEND ; return if LEND = FEND Lda VLIM Cmp LEND Bne MVD10 Lda VLIM + %1 Cmp LEND + %1 Bne MVD10 LdaIM %0 Sta ScrollOneShot MVD10 Jsr Right ; RSTAR Jsr ToPP ; @PP = @FP ; PP = PP + 1 ; FP = FP + 1 Jsr SetLBEG ; LBEG = PP LDA FP CMP FEND BNE MVDDONE LDA FP + %1 CMP FEND + %1 BNE MVDDONE JSR RDLine INC Vgap ;==== SHIT AWFUL ==== MVDDONE Jsr NewLEND ; grope LEND Lda ScrollOneShot Bne MVDend Jsr VLdown Inc ScrollOneShot MVDend RTS LNK BOT