Files much more complete. Needs a lot of cleanup though
This commit is contained in:
+263
-3
@@ -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];
|
||||||
|
|||||||
Reference in New Issue
Block a user