Files much more complete. Needs a lot of cleanup though

This commit is contained in:
JJ Bliss
2026-04-28 16:22:09 -04:00
parent cd93921b41
commit af7c1a40d1
+263 -3
View File
@@ -44,6 +44,7 @@ export type uxnFile = struct {
state: filestate, state: filestate,
dir: bool, dir: bool,
exists: bool, exists: bool,
fappend: bool,
}; };
export type filestate = enum { export type filestate = enum {
@@ -91,6 +92,7 @@ fn initialize_uxn_mem() *uxn = {
state = filestate::IDLE, state = filestate::IDLE,
dir = false, dir = false,
exists = false, exists = false,
fappend = false,
}...], }...],
})!; })!;
}; };
@@ -199,12 +201,20 @@ fn emu_deo(port: u8, value: u8, state: *uxn) void = {
const high = state.dev[0x90]; const high = state.dev[0x90];
const low = value; const low = value;
state.mouse_vector = short_from_bytes(high,low); state.mouse_vector = short_from_bytes(high,low);
case 0xa5 => // File/stat [0]
filestat_to_addr(0,state);
case 0xa6 => // File/delete [0]
delete_file(0,state);
case 0xa9 => // File/name [0] case 0xa9 => // File/name [0]
set_file_name(0,state); set_file_name(0,state);
case 0xad => // File/read [0] case 0xad => // File/read [0]
read_file_to_addr(0,state); read_file_to_addr(0,state);
case 0xaf => //File/write [0] case 0xaf => //File/write [0]
write_file_from_addr(0,state); write_file_from_addr(0,state);
case 0xb5 => // File/stat [1]
filestat_to_addr(1,state);
case 0xb6 => // File/delete [1]
delete_file(1,state);
case 0xb9 => // File/name [1] case 0xb9 => // File/name [1]
set_file_name(1,state); set_file_name(1,state);
case 0xbd => // File/read [1] case 0xbd => // File/read [1]
@@ -338,6 +348,108 @@ fn read_file_to_addr(fi: u8, state: *uxn) void = {
}; };
return; return;
}; };
fn filestat_to_addr(fi: u8, state: *uxn) void = {
const length = if(fi == 0) { yield short_from_bytes(state.dev[0xaa],state.dev[0xab]); }
else { yield short_from_bytes(state.dev[0xba],state.dev[0xbb]); };
const destaddr = if(fi == 0) { yield short_from_bytes(state.dev[0xa4],state.dev[0xa5]); }
else { yield short_from_bytes(state.dev[0xb4],state.dev[0xb5]); };
// fmt::printfln("Reading {} bytes to 0x{:x}", length, destaddr)!;
let bytesread = 0;
if(!state.files[fi].dir){
const nameaddr = if(fi == 0) { yield short_from_bytes(state.dev[0xa8],state.dev[0xa9]); }
else { yield short_from_bytes(state.dev[0xb8],state.dev[0xb9]); };
const nameslice: []u8 = bytes::cut(state.ram[nameaddr..],0x00).0;
const name: str = match(strings::fromutf8(nameslice)){
case let s: str =>
yield s;
case =>
fmt::fatal("Bad String encoding in filename");
};
const stat = os::fstat(state.files[fi].file: io::file)!;
const fsize = stat.sz: u32;
const modestring = if(fsize <= 0xFFFF){
yield fmt::asprintf("{:x.4}",fsize)!;
}else {
yield "????";
};
let modestringiter = strings::iter(modestring);
for(let i: u16 =0; i<length; i+=1){
let char: rune = match(strings::next(&modestringiter)){
case let r: rune =>
yield r;
case done =>
break;
};
bytesread += 1;
state.ram[destaddr+i] = char: u8;
};
for(let i: u16 =0; i<length; i+=1){
match (bufio::read_byte(state.files[fi].file)){
case let b: u8 =>
bytesread += 1;
// fmt::printfln("Reading byte {}: from file",b)!;
state.ram[destaddr+i] = b;
case let eof: io::EOF =>
state.ram[destaddr+i] = 0; //This might need to be done differently
case let err: io::error =>
fmt::fatalf("Error reading: {}", io::strerror(err));
};
};
}else {
const nameaddr = if(fi == 0) { yield short_from_bytes(state.dev[0xa8],state.dev[0xa9]); }
else { yield short_from_bytes(state.dev[0xb8],state.dev[0xb9]); };
const nameslice: []u8 = bytes::cut(state.ram[nameaddr..],0x00).0;
const name: str = match(strings::fromutf8(nameslice)){
case let s: str =>
yield s;
case =>
fmt::fatal("Bad String encoding in filename");
};
let dfs = os::diropen(name)!;
let df = os::dirfile(dfs);
const stat = os::fstat(df)!;
const fsize = stat.sz: u32;
const modestring = if(fsize <= 0xFFFF){
yield fmt::asprintf("{:x.4}",fsize)!;
}else {
yield "????";
};
let modestringiter = strings::iter(modestring);
for(let i: u16 =0; i<length; i+=1){
let char: rune = match(strings::next(&modestringiter)){
case let r: rune =>
yield r;
case done =>
break;
};
bytesread += 1;
state.ram[destaddr+i] = char: u8;
};
for(let i: u16 =0; i<length; i+=1){
match (bufio::read_byte(state.files[fi].file)){
case let b: u8 =>
bytesread += 1;
// fmt::printfln("Reading byte {}: from file",b)!;
state.ram[destaddr+i] = b;
case let eof: io::EOF =>
state.ram[destaddr+i] = 0; //This might need to be done differently
case let err: io::error =>
fmt::fatalf("Error reading: {}", io::strerror(err));
};
};
};
if(fi == 0){
state.dev[0xa2] = (bytesread >> 8): u8;
state.dev[0xa3] = (bytesread): u8;
}else if(fi ==1){
state.dev[0xb2] = (bytesread >> 8): u8;
state.dev[0xb3] = (bytesread): u8;
};
return;
};
fn write_file_from_addr(fi: u8,state: *uxn) void = { fn write_file_from_addr(fi: u8,state: *uxn) void = {
const length = if(fi == 0) { yield short_from_bytes(state.dev[0xaa],state.dev[0xab]); } const length = if(fi == 0) { yield short_from_bytes(state.dev[0xaa],state.dev[0xab]); }
else { yield short_from_bytes(state.dev[0xba],state.dev[0xbb]); }; else { yield short_from_bytes(state.dev[0xba],state.dev[0xbb]); };
@@ -360,17 +472,126 @@ fn write_file_from_addr(fi: u8,state: *uxn) void = {
case => case =>
fmt::fatal("Bad String encoding in filename"); fmt::fatal("Bad String encoding in filename");
}; };
state.files[fi].file = match (os::create(name,fs::mode::USER_RW,fs::flag::RDWR)){ const flags = if(appendf) {
state.files[fi].fappend = true;
yield (fs::flag::RDWR | fs::flag::APPEND);
} else {
yield fs::flag::RDWR;
};
state.files[fi].file = match (os::create(name,fs::mode::USER_RW,flags)){
case let f: io::file => case let f: io::file =>
state.files[fi].exists = true;
yield f; yield f;
case let err: fs::error => case let err: fs::error =>
fmt::fatalf("Error creating file file: {}", fs::strerror(err)); fmt::fatalf("Error creating file file: {}", fs::strerror(err));
}; };
}; };
if(appendf){
if(appendf && (state.files[fi].fappend == false)){
//Rewrite File or adjust pointer //Rewrite File or adjust pointer
yield; io::close(state.files[fi].file)!;
const nameaddr = if(fi == 0) { yield short_from_bytes(state.dev[0xa8],state.dev[0xa9]); }
else { yield short_from_bytes(state.dev[0xb8],state.dev[0xb9]); };
const nameslice: []u8 = bytes::cut(state.ram[nameaddr..],0x00).0;
const name: str = match(strings::fromutf8(nameslice)){
case let s: str =>
yield s;
case =>
fmt::fatal("Bad String encoding in filename");
};
state.files[fi].file = match (os::open(name,fs::flag::RDWR | fs::flag::APPEND)) {
case let file: io::file =>
state.files[fi].exists = true;
state.files[fi].dir = false;
yield file;
case let err: fs::error =>
//Try opening as dir
yield match(os::diropen(name)){
case let f: *fs::fs =>
let dfs = os::diropen(name)!;
let df = os::dirfile(dfs);
const stat = os::fstat(df)!;
state.files[fi].dir = fs::isdir(stat.mode);
if(state.files[fi].dir) {
state.files[fi].exists = true;
state.files[fi].dir = true;
};
io::close(df)!;
yield io::empty;
case let err: fs::error =>
// fmt::printfln("Error opening {}: {}", name, fs::strerror(err))!;
if(fi == 0){
state.dev[0xa2] = 0;
state.dev[0xa3] = 0;
}else if(fi ==1){
state.dev[0xb2] = 0;
state.dev[0xb3] = 0;
};
state.files[fi].exists = false;
state.files[fi].dir = false;
yield io::empty;
};
};
state.files[fi].fappend = true;
};
if(!appendf && (state.files[fi].fappend == true)){
io::close(state.files[fi].file)!;
const nameaddr = if(fi == 0) { yield short_from_bytes(state.dev[0xa8],state.dev[0xa9]); }
else { yield short_from_bytes(state.dev[0xb8],state.dev[0xb9]); };
const nameslice: []u8 = bytes::cut(state.ram[nameaddr..],0x00).0;
const name: str = match(strings::fromutf8(nameslice)){
case let s: str =>
yield s;
case =>
fmt::fatal("Bad String encoding in filename");
};
state.files[fi].file = match (os::open(name,fs::flag::RDWR)) {
case let file: io::file =>
state.files[fi].exists = true;
state.files[fi].dir = false;
yield file;
case let err: fs::error =>
//Try opening as dir
yield match(os::diropen(name)){
case let f: *fs::fs =>
let dfs = os::diropen(name)!;
let df = os::dirfile(dfs);
const stat = os::fstat(df)!;
state.files[fi].dir = fs::isdir(stat.mode);
if(state.files[fi].dir) {
state.files[fi].exists = true;
state.files[fi].dir = true;
};
io::close(df)!;
yield io::empty;
case let err: fs::error =>
// fmt::printfln("Error opening {}: {}", name, fs::strerror(err))!;
if(fi == 0){
state.dev[0xa2] = 0;
state.dev[0xa3] = 0;
}else if(fi ==1){
state.dev[0xb2] = 0;
state.dev[0xb3] = 0;
};
state.files[fi].exists = false;
state.files[fi].dir = false;
yield io::empty;
};
};
state.files[fi].fappend = false;
}; };
match (io::write(state.files[fi].file,bytes)){ match (io::write(state.files[fi].file,bytes)){
@@ -402,6 +623,7 @@ fn set_file_name(fi: u8, state: *uxn) void = {
}; };
io::close(state.files[fi].file)!; io::close(state.files[fi].file)!;
state.files[fi].fappend = false;
// fmt::printfln("Opening file: {}",name)!; // fmt::printfln("Opening file: {}",name)!;
state.files[fi].file = match (os::open(name,fs::flag::RDWR)) { state.files[fi].file = match (os::open(name,fs::flag::RDWR)) {
case let file: io::file => case let file: io::file =>
@@ -443,6 +665,44 @@ fn set_file_name(fi: u8, state: *uxn) void = {
return; return;
}; };
fn delete_file(fi: u8, state: *uxn) void = {
let success: u8 = 0;
if(state.files[fi].exists){
const nameaddr = if(fi == 0) { yield short_from_bytes(state.dev[0xa8],state.dev[0xa9]); }
else { yield short_from_bytes(state.dev[0xb8],state.dev[0xb9]); };
const nameslice: []u8 = bytes::cut(state.ram[nameaddr..],0x00).0;
const name: str = match(strings::fromutf8(nameslice)){
case let s: str =>
yield s;
case =>
fmt::fatal("Bad String encoding in filename");
};
if(!state.files[fi].dir){
match(os::remove(name)) {
case void =>
success = 1;
yield;
case let err: fs::error =>
fmt::printf("Error deleting file: {}", fs::strerror(err))!;
};
}else{
match(os::rmdir(name)) {
case void =>
success = 1;
yield;
case let err: fs::error =>
fmt::printf("Error deleting dir: {}", fs::strerror(err))!;
};
};
};
if(fi == 0){
state.dev[0xa2] = 0;
state.dev[0xa3] = success;
}else if(fi ==1){
state.dev[0xb2] = 0;
state.dev[0xb3] = success;
};
};
fn deo_expansion(addr: u16, state: *uxn) void = { fn deo_expansion(addr: u16, state: *uxn) void = {
const op = state.ram[addr]; const op = state.ram[addr];