/**************************************************************************** OS/A65 Version 2.0.0 Multitasking Operating System for 6502 Computers Copyright (C) 1989-1998 Andre Fachat This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ****************************************************************************/ /********************************************************************** * File handling for lib6502 * exports * Fgetc, Fputc, Fread, Fwrite * Fopen, Fclose * * Actually many routines just pass through to the kernel, and * do not check if parameters are right. * * Drive names are single char, "a-z" and "A-Z", case independent. */ .( .zero f1 .word 0 f2 .word 0 d =f2 .text &getfd .( /* this is called by others to get and lock an entry in the fd table. y then holds the fileno + LT_FTAB */ jsr fllock ldy #LT_FTAB l0 lda (zta),y beq foundfd iny cpy #LT_FTAB+MAXFILES bcc l0 bcs fderror foundfd lda #8 ; lock temporarily sta (zta),y clc fderror php jsr flunlock plp rts .) &Fclose .( stx zth txa clc adc #LT_FTAB sta zth+1 tay lda (zta),y beq nofd jsr fllock asl asl asl sta (zta),y ; clear lower bits to disable access from other threads and #8+32 ; read + directory beq noread tya clc adc #MAXFILES tay lda (zta),y tax lda #SC_NUL jsr STRCMD noread ldy zth+1 lda (zta),y and #16 ; write beq nowrite tya clc adc #2*MAXFILES tay lda (zta),y tax lda #SC_EOF jsr STRCMD nowrite jsr flunlock ldy zth+1 lda #0 sta (zta),y clc rts nofd lda #E_NOFILE sec rts .) /**************************************************************************** * currently we only have uni-directional opens allowed in this OS, * with the exception of non-seekable internet connection, which are * not handled here. We don't have to take care of them during open * here, only in the other routines. */ .( strerr pha ldy f1 lda #0 sta (zta),y pla .byt $2c fderror lda #E_NOFILE pha jsr flunlock ldx #SEM_SENDBUF jsr VSEM sec pla rts .data openmode .byt 0 .text &&Fopen sta zth sty zth+1 txa pha jsr taskinit ; be save... clc ldx #SEM_SENDBUF jsr PSEM ; this can block, so we do it first. pla tax jsr fopen2 php pha txa pha ldx #SEM_SENDBUF jsr VSEM pla tax pla plp rts &&fopen2 txa pha jsr fllock pla sta openmode ldy #LT_FTAB l0 lda (zta),y beq foundfd iny cpy #LT_FTAB+MAXFILES bcc l0 bcs fderror foundfd lda #8 ; lock temporarily sta (zta),y sty f1 jsr GETSTR bcs strerr stx PCBUF+FS_OPEN_STR lda f1 clc adc #MAXFILES tay txa sta (zta),y ; for reading tya clc adc #MAXFILES tay txa sta (zta),y ; for writing lda f1 pha ; save fd jsr getname lda zta clc adc #LT_PATH pha lda zta+1 adc #0 tay pla jsr usedir ; returns length in x bcs lengtherr lda #0 sta PCBUF+FS_OPEN_PFAD ldy openmode cpy #4 bcs cmderr lda localfscmd,y bmi cmderr pha txa tay pla jsr flunlock ; unlock file lib before thread lock pha ; save command ldx #SEND_FM jsr SEND sec jsr XRECEIVE cmp #E_OK bne fserr pla ; get command cmp #FS_OPEN_RD beq ord lda #2 .byt $2c ord lda #1 tax pla ; get fd back tay txa sta (zta),y tya sec sbc #LT_FTAB tax lda #E_OK clc rts cmderr lengtherr pla tay lda #0 ; we can unlock the fd w/o fllock sta (zta),y ldx PCBUF+FS_OPEN_STR jsr FRESTR lda #E_FNAMLEN sec rts fserr tay pla ; fs command pla ; fd tax tya pha ; error code txa pha ; fd clc adc #MAXFILES tay lda (zta),y tax jsr FRESTR pla ; fd tay lda #0 sta (zta),y pla ; error code sec rts localfscmd .byt FS_OPEN_RD, FS_OPEN_WR, <-1, FS_OPEN_AP .) /**************************************************************************** * Chdir is called with the argument address in a/y * it is changing the file path in (zta),LT_PATH * The implementation is horrible, and using PCBUF, but time is pressing... */ &Chdir .( sta zth sty zth+1 clc ldx #SEM_SENDBUF jsr PSEM jsr fllock lda zta clc adc #LT_PATH sta f1 lda zta+1 adc #0 sta f1+1 jsr getname lda PCBUF+FS_OPEN_DRV bmi nodrive ; no drive given ldy #PATH_DRV cmp (f1),y beq nodrive sta (f1),y iny lda #0 sta (f1),y ; drive given -> clear old path nodrive inc f1 ; inc f1 over drive byte bne nd1 inc f1+1 ldy #0 ; Name untersuchen nd1 ldx #FS_CMD_NAME lda PCBUF,x bne ndrx ; kein Name dann Pfad lschen sta (f1),y jmp cdend ndrx cmp #DIRSIGN ; Name beginnt mit DIRSIGN bne nd2 lda #0 ; dann Pfad loeschen sta (f1),y nd2a inx nd2 lda PCBUF,x ; weiter Name anschauen beq ndr ; kein Name dann Ende cmp #DIRSIGN beq nd2a ; DIRSIGN ueberlesen cmp #"." bne nameok ; kein '.' dann ok inx lda PCBUF,x ; hier mindestens ein '.' beq ndr ; Null dann Ende cmp #DIRSIGN ; DIRSIGN, beq nd2a ; dann '.' ignorieren cmp #"." ; noch'n Punkt ? bne nerrx ; nein, dann jsr getpos ldy d ; Position des letzten DIRSIGNs lda #0 sta (f1),y ; loeschen = eine Verzeichnis-Ebene hoeher beq nd2a ; (absolut) nerrx dex nameok jsr getpos ; y=Laenge des alten Pfads sty d ; hier Verzeichnis-Name an Pfad anhaengen no iny cpy #PATHLEN bcs nerr lda PCBUF,x beq nr cmp #DIRSIGN beq nr sta (f1),y inx bne no nr lda #0 sta (f1),y ldy d lda #DIRSIGN ; alles ok, dann Nullbyte (Ende alter Pfad) mit sta (f1),y ; DIRSIGN berschreiben lda PCBUF,x ; Ende des neuen Verzeichnisses bne nd2a ; nein, dann wieder nach oben cdend ndr clc .byt $24 nerr sec php jsr flunlock ldx #SEM_SENDBUF jsr VSEM plp lda #E_FNOPATH rts getpos ldy #0 ; holt y=Laenge des alten Pfadnamens sty d ; und d=Position des letzten DIRSIGNs no0 lda (f1),y beq no1 cmp #DIRSIGN bne no2 sty d no2 iny bne no0 no1 rts .) /**************************************************************************** * cwd returns the current working directory into a given buffer */ &Cwd .( sta zth sty zth+1 jsr fllock dex stx f2 cpx #2 bcc lerr lda zta clc adc #LT_PATH-1 sta f1 lda zta+1 adc #0 sta f1+1 ldy #1 lda (f1),y ; path byte (LT_PATH-1+1) clc adc #"a" dey sta (zth),y lda #":" iny sta (zth),y loop iny lda (f1),y sta (zth),y beq end cpy f2 bcc loop lerr lda #E_FNAMLEN .byt $2c end lda #E_OK jsr flunlock clc rts .) /**************************************************************************** * some of these routines are just grabbed from the oldlib code, as * they provide all the functionality I need for Fopen... * They have to be fllock'ed */ getname .( /* takes the name from (zth),0+ */ lda #0 sta PCBUF+FS_OPEN_NAME ldy #<-1 sty PCBUF+FS_OPEN_DRV g1 iny lda (zth),y beq gr cmp #" " beq g1 cmp #":" beq g1 cmp #34 ; " beq g2 iny lda (zth),y dey cmp #":" bne g2 lda (zth),y cmp #$41 ; "A" bcc g3 sbc #1 g3 and #$0f sta PCBUF+FS_OPEN_DRV iny iny g2 dey ldx #FS_OPEN_NAME ; bne g2a ; &set2name /* x=iobuf, y=pcbuf */ ; sta zp ; sty zp+1 ; ldy #<-1 ;g2a g2a lda #0 ;#" " sta d gn1 iny lda (zth),y beq gn3 ; cmp #" " ; remove leading " ". ; beq gn1 ; cmp #">" ; beq gn3 cmp #34 ; " bne gn2 iny sta d gn2 lda (zth),y beq gn3 cmp d beq gn3a sta PCBUF,x inx iny bne gn2 gn3a iny gn3 lda #0 sta PCBUF,x inx gr rts .) usedir .( sta f1 sty f1+1 lda PCBUF+FS_OPEN_DRV bpl ok ; drive given by user -> no path ldy #PATH_DRV lda (f1),y sta PCBUF+FS_OPEN_DRV ldx #FS_OPEN_NAME lda PCBUF,x cmp #DIRSIGN ; path given absolute -> no replacement beq ok ud2 iny ; find the length of the path lda (f1),y bne ud2 sty d ud4 lda PCBUF,x ; find the length of the name beq ud3 inx bne ud4 ud3 inx txa clc adc d sta d bcs nerr tay ud5 lda PCBUF,x ; copy name to new location sta PCBUF,y dey dex cpx #FS_OPEN_NAME bcs ud5 ldy #PATH_NAME ud6 lda (f1),y sta PCBUF+FS_OPEN_NAME-PATH_NAME,y beq ud7 iny bne ud6 ud7 lda #DIRSIGN sta PCBUF+FS_OPEN_NAME-PATH_NAME,y ldx d clc rts nerr sec rts ok ldx #FS_OPEN_NAME ok1 lda PCBUF,x beq oke inx bne ok1 oke inx clc rts .) /****************************************************************************/ &&Flib2osa_r &checkfd_r .( /* check if fd in x is ok for read, then return real fd in x. * otherwise clear stack and return to calling routine */ /* not allowed to use zth ! */ lda #1 .byt $2c &&&Flib2osa_w &&checkfd_w /* check for write */ lda #2 .byt $2c &&checkfd_d /* check for directory */ lda #4 pha txa clc bmi stdio adc #LT_FTAB tay pla and (zta),y beq error and #2 beq read tya ;clc adc #2*MAXFILES bne get read tya clc adc #MAXFILES get tay lda (zta),y tax rts stdio pla rts error sec lda #E_NOFILE rts .) /****************************************************************************/ fllock pha lda #LSEM_FILE jsr llock pla rts flunlock pha lda #LSEM_FILE jsr lunlock pla rts /****************************************************************************/ putf1 ldy #0 lda (zth),y sta f1 iny lda (zth),y sta f1+1 iny lda (zth),y sta f2 iny lda (zth),y sta f2+1 rts getf1 ldy #0 lda f1 sta (zth),y iny lda f1+1 sta (zth),y iny lda f2 sta (zth),y iny lda f2+1 sta (zth),y rts &Fwrite .( php sta zth sty zth+1 ldy #2 lda (zth),y iny ora (zth),y bne doit plp lda #E_ILLPAR sec rts doit txa pha jsr checkfd_w bcs xerr rl jsr fllock jsr putf1 next ldy #0 lda (f1),y jsr PUTC bcc ok pha jsr getf1 jsr flunlock pla cmp #E_NUL beq xerr ; carry is always set when jumping pla plp php pha bcc ret jsr YIELD jmp rl ok inc f1 bne o1 inc f1+1 o1 lda f2 bne o2 dec f2+1 o2 dec f2 lda f2 ora f2+1 bne next ; finished job jsr getf1 jsr flunlock ret lda #E_OK sec beq xerr /* err tay pla tax tya plp cmp #1 rts */ .) &Fread .( php sta zth sty zth+1 ldy #2 lda (zth),y iny ora (zth),y bne doit plp lda #E_ILLPAR sec rts doit txa pha jsr checkfd_r &xerr bcs err rl jsr fllock jsr putf1 next jsr GETC bcc ok pha jsr getf1 jsr flunlock pla cmp #E_EOF beq err pla plp php pha bcc ret jsr YIELD jmp rl ok ldy #0 sta (f1),y inc f1 bne o1 inc f1+1 o1 lda f2 bne o2 dec f2+1 o2 dec f2 lda f2 ora f2+1 bne next ; finished job jsr getf1 jsr flunlock ret lda #E_OK &err tay pla tax tya plp cmp #1 rts .) /****************************************************************************/ &Fputc .( stx zth sty zth+1 pha php jsr checkfd_w bcs err2 plp bcs fputw pla jsr PUTC ldx zth ldy zth+1 rts fputw pla pha jsr PUTC bcc ok cmp #E_NUL beq ok jsr YIELD jmp fputw err2 plp sec ok tax pla txa ldy zth+1 ldx zth rts .) &Fgetc .( php stx zth sty zth+1 pha jsr checkfd_r bcs err pla gl jsr GETC bcc ok cmp #E_EOF beq gcerr plp php bcc gcerr jsr YIELD jmp gl ok ldy zth+1 ldx zth plp clc rts gcerr ldy zth+1 ldx zth plp sec rts .) /****************************************************************************/ &Fseek .( lda #E_NOSEEK sec rts .) /****************************************************************************/ &Pipe .( jsr GETSTR bcc ok rts ok jsr fllock ldy #LT_FTAB l0 lda (zta),y beq found1 iny cpy #LT_FTAB+MAXFILES bcc l0 bcs err1 found1 sty f1 tya clc adc #MAXFILES tay txa sta (zta),y ldy f1 l1 iny cpy #LT_FTAB+MAXFILES bcs err2 lda (zta),y bne l1 sty f1+1 tya clc adc #2*MAXFILES tay txa sta (zta),y ldy f1 lda #1 sta (zta),y tya sec sbc #LT_FTAB pha ; read-fd ldy f1+1 lda #2 sta (zta),y tya sec sbc #LT_FTAB ; write-fd tay pla tax lda #E_OK jsr flunlock clc rts err1 err2 jsr FRESTR jsr flunlock lda #E_NOFILE sec rts .) /****************************************************************************/ &Dup .( jsr fllock stx f1 ldy #LT_FTAB l0 lda (zta),y beq found iny cpy #LT_FTAB+MAXFILES bcc l0 jsr flunlock lda #E_NOFILE sec rts found sty f1+1 lda f1 bmi stdio clc adc #LT_FTAB sta f1 tay found1 lda (zta),y ldy f1+1 sta (zta),y pha lda f1 clc adc #MAXFILES tay lda (zta),y tax lda f1+1 clc adc #MAXFILES tay txa sta (zta),y pla pha and #1 beq nord lda #SC_REG_RD jsr STRCMD nord lda f1 clc adc #2*MAXFILES tay lda (zta),y tax lda f1+1 clc adc #2*MAXFILES tay txa sta (zta),y pla pha and #2 beq nowr lda #SC_REG_WR jsr STRCMD nowr pla lda f1+1 sec sbc #LT_FTAB tax jsr flunlock clc rts stdio ldx f1 clc jsr DUP pha lda f1+1 clc adc #MAXFILES tay pla pha sta (zta),y tya clc adc #MAXFILES tay pla sta (zta),y lda f1 cmp #STDIN bne noin lda #1 .byt $2c noin lda #2 ldy f1+1 sta (zta),y sty f1 jmp found1 ; copy to itself, increasing rd/wr pointers in this way .) /****************************************************************************/ &Stddup .( jsr fllock stx f1 sty f2 tya clc adc #LT_FTAB sta f1+1 tay cpx #STDIN bne noread lda (zta),y and #1 beq ferr tya clc adc #MAXFILES x1 tay sty f1+1 lda (zta),y sec jsr DUP ldy f1+1 sta (zta),y clc ldx f2 jsr flunlock clc rts noread cpx #STDOUT beq write cpx #STDERR bne ferr write lda (zta),y and #2 beq ferr tya clc adc #2*MAXFILES bne x1 ; always ferr jsr flunlock lda #E_NOFILE sec rts .) /****************************************************************************/ &Fcntl .( jsr fllock stx f1 sta f1+1 cmp #FC_PUSH bne nopush jsr checkfd_w bcs efile lda #SC_SSTAT ldy #SCE_PUSH jsr STRCMD jmp ret nopush cmp #FC_PULL bne nopull jsr checkfd_r bcs efile lda #SC_SSTAT ldy #SCE_PULL jsr STRCMD efile lda #E_NOFILE .byt $2c enoti lda #E_NOTIMP .byt $2c enord lda #E_NOREAD .byt $2c enowr lda #E_NOWRITE .byt $2c ret lda #E_OK jsr flunlock cmp #1 rts nopull cmp #FC_WCHECK bne nowcheck jsr checkfd_w bcs efile lda #SC_STAT jsr STRCMD cmp #E_SFULL beq enowr cmp #E_NUL bne ret beq enowr nowcheck cmp #FC_RCHECK bne enoti jsr checkfd_r bcc rcok jsr checkfd_d bcs efile rcok lda #SC_GANZ jsr STRCMD bcs enord cmp #0 bne ret beq enord .) #if 0 &Fcntl .( jsr fllock stx f1 sta f1+1 txa clc adc #LT_FTAB tay sty f2 ldx f1+1 lda (zta),y cpx #FC_PUSH bne nopush and #2 beq ferr tya clc adc #2*MAXFILES tay lda (zta),y tax lda #SC_SSTAT ldy #SCE_PUSH jsr STRCMD jmp ret nopush cpx #FC_PULL bne nopull and #1 beq ferr tya clc adc #MAXFILES tay lda (zta),y tax lda #SC_SSTAT ldy #SCE_PULL jsr STRCMD ret jsr flunlock lda #E_OK clc rts ferr lda #E_NOFILE .byt $2c nowcheck lda #E_NOTIMP .byt $2c enord lda #E_NOREAD .byt $2c enowr lda #E_NOWRITE jsr flunlock sec rts nopull cpx #FC_RCHECK bne norcheck and #5 ; dir and read beq ferr pha tya clc adc #MAXFILES tay lda (zta),y tax lda #SC_GANZ jsr STRCMD tax pla ; missing check for directory-read bcs enord cpx #0 bne ret beq enord norcheck cpx #FC_WCHECK bne nowcheck and #2 beq ferr tya clc adc #2*MAXFILES tay lda (zta),y tax lda #SC_STAT jsr STRCMD cmp #E_SFULL beq enowr cmp #E_NUL bne ret beq enowr .) #endif /****************************************************************************/ .( lengtherr pla lda #E_FNAMLEN .byt $2c cmderr lda #E_NOTIMP jsr flunlock sec rts &&Fcmd sta zth sty zth+1 txa pha jsr taskinit ; be save... clc ldx #SEM_SENDBUF jsr PSEM ; this can block, so we do it first. jsr fllock jsr getname lda zta clc adc #LT_PATH pha lda zta+1 adc #0 tay pla jsr usedir ; returns length in x bcs lengtherr lda #0 sta PCBUF+FS_CMD_PFAD pla tay cpy #FC_CHKDSK+1 bcs cmderr cpy #FC_RENAME bcc cmderr bne no2nd tya pha ldy #0 a2 lda (zth),y beq a3 iny bne a2 a3 iny inx lda (zth),y sta PCBUF-1,x bne a3 pla tay no2nd lda localfscmd-FC_RENAME,y bmi cmderr pha txa tay pla jsr flunlock ; unlock file lib before thread lock ldx #SEND_FM jsr SEND sec jsr XRECEIVE pha ldx #SEM_SENDBUF jsr VSEM pla cmp #1 rts localfscmd .byt FS_RENAME, FS_DELETE, FS_MKDIR, FS_RMDIR, FS_FORMAT, FS_CHKDSK .) /********************************************************************** * Directory handling for lib6502 * exports * Fopendir, Freaddir * */ .( strerr pha ldy f1 lda #0 sta (zta),y pla .byt $2c fderror lda #E_NOFILE pha jsr flunlock ldx #SEM_SENDBUF jsr VSEM sec pla rts &&Fopendir sta zth sty zth+1 jsr taskinit ; be save... clc ldx #SEM_SENDBUF jsr PSEM ; this can block, so we do it first. jsr fllock ldy #LT_FTAB l0 lda (zta),y beq foundfd iny cpy #LT_FTAB+MAXFILES bcc l0 bcs fderror foundfd lda #8 ; lock temporarily sta (zta),y sty f1 jsr GETSTR bcs strerr stx PCBUF+FS_OPEN_STR lda f1 clc adc #MAXFILES tay txa sta (zta),y ; for reading lda f1 pha ; save fd jsr getname lda zta clc adc #LT_PATH pha lda zta+1 adc #0 tay pla jsr usedir ; returns length in x bcs lengtherr jsr flunlock ; unlock file lib before thread lock lda #0 sta PCBUF+FS_OPEN_PFAD txa tay lda #FS_OPEN_DR ldx #SEND_FM jsr SEND sec jsr XRECEIVE cmp #E_OK bne fserr ldx #SEM_SENDBUF jsr VSEM pla ; get fd back tay lda #4 sta (zta),y tya sec sbc #LT_FTAB tax lda #E_OK clc rts ;cmderr lengtherr pla tay lda #0 ; we can unlock the fd w/o fllock sta (zta),y ldx PCBUF+FS_OPEN_STR jsr FRESTR ldx #SEM_SENDBUF jsr VSEM lda #E_FNAMLEN sec rts fserr tax ; error code pla ; pull fd tay txa pha ; push error code tya pha ; push fd again clc adc #MAXFILES tay lda (zta),y tax jsr FRESTR pla ; pull fd tay lda #0 sta (zta),y ldx #SEM_SENDBUF jsr VSEM pla ; pull error code sec rts .) &Freaddir .( php sta zth sty zth+1 txa pha jsr checkfd_d ; now x has the real stream number pla plp ldy #FD_LENGTH l0 jsr dgetc bcs dderr sta (zth),y iny cpy #FD_LENGTH+4 bcc l0 ldy #FD_MDATE l1 jsr dgetc bcs dderr sta (zth),y iny cpy #FD_MDATE+6 bcc l1 jsr dgetc bcs dderr tay txa pha tya asl tax ldy #FD_PERM lda ftype,x sta (zth),y iny lda ftype+1,x sta (zth),y pla tax ldy #FD_NAME l2 jsr dgetc bcs dderr sta (zth),y cmp #0 beq end iny cpy #FD_NAME+MAX_FILENAME bcc l2 end ldy #FD_VALID lda #FDV_PERM + FDV_MDATE sta (zth),y clc rts dderr sec rts ftype .word S_IFREG + S_IRWXO, S_IFMNAME, S_IFMFREE, S_IFDIR + S_IRWXO dgetc .( jsr GETC bcs test rts test cmp #E_SEMPTY beq myield sec rts myield jsr YIELD jmp dgetc .) .) &getrwfd .( jsr fllock ldy #LT_FTAB l0 lda (zta),y beq foundfd iny cpy #LT_FTAB+MAXFILES bcc l0 bcs fderror foundfd lda #8 ; lock temporarily sta (zta),y sty f1 jsr GETSTR bcs fderr lda f1 clc adc #MAXFILES tay txa sta (zta),y ; for reading jsr GETSTR bcs strerr lda f1 clc adc #2*MAXFILES tay txa sta (zta),y ; for writing ldy f1 lda #3 ; reading and writing sta (zta),y tya sec sbc #LT_FTAB jsr flunlock tax clc rts strerr lda (zta),y ; y is kept in GETSTR tax jsr FRESTR fderr ldy f1 lda #0 sta (zta),y fderror jsr flunlock lda #E_NOFILE sec rts .) .)