* MAINMEM.SVC.S * (c) Bobbi 2021 GPLv3 * * Main memory entry points called by Applecorn MOS running in * aux memory. Each entry point performs some ProDOS service, * then returns to aux memory. * 12-Oct-2021 OSFIND exits with bad filename, allows OPENIN(dir), * exits with MFI error, returns error if no more buffers, * OPENOUT doesn't try to delete if nothing to delete. * 13-Oct-2021 OSFIND implementes CLOSE#0. * 13-Oct-2021 FIND, BGET, BPUT optimised passing registers to main. * 13-Oct-2021 ARGS, EOF returns errors, optimised. * 15-Oct-2021 LOADFILE updated. * 16-Oct-2021 LOADFILE only reads object info once. * 17-Oct-2021 SAVEFILE updated. * 18-Oct-2021 Optimised CREATE, removed dead code, RDDATA and WRDATA. * 23-Oct-2021 Moved all the OSFILE routines together. * Optimised entry and return from OSFILE routines. * DELETE returns 'Dir not empty' when appropriate. * 29-Oct-2021 DRVINFO reads current drive if "". * 01-Nov-2021 DRVINFO checks reading info on a root directory. * 02-Nov-2021 SETPERMS passed parsed access byte. * 03-Nov-2021 Optimised CAT/EX/INFO, DESTROY. * *BUG* RENAME won't rename between directories, eg RENAME CHARS VDU/CHARS. * ProDOS file handling to rename a file RENFILE >>> ENTMAIN JSR PREPATH ; Preprocess arg1 JSR MFtoTMP ; Stash arg1 JSR COPYMF21 ; Copy arg2 JSR PREPATH ; Preprocess arg2 JSR COPYMF12 ; Put it back in MOSFILE2 JSR TMPtoMF ; Recover arg1->MOSFILE RENFILE2 LDA #MOSFILE STA RENPL+2 LDA #MOSFILE2 STA RENPL+4 JSR MLI DB RENCMD DW RENPL >>> XF2AUX,RENRET * Set name of volume dir, for *TITLE * Special case of renaming * Case 1: Disk ID in MOSFILE, title in MOSFILE2 * Case 2: Title in MOSFILE, MOSFILE2="" * DISKTITLE >>> ENTMAIN LDA MOSFILE2 BNE :CASE1 JSR COPYMF12 ; Copy title->MOSFILE2 LDA #$01 ; MOSFILE2 = "@" STA MOSFILE1 LDA #'@' STA MOSFILE1 + 1 :CASE1 JSR PREPATH ; Preprocess pathname BCS :EXIT JSR TRUNCPATH ; Truncate to top level JMP RENFILE2 :EXIT >>> XF2AUX,RENRET * ProDOS file handling for file copying * Returns with ProDOS error code in A COPYFILE >>> ENTMAIN JSR MFtoTMP ; Swap MOSFILE & MOSFILE2 JSR COPYMF21 JSR TMPtoMF2 JSR PREPATH ; Preprocess arg2 (in MOSFILE) JSR WILDONE ; Handle any wildcards JSR EXISTS ; See if destination exists STA :DESTTYPE ; Stash for later JSR MFtoTMP ; Swap MOSFILE & MOSFILE2 again JSR COPYMF21 JSR TMPtoMF2 JSR PREPATH ; Preprocess arg1 SEC ; Force wildcard lookup JSR WILDCARD ; Handle any wildcards in arg1 BCS :NONE JSR HASWILD BCC :MAINLOOP ; No wildcards in final segment LDA :DESTTYPE ; Wildcards, check dest type CMP #$02 ; Existing directory? BNE :BADDEST ; If not, error BRA :MAINLOOP ; Source: wildcard, dest: dir :NOWILD :MAINLOOP LDA MOSFILE2 ; Length STA :OLDLEN JSR EXISTS ; See if source is file or dir CMP #$02 ; Directory BEQ :SKIP ; Skip directories LDA :DESTTYPE ; Check dest type CMP #$02 ; Existing directory? BNE :NOTDIR LDY MOSFILE2 ; Dest idx = length LDA MOSFILE2,Y ; Get last char CMP #'/' ; Is it slash? BEQ :HASSLSH LDA #'/' ; Add a '/' separator STA MOSFILE2+1,Y INY :HASSLSH LDX #$00 ; Source id :APPLOOP CPX MATCHBUF ; At end? BEQ :DONEAPP LDA MATCHBUF+1,X ; Appending MATCHBUF to MOSFILE2 STA MOSFILE2+1,Y INX INY BRA :APPLOOP :DONEAPP STY MOSFILE2 ; Update length :NOTDIR LDA :DESTTYPE ; Recover destination type JSR COPY1FILE ; Copy an individual file BCS :COPYERR :SKIP JSR WILDNEXT BCS :NOMORE LDA :OLDLEN ; Restore MOSFILE2 STA MOSFILE2 BRA :MAINLOOP JSR CLSDIR :EXIT >>> XF2AUX,COPYRET :NONE JSR CLSDIR LDA #$46 ; 'File not found' BRA :EXIT :BADDEST JSR CLSDIR LDA #$5E ; 'Wildcards' error BRA :EXIT :NOMORE JSR CLSDIR LDA #$00 BRA :EXIT :COPYERR PHA JSR CLSDIR PLA BRA :EXIT :DESTTYPE DB $00 :OLDLEN DB $00 * Copy a single file * Source is in MOSFILE, DEST in MOSFILE2 * Returns with carry set if error, carry clear otherwise * Returns with ProDOS error code in A * Buffer COPYBUF is used for the file copy, to avoid trashing * directory block in RDBUF (when doing wilcard search) COPY1FILE LDA #MOSFILE STA GINFOPL+2 STA OPENPL2+2 JSR GETINFO ; GET_FILE_INFO BCS :ERR LDA #MOSFILE2 STA GINFOPL+2 STA DESTPL+2 JSR MLI ; DESTROY DB DESTCMD DW DESTPL LDA #$07 ; Fix num parms in PL STA GINFOPL LDA #$C3 ; Default permissions STA GINFOPL+3 JSR MLI ; Call CREATE with .. DB CREATCMD ; .. PL from GET_FILE_INFO DW GINFOPL LDX #$0A ; Num parms back as we found it STX GINFOPL BCS :ERR ; Error creating dest file LDA #$00 ; Look for empty slot JSR FINDBUF STX :BUFIDX1 JSR BUFADDR BCS :ERR ; No I/O bufs available STA OPENPL2+3 STY OPENPL2+4 JSR MLI DB OPENCMD DW OPENPL2 BCS :ERR ; Open error BRA :S1 :ERR SEC ; Report error RTS :S1 LDA OPENPL2+5 ; File ref num STA RDPLCP+1 LDX :BUFIDX1 STA FILEREFS,X ; Record the ref number LDA #MOSFILE2 STA OPENPL2+2 LDA #$00 ; Look for empty slot JSR FINDBUF STX :BUFIDX2 JSR BUFADDR BCS :ERRCLS1 ; No I/O bufs available STA OPENPL2+3 STY OPENPL2+4 JSR MLI DB OPENCMD DW OPENPL2 BCS :ERRCLS1 LDA OPENPL2+5 ; File ref num STA WRTPLCP+1 LDX :BUFIDX2 STA FILEREFS,X ; Record the ref number :MAINLOOP JSR MLI ; Read a block DB READCMD DW RDPLCP BCC :RDOKAY CMP #$4C ; Is it EOF? BEQ :EOFEXIT BRA :ERRCLS2 ; Any other error :RDOKAY LDA RDPLCP+6 ; Trans count MSB STA WRTPLCP+4 ; Request count MSB LDA RDPLCP+7 ; Trans count MSB STA WRTPLCP+5 ; Request count MSB JSR MLI ; Write a block DB WRITECMD DW WRTPLCP BCS :ERRCLS2 ; Write error BRA :MAINLOOP :EOFEXIT CLC ; No error PHP LDA #$00 PHA :CLOSE2 LDA WRTPLCP+1 ; Close output file STA CLSPL+1 JSR CLSFILE LDX :BUFIDX2 STZ FILEREFS,X :CLOSE1 LDA RDPLCP+1 ; Close input file STA CLSPL+1 JSR CLSFILE LDX :BUFIDX1 STZ FILEREFS,X PLA PLP RTS :ERRCLS1 SEC PHP PHA BRA :CLOSE1 :ERRCLS2 SEC PHP PHA BRA :CLOSE2 :BUFIDX1 DB $00 :BUFIDX2 DB $00 * ProDOS file handling for MOS OSFIND OPEN call * Options in A: $40 'r', $80 'w', $C0 'rw' OFILE >>> ENTMAIN AND #$C0 ; Keep just action bits PHA ; Preserve arg for later JSR PREPATH ; Preprocess pathname BCS :JMPEXIT1 ; Bad filename PLA PHA CMP #$80 ; Is it "w"? BEQ :NOWILD ; If so, no wildcards JSR WILDONE ; Handle any wildcards :NOWILD JSR EXISTS ; See if file exists ... TAX CMP #$02 ; ... and is a directory BNE :NOTDIR PLA ; Get action back BPL :NOTDIR2 ; OPENIN(dir) allowed LDA #$41 ; $41=Directory exists PHA ; Balance PLA :JMPEXIT1 PLA :JMPEXIT JMP FINDEXIT :NOTDIR PLA :NOTDIR2 CMP #$80 ; Write mode BNE :S1 TXA BEQ :S0 ; No file, don't try to delete JSR DODELETE BCS FINDEXIT ; Abort if error :S0 LDX #$00 ; LOAD=$0000 LDY #$00 JSR CREATEFILE BCS FINDEXIT ; Abort if error * Looking for a buffer should be done before creating a file :S1 LDA #$00 ; Look for empty slot JSR FINDBUF STX BUFIDX JSR BUFADDR BCS NOBUFFS ; No empty slot (BUFIDX=FF) STA OPENPL2+3 STY OPENPL2+4 LDA #MOSFILE STA OPENPL2+2 JSR MLI DB OPENCMD DW OPENPL2 BCS FINDEXIT LDA OPENPL2+5 ; File ref number LDX BUFIDX STA FILEREFS,X ; Record the ref number FINDEXIT JSR CHKNOTFND ; Convert NotFound to $00 >>> XF2AUX,OSFINDRET NOBUFFS LDA #$42 ; $42=File buffers full BNE FINDEXIT BUFIDX DB $00 * ProDOS file handling for MOS OSFIND CLOSE call * ProDOS can do CLOSE#0 but we need to manually update FILEREFS CFILE >>> ENTMAIN LDX #$00 ; Prepare for one file TYA ; File ref number BNE :CFILE1 ; Close one file LDX #$03 ; Loop through all files :CFILE0 LDA FILEREFS,X BEQ :CFILE3 ; Not open, try next :CFILE1 PHX PHA STA CLSPL+1 JSR CLSFILE BCS :CFILEERR ; Error occured during closing PLA JSR FINDBUF BNE :CFILE2 LDA #$00 STA FILEREFS,X ; Release buffer :CFILE2 PLX :CFILE3 DEX BPL :CFILE0 ; Loop to close all files LDA #$00 BEQ FINDEXIT :CFILEERR PLX ; Balance stack PLX BCS FINDEXIT * ProDOS file handling for MOS OSGBPB call * A=1 : Write bytes to disk, using new seq pointer * A=2 : Write bytes to disk, ignoring seq pointer * A=3 : Read bytes from disk, using new seq pointer * A=4 : Read bytes from disk, ignoring seq pointer * All others unsupported GBPB >>> ENTMAIN PHA LSR A ; Test LSB of A BCC :L1 ; A=2 or 4, no seek LDA GBPBHDL ; File ref number STA GMARKPL+1 LDY #$02 ; Copy file pointer :L0 LDA GBPBPTR+0,Y STA GMARKPL+2,Y DEY BPL :L0 JSR MLI ; Perform seek DB SMARKCMD DW GMARKPL BCC :L1 JMP :ERR :L1 PLA PHA CMP #$02 ; If A<=2 WRITE BCC :WRITE :READ LDA GBPBHDL ; File ref number STA READPL2+1 JSR MLI ; Read one byte from file DB READCMD DW READPL2 BCS :ERR LDA GBPBDAT+0 STA ZPMOS+0 LDA GBPBDAT+1 STA ZPMOS+1 LDA BLKBUF STA WRCARDRAM ; Write to aux STA (ZPMOS) ; Store byte in aux mem STA WRMAINRAM ; Write to main again BRA :UPDCB :WRITE LDA #BLKBUF STA A4H LDA GBPBDAT ; Start & end of source buf STA A1L ; (one byte buffer) STA A2L LDA GBPBDAT+1 STA A1H STA A2H :S0 CLC ; AUX -> Main JSR AUXMOVE LDA GBPBHDL ; File ref number STA WRITEPL+1 LDA #$01 ; Write one byte STA WRITEPL+4 LDA #$00 STA WRITEPL+5 JSR WRTFILE ; Write one byte to file :UPDCB INC GBPBDAT+0 ; Increment data pointer BNE :S1 INC GBPBDAT+1 :S1 INC GBPBPTR+0 ; Increment file pointer BNE :S2 INC GBPBPTR+1 BNE :S2 INC GBPBPTR+2 :S2 LDA GBPBNUM+0 ; Decrement number of bytes BNE :S3 LDA GBPBNUM+1 BEQ :ZERO ; Zero remaining, done! DEC GBPBNUM+1 :S3 DEC GBPBNUM+0 JMP :L1 :ERR :ZERO PLA ; Throw away A >>> ALTZP ; Control block can be in ZP! STA WRCARDRAM ; Write to aux LDA GBPBAUXCB+0 ; Copy control block back to aux STA $B0+0 ; $B0 in AltZP is temp FS workspace LDA GBPBAUXCB+1 STA $B0+1 LDY #$0C :L2 LDA GBPBBLK,Y STA ($B0),Y DEY BPL :L2 STA WRMAINRAM ; Write to main again >>> MAINZP >>> XF2AUX,OSGBPBRET * ProDOS file handling for MOS OSBGET call * Returns with char read in A and error num in Y (or 0) FILEGET >>> ENTMAIN STY READPL2+1 ; File ref number JSR MLI DB READCMD DW READPL2 TAY ; Error number in Y BCS :EXIT LDY #$00 ; 0=Ok LDA BLKBUF :EXIT >>> XF2AUX,OSBGETRET * ProDOS file handling for MOS OSBPUT call * Enters with char to write in A FILEPUT >>> ENTMAIN STA BLKBUF ; Byte to write STY WRITEPL+1 ; File ref number LDA #$01 ; Bytes to write STA WRITEPL+4 LDA #$00 STA WRITEPL+5 JSR WRTFILE BCS :FILEPUT2 LDA #$00 ; 0=Ok :FILEPUT2 >>> XF2AUX,OSBPUTRET * ProDOS file handling for FSC $01 called by OSBYTE $7F EOF * Returns EOF status in A ($FF for EOF, $00 otherwise) * A=channel to test FILEEOF >>> ENTMAIN STA GEOFPL+1 STA GMARKPL+1 JSR MLI DB GEOFCMD DW GEOFPL TAY BCS :EXIT ; Abort with any error JSR MLI DB GMARKCMD DW GMARKPL TAY BCS :EXIT ; Abort with any error SEC LDA GEOFPL+2 ; Subtract Mark from EOF SBC GMARKPL+2 STA GEOFPL+2 LDA GEOFPL+3 SBC GMARKPL+3 STA GEOFPL+3 LDA GEOFPL+4 SBC GMARKPL+4 STA GEOFPL+4 LDA GEOFPL+2 ; Check bytes remaining ORA GEOFPL+3 ORA GEOFPL+4 BEQ :ISEOF ; EOF -> $00 LDA #$FF ; Not EOF -> $FF :ISEOF EOR #$FF ; EOF -> $FF, Not EOF ->$00 LDY #$00 ; 0=No error :EXIT >>> XF2AUX,CHKEOFRET * ProDOS file handling for OSARGS flush commands FLUSH >>> ENTMAIN STY FLSHPL+1 ; File ref number JSR MLI DB FLSHCMD DW FLSHPL JMP TELLEXIT * ProDOS file handling for OSARGS set ptr command * GMARKPL+1=channel, GMARKPL+2,+3,+4=offset already set SEEK >>> ENTMAIN JSR MLI DB SMARKCMD DW GMARKPL JMP TELLEXIT * ProDOS file handling for OSARGS get ptr command * and for OSARGs get length command * A=ZP, Y=channel SIZE LDX #$02 ; $02=SIZE, Read EXT BNE TELL2 TELL LDX #$00 ; $00=TELL, Read PTR TELL2 STY GMARKPL+1 ; File ref number PHA ; Pointer to zero page CPX #$00 ; OSARGS parameter BEQ :POS JSR MLI DB GEOFCMD DW GMARKPL ; MARK parms same as EOF parms BRA :S1 :POS JSR MLI DB GMARKCMD DW GMARKPL :S1 PLX ; Pointer to ZP control block BCS TELLEXIT ; Exit with error >>> ALTZP ; Alt ZP & Alt LC on LDA GMARKPL+2 STA $00,X LDA GMARKPL+3 STA $01,X LDA GMARKPL+4 STA $02,X STZ $03,X ; Sizes are $00xxxxxx >>> MAINZP ; Alt ZP off, ROM back in LDA #$00 ; 0=Ok TELLEXIT >>> XF2AUX,OSARGSRET ZPMOS EQU $30 * ProDOS file MOS OSFILE calls CALLFILE >>> ENTMAIN JSR FILEDISPATCH >>> XF2AUX,OSFILERET FILEDISPATCH CMP #$00 BEQ SVCSAVE ; A=00 -> SAVE CMP #$FF BEQ SVCLOAD ; A=FF -> LOAD CMP #$06 BEQ DELFILE ; A=06 -> DELETE BCC INFOFILE ; A=01-05 -> INFO CMP #$08 BEQ MAKEDIR ; A=08 -> MKDIR RTS SVCSAVE JMP SAVEFILE SVCLOAD JMP LOADFILE INFOFILE JSR UPDPATH ; Process path and get info JMP COPYFB ; Copy back to aux mem * ProDOS file handling to delete a file * Called by AppleMOS OSFILE * Return A=0 no object, A=1 file deleted, A=2 dir deleted * A>$1F ProDOS error DELFILE JSR UPDPATH ; Process path and get info JSR COPYFB ; Copy back to aux mem PHA ; Save object type JSR DODELETE BCC :DELETED ; Success TAX ; X=error code PLA ; Get object back CPX #$4E BNE :DELERROR ; Not 'Insuff. access', return it LDX #$4F ; Change to 'Locked' CMP #$02 BNE :DELERROR ; Wasn't a directory, return 'Locked' LDA FBATTR+0 AND #$08 BNE :DELERROR ; Dir locked, return 'Locked' LDX #$54 ; Change to 'Dir not empty' :DELERROR TXA JSR CHKNOTFND PHA :DELETED PLA ; Get object back :EXIT RTS DODELETE LDA #MOSFILE STA DESTPL+2 JSR MLI DB DESTCMD DW DESTPL RTS * ProDOS file handling to create a directory * Invoked by AppleMOS OSFILE * Return A=$02 on success (ie: 'directory') * A>$1F ProDOS error, translated by OSFILE handler MAKEDIR JSR UPDPATH ; Process path and get info CMP #$02 BEQ :EXIT1 ; Dir already exists LDA #$0D ; OBJT='Directory' STA CREATEPL+7 ; ->Storage type LDA #$0F ; TYPE='Directory' LDX #$00 ; LOAD=$0000 LDY #$00 JSR CREATEOBJ BCS :EXIT ; Failed, exit with ProDOS result JSR UPDFB ; Update FILEBLK, returns A=$02 :EXIT1 JSR COPYFB ; Copy FILEBLK to aux mem :EXIT RTS * ProDOS file handling for MOS OSFILE LOAD call * Invoked by AppleMOS OSFILE * Return A=01 if successful (meaning 'file') * A>$1F ProDOS error, translated by FILERET LOADFILE LDX #4 :LP LDA FBLOAD,X ; Get address to load to STA ZPMOS,X DEX BPL :LP JSR PREPATH ; Preprocess pathname JSR WILDONE ; Handle any wildcards JSR UPDFB ; Get object info CMP #$20 BCS :JMPEXIT ; Error occured CMP #$01 ; Is it a file BEQ :ISFILE ROL A ; 0->0, 2->5 EOR #$05 ; 0->5, 2->0 ADC #$41 ; 0->$46, 2->$41 :JMPEXIT JMP :EXIT2 ; Return error :ISFILE LDA ZPMOS+4 ; If FBEXEC is zero, use addr BEQ :CBADDR ; in the control block LDA FBLOAD+0 ; Otherwise, use file's address STA ZPMOS+0 LDA FBLOAD+1 STA ZPMOS+1 :CBADDR JSR OPENMOSFILE BCS :EXIT2 ; File not opened :L1 LDA OPENPL+5 ; File ref number JSR READDATA ; Read data from open file PHA ; Save result LDA OPENPL+5 ; File ref num STA CLSPL+1 JSR CLSFILE PLA BNE :EXIT2 JSR COPYFB ; Copy FILEBLK to auxmem LDA #$01 ; $01=File :EXIT2 RTS * A=channel, MOSZP+0/1=address to load to, TO DO: MOS+4/5=length to read READDATA STA READPL+1 :RDLP JSR RDFILE BCS :READERR ; Close file and return any error LDA #start of data buffer ADC READPL+6 ; LSB of trans count TAX ; X=>LSB end of data buffer LDA #>BLKBUF ; MSB of start of data buffer STA A1H ; A1=>start of data buffer ADC READPL+7 ; MSB of trans count TAY ; Y=>MSB end of data buffer TXA BNE :L2 DEY :L2 DEX ; XY=XY-1, end address is start+len-1 STX A2L ; A2=>end of data buffer STY A2H LDA ZPMOS+0 ; A4=>address to load to STA A4L LDA ZPMOS+1 STA A4H INC ZPMOS+1 ; Step to next block INC ZPMOS+1 SEC ; Main -> AUX JSR AUXMOVE ; A4 updated to next address JMP :RDLP :READERR CMP #$4C BNE :EXITERR :EXITOK LDA #$00 ; $00=Success :EXITERR RTS * ProDOS file handling for MOS OSFILE SAVE call * Invoked by AppleMOS OSFILE * Return A=01 if successful (ie: 'file') * A>$1F ProDOS error translated by FILERET SAVEFILE SEC ; Compute file length LDA FBEND+0 SBC FBSTRT+0 STA LENREM+0 LDA FBEND+1 SBC FBSTRT+1 STA LENREM+1 LDA FBEND+2 SBC FBSTRT+2 BNE :TOOBIG ; >64K LDA FBEND+3 SBC FBSTRT+3 BEQ :L0 ; >16M :TOOBIG LDA #$2C ; Bad byte count - file too long RTS :L0 JSR PREPATH ; Preprocess pathname JSR EXISTS ; See if file exists ... CMP #$01 BEQ :NOTDIR ; Overwrite file BCC :NOFILE ; Create new file CMP #$02 BNE :JMPEXIT2 LDA #$41 ; Dir exists, return $41 :JMPEXIT2 JMP :EXIT2 :NOTDIR LDA #MOSFILE STA DESTPL+2 JSR MLI DB DESTCMD DW DESTPL BCS :EXIT2 ; Error trying to delete :NOFILE LDX FBLOAD+0 ; Auxtype = load address LDY FBLOAD+1 JSR CREATEFILE BCS :JMPEXIT2 ; Error trying to create JSR OPENMOSFILE BCS :JMPEXIT2 ; Error trying to open LDA OPENPL+5 ; File ref number JSR WRITEDATA :EXIT1 PHA ; Save result LDA OPENPL+5 ; File ref num STA CLSPL+1 JSR CLSFILE PLA BNE :EXIT2 ; Error returned JSR UPDFB ; Update FILEBLK JSR COPYFB ; Copy FILEBLK to aux mem LDA #$01 ; Return A='File' :EXIT2 CMP #$4E BNE :EXIT3 ; Change 'Insuff. access' LDA #$4F ; to 'Locked' :EXIT3 RTS * A=channel, FBSTRT+0/1=address to save from * LENREM+0/1=length to write WRITEDATA STA WRITEPL+1 :L1 LDA #$00 ; 512 bytes request count STA WRITEPL+4 LDA #$02 STA WRITEPL+5 LDA LENREM+1 CMP #$02 BCS :L15 ; More than 511 bytes remaining STA WRITEPL+5 LDA LENREM+0 STA WRITEPL+4 ORA WRITEPL+5 BEQ :SAVEOK ; Zero bytes remaining :L15 SEC LDA LENREM+0 ; LENREM=LENREM-count SBC WRITEPL+4 STA LENREM+0 LDA LENREM+1 SBC WRITEPL+5 STA LENREM+1 CLC LDA FBSTRT+0 STA A1L ; A1=>start of this block ADC WRITEPL+4 STA FBSTRT+0 ; Update FBSTRT=>start of next block TAX ; X=>end of this block LDA FBSTRT+1 STA A1H ADC WRITEPL+5 STA FBSTRT+1 TAY TXA BNE :L2 DEY :L2 DEX ; XY=XY-1, end address is start+len-1 STX A2L ; A2=>end of data buffer STY A2H :S2 LDA #BLKBUF STA A4H CLC ; Aux -> Main JSR AUXMOVE ; Copy data from aux to local buffer JSR WRTFILE ; Write the data BCS :WRITEERR JMP :L1 ; Loop back for next block :SAVEOK ; Enter here with A=$00 :WRITEERR RTS LENREM DW $0000 ; Remaining length CREATEFILE LDA #$01 ; Storage type - file STA CREATEPL+7 LDA #$06 ; Filetype BIN CREATEOBJ STA CREATEPL+4 ; Type = BIN or DIR STX CREATEPL+5 ; Auxtype = load address STY CREATEPL+6 JMP CRTFILE * Process pathname and read object info UPDPATH JSR PREPATH ; Process pathname BCC UPDFB ; If no error, update control block RTS * Update FILEBLK before returning to aux memory * Returns A=object type or ProDOS error UPDFB LDA #MOSFILE STA GINFOPL+2 JSR GETINFO ; Call GET_FILE_INFO BCC :UPDFB1 JMP CHKNOTFND :UPDFB1 LDA GINFOPL+5 ; Aux type LSB STA FBLOAD STA FBEXEC LDA GINFOPL+6 ; Aux type MSB STA FBLOAD+1 STA FBEXEC+1 STZ FBLOAD+2 STZ FBEXEC+2 STZ FBLOAD+3 STZ FBEXEC+3 * LDA GINFOPL+3 ; Access byte CMP #$40 ; Locked? AND #$03 ; ------wr PHP STA FBATTR+0 ASL A ; -----wr- ASL A ; ----wr-- ASL A ; ---wr--- ASL A ; --wr---- PLP BCS :UPDFB2 ORA #$08 ; --wrl--- :UPDFB2 ORA FBATTR+0 ; --wrl-wr STA FBATTR+0 * LDA GINFOPL+11 ; yyyyyyym PHA ROR A ; ?yyyyyyy m LDA GINFOPL+10 ; mmmddddd m PHA ROR A ; mmmmdddd LSR A ; -mmmmddd LSR A ; --mmmmdd LSR A ; ---mmmmd LSR A ; ----mmmm STA FBATTR+2 PLA ; mmmddddd AND #31 ; ---ddddd STA FBATTR+1 PLA ; yyyyyyym SEC SBC #81*2 ; Offset from 1981 BCS :UPDFB3 ; 1981-1999 -> 00-18 ADC #100*2 ; 2000-2080 -> 19-99 :UPDFB3 PHA ; yyyyyyym AND #$E0 ; yyy----- ORA FBATTR+1 ; yyyddddd STA FBATTR+1 PLA ; yyyyyyym AND #$FE ; yyyyyyy0 ASL A ; yyyyyy00 ASL A ; yyyyy000 ASL A ; yyyy0000 ORA FBATTR+2 ; yyyymmmm STA FBATTR+2 STZ FBATTR+3 JSR OPENMOSFILE ; Open file BCS :ERR LDA OPENPL+5 ; File ref number STA GMARKPL+1 JSR MLI ; Call GET_EOF MLI DB GEOFCMD DW GMARKPL ; MARK parms same as EOF LDA GMARKPL+2 STA FBSIZE+0 LDA GMARKPL+3 STA FBSIZE+1 LDA GMARKPL+4 STA FBSIZE+2 STZ FBSIZE+3 LDA OPENPL+5 ; File ref number STA CLSPL+1 JSR CLSFILE LDA #$01 ; Prepare A=file LDX GINFOPL+7 CPX #$0D ; Is it a directory? ADC #$00 ; Becomes A=2 for directory :UPDFB5 RTS :ERR CHKNOTFND CMP #$44 ; Convert ProDOS 'not found' BEQ :NOTFND ; into result=$00 CMP #$45 BEQ :NOTFND CMP #$46 BNE :CHKNOTFND2 :NOTFND LDA #$00 :CHKNOTFND2 RTS * Quit to ProDOS QUIT JSR AUDIOSTOP ; Shut down audio, dereg ISR INC PWRDUP ; Invalidate powerup byte STA PAGE1 ; PAGE2 off STA CLRALTCHAR ; Alt font off JSR MLI DB QUITCMD DW QUITPL RTS * Used for *CAT, *EX and *INFO * On entry: b7=0 - short info (*CAT) * b7=1 - long info (*INFO, *EX) * b6=0 - single entry, parameter is object (*INFO) * b6=1 - multiple items, parameter is dir (*CAT, *EX) * CATALOG >>> ENTMAIN STA CATARG ; Stash argument CMP #$80 ; Is it *INFO? BNE :NOTINFO JMP INFO ; Handle entry for *INFO :NOTINFO LDA MOSFILE ; Length of pathname BEQ :NOPATH ; If zero use prefix JSR PREPATH ; Preprocess pathname JSR WILDONE ; Handle any wildcards JSR EXISTS ; See if path exists ... BEQ :NOTFND ; Not found CMP #$02 BEQ :DIRFOUND LDA #$0D ; Becomes Not a directory :NOTFND EOR #$46 ; $00->$46, $xx->$4B BNE CATEXIT :NOPATH JSR GETPREF ; Fetch prefix into PREFIX LDX #prefix LDY #>PREFIX BRA :OPEN :DIRFOUND LDX #specified directory LDY #>MOSFILE :OPEN STX OPENPL+1 ; Open the specified directory STY OPENPL+2 JSR OPENFILE BCS CATEXIT ; Can't open dir CATREENTRY LDA OPENPL+5 ; File ref num STA READPL+1 JSR RDFILE BCS :CATERR >>> XF2AUX,PRONEBLK :CATERR CMP #$4C ; EOF BNE :NOTEOF LDA #$00 :NOTEOF PHA LDA OPENPL+5 ; File ref num STA CLSPL+1 JSR CLSFILE PLA CATEXIT >>> XF2AUX,STARCATRET * Handle *INFO INFO JSR PREPATH ; Preprocess pathname SEC JSR WILDCARD ; Handle any wildcards JSR EXISTS ; Check matches something BNE INFOFIRST ; Match found, start listing LDA #$46 ; No match, error Not found INFOEXIT CMP #$4C ; EOF BNE INFOCLS LDA #$00 ; EOF is not an error INFOCLS PHA JSR CLSDIR ; Be sure to close it! PLA BRA CATEXIT * PRONEBLK call returns here ... CATALOGRET >>> ENTMAIN LDA CATARG CMP #$80 ; Is this an *INFO call? BNE CATREENTRY ; No, go back and do another CAT/EX INFOREENTRY JSR WILDNEXT2 ; Start of new block BCS INFOEXIT ; No more matches INFOFIRST LDA WILDIDX CMP #$FF ; Is WILDNEXT about to read new blk? BEQ :DONEBLK ; If so, print this blk first JSR WILDNEXT2 BCC INFOFIRST ; Find more entries :DONEBLK >>> XF2AUX,PRONEBLK CATARG DB $00 * Helper routine to truncate path in MOSFILE at the top level * So '/FOO/BAR/BAZ' -> '/FOO' TRUNCPATH LDX #$01 ; Skip over initial '/' :L1 CPX MOSFILE ; See if end of string BCS :EXIT ; If so ... we are done BEQ :EXIT LDA MOSFILE+1,X ; Get char from path CMP #'/' ; See if it is slash BNE :NOTSLASH STX MOSFILE ; If so, truncate here BRA :EXIT :NOTSLASH INX BRA :L1 :EXIT RTS * Set prefix. Used by *CHDIR/*DRIVE to change directory * Y= $00 - CHDIR, select any directory * Y<>$00 - DRIVE, must select root * SETPFX >>> ENTMAIN PHY ; Save CHDIR/DRIVE flag JSR PREPATH ; Preprocess pathname BCS :EXIT JSR WILDONE ; Handle any wildcards LDA #$2E BCS :EXIT ; Exit with wildcard path PLY ; CHDIR/DRIVE flag CPY #$00 ; If <> $00 (ie: *DRIVE) BEQ :CHDIR JSR TRUNCPATH ; Truncate to top level :CHDIR LDA #MOSFILE STA SPFXPL+2 JSR MLI ; SET_PREFIX DB SPFXCMD DW SPFXPL :EXIT >>> XF2AUX,CHDIRRET * Obtain info on total/used blocks DRVINFO >>> ENTMAIN LDA MOSFILE BNE :DRVINF2 INC MOSFILE LDA #'@' STA MOSFILE+1 ; Convert "" to "@" :DRVINF2 JSR PREPATH BCS :EXIT JSR TRUNCPATH ; Truncate to top level LDA #MOSFILE STA GINFOPL+2 JSR GETINFO ; GET_FILE_INFO BCS :EXIT LDA GINFOPL+7 CMP #$0F BNE :EXIT1 ; Not a drive, exit with 'Bad drive' LDA GINFOPL+8 ; Blocks used LSB STA BLKBUF+0 LDA GINFOPL+9 ; Blocks used MSB STA BLKBUF+1 LDA GINFOPL+5 ; Total blocks LSB STA BLKBUF+2 LDA GINFOPL+6 ; Total blocks MSB STA BLKBUF+3 LDA #$00 ; $00=Ok :EXIT CMP #$46 BNE :EXIT2 :EXIT1 LDA #$2A ; Change 'Not found' to 'Bad drive' :EXIT2 >>> XF2AUX,FREERET * Change file permissions, for *ACCESS * Filename in MOSFILE, access mask in A * SETPERM >>> ENTMAIN PHA ; Save access mask JSR PREPATH ; Preprocess pathname BCS :SYNERR CLC JSR WILDCARD ; Handle any wildcards BCS :NONE BCC :MAINLOOP * STZ :LFLAG * STZ :WFLAG * STZ :RFLAG * LDX MOSFILE2 ; Length of arg2 * INX *:L1 DEX * CPX #$00 * BEQ :MAINLOOP * LDA MOSFILE2,X ; Read arg2 char * CMP #'L' ; L=Locked * BNE :S1 * STA :LFLAG * BRA :L1 *:S1 CMP #'R' ; R=Readable * BNE :S2 * STA :RFLAG * BRA :L1 *:S2 CMP #'W' ; W=Writable * BNE :ERR2 ; Bad attribute * STA :WFLAG * BRA :L1 :SYNERR LDA #$40 ; Invalid pathname syn BRA :EXIT :NONE JSR CLSDIR LDA #$46 ; 'File not found' BRA :EXIT :MAINLOOP LDA #MOSFILE STA GINFOPL+2 JSR GETINFO ; GET_FILE_INFO BCS :EXIT PLA ; Access byte PHA * LDA GINFOPL+3 ; Access byte * AND #$03 ; Start with R, W off * ORA #$C0 ; Start with dest/ren on * LDX :RFLAG * BEQ :S3 * ORA #$01 ; Turn on read enable *:S3 LDX :WFLAG * BEQ :S4 * ORA #$02 ; Turn on write enable *:S4 LDX :LFLAG * BEQ :S5 * AND #$3D ; Turn off destroy/ren/write :S5 STA GINFOPL+3 ; Access byte JSR SETINFO ; SET_FILE_INFO JSR WILDNEXT BCC :MAINLOOP * BCS :NOMORE :NOMORE JSR CLSDIR LDA #$00 * BRA :EXIT :EXIT PLX ; Drop access byte >>> XF2AUX,ACCRET :ERR2 LDA #$53 ; Invalid parameter BRA :EXIT *:LFLAG DB $00 ; 'L' attribute *:WFLAG DB $00 ; 'W' attribute *:RFLAG DB $00 ; 'R' attribute * Multi file delete, for *DESTROY * Filename in MOSFILE * MULTIDEL >>> ENTMAIN JSR PREPATH ; Preprocess pathname BCS :EXIT * CLC ; CC already set JSR WILDCARD ; Handle any wildcards BCC :MAINLOOP LDA #$46 ; 'File not found' BRA :DELERR :MAINLOOP JSR DODELETE BCS :DELERR JSR WILDNEXT BCC :MAINLOOP ; More to do LDA #$00 ; $00=Done :DELERR PHA JSR CLSDIR PLA :EXIT >>> XF2AUX,DESTRET * Read machid from auxmem MACHRD LDA ROMIN LDA ROMIN LDA $FBC0 SEC JSR $FE1F BRA MAINRDEXIT * Read mainmem from auxmem MAINRDMEM STA A1L STY A1H LDA ROMIN LDA ROMIN LDA (A1L) MAINRDEXIT >>> XF2AUX,NULLRTS ; Back to an RTS