Nasal-Interpreter/src/io_lib.cpp

218 lines
6.0 KiB
C++

#include "io_lib.h"
namespace nasal {
const auto file_type_name = "file";
void filehandle_destructor(void* ptr) {
if (static_cast<FILE*>(ptr)==stdin) {
return;
}
fclose(static_cast<FILE*>(ptr));
}
var builtin_readfile(var* local, gc& ngc) {
var val = local[1];
if (val.type!=vm_str) {
return nas_err("io::readfile", "\"filename\" must be string");
}
std::ifstream in(val.str(), std::ios::binary);
std::stringstream rd;
if (!in.fail()) {
rd << in.rdbuf();
}
return ngc.newstr(rd.str());
}
var builtin_fout(var* local, gc& ngc) {
var val = local[1];
var str = local[2];
if (val.type!=vm_str) {
return nas_err("io::fout", "\"filename\" must be string");
}
std::ofstream out(val.str());
if (out.fail()) {
return nas_err("io::fout", "cannot open <"+val.str()+">");
}
out << str;
return nil;
}
var builtin_exists(var* local, gc& ngc) {
if (local[1].type!=vm_str) {
return zero;
}
return access(local[1].str().c_str(), F_OK)!=-1?one:zero;
}
var builtin_open(var* local, gc& ngc) {
var name = local[1];
var mode = local[2];
if (name.type!=vm_str) {
return nas_err("open", "\"filename\" must be string");
}
if (mode.type!=vm_str) {
return nas_err("open", "\"mode\" must be string");
}
FILE* res = fopen(name.str().c_str(), mode.str().c_str());
if (!res) {
return nas_err("open", "failed to open file <"+name.str()+">");
}
var ret = ngc.alloc(vm_obj);
ret.obj().set(file_type_name, filehandle_destructor, res);
return ret;
}
var builtin_close(var* local, gc& ngc) {
var fd = local[1];
if (!fd.objchk(file_type_name)) {
return nas_err("close", "not a valid filehandle");
}
fd.obj().clear();
return nil;
}
var builtin_read(var* local, gc& ngc) {
var fd = local[1];
var buf = local[2];
var len = local[3];
if (!fd.objchk(file_type_name)) {
return nas_err("read", "not a valid filehandle");
}
if (buf.type!=vm_str || buf.val.gcobj->unmut) {
return nas_err("read", "\"buf\" must be mutable string");
}
if (len.type!=vm_num) {
return nas_err("read", "\"len\" must be number");
}
if (len.num()<=0 || len.num()>=(1<<30)) {
return nas_err("read", "\"len\" less than 1 or too large");
}
char* buff = new char[(usize)len.num()+1];
if (!buff) {
return nas_err("read", "malloc failed");
}
f64 res = fread(buff, 1, len.num(), static_cast<FILE*>(fd.obj().pointer));
buf.str() = buff;
buf.val.gcobj->unmut = true;
delete []buff;
return var::num(res);
}
var builtin_write(var* local, gc& ngc) {
var fd = local[1];
var str = local[2];
if (!fd.objchk(file_type_name)) {
return nas_err("write", "not a valid filehandle");
}
if (str.type!=vm_str) {
return nas_err("write", "\"str\" must be string");
}
return var::num(static_cast<f64>(fwrite(
str.str().c_str(),
1,
str.str().length(),
static_cast<FILE*>(fd.obj().pointer)
)));
}
var builtin_seek(var* local, gc& ngc) {
var fd = local[1];
var pos = local[2];
var whence = local[3];
if (!fd.objchk(file_type_name)) {
return nas_err("seek", "not a valid filehandle");
}
return var::num(static_cast<f64>(fseek(
static_cast<FILE*>(fd.obj().pointer),
pos.num(),
whence.num()
)));
}
var builtin_tell(var* local, gc& ngc) {
var fd = local[1];
if (!fd.objchk(file_type_name)) {
return nas_err("tell", "not a valid filehandle");
}
return var::num(static_cast<f64>(
ftell(static_cast<FILE*>(fd.obj().pointer))
));
}
var builtin_readln(var* local, gc& ngc) {
var fd = local[1];
if (!fd.objchk(file_type_name)) {
return nas_err("readln", "not a valid filehandle");
}
var str = ngc.alloc(vm_str);
char c;
while((c = fgetc(static_cast<FILE*>(fd.obj().pointer)))!=EOF) {
if (c=='\r') {
continue;
}
if (c=='\n') {
return str;
}
str.str() += c;
}
if (str.str().length()) {
return str;
}
return nil;
}
var builtin_stat(var* local, gc& ngc) {
var name = local[1];
if (name.type!=vm_str) {
return nas_err("stat", "\"filename\" must be string");
}
struct stat buf;
if (stat(name.str().c_str(),&buf)<0) {
return nas_err("stat", "failed to open file <"+name.str()+">");
}
var ret = ngc.alloc(vm_vec);
ret.vec().elems = {
var::num(static_cast<f64>(buf.st_dev)),
var::num(static_cast<f64>(buf.st_ino)),
var::num(static_cast<f64>(buf.st_mode)),
var::num(static_cast<f64>(buf.st_nlink)),
var::num(static_cast<f64>(buf.st_uid)),
var::num(static_cast<f64>(buf.st_gid)),
var::num(static_cast<f64>(buf.st_rdev)),
var::num(static_cast<f64>(buf.st_size)),
var::num(static_cast<f64>(buf.st_atime)),
var::num(static_cast<f64>(buf.st_mtime)),
var::num(static_cast<f64>(buf.st_ctime))
};
return ret;
}
var builtin_eof(var* local, gc& ngc) {
var fd = local[1];
if (!fd.objchk(file_type_name)) {
return nas_err("readln", "not a valid filehandle");
}
return var::num(static_cast<f64>(
feof(static_cast<FILE*>(fd.obj().pointer))
));
}
nasal_builtin_table io_lib_native[] = {
{"__readfile", builtin_readfile},
{"__fout", builtin_fout},
{"__exists", builtin_exists},
{"__open", builtin_open},
{"__close", builtin_close},
{"__read", builtin_read},
{"__write", builtin_write},
{"__seek", builtin_seek},
{"__tell", builtin_tell},
{"__readln", builtin_readln},
{"__stat", builtin_stat},
{"__eof", builtin_eof},
{nullptr, nullptr}
};
}