commit c970e2c5ef616c90ae557ba09b47b258cae508be
parent 9b15f90008b69c5db210a1e24ee32e3cbaece8a7
Author: Andrew Alderwick <andrew@alderwick.co.uk>
Date: Fri, 5 Nov 2021 21:32:45 +0000
File device: drop offset shorts, add stat and delete.
Diffstat:
20 files changed, 240 insertions(+), 54 deletions(-)
diff --git a/build.sh b/build.sh
@@ -17,6 +17,8 @@ then
clang-format -i src/devices/ppu.c
clang-format -i src/devices/apu.h
clang-format -i src/devices/apu.c
+ clang-format -i src/devices/file.h
+ clang-format -i src/devices/file.c
clang-format -i src/uxnasm.c
clang-format -i src/uxnemu.c
clang-format -i src/uxncli.c
@@ -49,8 +51,8 @@ fi
echo "Building.."
cc ${CFLAGS} src/uxnasm.c -o bin/uxnasm
-cc ${CFLAGS} ${CORE} src/devices/ppu.c src/devices/apu.c src/uxnemu.c ${UXNEMU_LDFLAGS} -o bin/uxnemu
-cc ${CFLAGS} ${CORE} src/uxncli.c -o bin/uxncli
+cc ${CFLAGS} ${CORE} src/devices/file.c src/devices/ppu.c src/devices/apu.c src/uxnemu.c ${UXNEMU_LDFLAGS} -o bin/uxnemu
+cc ${CFLAGS} ${CORE} src/devices/file.c src/uxncli.c -o bin/uxncli
if [ -d "$HOME/bin" ]
then
diff --git a/projects/examples/blank.tal b/projects/examples/blank.tal
@@ -21,7 +21,7 @@
|60 @Audio3 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ]
|80 @Controller [ &vector $2 &button $1 &key $1 ]
|90 @Mouse [ &vector $2 &x $2 &y $2 &state $1 &wheel $1 ]
-|a0 @File [ &vector $2 &success $2 &offset-hs $2 &offset-ls $2 &name $2 &length $2 &load $2 &save $2 ]
+|a0 @File [ &vector $2 &name $2 &length $2 &success $2 &load $2 &save $2 &stat $2 &delete $1 ]
|b0 @DateTime [ &year $2 &month $1 &day $1 &hour $1 &minute $1 &second $1 &dotw $1 &doty $2 &isdst $1 ]
( variables )
diff --git a/projects/examples/demos/asma-piano.tal b/projects/examples/demos/asma-piano.tal
@@ -2,7 +2,7 @@
|00 @System [ &vector $2 &wst $1 &rst $1 &pad $4 &r $2 &g $2 &b $2 &debug $1 &halt $1 ]
|10 @Console [ &vector $2 &read $1 &pad $5 &write $1 &error $1 ]
-|a0 @File [ &vector $2 &success $2 &offset-hs $2 &offset-ls $2 &name $2 &length $2 &load $2 &save $2 ]
+|a0 @File [ &vector $2 &name $2 &length $2 &success $2 &load $2 &save $2 &stat $2 &delete $1 ]
( vectors )
@@ -51,7 +51,6 @@
that will prevent an infinite loop.
)
;&dest-file .File/name DEO2
- #0000 .File/offset-ls DEO2
#ff00 .File/length DEO2
#0100 .File/load
LIT DEO2 #00ff STA
diff --git a/projects/examples/demos/drum-rack.tal b/projects/examples/demos/drum-rack.tal
@@ -30,7 +30,7 @@
|70 @Midi [ &vector $2 &channel $1 ¬e $1 &velocity $1 ]
|80 @Controller [ &vector $2 &button $1 &key $1 ]
|90 @Mouse [ &vector $2 &x $2 &y $2 &state $1 &wheel $1 ]
-|a0 @File [ &vector $2 &success $2 &offset-hs $2 &offset-ls $2 &name $2 &length $2 &load $2 &save $2 ]
+|a0 @File [ &vector $2 &name $2 &length $2 &success $2 &load $2 &save $2 &stat $2 &delete $1 ]
( variables )
diff --git a/projects/examples/demos/font.tal b/projects/examples/demos/font.tal
@@ -12,7 +12,7 @@
|00 @System &vector $2 &pad $6 &r $2 &g $2 &b $2
|20 @Screen &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1
-|a0 @File &vector $2 &success $2 &offset-hs $2 &offset-ls $2 &name $2 &length $2 &load $2 &save $2
+|a0 @File &vector $2 &name $2 &length $2 &success $2 &load $2 &save $2 &stat $2 &delete $1
( variables )
diff --git a/projects/examples/demos/piano.tal b/projects/examples/demos/piano.tal
@@ -27,7 +27,7 @@
|70 @Midi [ &vector $2 &channel $1 ¬e $1 &velocity $1 ]
|80 @Controller [ &vector $2 &button $1 &key $1 ]
|90 @Mouse [ &vector $2 &x $2 &y $2 &state $1 &wheel $1 ]
-|a0 @File [ &vector $2 &success $2 &offset-hs $2 &offset-ls $2 &name $2 &length $2 &load $2 &save $2 ]
+|a0 @File [ &vector $2 &name $2 &length $2 &success $2 &load $2 &save $2 &stat $2 &delete $1 ]
( variables )
diff --git a/projects/examples/devices/file.load.tal b/projects/examples/devices/file.load.tal
@@ -4,7 +4,7 @@
|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1 ]
-|a0 @File [ &vector $2 &success $2 &offset-hs $2 &offset-ls $2 &name $2 &length $2 &load $2 &save $2 ]
+|a0 @File [ &vector $2 &name $2 &length $2 &success $2 &load $2 &save $2 &stat $2 &delete $1 ]
( variables )
diff --git a/projects/examples/devices/file.save.tal b/projects/examples/devices/file.save.tal
@@ -3,7 +3,7 @@
( devices )
|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
-|a0 @File [ &vector $2 &success $2 &offset-hs $2 &offset-ls $2 &name $2 &length $2 &load $2 &save $2 ]
+|a0 @File [ &vector $2 &name $2 &length $2 &success $2 &load $2 &save $2 &stat $2 &delete $1 ]
( variables )
diff --git a/projects/examples/devices/file.tal b/projects/examples/devices/file.tal
@@ -8,7 +8,7 @@
|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
|10 @Console [ &pad $8 &write $1 ]
|20 @Screen [ &vector $2 &width $2 &height $2 &pad $2 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1 ]
-|a0 @File [ &vector $2 &success $2 &offset-hs $2 &offset-ls $2 &name $2 &length $2 &load $2 &save $2 ]
+|a0 @File [ &vector $2 &name $2 &length $2 &success $2 &load $2 &save $2 &stat $2 &delete $1 ]
( variables )
diff --git a/projects/examples/gui/picture.tal b/projects/examples/gui/picture.tal
@@ -7,7 +7,7 @@
|00 @System [ &vector $2 &pad $6 &r $2 &g $2 &b $2 ]
|20 @Screen [ &vector $2 &width $2 &height $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1 ]
-|a0 @File [ &vector $2 &success $2 &offset-hs $2 &offset-ls $2 &name $2 &length $2 &load $2 &save $2 ]
+|a0 @File [ &vector $2 &name $2 &length $2 &success $2 &load $2 &save $2 &stat $2 &delete $1 ]
( variables )
diff --git a/projects/library/asma.tal b/projects/library/asma.tal
@@ -196,12 +196,11 @@
@asma-init-next-pass ( -- )
;asma/pass LDA INC ;asma/pass STA
;asma-write-buffer ;asma-output/ptr STA2
- #0000 DUP2k
- ;asma-output/offset STA2
+ #0000 DUP2
;asma/addr STA2
;asma/state STA
#01 SWP ( 0100 ) ;asma/written-addr STA2
- ;&preamble-end ;&preamble SUB2k ,asma-assemble-chunk JSR POP2 POP2
+ ;&preamble-end ;&preamble SUB2k ;asma-assemble-chunk JSR2 POP2 POP2
JMP2r
&preamble
@@ -498,15 +497,14 @@ include projects/library/binary-tree.tal
NIP2 ( start* )
,&after-flush JMP
-@asma-output [ &ptr $2 &offset $2 ]
+@asma-output [ &ptr $2 ]
@asma-flush-ignore ( len* -- )
POP2
JMP2r
@asma-flush-to-file ( len* -- )
- DUP2 .File/length DEO2
- ,asma-output/offset LDR2 DUP2 .File/offset-ls DEO2 ADD2 ,asma-output/offset STR2
+ .File/length DEO2
;asma/dest-filename LDA2 .File/name DEO2
;asma-write-buffer .File/save DEO2
JMP2r
diff --git a/projects/library/file-read-chunks.tal b/projects/library/file-read-chunks.tal
@@ -2,6 +2,14 @@
# Summary
+*** CAUTION: this library is deprecated! ***
+
+Chunked file reads are now possible in the File device directly: just use
+File/load or File/save multiple times. This library exists for compatibility to
+keep asma going until it gets a more substantial rewrite.
+
+***
+
Reads a file in chunks - perfect for when you have a small buffer or when you
don't know the file size. Copes with files up to 4,294,967,295 bytes long.
@@ -17,9 +25,11 @@ don't know the file size. Copes with files up to 4,294,967,295 bytes long.
&loop
STH2kr .File/name DEO2 ( F* U* B* OL* OH* SZ* / FN* )
- STH2k .File/length DEO2 ( F* U* B* OL* OH* / FN* SZ* )
- STH2k .File/offset-hs DEO2 ( F* U* B* OL* / FN* SZ* OH* )
- STH2k .File/offset-ls DEO2 ( F* U* B* / FN* SZ* OH* OL* )
+ STH2k ,ffwd/length STR2 ( F* U* B* OL* OH* / FN* SZ* )
+ STH2 ( F* U* B* OL* / FN* SZ* OH* )
+ STH2k ,ffwd/offset STR2 ( F* U* B* / FN* SZ* OH* OL* )
+ DUP2 ,ffwd/addr STR2
+ ,ffwd JSR
SWP2 ( F* B* U* / FN* SZ* OH* OL* )
ROT2k NIP2 ( F* B* U* B* F* / FN* SZ* OH* OL* )
OVR2 .File/load DEO2 ( F* B* U* B* F* / FN* SZ* OH* OL* )
@@ -40,6 +50,25 @@ don't know the file size. Copes with files up to 4,294,967,295 bytes long.
STH2r STH2r ( F* U'* B* OL'* OH'* SZ* / FN* )
,&loop JMP
+@ffwd
+ LIT2 &length $2
+ LIT2 &offset $2
+
+ &coarse ( length* offset* )
+ GTH2k ,&fine JCN
+ OVR2 .File/length DEO2
+ ,&addr LDR2 .File/load DEO2
+ OVR2 SUB2
+ ,&coarse JMP
+
+ &fine ( length* offset* )
+ .File/length DEO2 ( length* )
+ ,&addr LDR2 .File/load DEO2
+ .File/length DEO2 ( )
+ JMP2r
+
+ &addr $2
+
(
# Arguments
diff --git a/projects/library/load-rom.tal b/projects/library/load-rom.tal
@@ -11,8 +11,6 @@
)
.File/name DEO2
- #0000 .File/offset-hs DEO2
- #0000 .File/offset-ls DEO2
( return if file can't be found, or zero length )
#0001 .File/length DEO2
diff --git a/projects/software/asma.tal b/projects/software/asma.tal
@@ -1,8 +1,8 @@
( devices )
-|00 @System [ &vector $2 &wst $1 &rst $1 &pad $4 &r $2 &g $2 &b $2 &debug $1 &halt $1 ]
-|10 @Console [ &vector $2 &read $1 &pad $5 &write $1 &error $1 ]
-|a0 @File [ &vector $2 &success $2 &offset-hs $2 &offset-ls $2 &name $2 &length $2 &load $2 &save $2 ]
+|00 @System [ &vector $2 &wst $1 &rst $1 &pad $4 &r $2 &g $2 &b $2 &debug $1 &halt $1 ]
+|10 @Console [ &vector $2 &read $1 &pad $5 &write $1 &error $1 ]
+|a0 @File [ &vector $2 &name $2 &length $2 &success $2 &load $2 &save $2 &stat $2 &delete $1 ]
( vectors )
diff --git a/projects/software/calc.tal b/projects/software/calc.tal
@@ -35,7 +35,7 @@
|30 @Audio0 [ &vector $2 &position $2 &output $1 &pad $3 &adsr $2 &length $2 &addr $2 &volume $1 &pitch $1 ]
|80 @Controller [ &vector $2 &button $1 &key $1 ]
|90 @Mouse [ &vector $2 &x $2 &y $2 &state $1 &wheel $1 ]
-|a0 @File [ &vector $2 &success $2 &offset-hs $2 &offset-ls $2 &name $2 &length $2 &load $2 &save $2 ]
+|a0 @File [ &vector $2 &name $2 &length $2 &success $2 &load $2 &save $2 &stat $2 &delete $1 ]
( variables )
diff --git a/projects/software/launcher.tal b/projects/software/launcher.tal
@@ -22,7 +22,7 @@
|20 @Screen &vector $2 &width $2 &height $2 &auto $1 &pad $1 &x $2 &y $2 &addr $2 &pixel $1 &sprite $1
|80 @Controller [ &vector $2 &button $1 &key $1 ]
|90 @Mouse [ &vector $2 &x $2 &y $2 &state $1 &wheel $1 ]
-|a0 @File &vector $2 &success $2 &offset-hs $2 &offset-ls $2 &name $2 &length $2 &load $2 &save $2
+|a0 @File &vector $2 &name $2 &length $2 &success $2 &load $2 &save $2 &stat $2 &delete $1
|b0 @DateTime [ &year $2 &month $1 &day $1 &hour $1 &minute $1 &second $1 &dotw $1 &doty $2 &isdst $1 ]
( variables )
diff --git a/src/devices/file.c b/src/devices/file.c
@@ -0,0 +1,135 @@
+#include "../uxn.h"
+#include "file.h"
+
+/*
+Copyright (c) 2021 Devine Lu Linvega
+Copyright (c) 2021 Andrew Alderwick
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE.
+*/
+
+#define _POSIX_C_SOURCE 200809L
+
+#include <stdio.h>
+#include <dirent.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+static FILE *f;
+static DIR *d;
+static int dir_fd;
+static char *current_filename;
+static enum { IDLE,
+ FILE_READ,
+ FILE_WRITE,
+ DIR_READ } state;
+static struct dirent *de;
+
+static char hex[] = "0123456789abcdef";
+
+static void
+reset(void)
+{
+ if(f != NULL) {
+ fclose(f);
+ f = NULL;
+ }
+ if(d != NULL) {
+ closedir(d);
+ d = NULL;
+ }
+ de = NULL;
+ state = IDLE;
+}
+
+void
+file_prepare(void *filename)
+{
+ reset();
+ current_filename = (char *)filename;
+}
+
+static Uint16
+write_entry(char *p, Uint16 len, const char *filename, struct stat *st)
+{
+ if(len < strlen(filename) + 7) return 0;
+ memcpy(p, "???? ", 5);
+ strcpy(p + 5, filename);
+ strcat(p, "\n");
+ if(S_ISDIR(st->st_mode)) {
+ memcpy(p, "---- ", 5);
+ } else if(st->st_size < 0x10000) {
+ p[0] = hex[(st->st_size >> 12) & 0xf];
+ p[1] = hex[(st->st_size >> 8) & 0xf];
+ p[2] = hex[(st->st_size >> 4) & 0xf];
+ p[3] = hex[(st->st_size >> 0) & 0xf];
+ }
+ return strlen(p);
+}
+
+Uint16
+file_read(void *dest, Uint16 len)
+{
+ if(state != FILE_READ && state != DIR_READ) {
+ reset();
+ if((d = opendir(current_filename)) != NULL) {
+ state = DIR_READ;
+ dir_fd = dirfd(d);
+ } else if((f = fopen(current_filename, "rb")) != NULL)
+ state = FILE_READ;
+ }
+ if(state == FILE_READ)
+ return fread(dest, 1, len, f);
+ if(state == DIR_READ) {
+ char *p = dest;
+ if(de == NULL) de = readdir(d);
+ for(; de != NULL; de = readdir(d)) {
+ struct stat st;
+ Uint16 n;
+ if(de->d_name[0] == '.' && de->d_name[1] == '\0')
+ continue;
+ if(fstatat(dir_fd, de->d_name, &st, 0))
+ continue;
+ n = write_entry(p, len, de->d_name, &st);
+ if(!n) break;
+ p += n;
+ len -= n;
+ }
+ return p - (char *)dest;
+ }
+ return 0;
+}
+
+Uint16
+file_write(void *src, Uint16 len)
+{
+ if(state != FILE_WRITE) {
+ reset();
+ if((f = fopen(current_filename, "ab")) != NULL)
+ state = FILE_WRITE;
+ }
+ if(state == FILE_WRITE)
+ return fwrite(src, 1, len, f);
+ return 0;
+}
+
+Uint16
+file_stat(void *dest, Uint16 len)
+{
+ struct stat st;
+ if(stat(current_filename, &st))
+ return 0;
+ return write_entry((char *)dest, len, current_filename, &st);
+}
+
+Uint16
+file_delete(void)
+{
+ return unlink(current_filename);
+}
diff --git a/src/devices/file.h b/src/devices/file.h
@@ -0,0 +1,17 @@
+/*
+Copyright (c) 2021 Devine Lu Linvega
+Copyright (c) 2021 Andrew Alderwick
+
+Permission to use, copy, modify, and distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE.
+*/
+
+void file_prepare(void *filename);
+Uint16 file_read(void *dest, Uint16 len);
+Uint16 file_write(void *src, Uint16 len);
+Uint16 file_stat(void *dest, Uint16 len);
+Uint16 file_delete();
diff --git a/src/uxncli.c b/src/uxncli.c
@@ -2,6 +2,7 @@
#include <unistd.h>
#include <time.h>
#include "uxn.h"
+#include "devices/file.h"
/*
Copyright (c) 2021 Devine Lu Linvega
@@ -78,19 +79,22 @@ console_deo(Device *d, Uint8 port)
static void
file_deo(Device *d, Uint8 port)
{
- Uint8 read = port == 0xd;
- if(read || port == 0xf) {
- char *name = (char *)&d->mem[peek16(d->dat, 0x8)];
- Uint16 result = 0, length = peek16(d->dat, 0xa);
- long offset = (peek16(d->dat, 0x4) << 16) + peek16(d->dat, 0x6);
- Uint16 addr = peek16(d->dat, port - 1);
- FILE *f = fopen(name, read ? "rb" : (offset ? "ab" : "wb"));
- if(f) {
- if(fseek(f, offset, SEEK_SET) != -1)
- result = read ? fread(&d->mem[addr], 1, length, f) : fwrite(&d->mem[addr], 1, length, f);
- fclose(f);
- }
- poke16(d->dat, 0x2, result);
+ switch(port) {
+ case 0x3:
+ file_prepare(&d->mem[peek16(d->dat, 0x2)]);
+ break;
+ case 0x9:
+ poke16(d->dat, 0x6, file_read(&d->mem[peek16(d->dat, 0x8)], peek16(d->dat, 0x4)));
+ break;
+ case 0xb:
+ poke16(d->dat, 0x6, file_write(&d->mem[peek16(d->dat, 0xa)], peek16(d->dat, 0x4)));
+ break;
+ case 0xd:
+ poke16(d->dat, 0x6, file_stat(&d->mem[peek16(d->dat, 0xc)], peek16(d->dat, 0x4)));
+ break;
+ case 0xe:
+ poke16(d->dat, 0x6, file_delete());
+ break;
}
}
diff --git a/src/uxnemu.c b/src/uxnemu.c
@@ -8,6 +8,7 @@
#include <SDL.h>
#include "devices/ppu.h"
#include "devices/apu.h"
+#include "devices/file.h"
#pragma GCC diagnostic pop
/*
@@ -370,19 +371,22 @@ screen_deo(Device *d, Uint8 port)
static void
file_deo(Device *d, Uint8 port)
{
- Uint8 read = port == 0xd;
- if(read || port == 0xf) {
- char *name = (char *)&d->mem[peek16(d->dat, 0x8)];
- Uint16 result = 0, length = peek16(d->dat, 0xa);
- long offset = (peek16(d->dat, 0x4) << 16) + peek16(d->dat, 0x6);
- Uint16 addr = peek16(d->dat, port - 1);
- FILE *f = fopen(name, read ? "rb" : (offset ? "ab" : "wb"));
- if(f) {
- if(fseek(f, offset, SEEK_SET) != -1)
- result = read ? fread(&d->mem[addr], 1, length, f) : fwrite(&d->mem[addr], 1, length, f);
- fclose(f);
- }
- poke16(d->dat, 0x2, result);
+ switch(port) {
+ case 0x3:
+ file_prepare(&d->mem[peek16(d->dat, 0x2)]);
+ break;
+ case 0x9:
+ poke16(d->dat, 0x6, file_read(&d->mem[peek16(d->dat, 0x8)], peek16(d->dat, 0x4)));
+ break;
+ case 0xb:
+ poke16(d->dat, 0x6, file_write(&d->mem[peek16(d->dat, 0xa)], peek16(d->dat, 0x4)));
+ break;
+ case 0xd:
+ poke16(d->dat, 0x6, file_stat(&d->mem[peek16(d->dat, 0xc)], peek16(d->dat, 0x4)));
+ break;
+ case 0xe:
+ poke16(d->dat, 0x6, file_delete());
+ break;
}
}