Apple2: Rewrite readdir() and closedir() to assembly
This commit is contained in:
committed by
Oliver Schmidt
parent
700c01fa8b
commit
f663ee428d
@@ -1,57 +0,0 @@
|
|||||||
/*****************************************************************************/
|
|
||||||
/* */
|
|
||||||
/* closedir.c */
|
|
||||||
/* */
|
|
||||||
/* Close a directory */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* (C) 2005 Oliver Schmidt, <ol.sc@web.de> */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* This software is provided 'as-is', without any expressed or implied */
|
|
||||||
/* warranty. In no event will the authors be held liable for any damages */
|
|
||||||
/* arising from the use of this software. */
|
|
||||||
/* */
|
|
||||||
/* Permission is granted to anyone to use this software for any purpose, */
|
|
||||||
/* including commercial applications, and to alter it and redistribute it */
|
|
||||||
/* freely, subject to the following restrictions: */
|
|
||||||
/* */
|
|
||||||
/* 1. The origin of this software must not be misrepresented; you must not */
|
|
||||||
/* claim that you wrote the original software. If you use this software */
|
|
||||||
/* in a product, an acknowledgment in the product documentation would be */
|
|
||||||
/* appreciated but is not required. */
|
|
||||||
/* 2. Altered source versions must be plainly marked as such, and must not */
|
|
||||||
/* be misrepresented as being the original software. */
|
|
||||||
/* 3. This notice may not be removed or altered from any source */
|
|
||||||
/* distribution. */
|
|
||||||
/* */
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include "dir.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* Code */
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int __fastcall__ closedir (DIR* dir)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
/* Cleanup directory file */
|
|
||||||
result = close (dir->fd);
|
|
||||||
|
|
||||||
/* Cleanup DIR */
|
|
||||||
free (dir);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
35
libsrc/apple2/closedir.s
Normal file
35
libsrc/apple2/closedir.s
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
;
|
||||||
|
; Colin Leroy-Mira <colin@colino.net>, 2024
|
||||||
|
;
|
||||||
|
; int __fastcall__ closedir (DIR *dir)
|
||||||
|
;
|
||||||
|
|
||||||
|
.export _closedir, closedir_ptr1
|
||||||
|
|
||||||
|
.import _close
|
||||||
|
.import _free
|
||||||
|
.import pushax, popax, pushptr1, swapstk
|
||||||
|
|
||||||
|
.importzp ptr1
|
||||||
|
|
||||||
|
.include "apple2.inc"
|
||||||
|
.include "dir.inc"
|
||||||
|
.include "errno.inc"
|
||||||
|
.include "fcntl.inc"
|
||||||
|
.include "zeropage.inc"
|
||||||
|
|
||||||
|
_closedir:
|
||||||
|
sta ptr1
|
||||||
|
stx ptr1+1
|
||||||
|
closedir_ptr1:
|
||||||
|
; Close fd
|
||||||
|
jsr pushptr1 ; Backup ptr1
|
||||||
|
ldy #$00
|
||||||
|
lda (ptr1),y ; Get fd
|
||||||
|
ldx #$00
|
||||||
|
jsr _close
|
||||||
|
jsr swapstk ; Store result, pop ptr1
|
||||||
|
|
||||||
|
; Free dir structure
|
||||||
|
jsr _free
|
||||||
|
jmp popax ; Return result
|
||||||
@@ -4,16 +4,18 @@
|
|||||||
; DIR* __fastcall__ opendir (register const char* name)
|
; DIR* __fastcall__ opendir (register const char* name)
|
||||||
;
|
;
|
||||||
|
|
||||||
.export _opendir
|
.export _opendir, read_dir_block_ptr1
|
||||||
|
|
||||||
|
.import closedir_ptr1
|
||||||
.import _open, _read, _close
|
.import _open, _read, _close
|
||||||
.import _malloc, _free
|
.import _malloc
|
||||||
.import ___directerrno
|
.import ___directerrno
|
||||||
|
|
||||||
.import ___oserror, __cwd
|
.import ___oserror, __cwd
|
||||||
|
|
||||||
.import pushptr1, popptr1
|
.import pushptr1, popptr1
|
||||||
.import pushax, pusha0
|
.import pushax, pusha0
|
||||||
|
.import return0, returnFFFF
|
||||||
|
|
||||||
.importzp ptr1
|
.importzp ptr1
|
||||||
|
|
||||||
@@ -37,7 +39,7 @@
|
|||||||
sta ptr1
|
sta ptr1
|
||||||
stx ptr1+1
|
stx ptr1+1
|
||||||
|
|
||||||
: ; open directory
|
: ; Open directory
|
||||||
jsr pushptr1
|
jsr pushptr1
|
||||||
lda #O_RDONLY
|
lda #O_RDONLY
|
||||||
jsr pusha0
|
jsr pusha0
|
||||||
@@ -58,23 +60,17 @@
|
|||||||
; We failed to allocate
|
; We failed to allocate
|
||||||
pla ; Get fd back
|
pla ; Get fd back
|
||||||
ldx #$00
|
ldx #$00
|
||||||
jsr _close ; close it
|
jsr _close ; Close it
|
||||||
|
|
||||||
lda #ENOMEM ; Set error
|
lda #ENOMEM ; Set error
|
||||||
jsr ___directerrno
|
jsr ___directerrno
|
||||||
|
|
||||||
@return_null:
|
@return_null:
|
||||||
lda #$00
|
jmp return0
|
||||||
tax
|
|
||||||
rts
|
|
||||||
|
|
||||||
: ; Store dir struct to pointer
|
: ; Store dir struct to pointer
|
||||||
sta ptr1
|
sta ptr1
|
||||||
stx ptr1+1
|
stx ptr1+1
|
||||||
|
|
||||||
; Push ptr1, read will destroy it
|
|
||||||
jsr pushptr1
|
|
||||||
|
|
||||||
; Save fd to dir struct
|
; Save fd to dir struct
|
||||||
lda #$00
|
lda #$00
|
||||||
ldy #DIR::FD + 1
|
ldy #DIR::FD + 1
|
||||||
@@ -84,49 +80,15 @@
|
|||||||
pla ; Get fd back
|
pla ; Get fd back
|
||||||
sta (ptr1),y
|
sta (ptr1),y
|
||||||
|
|
||||||
jsr pusha0 ; push fd for read
|
jsr read_dir_block_ptr1
|
||||||
lda #<DIR::BYTES
|
bcc @read_ok
|
||||||
clc
|
|
||||||
adc ptr1
|
|
||||||
pha
|
|
||||||
lda #>DIR::BYTES
|
|
||||||
adc ptr1+1
|
|
||||||
tax
|
|
||||||
pla
|
|
||||||
jsr pushax ; Push dir->block.bytes for read
|
|
||||||
|
|
||||||
lda #<.sizeof(DIR::BYTES)
|
; Close directory, free it
|
||||||
ldx #>.sizeof(DIR::BYTES)
|
jsr closedir_ptr1
|
||||||
|
jmp return0 ; Return NULL
|
||||||
jsr _read ; Read directory block
|
|
||||||
cpx #>.sizeof(DIR::BYTES)
|
|
||||||
bne @err_read
|
|
||||||
cmp #<.sizeof(DIR::BYTES)
|
|
||||||
beq @read_ok
|
|
||||||
|
|
||||||
@err_read:
|
|
||||||
; Read failed, exit
|
|
||||||
lda ___oserror
|
|
||||||
bne :+
|
|
||||||
lda #EINVAL
|
|
||||||
jsr ___directerrno
|
|
||||||
|
|
||||||
: ; Close fd
|
|
||||||
jsr popptr1 ; Restore our dir pointer
|
|
||||||
ldy #$00
|
|
||||||
lda (ptr1),y ; Get fd
|
|
||||||
ldx #$00
|
|
||||||
jsr _close
|
|
||||||
|
|
||||||
; Free dir structure
|
|
||||||
lda ptr1
|
|
||||||
ldx ptr1+1
|
|
||||||
jsr _free
|
|
||||||
jmp @return_null
|
|
||||||
|
|
||||||
@read_ok:
|
@read_ok:
|
||||||
; Read succeeded, populate dir struct
|
; Read succeeded, populate dir struct
|
||||||
jsr popptr1 ; Restore our dir pointer
|
|
||||||
|
|
||||||
; Get file_count to entry_length from block
|
; Get file_count to entry_length from block
|
||||||
ldy #$26 + DIR::BYTES
|
ldy #$26 + DIR::BYTES
|
||||||
@@ -153,3 +115,45 @@
|
|||||||
ldx ptr1+1
|
ldx ptr1+1
|
||||||
rts
|
rts
|
||||||
.endproc
|
.endproc
|
||||||
|
|
||||||
|
; Read a directory for the DIR* pointer in ptr1
|
||||||
|
; Return with carry clear on success
|
||||||
|
read_dir_block_ptr1:
|
||||||
|
; Push ptr1, read will destroy it
|
||||||
|
jsr pushptr1
|
||||||
|
|
||||||
|
ldy #DIR::FD
|
||||||
|
lda (ptr1),y
|
||||||
|
|
||||||
|
jsr pusha0 ; Push fd for read
|
||||||
|
lda #<DIR::BYTES
|
||||||
|
clc
|
||||||
|
adc ptr1
|
||||||
|
pha
|
||||||
|
lda #>DIR::BYTES
|
||||||
|
adc ptr1+1
|
||||||
|
tax
|
||||||
|
pla
|
||||||
|
jsr pushax ; Push dir->block.bytes for read
|
||||||
|
|
||||||
|
lda #<.sizeof(DIR::BYTES)
|
||||||
|
ldx #>.sizeof(DIR::BYTES)
|
||||||
|
|
||||||
|
jsr _read ; Read directory block
|
||||||
|
cpx #>.sizeof(DIR::BYTES)
|
||||||
|
bne @read_err
|
||||||
|
cmp #<.sizeof(DIR::BYTES)
|
||||||
|
beq @read_ok
|
||||||
|
|
||||||
|
@read_err:
|
||||||
|
; Read failed, exit
|
||||||
|
lda ___oserror
|
||||||
|
bne :+
|
||||||
|
lda #EINVAL
|
||||||
|
jsr ___directerrno
|
||||||
|
: sec
|
||||||
|
bcs @out
|
||||||
|
@read_ok:
|
||||||
|
clc
|
||||||
|
@out:
|
||||||
|
jmp popptr1
|
||||||
|
|||||||
@@ -1,90 +0,0 @@
|
|||||||
/*****************************************************************************/
|
|
||||||
/* */
|
|
||||||
/* readdir.c */
|
|
||||||
/* */
|
|
||||||
/* Read directory entry */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* (C) 2005 Oliver Schmidt, <ol.sc@web.de> */
|
|
||||||
/* */
|
|
||||||
/* */
|
|
||||||
/* This software is provided 'as-is', without any expressed or implied */
|
|
||||||
/* warranty. In no event will the authors be held liable for any damages */
|
|
||||||
/* arising from the use of this software. */
|
|
||||||
/* */
|
|
||||||
/* Permission is granted to anyone to use this software for any purpose, */
|
|
||||||
/* including commercial applications, and to alter it and redistribute it */
|
|
||||||
/* freely, subject to the following restrictions: */
|
|
||||||
/* */
|
|
||||||
/* 1. The origin of this software must not be misrepresented; you must not */
|
|
||||||
/* claim that you wrote the original software. If you use this software */
|
|
||||||
/* in a product, an acknowledgment in the product documentation would be */
|
|
||||||
/* appreciated but is not required. */
|
|
||||||
/* 2. Altered source versions must be plainly marked as such, and must not */
|
|
||||||
/* be misrepresented as being the original software. */
|
|
||||||
/* 3. This notice may not be removed or altered from any source */
|
|
||||||
/* distribution. */
|
|
||||||
/* */
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include "dir.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* Code */
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct dirent* __fastcall__ readdir (register DIR* dir)
|
|
||||||
{
|
|
||||||
register unsigned char* entry;
|
|
||||||
|
|
||||||
/* Search for the next active directory entry */
|
|
||||||
do {
|
|
||||||
|
|
||||||
/* Read next directory block if necessary */
|
|
||||||
if (dir->current_entry == dir->entries_per_block) {
|
|
||||||
if (read (dir->fd,
|
|
||||||
dir->block.bytes,
|
|
||||||
sizeof (dir->block)) != sizeof (dir->block)) {
|
|
||||||
|
|
||||||
/* Just return failure as read() has */
|
|
||||||
/* set errno if (and only if) no EOF */
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Start with first entry in next block */
|
|
||||||
dir->current_entry = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compute pointer to current entry */
|
|
||||||
entry = dir->block.content.entries +
|
|
||||||
dir->current_entry * dir->entry_length;
|
|
||||||
|
|
||||||
/* Switch to next entry */
|
|
||||||
++dir->current_entry;
|
|
||||||
} while (entry[0x00] == 0);
|
|
||||||
|
|
||||||
/* Move creation date/time to allow for next step below */
|
|
||||||
*(unsigned long*)&entry[0x1A] = *(unsigned long*)&entry[0x18];
|
|
||||||
|
|
||||||
/* Feature unsigned long access to EOF by extension from 3 to 4 bytes */
|
|
||||||
entry[0x18] = 0;
|
|
||||||
|
|
||||||
/* Move file type to allow for next step below */
|
|
||||||
entry[0x19] = entry[0x10];
|
|
||||||
|
|
||||||
/* Zero-terminate file name */
|
|
||||||
entry[0x01 + (entry[0x00] & 0x0F)] = 0;
|
|
||||||
|
|
||||||
/* Return success */
|
|
||||||
return (struct dirent*)&entry[0x01];
|
|
||||||
}
|
|
||||||
113
libsrc/apple2/readdir.s
Normal file
113
libsrc/apple2/readdir.s
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
;
|
||||||
|
; Colin Leroy-Mira <colin@colino.net>, 2024
|
||||||
|
;
|
||||||
|
; struct dirent * __fastcall__ readdir (DIR *dir)
|
||||||
|
;
|
||||||
|
.export _readdir
|
||||||
|
.import read_dir_block_ptr1
|
||||||
|
|
||||||
|
.import incax1, return0
|
||||||
|
.import tosaddax, tosumula0, incaxy
|
||||||
|
.import pushax, pusha0, pushptr1, popptr1
|
||||||
|
.importzp ptr1, ptr4
|
||||||
|
|
||||||
|
.include "dir.inc"
|
||||||
|
|
||||||
|
.proc _readdir
|
||||||
|
sta ptr1
|
||||||
|
stx ptr1+1
|
||||||
|
|
||||||
|
@next_entry:
|
||||||
|
; Do we need to read the next directory block?
|
||||||
|
ldy #DIR::CURRENT_ENTRY
|
||||||
|
lda (ptr1),y
|
||||||
|
ldy #DIR::ENTRIES_PER_BLOCK
|
||||||
|
cmp (ptr1),y
|
||||||
|
bne @read_entry ; We don't
|
||||||
|
|
||||||
|
jsr read_dir_block_ptr1
|
||||||
|
bcc @read_ok
|
||||||
|
|
||||||
|
; We had a read error
|
||||||
|
jmp return0
|
||||||
|
|
||||||
|
@read_ok:
|
||||||
|
ldy #DIR::CURRENT_ENTRY
|
||||||
|
lda #$00
|
||||||
|
sta (ptr1),y
|
||||||
|
|
||||||
|
@read_entry:
|
||||||
|
; Compute pointer to current entry:
|
||||||
|
; entry = dir->block.content.entries +
|
||||||
|
; dir->current_entry * dir->entry_length
|
||||||
|
|
||||||
|
jsr pushptr1 ; Backup ptr1
|
||||||
|
lda ptr1
|
||||||
|
ldx ptr1+1
|
||||||
|
ldy #DIR::BYTES + DIR::CONTENT::ENTRIES
|
||||||
|
jsr incaxy
|
||||||
|
jsr pushax
|
||||||
|
ldy #DIR::CURRENT_ENTRY
|
||||||
|
lda (ptr1),y
|
||||||
|
jsr pusha0
|
||||||
|
ldy #DIR::ENTRY_LENGTH
|
||||||
|
lda (ptr1),y
|
||||||
|
jsr tosumula0
|
||||||
|
jsr tosaddax
|
||||||
|
; Store pointer to current entry
|
||||||
|
sta ptr4
|
||||||
|
stx ptr4+1
|
||||||
|
jsr popptr1
|
||||||
|
|
||||||
|
; Switch to next entry
|
||||||
|
ldy #DIR::CURRENT_ENTRY
|
||||||
|
lda (ptr1),y
|
||||||
|
clc
|
||||||
|
adc #1
|
||||||
|
sta (ptr1),y
|
||||||
|
|
||||||
|
; Check if entry[0] == 0
|
||||||
|
ldy #$00
|
||||||
|
lda (ptr4),y
|
||||||
|
beq @next_entry ; Yes, skip entry
|
||||||
|
|
||||||
|
; Move creation date/time to allow for next step below
|
||||||
|
; 18-19-1A-1B => 1A-1B-1C-1D
|
||||||
|
ldy #$1B
|
||||||
|
: lda (ptr4),y
|
||||||
|
iny
|
||||||
|
iny
|
||||||
|
sta (ptr4),y
|
||||||
|
dey
|
||||||
|
dey
|
||||||
|
dey
|
||||||
|
cpy #$17
|
||||||
|
bne :-
|
||||||
|
|
||||||
|
; Feature unsigned long access to EOF by extension from 3 to 4 bytes
|
||||||
|
; entry[0x18] = 0
|
||||||
|
iny
|
||||||
|
lda #$00
|
||||||
|
sta (ptr4),y
|
||||||
|
|
||||||
|
; Move file type to allow for next step below
|
||||||
|
; entry[0x19] = entry[0x10]
|
||||||
|
ldy #$10
|
||||||
|
lda (ptr4),y
|
||||||
|
ldy #$19
|
||||||
|
sta (ptr4),y
|
||||||
|
|
||||||
|
; Zero-terminate file name
|
||||||
|
ldy #$00
|
||||||
|
lda (ptr4),y
|
||||||
|
and #$0F
|
||||||
|
tay
|
||||||
|
iny
|
||||||
|
lda #$00
|
||||||
|
sta (ptr4),y
|
||||||
|
|
||||||
|
; Return pointer to entry+1
|
||||||
|
lda ptr4
|
||||||
|
ldx ptr4+1
|
||||||
|
jmp incax1
|
||||||
|
.endproc
|
||||||
Reference in New Issue
Block a user