Implement "spit" function to write strings to a file

This commit is contained in:
Konstantin Nazarov 2024-09-29 21:43:23 +01:00
parent fb2cc0b1f0
commit c097273aec
Signed by: knazarov
GPG key ID: 4CFE0A42FA409C22
3 changed files with 87 additions and 2 deletions

View file

@ -28,6 +28,28 @@ Result<ByteArray> read_fh(FILE* file) {
return std::move(res); return std::move(res);
} }
Result<void> write_fh(FILE* file, const ByteArray& bytes) {
auto size = TRY(bytes.size());
const char* raw_bytes = bytes.raw_bytes();
size_t pos = 0;
while (true) {
size_t remaining_bytes = size - pos;
size_t batch_size = std::min(remaining_bytes, (size_t)10);
size_t num_bytes = fwrite(raw_bytes + pos, 1, batch_size, file);
if (ferror(stdin)) {
return ERROR(IOError);
}
pos += num_bytes;
if (pos >= size) break;
}
return Result<void>();
}
Result<ByteArray> read_file(const char* filename) { Result<ByteArray> read_file(const char* filename) {
FILE* fh = fopen(filename, "r"); FILE* fh = fopen(filename, "r");
@ -42,7 +64,6 @@ Result<ByteArray> read_file(const char* filename) {
Result<ByteArray> read_file(const ByteArray& filename) { Result<ByteArray> read_file(const ByteArray& filename) {
auto filename_bytes = TRY(filename.concat("\0")); auto filename_bytes = TRY(filename.concat("\0"));
FILE* fh = fopen(filename_bytes.raw_bytes(), "r"); FILE* fh = fopen(filename_bytes.raw_bytes(), "r");
if (!fh) { if (!fh) {
@ -57,7 +78,16 @@ Result<ByteArray> read_file(const ByteArray& filename) {
Result<ByteArray> read_stdin() { return read_fh(stdin); } Result<ByteArray> read_stdin() { return read_fh(stdin); }
Result<void> write_file(const ByteArray& filename, const ByteArray& contents) { Result<void> write_file(const ByteArray& filename, const ByteArray& contents) {
return ERROR(NotImplemented); auto filename_bytes = TRY(filename.concat("\0"));
FILE* fh = fopen(filename_bytes.raw_bytes(), "w");
if (!fh) {
return ERROR(IOError);
}
auto res = write_fh(fh, contents);
fclose(fh);
return res;
} }
// TODO: though unlikely, but isatty can possibly set an error. Need to check it // TODO: though unlikely, but isatty can possibly set an error. Need to check it

View file

@ -133,6 +133,24 @@ Result<StackFrame> stdlib_slurp(const StackFrame& stack) {
return raise_task(stack, StdlibTaskId::ReadFile, fname); return raise_task(stack, StdlibTaskId::ReadFile, fname);
} }
Result<StackFrame> stdlib_spit(const StackFrame& stack) {
auto params = TRY(stack.get(0));
auto stack_size = TRY(stack.size());
if (stack_size > 1) {
return task_return(stack, 1);
}
if (TRY(params.size()) != 2) {
return ERROR(ArgumentCountMismatch);
}
if (!params.is<Array>()) {
return ERROR(TypeMismatch);
}
return raise_task(stack, StdlibTaskId::WriteFile, *params.to<Array>());
}
Result<StackFrame> stdlib_assert(const StackFrame& stack) { Result<StackFrame> stdlib_assert(const StackFrame& stack) {
auto params = TRY(stack.get(0)); auto params = TRY(stack.get(0));
auto size = TRY(params.size()); auto size = TRY(params.size());
@ -426,6 +444,7 @@ static StdlibFunctionEntry function_entries[] = {
STDLIB_FUNCTION(println, PrintLn), STDLIB_FUNCTION(println, PrintLn),
STDLIB_FUNCTION(prn, Prn), STDLIB_FUNCTION(prn, Prn),
STDLIB_FUNCTION(slurp, Slurp), STDLIB_FUNCTION(slurp, Slurp),
STDLIB_FUNCTION(spit, Spit),
STDLIB_FUNCTION(assert, Assert), STDLIB_FUNCTION(assert, Assert),
STDLIB_FUNCTION(dict, Dict), STDLIB_FUNCTION(dict, Dict),
STDLIB_FUNCTION(list, List), STDLIB_FUNCTION(list, List),
@ -489,6 +508,39 @@ Result<Value> stdlib_task_read_file(const Array& params) {
return contents; return contents;
} }
Result<Value> stdlib_task_write_file(const Array& params) {
auto size = TRY(params.size());
if (size != 2) {
auto err = Value(TRY(
Error::create("argument-count-mismatch", "Argument count mismatch")));
return ERROR_OBJ(ArgumentCountMismatch, err);
}
auto fname = TRY(params.get(0));
if (!fname.is<String>()) {
auto err = Value(TRY(Error::create("type-mismatch", "Type mismatch")));
return ERROR_OBJ(TypeMismatch, err);
}
auto contents = TRY(params.get(1));
if (!contents.is<String>()) {
auto err = Value(TRY(Error::create("type-mismatch", "Type mismatch")));
return ERROR_OBJ(TypeMismatch, err);
}
String& fname_string = *fname.to<String>();
ByteArray fname_bytes = TRY(ByteArray::create(fname_string));
String& contents_string = *contents.to<String>();
ByteArray contents_bytes = TRY(ByteArray::create(contents_string));
TRY(write_file(fname_bytes, contents_bytes));
return Value(TRY(Nil::create()));
}
#define STDLIB_TASK(name, id) \ #define STDLIB_TASK(name, id) \
[(uint64_t)StdlibTaskId::id] = {#name, StdlibTaskId::id, stdlib_task_##name} [(uint64_t)StdlibTaskId::id] = {#name, StdlibTaskId::id, stdlib_task_##name}
@ -496,6 +548,7 @@ static StdlibTaskEntry task_entries[] = {
STDLIB_TASK(unknown, Unknown), STDLIB_TASK(unknown, Unknown),
STDLIB_TASK(print, Print), STDLIB_TASK(print, Print),
STDLIB_TASK(read_file, ReadFile), STDLIB_TASK(read_file, ReadFile),
STDLIB_TASK(write_file, WriteFile),
[(uint64_t)StdlibTaskId::Max] = {0, StdlibTaskId::Max, stdlib_task_unknown}, [(uint64_t)StdlibTaskId::Max] = {0, StdlibTaskId::Max, stdlib_task_unknown},
}; };

View file

@ -10,6 +10,7 @@ enum class StdlibFunctionId : uint64_t {
PrintLn, PrintLn,
Prn, Prn,
Slurp, Slurp,
Spit,
Assert, Assert,
Dict, Dict,
List, List,
@ -29,6 +30,7 @@ enum class StdlibTaskId : uint64_t {
Unknown, Unknown,
Print, Print,
ReadFile, ReadFile,
WriteFile,
Max, Max,
}; };