From d864e7357978f598a386970f8dce94548d6b7179 Mon Sep 17 00:00:00 2001 From: Oliver Schmidt Date: Sat, 15 Oct 2016 16:33:24 +0200 Subject: [PATCH] Added directory functions to the Commodore Platform File System. They reduce the Telnet server's run size by 1231 bytes. --- core/cfs/cfs-posix-dir.c | 1 + core/cfs/cfs-posix.c | 1 + cpu/6502/lib/pfs.h | 7 + examples/telnet-server/Makefile.c128.defines | 2 +- platform/c128/Makefile.c128 | 3 +- platform/c128/contiki-conf.h | 6 + platform/c128/lib/pfs-dir-asm.S | 114 +++++++++++++ platform/c128/lib/pfs-dir.c | 171 +++++++++++++++++++ platform/c128/lib/pfs.S | 28 ++- platform/c64/Makefile.c64 | 3 +- platform/c64/contiki-conf.h | 6 + platform/c64/lib/pfs-dir-asm.S | 114 +++++++++++++ platform/c64/lib/pfs-dir.c | 171 +++++++++++++++++++ platform/c64/lib/pfs.S | 28 ++- 14 files changed, 636 insertions(+), 19 deletions(-) create mode 100644 platform/c128/lib/pfs-dir-asm.S create mode 100644 platform/c128/lib/pfs-dir.c create mode 100644 platform/c64/lib/pfs-dir-asm.S create mode 100644 platform/c64/lib/pfs-dir.c diff --git a/core/cfs/cfs-posix-dir.c b/core/cfs/cfs-posix-dir.c index 0eb2ba9cb..623471b29 100644 --- a/core/cfs/cfs-posix-dir.c +++ b/core/cfs/cfs-posix-dir.c @@ -36,6 +36,7 @@ #include #include +#define CFS_IMPL 1 #include "cfs/cfs.h" struct cfs_posix_dir { diff --git a/core/cfs/cfs-posix.c b/core/cfs/cfs-posix.c index 1ee1b99df..452ddbbbb 100644 --- a/core/cfs/cfs-posix.c +++ b/core/cfs/cfs-posix.c @@ -40,6 +40,7 @@ #include #endif +#define CFS_IMPL 1 #include "cfs/cfs.h" /*---------------------------------------------------------------------------*/ diff --git a/cpu/6502/lib/pfs.h b/cpu/6502/lib/pfs.h index 73102ce55..51fcd7c5b 100644 --- a/cpu/6502/lib/pfs.h +++ b/cpu/6502/lib/pfs.h @@ -29,6 +29,7 @@ * This file is part of the Contiki operating system. * * Author: Oliver Schmidt + * Author: Greg King * */ @@ -37,11 +38,17 @@ #include +struct cfs_dir; +struct cfs_dirent; + int __fastcall__ pfs_open(const char *name, int flags); void __fastcall__ pfs_close(int fd); int __fastcall__ pfs_read(int fd, void *buf, unsigned int len); int __fastcall__ pfs_write(int fd, const void *buf, unsigned int len); off_t __fastcall__ pfs_seek(int fd, off_t offset, int whence); int __fastcall__ pfs_remove(const char *name); +int __fastcall__ pfs_opendir(struct cfs_dir *dirp, const char *name); +void __fastcall__ pfs_closedir(struct cfs_dir *dirp); +int __fastcall__ pfs_readdir(struct cfs_dir *dirp, struct cfs_dirent *dirent); #endif /* PFS_H_ */ diff --git a/examples/telnet-server/Makefile.c128.defines b/examples/telnet-server/Makefile.c128.defines index 062a12cd7..d8cd8baee 100644 --- a/examples/telnet-server/Makefile.c128.defines +++ b/examples/telnet-server/Makefile.c128.defines @@ -1 +1 @@ -DEFINES = WITH_LOGGING,WITH_80COL +DEFINES = WITH_LOGGING,WITH_PFS,WITH_80COL diff --git a/platform/c128/Makefile.c128 b/platform/c128/Makefile.c128 index 0c674ee38..dab80b1dc 100644 --- a/platform/c128/Makefile.c128 +++ b/platform/c128/Makefile.c128 @@ -31,7 +31,8 @@ # Author: Oliver Schmidt # -CONTIKI_TARGET_SOURCEFILES += exec.c lseek.c pfs.S pfs_remove.S pfs_seek.S pfs_write.S +CONTIKI_TARGET_SOURCEFILES += exec.c lseek.c \ + pfs.S pfs-dir.c pfs-dir-asm.S pfs_remove.S pfs_seek.S pfs_write.S CONTIKI_CPU = $(CONTIKI)/cpu/6502 include $(CONTIKI_CPU)/Makefile.6502 diff --git a/platform/c128/contiki-conf.h b/platform/c128/contiki-conf.h index 057d6473d..0e72f20c4 100644 --- a/platform/c128/contiki-conf.h +++ b/platform/c128/contiki-conf.h @@ -37,6 +37,12 @@ #include "6502def.h" +#if (WITH_PFS && !CFS_IMPL) +#define cfs_opendir pfs_opendir +#define cfs_closedir pfs_closedir +#define cfs_readdir pfs_readdir +#endif + #define CTK_CONF_MENU_KEY CH_F1 #define CTK_CONF_WINDOWSWITCH_KEY CH_F3 #define CTK_CONF_WIDGETUP_KEY CH_F5 diff --git a/platform/c128/lib/pfs-dir-asm.S b/platform/c128/lib/pfs-dir-asm.S new file mode 100644 index 000000000..dbc1c956f --- /dev/null +++ b/platform/c128/lib/pfs-dir-asm.S @@ -0,0 +1,114 @@ +; +; Helper functions for pfs_opendir() and pfs_readdir() +; +; Close a directory listing that had been openned by pfs_opendir(). +; +; 2012-06-01, Ullrich von Bassewitz +; 2016-04-10, Greg King +; + + .importzp sp, ptr1, tmp1 + .import pushax, _pfs_read, _pfs_close + .export __pfs_dirread1, __pfs_dirread + + .export _pfs_closedir + +;--------------------------------------------------------------------------- +; Data structure + +.struct DIR + fd .word +.endstruct + +;--------------------------------------------------------------------------- +; /* Read one byte from the directory into the supplied buffer. +; ** Return true if the read was successful, and false otherwise. +; */ +; unsigned char __fastcall__ _pfs_dirread1(struct cfs_dir *dir, void *buf); + +__pfs_dirread1: + jsr pushax ; Push buf + lda #1 ; Load count = 1 + +; Run directly into __dirread + +;--------------------------------------------------------------------------- +; /* Read characters from the directory into the supplied buffer. +; ** Return true if the read was successful, and false otherwise. +; */ +; unsigned char __fastcall__ _pfs_dirread(struct cfs_dir *dir, void *buf, + +__pfs_dirread: + pha ; Save count + +; Replace dir by ((DIR*)dir)->fd. + + ldy #$02 + lda (sp),y + sta ptr1 + iny + lda (sp),y + sta ptr1+1 + ldy #DIR::fd+1 + lda (ptr1),y + pha + dey + lda (ptr1),y + ldy #$02 + sta (sp),y + pla + iny + sta (sp),y + +; Get count, save it again, clear the high byte, and call pfs_read(). +; By the previous actions, the stack frame is as pfs_read() needs it; +; and, pfs_read() also will drop it. + + pla + pha + ldx #>$0000 + jsr _pfs_read + +; Check for errors. + + cpx #>-1 + beq L3 + +; pfs_read() was successful; check number of bytes read. We assume that +; pfs_read() will not return more than count; so, .X is zero if we come here. + + sta tmp1 ; Save returned count + pla ; Our count + cmp tmp1 + beq L2 ; OK, return count + +; Didn't read enough bytes. That is an error for us. + + bne L1 ; Branch always + +; pfs_read() returned an error. + +L3: pla ; Drop count + inx ; .X = 0 +L1: txa ; Return zero +L2: rts + +;--------------------------------------------------------------------------- +; void __fastcall__ pfs_closedir(struct cfs_dir *dirp); + +.proc _pfs_closedir + sta ptr1 + stx ptr1+1 + +; Load ((DIR *)dirp)->fd. + + ldy #DIR::fd+1 + lda (ptr1),y + tax + dey + lda (ptr1),y + +; Close the directory file. + + jmp _pfs_close +.endproc diff --git a/platform/c128/lib/pfs-dir.c b/platform/c128/lib/pfs-dir.c new file mode 100644 index 000000000..2b9d959f9 --- /dev/null +++ b/platform/c128/lib/pfs-dir.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2016, Greg King + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions, and the following + * disclaimer, in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS"; AND, ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is a part of the Contiki operating system. + */ + +/* +** Open a directory listing, so that it can be read by pfs_readdir(). +** +** Read one file-name from a directory listing that was opened by pfs_opendir(). +** +** 2012-05-30, Ullrich von Bassewitz +** 2016-04-22, Greg King +*/ + +#include "cfs.h" + +typedef struct { + int fd; /* File descriptor for a directory */ +} DIR; + +/*---------------------------------------------------------------------------*/ +/* +** Read characters from the directory into the supplied buffer. +** Return true if the read was successful, and false otherwise. +*/ +extern unsigned char __fastcall__ _pfs_dirread(struct cfs_dir *dir, void *buf, + unsigned char count); + +/* +** Read one byte from the directory into the supplied buffer. +** Return true if the read was successful, and false otherwise. +*/ +extern unsigned char __fastcall__ _pfs_dirread1(struct cfs_dir *dir, void *buf); +/*---------------------------------------------------------------------------*/ +int __fastcall__ +pfs_opendir(struct cfs_dir *dirp, register const char *name) +{ + static int fd; + static char buf[2 + 1] = "$"; + + /* Set up the actual file name that is sent to the DOS. + ** We accept "0:", "1:", "/", and "." as directory names. + */ + if(name == NULL || name[0] == '\0' || (name[0] == '.' || name[0] == '/') && name[1] == '\0') { + buf[1] = '\0'; + } else if((name[0] == '0' || name[0] == '1') && name[1] == ':' && name[2] == '\0') { + buf[1] = name[0]; + buf[2] = '\0'; + } else { + return -1; + } + + /* Open the directory on a disk, for reading. */ + fd = pfs_open(buf, CFS_READ); + if(fd >= 0) { + ((DIR *)dirp)->fd = fd; + + /* Skip the load address. */ + if(_pfs_dirread(dirp, buf + 1, 2)) { + return 0; + } else { + pfs_close(fd); + } + } + + return -1; +} +/*---------------------------------------------------------------------------*/ +int __fastcall__ +pfs_readdir(struct cfs_dir *dirp, register struct cfs_dirent *dirent) +{ + register unsigned char *b; + register unsigned char i; + register unsigned char count; + unsigned char buffer[0x40]; + static unsigned char s; + static unsigned char j; + + /* Skip the BASIC line-link. */ + if(!_pfs_dirread(dirp, buffer, 2)) { + return -1; + } + + /* Read the number of blocks. It's a two-byte number; but, the size is + ** a four-byte number. Zero the size; then, put the block number in + ** the first two bytes. It works because the 6502 CPU's numbers are + ** little-endian. + */ + dirent->size = 0; + if(!_pfs_dirread(dirp, &dirent->size, 2)) { + return -1; + } + + /* Read the next file entry into a buffer. */ + for(count = 0, b = buffer; count < sizeof(buffer); ++b) { + if(!_pfs_dirread1(dirp, b)) { + return -1; + } + ++count; + if(*b == '\0') { + break; + } + } + + /* The end of the directory was reached if the buffer contains "blocks free." + ** It is sufficient here to check for the leading 'b'. The buffer will have + ** at least one byte if we come here. + */ + if(buffer[0] == 'b') { + return -1; + } + + /* Parse the buffer for the file-name. */ + b = buffer; + j = 0; + s = 0; + i = 0; + while(i < count) { + switch(s) { + case 0: + /* Search for the start of the file-name. */ + if(*b == '"') { + s = 1; + } + break; + case 1: + /* Within the file-name. */ + if(*b == '"') { + /* The end of the file-name was found. */ + dirent->name[j] = '\0'; + return 0; + } else if(j < sizeof(dirent->name) - 1) { + dirent->name[j] = *b; + ++j; + } + break; + } + ++b; + ++i; + } + + /* The file-name is too long for the buffer. Return what could be read. */ + dirent->name[j] = '\0'; + return 0; +} diff --git a/platform/c128/lib/pfs.S b/platform/c128/lib/pfs.S index 7947b67d8..b835f613e 100644 --- a/platform/c128/lib/pfs.S +++ b/platform/c128/lib/pfs.S @@ -36,7 +36,7 @@ .constructor init_pfs .destructor done_pfs - .importzp sp, ptr1, ptr2, ptr3 + .importzp sp, ptr1, ptr2, ptr3, tmp1 .import curunit, __filetype, popax, addysp, subysp .export pfs_rwcommon, pfs_rwsetflags, pfs_rwcommonend .if F_IDE64 @@ -46,6 +46,7 @@ .export pfs_makename, pfs_scratch .export _pfs_open, _pfs_read, _pfs_close + ;--------------------------------------------------------------------- MAXLEN = 80 ;maximum filename length @@ -107,7 +108,14 @@ _pfs_open: lda FNL beq error ;must have a filename - lda #2 - 1 ;file number + ; A directory listing needs a special secondary address + ldy tmp1 + bne open1 ;branch if not directory + lda #2 - 1 + dey ;.Y = 0 - 1 + bne open2 ;branch always + +open1: lda #2 - 1 ;file number tay ;secondary address open2: sta ptr2 sty ptr2 + 1 @@ -118,10 +126,6 @@ next: inc ptr2 ;next file number bcs error ;no more files lda flags - 1,x bne next ;already used - lda ptr2 + 1 - bne nextsa - inx - stx ptr2 + 1 nextsa: inc ptr2 + 1 ;next channel retr: lda ptr2 ;file number ldx curunit @@ -209,7 +213,7 @@ pfs_makename: ; Validate the name; and, find its length ldy #<-1 - sty ptr3 + sty ptr3 ;init. the count of retries sty ptr1 @L10: iny cpy #MAXLEN @@ -227,9 +231,17 @@ pfs_makename: bne @L10 cpy #0 beq badchr ;no name + sty FNL ;save original length tay ;zero index reg. - lda #'0' ;drive 0 or current partition + lda (FN),y + sta tmp1 ;preset not-directory flag to true + cmp #'$' + bne @L9 + sty tmp1 ;set not-directory flag to false + rts + +@L9: lda #'0' ;drive 0 or current partition sta (sp),y iny inc ptr1 diff --git a/platform/c64/Makefile.c64 b/platform/c64/Makefile.c64 index f78dcf717..96b54c287 100644 --- a/platform/c64/Makefile.c64 +++ b/platform/c64/Makefile.c64 @@ -31,7 +31,8 @@ # Author: Oliver Schmidt # -CONTIKI_TARGET_SOURCEFILES += exec.c lseek.c pfs.S pfs_remove.S pfs_seek.S pfs_write.S +CONTIKI_TARGET_SOURCEFILES += exec.c lseek.c \ + pfs.S pfs-dir.c pfs-dir-asm.S pfs_remove.S pfs_seek.S pfs_write.S CONTIKI_CPU = $(CONTIKI)/cpu/6502 include $(CONTIKI_CPU)/Makefile.6502 diff --git a/platform/c64/contiki-conf.h b/platform/c64/contiki-conf.h index 7d5a8d070..102d01a77 100644 --- a/platform/c64/contiki-conf.h +++ b/platform/c64/contiki-conf.h @@ -37,6 +37,12 @@ #include "6502def.h" +#if (WITH_PFS && !CFS_IMPL) +#define cfs_opendir pfs_opendir +#define cfs_closedir pfs_closedir +#define cfs_readdir pfs_readdir +#endif + #define CTK_CONF_MENU_KEY CH_F1 #define CTK_CONF_WINDOWSWITCH_KEY CH_F3 #define CTK_CONF_WIDGETUP_KEY CH_F5 diff --git a/platform/c64/lib/pfs-dir-asm.S b/platform/c64/lib/pfs-dir-asm.S new file mode 100644 index 000000000..dbc1c956f --- /dev/null +++ b/platform/c64/lib/pfs-dir-asm.S @@ -0,0 +1,114 @@ +; +; Helper functions for pfs_opendir() and pfs_readdir() +; +; Close a directory listing that had been openned by pfs_opendir(). +; +; 2012-06-01, Ullrich von Bassewitz +; 2016-04-10, Greg King +; + + .importzp sp, ptr1, tmp1 + .import pushax, _pfs_read, _pfs_close + .export __pfs_dirread1, __pfs_dirread + + .export _pfs_closedir + +;--------------------------------------------------------------------------- +; Data structure + +.struct DIR + fd .word +.endstruct + +;--------------------------------------------------------------------------- +; /* Read one byte from the directory into the supplied buffer. +; ** Return true if the read was successful, and false otherwise. +; */ +; unsigned char __fastcall__ _pfs_dirread1(struct cfs_dir *dir, void *buf); + +__pfs_dirread1: + jsr pushax ; Push buf + lda #1 ; Load count = 1 + +; Run directly into __dirread + +;--------------------------------------------------------------------------- +; /* Read characters from the directory into the supplied buffer. +; ** Return true if the read was successful, and false otherwise. +; */ +; unsigned char __fastcall__ _pfs_dirread(struct cfs_dir *dir, void *buf, + +__pfs_dirread: + pha ; Save count + +; Replace dir by ((DIR*)dir)->fd. + + ldy #$02 + lda (sp),y + sta ptr1 + iny + lda (sp),y + sta ptr1+1 + ldy #DIR::fd+1 + lda (ptr1),y + pha + dey + lda (ptr1),y + ldy #$02 + sta (sp),y + pla + iny + sta (sp),y + +; Get count, save it again, clear the high byte, and call pfs_read(). +; By the previous actions, the stack frame is as pfs_read() needs it; +; and, pfs_read() also will drop it. + + pla + pha + ldx #>$0000 + jsr _pfs_read + +; Check for errors. + + cpx #>-1 + beq L3 + +; pfs_read() was successful; check number of bytes read. We assume that +; pfs_read() will not return more than count; so, .X is zero if we come here. + + sta tmp1 ; Save returned count + pla ; Our count + cmp tmp1 + beq L2 ; OK, return count + +; Didn't read enough bytes. That is an error for us. + + bne L1 ; Branch always + +; pfs_read() returned an error. + +L3: pla ; Drop count + inx ; .X = 0 +L1: txa ; Return zero +L2: rts + +;--------------------------------------------------------------------------- +; void __fastcall__ pfs_closedir(struct cfs_dir *dirp); + +.proc _pfs_closedir + sta ptr1 + stx ptr1+1 + +; Load ((DIR *)dirp)->fd. + + ldy #DIR::fd+1 + lda (ptr1),y + tax + dey + lda (ptr1),y + +; Close the directory file. + + jmp _pfs_close +.endproc diff --git a/platform/c64/lib/pfs-dir.c b/platform/c64/lib/pfs-dir.c new file mode 100644 index 000000000..2b9d959f9 --- /dev/null +++ b/platform/c64/lib/pfs-dir.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2016, Greg King + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions, and the following + * disclaimer, in the documentation and/or other materials provided + * with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS"; AND, ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is a part of the Contiki operating system. + */ + +/* +** Open a directory listing, so that it can be read by pfs_readdir(). +** +** Read one file-name from a directory listing that was opened by pfs_opendir(). +** +** 2012-05-30, Ullrich von Bassewitz +** 2016-04-22, Greg King +*/ + +#include "cfs.h" + +typedef struct { + int fd; /* File descriptor for a directory */ +} DIR; + +/*---------------------------------------------------------------------------*/ +/* +** Read characters from the directory into the supplied buffer. +** Return true if the read was successful, and false otherwise. +*/ +extern unsigned char __fastcall__ _pfs_dirread(struct cfs_dir *dir, void *buf, + unsigned char count); + +/* +** Read one byte from the directory into the supplied buffer. +** Return true if the read was successful, and false otherwise. +*/ +extern unsigned char __fastcall__ _pfs_dirread1(struct cfs_dir *dir, void *buf); +/*---------------------------------------------------------------------------*/ +int __fastcall__ +pfs_opendir(struct cfs_dir *dirp, register const char *name) +{ + static int fd; + static char buf[2 + 1] = "$"; + + /* Set up the actual file name that is sent to the DOS. + ** We accept "0:", "1:", "/", and "." as directory names. + */ + if(name == NULL || name[0] == '\0' || (name[0] == '.' || name[0] == '/') && name[1] == '\0') { + buf[1] = '\0'; + } else if((name[0] == '0' || name[0] == '1') && name[1] == ':' && name[2] == '\0') { + buf[1] = name[0]; + buf[2] = '\0'; + } else { + return -1; + } + + /* Open the directory on a disk, for reading. */ + fd = pfs_open(buf, CFS_READ); + if(fd >= 0) { + ((DIR *)dirp)->fd = fd; + + /* Skip the load address. */ + if(_pfs_dirread(dirp, buf + 1, 2)) { + return 0; + } else { + pfs_close(fd); + } + } + + return -1; +} +/*---------------------------------------------------------------------------*/ +int __fastcall__ +pfs_readdir(struct cfs_dir *dirp, register struct cfs_dirent *dirent) +{ + register unsigned char *b; + register unsigned char i; + register unsigned char count; + unsigned char buffer[0x40]; + static unsigned char s; + static unsigned char j; + + /* Skip the BASIC line-link. */ + if(!_pfs_dirread(dirp, buffer, 2)) { + return -1; + } + + /* Read the number of blocks. It's a two-byte number; but, the size is + ** a four-byte number. Zero the size; then, put the block number in + ** the first two bytes. It works because the 6502 CPU's numbers are + ** little-endian. + */ + dirent->size = 0; + if(!_pfs_dirread(dirp, &dirent->size, 2)) { + return -1; + } + + /* Read the next file entry into a buffer. */ + for(count = 0, b = buffer; count < sizeof(buffer); ++b) { + if(!_pfs_dirread1(dirp, b)) { + return -1; + } + ++count; + if(*b == '\0') { + break; + } + } + + /* The end of the directory was reached if the buffer contains "blocks free." + ** It is sufficient here to check for the leading 'b'. The buffer will have + ** at least one byte if we come here. + */ + if(buffer[0] == 'b') { + return -1; + } + + /* Parse the buffer for the file-name. */ + b = buffer; + j = 0; + s = 0; + i = 0; + while(i < count) { + switch(s) { + case 0: + /* Search for the start of the file-name. */ + if(*b == '"') { + s = 1; + } + break; + case 1: + /* Within the file-name. */ + if(*b == '"') { + /* The end of the file-name was found. */ + dirent->name[j] = '\0'; + return 0; + } else if(j < sizeof(dirent->name) - 1) { + dirent->name[j] = *b; + ++j; + } + break; + } + ++b; + ++i; + } + + /* The file-name is too long for the buffer. Return what could be read. */ + dirent->name[j] = '\0'; + return 0; +} diff --git a/platform/c64/lib/pfs.S b/platform/c64/lib/pfs.S index 49ef496ec..eae0838d4 100644 --- a/platform/c64/lib/pfs.S +++ b/platform/c64/lib/pfs.S @@ -36,7 +36,7 @@ .constructor init_pfs .destructor done_pfs - .importzp sp, ptr1, ptr2, ptr3 + .importzp sp, ptr1, ptr2, ptr3, tmp1 .import curunit, __filetype, popax, addysp, subysp .export pfs_rwcommon, pfs_rwsetflags, pfs_rwcommonend .if F_IDE64 @@ -46,6 +46,7 @@ .export pfs_makename, pfs_scratch .export _pfs_open, _pfs_read, _pfs_close + ;--------------------------------------------------------------------- MAXLEN = 80 ;maximum filename length @@ -107,7 +108,14 @@ _pfs_open: lda FNL beq error ;must have a filename - lda #2 - 1 ;file number + ; A directory listing needs a special secondary address + ldy tmp1 + bne open1 ;branch if not directory + lda #2 - 1 + dey ;.Y = 0 - 1 + bne open2 ;branch always + +open1: lda #2 - 1 ;file number tay ;secondary address open2: sta ptr2 sty ptr2 + 1 @@ -118,10 +126,6 @@ next: inc ptr2 ;next file number bcs error ;no more files lda flags - 1,x bne next ;already used - lda ptr2 + 1 - bne nextsa - inx - stx ptr2 + 1 nextsa: inc ptr2 + 1 ;next channel retr: lda ptr2 ;file number ldx curunit @@ -209,7 +213,7 @@ pfs_makename: ; Validate the name; and, find its length ldy #<-1 - sty ptr3 + sty ptr3 ;init. the count of retries sty ptr1 @L10: iny cpy #MAXLEN @@ -227,9 +231,17 @@ pfs_makename: bne @L10 cpy #0 beq badchr ;no name + sty FNL ;save original length tay ;zero index reg. - lda #'0' ;drive 0 or current partition + lda (FN),y + sta tmp1 ;preset not-directory flag to true + cmp #'$' + bne @L9 + sty tmp1 ;set not-directory flag to false + rts + +@L9: lda #'0' ;drive 0 or current partition sta (sp),y iny inc ptr1