use fmt; use os; use fs; use io; use bytes; use bufio; use strings; 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 = { 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[0xac],state.dev[0xad]); } else { yield short_from_bytes(state.dev[0xbc],state.dev[0xbd]); }; // fmt::printfln("Reading {} bytes to 0x{:x}", length, destaddr)!; let bytesread = 0; if(!state.files[fi].dir){ for(let i: u16 =0; i bytesread += 1; // fmt::printfln("Reading byte {}: from file",b)!; state.ram[destaddr+i] = b; case let eof: io::EOF => break; 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 dirstring = generate_dir_string(name); let dirstringiter = strings::iter(dirstring); for(let i: u16 =0; i yield r; case done => break; }; bytesread += 1; state.ram[destaddr+i] = char: u8; }; // fmt::printf(dirstring)!; }; 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 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 fstat = match(os::fstat(state.files[fi].file: io::file)){ case let fstat: fs::filestat => yield fstat; case let err: fs::error => yield void; }; const fsize = match(fstat){ case let stat: fs::filestat => yield stat.sz: u32; case => yield 0: 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 yield r; case done => break; }; bytesread += 1; state.ram[destaddr+i] = char: u8; }; for(let i: u16 =0; i 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 yield r; case done => break; }; bytesread += 1; state.ram[destaddr+i] = char: u8; }; for(let i: u16 =0; i 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 = { 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]); }; let 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)!; fmt::printfln("Writing {} bytes from 0x{:x} to 0x{:x}", endaddr-srcaddr, srcaddr,endaddr)!; // const bytes: []u8 = state.ram[srcaddr..endaddr]; const bytes: []u8 = if(endaddr < srcaddr){ yield state.ram[srcaddr..]; } else { yield 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"); }; 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 => state.files[fi].exists = true; yield f; case let err: fs::error => fmt::fatalf("Error creating file file: {}", fs::strerror(err)); }; }; if(appendf && (state.files[fi].fappend == false)){ //Rewrite File or adjust pointer 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)){ 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; }; fn set_file_name(fi: u8, state: *uxn) void = { 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"); }; io::close(state.files[fi].file)!; state.files[fi].fappend = false; // fmt::printfln("Opening file: {}",name)!; 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; }; }; 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; }; };