diff --git a/apps/plugins/varvara/devices/file.c b/apps/plugins/varvara/devices/file.c index 58b8135ca6..e1241296ce 100644 --- a/apps/plugins/varvara/devices/file.c +++ b/apps/plugins/varvara/devices/file.c @@ -22,24 +22,24 @@ WITH REGARD TO THIS SOFTWARE. //#include #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); } diff --git a/apps/plugins/varvara/devices/file.h b/apps/plugins/varvara/devices/file.h index affd28ce34..2275a9c03e 100644 --- a/apps/plugins/varvara/devices/file.h +++ b/apps/plugins/varvara/devices/file.h @@ -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); diff --git a/apps/plugins/varvara/varvara.c b/apps/plugins/varvara/varvara.c index 207214c13e..e814a3f5bf 100644 --- a/apps/plugins/varvara/varvara.c +++ b/apps/plugins/varvara/varvara.c @@ -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 @@ -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; }