Added directory functions to the Commodore Platform File System.

They reduce the Telnet server's run size by 1231 bytes.
This commit is contained in:
Oliver Schmidt 2016-10-15 16:33:24 +02:00
parent c25e965b0c
commit d864e73579
14 changed files with 636 additions and 19 deletions

View File

@ -36,6 +36,7 @@
#include <dirent.h>
#include <string.h>
#define CFS_IMPL 1
#include "cfs/cfs.h"
struct cfs_posix_dir {

View File

@ -40,6 +40,7 @@
#include <unistd.h>
#endif
#define CFS_IMPL 1
#include "cfs/cfs.h"
/*---------------------------------------------------------------------------*/

View File

@ -29,6 +29,7 @@
* This file is part of the Contiki operating system.
*
* Author: Oliver Schmidt <ol.sc@web.de>
* Author: Greg King <gregdk@users.sf.net>
*
*/
@ -37,11 +38,17 @@
#include <sys/types.h>
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_ */

View File

@ -1 +1 @@
DEFINES = WITH_LOGGING,WITH_80COL
DEFINES = WITH_LOGGING,WITH_PFS,WITH_80COL

View File

@ -31,7 +31,8 @@
# Author: Oliver Schmidt <ol.sc@web.de>
#
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

View File

@ -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

View File

@ -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

171
platform/c128/lib/pfs-dir.c Normal file
View File

@ -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;
}

View File

@ -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

View File

@ -31,7 +31,8 @@
# Author: Oliver Schmidt <ol.sc@web.de>
#
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

View File

@ -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

View File

@ -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

171
platform/c64/lib/pfs-dir.c Normal file
View File

@ -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;
}

View File

@ -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