diff --git a/src/devices/file.c b/src/devices/file.c index 56a1baf..583a54b 100644 --- a/src/devices/file.c +++ b/src/devices/file.c @@ -76,26 +76,70 @@ reset(UxnFile *c) } static Uint16 -get_entry(char *p, Uint16 len, const char *pathname, const char *basename, int fail_nonzero) +stat_fill(Uint16 addr, Uint16 len, char c) { - struct stat st; - if(len < strlen(basename) + 8) - return 0; - if(stat(pathname, &st)) - return fail_nonzero ? snprintf(p, len, "!!!! %s\n", basename) : 0; - else if(S_ISDIR(st.st_mode)) - return snprintf(p, len, "---- %s/\n", basename); - else if(st.st_size < 0x10000) - return snprintf(p, len, "%04x %s\n", (unsigned int)st.st_size, basename); - else - return snprintf(p, len, "???? %s\n", basename); + Uint16 i; + for (i = 0; i < len; i++) + uxn.ram[(addr + i) & 0xffff] = c; + return len; } static Uint16 -file_read_dir(UxnFile *c, char *dest, Uint16 len) +stat_size(Uint16 addr, Uint16 len, off_t size) +{ + Uint16 i; + for (i = 1; i <= len; i++) { + char c = '0' + (Uint8)(size & 0xf); + if (c > '9') c += 39; + uxn.ram[(addr + len - i) & 0xffff] = c; + size = size >> 4; + } + if (size > 0) + stat_fill(addr, len, '?'); + return len; +} + +static Uint16 +stat_entry(Uint16 addr, char sym, off_t size, const char *s) +{ + Uint16 pos = addr; + pos += sym ? stat_fill(pos, 4, sym) : stat_size(pos, 4, size); + uxn.ram[(pos++) & 0xffff] = ' '; + while(*s) + uxn.ram[(pos++) & 0xffff] = *(s++); + if (sym == '-') + uxn.ram[(pos++) & 0xffff] = '/'; + uxn.ram[(pos++) & 0xffff] = '\n'; + return pos - addr; +} + +static Uint16 +get_entry(Uint16 addr, Uint16 len, const char *pathname, const char *basename) +{ + struct stat st; + int row_size = strlen(basename) + 6; /* 4 bytes, ' ', basename, '\n' */ + char sym = 0; + off_t size = 0; + + if(stat(pathname, &st)) + sym = '!'; + else if(S_ISDIR(st.st_mode)) { + sym = '-'; + row_size++; /* directories have a '/' suffix */ + } else if(st.st_size >= 0x10000) + sym = '?'; + else + size = st.st_size; + + return len < row_size ? 0 : stat_entry(addr, sym, size, basename); +} + +static Uint16 +file_read_dir(UxnFile *c, Uint16 addr, Uint16 len) { static char pathname[4352]; - char *p = dest; + Uint16 pos = addr; + char cwd[PATH_MAX] = {'\0'}, *t; if(c->de == NULL) c->de = readdir(c->dir); for(; c->de != NULL; c->de = readdir(c->dir)) { Uint16 n; @@ -103,7 +147,6 @@ file_read_dir(UxnFile *c, char *dest, Uint16 len) continue; if(strcmp(c->de->d_name, "..") == 0) { /* hide "sandbox/.." */ - char cwd[PATH_MAX] = {'\0'}, *t; /* Note there's [currently] no way of chdir()ing from uxn, so $PWD * is always the sandbox top level. */ getcwd(cwd, sizeof(cwd)); @@ -119,12 +162,12 @@ file_read_dir(UxnFile *c, char *dest, Uint16 len) snprintf(pathname, sizeof(pathname), "%s/%s", c->current_filename, c->de->d_name); else pathname[0] = '\0'; - n = get_entry(p, len, pathname, c->de->d_name, 1); + n = get_entry(pos, len, pathname, c->de->d_name); if(!n) break; - p += n; + pos += n; len -= n; } - return p - dest; + return pos - addr; } static char * @@ -176,26 +219,35 @@ file_check_sandbox(UxnFile *c) } static Uint16 -file_init(UxnFile *c, char *filename, size_t max_len, int override_sandbox) +file_init(UxnFile *c, Uint16 addr) { char *p = c->current_filename; - size_t len = sizeof(c->current_filename); + Uint16 i = addr; reset(c); - if(len > max_len) len = max_len; - while(len) { - if((*p++ = *filename++) == '\0') { - if(!override_sandbox) /* override sandbox for loading roms */ - file_check_sandbox(c); + for(;; p++, i++) { + if((*p = uxn.ram[i & 0xffff]) == '\0') { + file_check_sandbox(c); return 0; } - len--; } - c->current_filename[0] = '\0'; return 0; } static Uint16 -file_read(UxnFile *c, void *dest, int len) +file_read_file(Uint16 addr, int len, FILE *f) +{ + int total = addr + len; + if (total <= 0x10000) { + return fread(&uxn.ram[addr], 1, len, f); + } else { + size_t n1 = fread(&uxn.ram[addr], 1, 0x10000 - addr, f); + size_t n2 = fread(&uxn.ram[0], 1, total - 0x10000, f); + return n1 + n2; + } +} + +static Uint16 +file_read(UxnFile *c, Uint16 addr, int len) { if(c->outside_sandbox) return 0; if(c->state != FILE_READ && c->state != DIR_READ) { @@ -206,9 +258,9 @@ file_read(UxnFile *c, void *dest, int len) c->state = FILE_READ; } if(c->state == FILE_READ) - return fread(dest, 1, len, c->f); + return file_read_file(addr, len, c->f); if(c->state == DIR_READ) - return file_read_dir(c, dest, len); + return file_read_dir(c, addr, len); return 0; } @@ -245,7 +297,22 @@ ensure_parent_dirs(char *p) } static Uint16 -file_write(UxnFile *c, void *src, Uint16 len, Uint8 flags) +file_write_file(Uint16 addr, int len, FILE *f) +{ + int total = addr + len; + fflush(stdout); + if (total <= 0x10000) { + Uint16 n = fwrite(&uxn.ram[addr], 1, len, f); + return fflush(f) == 0 ? n : 0; + } else { + Uint16 n1 = fwrite(&uxn.ram[addr], 1, 0x10000 - addr, f); + Uint16 n2 = fwrite(&uxn.ram[0], 1, total - 0x10000, f); + return fflush(f) == 0 ? n1 + n2 : 0; + } +} + +static Uint16 +file_write(UxnFile *c, Uint16 addr, Uint16 len, Uint8 flags) { Uint16 ret = 0; if(c->outside_sandbox) return 0; @@ -258,8 +325,7 @@ file_write(UxnFile *c, void *src, Uint16 len, Uint8 flags) c->state = FILE_WRITE; } if(c->state == FILE_WRITE) { - if((ret = fwrite(src, 1, len, c->f)) > 0 && fflush(c->f) != 0) - ret = 0; + ret = file_write_file(addr, len, c->f); } if (c->state == DIR_WRITE) { ret = dir_exists(c->current_filename); @@ -268,38 +334,17 @@ file_write(UxnFile *c, void *src, Uint16 len, Uint8 flags) } static Uint16 -stat_fill(Uint8 *dest, Uint16 len, char c) -{ - Uint16 i; - for (i = 0; i < len; i++) - *(dest++) = c; - return len; -} - -static Uint16 -stat_size(Uint8 *dest, Uint16 len, off_t size) -{ - Uint16 i; - dest += len - 1; - for (i = 0; i < len; i++) { - *(dest--) = '0' + (Uint8)(size & 0xf); - size = size >> 4; - } - return size == 0 ? len : stat_fill(dest, len, '?'); -} - -static Uint16 -file_stat(UxnFile *c, void *dest, Uint16 len) +file_stat(UxnFile *c, Uint16 addr, Uint16 len) { struct stat st; if(c->outside_sandbox) return 0; else if(stat(c->current_filename, &st)) - return stat_fill(dest, len, '!'); + return stat_fill(addr, len, '!'); else if(S_ISDIR(st.st_mode)) - return stat_fill(dest, len, '-'); + return stat_fill(addr, len, '-'); else - return stat_size(dest, len, st.st_size); + return stat_size(addr, len, st.st_size); } static Uint16 @@ -318,9 +363,7 @@ file_deo(Uint8 port) case 0xa5: addr = PEEK2(&uxn.dev[0xa4]); len = PEEK2(&uxn.dev[0xaa]); - if(len > 0x10000 - addr) - len = 0x10000 - addr; - res = file_stat(&uxn_file[0], &uxn.ram[addr], len); + res = file_stat(&uxn_file[0], addr, len); POKE2(&uxn.dev[0xa2], res); break; case 0xa6: @@ -329,32 +372,26 @@ file_deo(Uint8 port) break; case 0xa9: addr = PEEK2(&uxn.dev[0xa8]); - res = file_init(&uxn_file[0], (char *)&uxn.ram[addr], 0x10000 - addr, 0); + res = file_init(&uxn_file[0], addr); POKE2(&uxn.dev[0xa2], res); break; case 0xad: addr = PEEK2(&uxn.dev[0xac]); len = PEEK2(&uxn.dev[0xaa]); - if(len > 0x10000 - addr) - len = 0x10000 - addr; - res = file_read(&uxn_file[0], &uxn.ram[addr], len); + res = file_read(&uxn_file[0], addr, len); POKE2(&uxn.dev[0xa2], res); break; case 0xaf: addr = PEEK2(&uxn.dev[0xae]); len = PEEK2(&uxn.dev[0xaa]); - if(len > 0x10000 - addr) - len = 0x10000 - addr; - res = file_write(&uxn_file[0], &uxn.ram[addr], len, uxn.dev[0xa7]); + res = file_write(&uxn_file[0], addr, len, uxn.dev[0xa7]); POKE2(&uxn.dev[0xa2], res); break; /* File 2 */ case 0xb5: addr = PEEK2(&uxn.dev[0xb4]); len = PEEK2(&uxn.dev[0xba]); - if(len > 0x10000 - addr) - len = 0x10000 - addr; - res = file_stat(&uxn_file[1], &uxn.ram[addr], len); + res = file_stat(&uxn_file[1], addr, len); POKE2(&uxn.dev[0xb2], res); break; case 0xb6: @@ -363,23 +400,19 @@ file_deo(Uint8 port) break; case 0xb9: addr = PEEK2(&uxn.dev[0xb8]); - res = file_init(&uxn_file[1], (char *)&uxn.ram[addr], 0x10000 - addr, 0); + res = file_init(&uxn_file[1], addr); POKE2(&uxn.dev[0xb2], res); break; case 0xbd: addr = PEEK2(&uxn.dev[0xbc]); len = PEEK2(&uxn.dev[0xba]); - if(len > 0x10000 - addr) - len = 0x10000 - addr; - res = file_read(&uxn_file[1], &uxn.ram[addr], len); + res = file_read(&uxn_file[1], addr, len); POKE2(&uxn.dev[0xb2], res); break; case 0xbf: addr = PEEK2(&uxn.dev[0xbe]); len = PEEK2(&uxn.dev[0xba]); - if(len > 0x10000 - addr) - len = 0x10000 - addr; - res = file_write(&uxn_file[1], &uxn.ram[addr], len, uxn.dev[0xb7]); + res = file_write(&uxn_file[1], addr, len, uxn.dev[0xb7]); POKE2(&uxn.dev[0xb2], res); break; }