diff --git a/src/fio.cpp b/src/fio.cpp index e8629e4..922f338 100644 --- a/src/fio.cpp +++ b/src/fio.cpp @@ -28,6 +28,28 @@ Result read_fh(FILE* file) { return std::move(res); } +Result 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(); +} + Result read_file(const char* filename) { FILE* fh = fopen(filename, "r"); @@ -42,7 +64,6 @@ Result read_file(const char* filename) { Result read_file(const ByteArray& filename) { auto filename_bytes = TRY(filename.concat("\0")); - FILE* fh = fopen(filename_bytes.raw_bytes(), "r"); if (!fh) { @@ -57,7 +78,16 @@ Result read_file(const ByteArray& filename) { Result read_stdin() { return read_fh(stdin); } Result 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 diff --git a/src/stdlib.cpp b/src/stdlib.cpp index 7113d4a..b5d1e10 100644 --- a/src/stdlib.cpp +++ b/src/stdlib.cpp @@ -133,6 +133,24 @@ Result stdlib_slurp(const StackFrame& stack) { return raise_task(stack, StdlibTaskId::ReadFile, fname); } +Result 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()) { + return ERROR(TypeMismatch); + } + return raise_task(stack, StdlibTaskId::WriteFile, *params.to()); +} + Result stdlib_assert(const StackFrame& stack) { auto params = TRY(stack.get(0)); auto size = TRY(params.size()); @@ -426,6 +444,7 @@ static StdlibFunctionEntry function_entries[] = { STDLIB_FUNCTION(println, PrintLn), STDLIB_FUNCTION(prn, Prn), STDLIB_FUNCTION(slurp, Slurp), + STDLIB_FUNCTION(spit, Spit), STDLIB_FUNCTION(assert, Assert), STDLIB_FUNCTION(dict, Dict), STDLIB_FUNCTION(list, List), @@ -489,6 +508,39 @@ Result stdlib_task_read_file(const Array& params) { return contents; } +Result 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()) { + auto err = Value(TRY(Error::create("type-mismatch", "Type mismatch"))); + return ERROR_OBJ(TypeMismatch, err); + } + + auto contents = TRY(params.get(1)); + + if (!contents.is()) { + auto err = Value(TRY(Error::create("type-mismatch", "Type mismatch"))); + return ERROR_OBJ(TypeMismatch, err); + } + + String& fname_string = *fname.to(); + ByteArray fname_bytes = TRY(ByteArray::create(fname_string)); + + String& contents_string = *contents.to(); + 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) \ [(uint64_t)StdlibTaskId::id] = {#name, StdlibTaskId::id, stdlib_task_##name} @@ -496,6 +548,7 @@ static StdlibTaskEntry task_entries[] = { STDLIB_TASK(unknown, Unknown), STDLIB_TASK(print, Print), STDLIB_TASK(read_file, ReadFile), + STDLIB_TASK(write_file, WriteFile), [(uint64_t)StdlibTaskId::Max] = {0, StdlibTaskId::Max, stdlib_task_unknown}, }; diff --git a/src/stdlib.hpp b/src/stdlib.hpp index 1af10a0..9b91129 100644 --- a/src/stdlib.hpp +++ b/src/stdlib.hpp @@ -10,6 +10,7 @@ enum class StdlibFunctionId : uint64_t { PrintLn, Prn, Slurp, + Spit, Assert, Dict, List, @@ -29,6 +30,7 @@ enum class StdlibTaskId : uint64_t { Unknown, Print, ReadFile, + WriteFile, Max, };