1
0
mirror of https://github.com/cc65/cc65.git synced 2025-04-15 19:37:46 +00:00

Apple2: Rewrite readdir() and closedir() to assembly

This commit is contained in:
Colin Leroy-Mira 2024-11-16 21:59:00 +01:00 committed by Oliver Schmidt
parent 700c01fa8b
commit f663ee428d
5 changed files with 202 additions and 197 deletions

View File

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

View File

@ -4,16 +4,18 @@
; DIR* __fastcall__ opendir (register const char* name)
;
.export _opendir
.export _opendir, read_dir_block_ptr1
.import closedir_ptr1
.import _open, _read, _close
.import _malloc, _free
.import _malloc
.import ___directerrno
.import ___oserror, __cwd
.import pushptr1, popptr1
.import pushax, pusha0
.import return0, returnFFFF
.importzp ptr1
@ -37,7 +39,7 @@
sta ptr1
stx ptr1+1
: ; open directory
: ; Open directory
jsr pushptr1
lda #O_RDONLY
jsr pusha0
@ -58,23 +60,17 @@
; We failed to allocate
pla ; Get fd back
ldx #$00
jsr _close ; close it
jsr _close ; Close it
lda #ENOMEM ; Set error
jsr ___directerrno
@return_null:
lda #$00
tax
rts
jmp return0
: ; Store dir struct to pointer
sta ptr1
stx ptr1+1
; Push ptr1, read will destroy it
jsr pushptr1
; Save fd to dir struct
lda #$00
ldy #DIR::FD + 1
@ -84,49 +80,15 @@
pla ; Get fd back
sta (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
jsr read_dir_block_ptr1
bcc @read_ok
lda #<.sizeof(DIR::BYTES)
ldx #>.sizeof(DIR::BYTES)
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
; Close directory, free it
jsr closedir_ptr1
jmp return0 ; Return NULL
@read_ok:
; Read succeeded, populate dir struct
jsr popptr1 ; Restore our dir pointer
; Get file_count to entry_length from block
ldy #$26 + DIR::BYTES
@ -153,3 +115,45 @@
ldx ptr1+1
rts
.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

View File

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