Implement File device with Rockbox API.

This commit is contained in:
Andrew Alderwick 2021-11-14 22:23:14 +00:00
parent 52883316fd
commit ba0e3268e8
3 changed files with 66 additions and 40 deletions

View File

@ -22,24 +22,24 @@ WITH REGARD TO THIS SOFTWARE.
//#include <unistd.h>
#include "plugin.h"
static FILE *f;
static int f = -1;
static DIR *d;
static char *current_filename = "";
static char current_filename[4096];
static enum { IDLE,
FILE_READ,
FILE_WRITE,
DIR_READ } state;
static struct dirent *de;
static void
reset(void)
void
file_cleanup(void)
{
if(f != NULL) {
fclose(f);
f = NULL;
if(f >= 0) {
rb->close(f);
f = -1;
}
if(d != NULL) {
closedir(d);
rb->closedir(d);
d = NULL;
}
de = NULL;
@ -47,17 +47,14 @@ reset(void)
}
static Uint16
get_entry(char *p, Uint16 len, const char *pathname, const char *basename, int fail_nonzero)
get_entry(char *p, Uint16 len, const char *basename, struct dirinfo info)
{
struct stat st;
if(len < strlen(basename) + 7)
return 0;
if(stat(pathname, &st))
return fail_nonzero ? snprintf(p, len, "!!!! %s\n", basename) : 0;
else if(S_ISDIR(st.st_mode))
else if(info.attribute & ATTR_DIRECTORY)
return snprintf(p, len, "---- %s\n", basename);
else if(st.st_size < 0x10000)
return snprintf(p, len, "%04x %s\n", (Uint16)st.st_size, basename);
else if(info.size < 0x10000)
return snprintf(p, len, "%04x %s\n", (Uint16)info.size, basename);
else
return snprintf(p, len, "???? %s\n", basename);
}
@ -65,15 +62,13 @@ get_entry(char *p, Uint16 len, const char *pathname, const char *basename, int f
static Uint16
file_read_dir(char *dest, Uint16 len)
{
static char pathname[4096];
char *p = dest;
if(de == NULL) de = readdir(d);
for(; de != NULL; de = readdir(d)) {
if(de == NULL) de = rb->readdir(d);
for(; de != NULL; de = rb->readdir(d)) {
Uint16 n;
if(de->d_name[0] == '.' && de->d_name[1] == '\0')
continue;
snprintf(pathname, sizeof(pathname), "%s/%s", current_filename, de->d_name);
n = get_entry(p, len, pathname, de->d_name, 1);
n = get_entry(p, len, de->d_name, rb->dir_get_info(d, de));
if(!n) break;
p += n;
len -= n;
@ -82,10 +77,10 @@ file_read_dir(char *dest, Uint16 len)
}
Uint16
file_init(void *filename)
file_init(const char *filename)
{
reset();
current_filename = filename;
file_cleanup();
snprintf(current_filename, sizeof(current_filename), "/%s", (filename[0] == '/') ? &filename[1] : filename);
return 0;
}
@ -93,14 +88,15 @@ Uint16
file_read(void *dest, Uint16 len)
{
if(state != FILE_READ && state != DIR_READ) {
reset();
if((d = opendir(current_filename)) != NULL)
file_cleanup();
if((d = rb->opendir(current_filename)) != NULL)
state = DIR_READ;
else if((f = fopen(current_filename, "rb")) != NULL)
else if((f = rb->open(current_filename, O_RDONLY)) >= 0)
state = FILE_READ;
}
if(state == FILE_READ)
return fread(dest, 1, len, f);
if(state == FILE_READ) {
return rb->read(f, dest, len);
}
if(state == DIR_READ)
return file_read_dir(dest, len);
return 0;
@ -111,13 +107,12 @@ file_write(void *src, Uint16 len, Uint8 flags)
{
Uint16 ret = 0;
if(state != FILE_WRITE) {
reset();
if((f = fopen(current_filename, (flags & 0x01) ? "ab" : "wb")) != NULL)
file_cleanup();
if((f = rb->open(current_filename, O_WRONLY | ((flags & 0x01) ? O_APPEND : 0))) >= 0)
state = FILE_WRITE;
}
if(state == FILE_WRITE) {
if((ret = fwrite(src, 1, len, f)) > 0 && fflush(f) != 0)
ret = 0;
ret = rb->write(f, src, len);
}
return ret;
}
@ -125,16 +120,31 @@ file_write(void *src, Uint16 len, Uint8 flags)
Uint16
file_stat(void *dest, Uint16 len)
{
DIR *sd;
struct dirent *sde;
char *basename = strrchr(current_filename, '/');
if(basename != NULL)
if(basename != current_filename) {
*basename = '\0';
sd = rb->opendir(current_filename);
*basename++ = '/';
} else {
sd = rb->opendir("/");
++basename;
else
basename = current_filename;
return get_entry(dest, len, current_filename, basename, 0);
}
if(sd == NULL) return 0;
while((sde = rb->readdir(sd)) != NULL) {
if(!strcmp(sde->d_name, basename)) {
Uint16 ret = get_entry(dest, len, basename, rb->dir_get_info(sd, sde));
rb->closedir(sd);
return ret;
}
}
rb->closedir(sd);
return 0;
}
Uint16
file_delete(void)
{
return unlink(current_filename);
return rb->remove(current_filename);
}

View File

@ -10,8 +10,9 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE.
*/
Uint16 file_init(void *filename);
Uint16 file_init(const char *filename);
Uint16 file_read(void *dest, Uint16 len);
Uint16 file_write(void *src, Uint16 len, Uint8 flags);
Uint16 file_stat(void *dest, Uint16 len);
Uint16 file_delete(void);
void file_cleanup(void);

View File

@ -18,7 +18,7 @@ TODO clean up
#include "uxn.h"
#include "devices/ppu.h"
// #include "devices/file.h"
#include "devices/file.h"
#include "plugin.h"
#include "keymaps.h"
#include <stdio.h>
@ -164,6 +164,20 @@ screen_talk(Device *d, Uint8 b0, Uint8 w)
return 1;
}
static int
file_talk(Device *d, Uint8 b0, Uint8 w)
{
if(w) switch(b0) {
case 0x1: d->vector = peek16(d->dat, 0x0); break;
case 0x9: poke16(d->dat, 0x2, file_init(&d->mem[peek16(d->dat, 0x8)])); break;
case 0xd: poke16(d->dat, 0x2, file_read(&d->mem[peek16(d->dat, 0xc)], peek16(d->dat, 0xa))); break;
case 0xf: poke16(d->dat, 0x2, file_write(&d->mem[peek16(d->dat, 0xe)], peek16(d->dat, 0xa), d->dat[0x7])); break;
case 0x5: poke16(d->dat, 0x2, file_stat(&d->mem[peek16(d->dat, 0x4)], peek16(d->dat, 0xa))); break;
case 0x6: poke16(d->dat, 0x2, file_delete()); break;
}
return 1;
}
static int
nil_talk(Device *d, Uint8 b0, Uint8 w)
{
@ -329,7 +343,7 @@ enum plugin_status plugin_start(const void* parameter)
/* empty */ uxn_port(&u, 0x7, nil_talk);
/* control */ devctrl = uxn_port(&u, 0x8, nil_talk);
/* mouse */ uxn_port(&u, 0x9, nil_talk);
/* file */ uxn_port(&u, 0xa, nil_talk);
/* file */ uxn_port(&u, 0xa, file_talk);
/* datetime */ uxn_port(&u, 0xb, datetime_talk);
/* empty */ uxn_port(&u, 0xc, nil_talk);
/* empty */ uxn_port(&u, 0xd, nil_talk);
@ -337,6 +351,7 @@ enum plugin_status plugin_start(const void* parameter)
/* empty */ uxn_port(&u, 0xf, nil_talk);
uxn_eval(&u, 0x0100);
run();
file_cleanup();
return PLUGIN_OK;
}