Basic reading and writing files. Still need to implement stat

This commit is contained in:
JJ Bliss
2026-04-28 15:03:42 -04:00
parent 5f6bc2fc86
commit cd93921b41
+163 -6
View File
@@ -42,6 +42,8 @@ export type uxnFile = struct {
file: io::handle, file: io::handle,
filepath: str, filepath: str,
state: filestate, state: filestate,
dir: bool,
exists: bool,
}; };
export type filestate = enum { export type filestate = enum {
@@ -87,6 +89,8 @@ fn initialize_uxn_mem() *uxn = {
file = io::empty, file = io::empty,
filepath = "", filepath = "",
state = filestate::IDLE, state = filestate::IDLE,
dir = false,
exists = false,
}...], }...],
})!; })!;
}; };
@@ -224,18 +228,74 @@ fn emu_deo(port: u8, value: u8, state: *uxn) void = {
}; };
}; };
fn generate_dir_string(name: str) str = {
// fmt::println("Generating dir string!")!;
let list: []u8 = [];
const fs: *fs::fs = match(os::diropen(name)){
case let f: *fs::fs =>
yield f;
case let err: fs::error =>
fmt::fatalf("Error opening directory: {}", fs::strerror(err));
};
let iter: *fs::iterator = match(fs::iter(fs,".")){
case let i: *fs::iterator =>
yield i;
case let err: fs::error =>
fmt::fatalf("No iterator in directory: {}", fs::strerror(err));
// case null =>
// fmt::fatalf("Null pointer when opening directory: {}", name);
};
for(let item => fs::next(iter)){
match(item){
case let d: fs::dirent =>
//001a file.txt
//???? large_file.mp4
// 0-f A file
// - A directory
// ? A file that is larger than 64kb
// ! A missing file
let leftstring = "!!!!";
let namestring = d.name;
if(d.ftype == fs::mode::DIR){
leftstring = "----";
namestring = strings::concat(d.name,"/")!;
}else{
const stat = fs::stat(fs,d.name)!;
const fsize = stat.sz: u32;
if(fsize <= 0xFFFF){
leftstring = fmt::asprintf("{:x.4}",fsize)!;
}else {
leftstring = "????";
};
};
const wholestring = strings::concat(strings::join(" ", leftstring, d.name)!, "\n")!;
const utf8 = strings::toutf8(wholestring);
for( let c .. utf8 ){
append(list,c)!;
};
case let err: fs::error =>
fmt::fatalf("Error looking in directory: {}", fs::strerror(err));
};
};
return strings::fromutf8(list)!;
};
fn read_file_to_addr(fi: u8, state: *uxn) void = { fn read_file_to_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]); };
const destaddr = if(fi == 0) { yield short_from_bytes(state.dev[0xac],state.dev[0xad]); } const destaddr = if(fi == 0) { yield short_from_bytes(state.dev[0xac],state.dev[0xad]); }
else { yield short_from_bytes(state.dev[0xbd],state.dev[0xbd]); }; else { yield short_from_bytes(state.dev[0xbc],state.dev[0xbd]); };
fmt::printfln("Reading {} bytes to 0x{:x}", length, destaddr)!; // fmt::printfln("Reading {} bytes to 0x{:x}", length, destaddr)!;
let bytesread = 0; let bytesread = 0;
if(!state.files[fi].dir){
for(let i: u16 =0; i<length; i+=1){ for(let i: u16 =0; i<length; i+=1){
match (bufio::read_byte(state.files[fi].file)){ match (bufio::read_byte(state.files[fi].file)){
case let b: u8 => case let b: u8 =>
bytesread += 1; bytesread += 1;
fmt::printfln("Reading byte {}: from file",b)!; // fmt::printfln("Reading byte {}: from file",b)!;
state.ram[destaddr+i] = b; state.ram[destaddr+i] = b;
case let eof: io::EOF => case let eof: io::EOF =>
break; break;
@@ -244,6 +304,31 @@ fn read_file_to_addr(fi: u8, state: *uxn) void = {
}; };
}; };
}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 dirstring = generate_dir_string(name);
let dirstringiter = strings::iter(dirstring);
for(let i: u16 =0; i<length; i+=1){
let char: rune = match(strings::next(&dirstringiter)){
case let r: rune =>
yield r;
case done =>
break;
};
bytesread += 1;
state.ram[destaddr+i] = char: u8;
};
// fmt::printf(dirstring)!;
};
if(fi == 0){ if(fi == 0){
state.dev[0xa2] = (bytesread >> 8): u8; state.dev[0xa2] = (bytesread >> 8): u8;
state.dev[0xa3] = (bytesread): u8; state.dev[0xa3] = (bytesread): u8;
@@ -254,6 +339,55 @@ fn read_file_to_addr(fi: u8, state: *uxn) void = {
return; 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]); }
else { yield short_from_bytes(state.dev[0xba],state.dev[0xbb]); };
const srcaddr = if(fi == 0) { yield short_from_bytes(state.dev[0xae],state.dev[0xaf]); }
else { yield short_from_bytes(state.dev[0xbe],state.dev[0xbf]); };
const endaddr = srcaddr + length;
const appendf: bool = if(fi == 0) { yield state.dev[0xa7] != 0; }
else { yield state.dev[0xb7] != 0; };
fmt::printfln("Writing {} bytes from 0x{:x}", length, srcaddr)!;
const bytes: []u8 = state.ram[srcaddr..endaddr];
let byteswritten: u16 = 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");
};
state.files[fi].file = match (os::create(name,fs::mode::USER_RW,fs::flag::RDWR)){
case let f: io::file =>
yield f;
case let err: fs::error =>
fmt::fatalf("Error creating file file: {}", fs::strerror(err));
};
};
if(appendf){
//Rewrite File or adjust pointer
yield;
};
match (io::write(state.files[fi].file,bytes)){
case let s: size =>
byteswritten += s: u16;
fmt::printfln("Writing {} bytes to file",s)!;
case let err: io::error =>
fmt::fatalf("Error writing file: {}", io::strerror(err));
};
if(fi == 0){
state.dev[0xa2] = (byteswritten >> 8): u8;
state.dev[0xa3] = (byteswritten): u8;
}else if(fi ==1){
state.dev[0xb2] = (byteswritten >> 8): u8;
state.dev[0xb3] = (byteswritten): u8;
};
return; return;
}; };
fn set_file_name(fi: u8, state: *uxn) void = { fn set_file_name(fi: u8, state: *uxn) void = {
@@ -268,12 +402,29 @@ fn set_file_name(fi: u8, state: *uxn) void = {
}; };
io::close(state.files[fi].file)!; io::close(state.files[fi].file)!;
fmt::printfln("Opening file: {}",name)!; // fmt::printfln("Opening file: {}",name)!;
state.files[fi].file = match (os::open(name,fs::flag::RDONLY)) { state.files[fi].file = match (os::open(name,fs::flag::RDWR)) {
case let file: io::file => case let file: io::file =>
state.files[fi].exists = true;
state.files[fi].dir = false;
yield file; yield file;
case let err: fs::error => case let err: fs::error =>
fmt::printfln("Error opening {}: {}", name, fs::strerror(err))!; //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){ if(fi == 0){
state.dev[0xa2] = 0; state.dev[0xa2] = 0;
state.dev[0xa3] = 0; state.dev[0xa3] = 0;
@@ -281,7 +432,13 @@ fn set_file_name(fi: u8, state: *uxn) void = {
state.dev[0xb2] = 0; state.dev[0xb2] = 0;
state.dev[0xb3] = 0; state.dev[0xb3] = 0;
}; };
state.files[fi].exists = false;
state.files[fi].dir = false;
yield io::empty; yield io::empty;
};
}; };
return; return;
}; };