diff --git a/docs/docs/standard-lib/io.md b/docs/docs/standard-lib/io.md index f3a81781..b0b59bd7 100644 --- a/docs/docs/standard-lib/io.md +++ b/docs/docs/standard-lib/io.md @@ -41,3 +41,13 @@ Prints a given list of values to stdout with an appended newline character. IO.println("Dictu!"); // Dictu! ``` + +### IO.copyFile(String: src, String: dst) -> Result\ + +Copies the contents from the source file to the destination file. + +Returns a Result type and on success will unwrap to nil. + +```cs +IO.copyFile(src, dst); +``` diff --git a/docs/docs/standard-lib/system.md b/docs/docs/standard-lib/system.md index 694ad846..b1e54e8b 100644 --- a/docs/docs/standard-lib/system.md +++ b/docs/docs/standard-lib/system.md @@ -280,13 +280,3 @@ Note: This is not available on Windows systems. System.mkdirTemp().unwrap(); // "VOO16s" System.mkdirTemp("test_XXXXXX").unwrap(); // "test_0bL2qS" ``` - -### System.copyFile(String: src, String: dst) -> Result\ - -Copies the contents from the source file to the destination file. - -Returns a Result type and on success will unwrap to nil. - -```cs -System.copyFile(src, dst); -``` diff --git a/examples/copyFile.du b/examples/copyFile.du index 9f8ec5db..76c47da1 100644 --- a/examples/copyFile.du +++ b/examples/copyFile.du @@ -1,3 +1,4 @@ +import IO; import Path; import System; @@ -36,7 +37,7 @@ def cleanup(tmpDir) { print(file.read()); } - System.copyFile(Path.join(tmpDir, srcFile), Path.join(tmpDir, dstFile)).match( + IO.copyFile(Path.join(tmpDir, srcFile), Path.join(tmpDir, dstFile)).match( def(result) => result, def(error) => { print(error); diff --git a/src/optionals/io.c b/src/optionals/io.c index 5ef8ad48..877233b3 100644 --- a/src/optionals/io.c +++ b/src/optionals/io.c @@ -1,3 +1,13 @@ +#include +#ifndef _WIN32 +#include +#endif +#if defined(__APPLE__) || defined(__FreeBSD__) +#include +#elif defined(__linux__) +#include +#endif + #include "io.h" @@ -28,6 +38,86 @@ static Value printlnIO(DictuVM *vm, int argCount, Value *args) { return NIL_VAL; } +#ifdef _WIN32 +static Value copyFileIO(DictuVM *vm, int argCount, Value *args) { + if (argCount != 2) { + runtimeError(vm, "copyFile() takes 2 arguments (%d given).", argCount); + return EMPTY_VAL; + } + + if (!IS_STRING(args[0]) || !IS_STRING(args[1])) { + runtimeError(vm, "copyFile() arguments must be strings."); + return EMPTY_VAL; + } + + char *srcFile = AS_STRING(args[0])->chars; + char *dstFile = AS_STRING(args[1])->chars; + + FILE *sf = fopen(srcFile, "r"); + if (sf == NULL) { + return newResultError(vm, "cannot open src file"); + } + + FILE *df = fopen(dstFile, "w"); + if (df == NULL) { + fclose(sf); + return newResultError(vm, "cannot open dst file"); + } + + int buffer = fgetc(sf); + while (buffer != EOF) { + fputc(buffer, df); + buffer = fgetc(sf); + } + + fclose(sf); + fclose(df); + + return newResultSuccess(vm, NIL_VAL); +} +#endif + +#ifndef _WIN32 +static Value copyFileIO(DictuVM *vm, int argCount, Value *args) { + if (argCount != 2) { + runtimeError(vm, "copyFile() takes 2 arguments (%d given)", argCount); + return EMPTY_VAL; + } + + if (!IS_STRING(args[0]) || !IS_STRING(args[1])) { + runtimeError(vm, "copyFile() arguments must be strings."); + return EMPTY_VAL; + } + + char *src = AS_STRING(args[0])->chars; + char *dst = AS_STRING(args[1])->chars; + + int in = 0; + int out = 0; + + if ((in = open(src, O_RDONLY)) == -1) { + return newResultError(vm, "failed to open src file"); + } + if ((out = creat(dst, 0660)) == -1) { + close(in); + return newResultError(vm, "failed to create/open dst file"); + } + +#if defined(__APPLE__) || defined(__FreeBSD__) + fcopyfile(in, out, 0, COPYFILE_ALL); +#elif defined(__linux__) + off_t bytes = 0; + struct stat fileinfo = {0}; + fstat(in, &fileinfo); + sendfile(out, in, &bytes, fileinfo.st_size); +#endif + close(in); + close(out); + + return newResultSuccess(vm, NIL_VAL); +} +#endif + Value createIOModule(DictuVM *vm) { ObjString *name = copyString(vm, "IO", 2); push(vm, OBJ_VAL(name)); @@ -43,6 +133,7 @@ Value createIOModule(DictuVM *vm) { */ defineNative(vm, &module->values, "print", printIO); defineNative(vm, &module->values, "println", printlnIO); + defineNative(vm, &module->values, "copyFile", copyFileIO); pop(vm); pop(vm); diff --git a/src/optionals/system.c b/src/optionals/system.c index f8ac6f95..da7ed6e6 100644 --- a/src/optionals/system.c +++ b/src/optionals/system.c @@ -490,43 +490,6 @@ static Value chmodNative(DictuVM *vm, int argCount, Value *args) { return newResultSuccess(vm, NIL_VAL); } -static Value copyFileNative(DictuVM *vm, int argCount, Value *args) { - if (argCount != 2) { - runtimeError(vm, "copyFile() takes 2 arguments (%d given).", argCount); - return EMPTY_VAL; - } - - if (!IS_STRING(args[0]) || !IS_STRING(args[1])) { - runtimeError(vm, "copyFile() arguments must be strings."); - return EMPTY_VAL; - } - - char *srcFile = AS_STRING(args[0])->chars; - char *dstFile = AS_STRING(args[1])->chars; - - FILE *sf = fopen(srcFile, "r"); - if (sf == NULL) { - return newResultError(vm, "cannot open src file"); - } - - FILE *df = fopen(dstFile, "w"); - if (df == NULL) { - fclose(sf); - return newResultError(vm, "cannot open dst file"); - } - - int buffer = fgetc(sf); - while (buffer != EOF) { - fputc(buffer, df); - buffer = fgetc(sf); - } - - fclose(sf); - fclose(df); - - return newResultSuccess(vm, NIL_VAL); -} - void initArgv(DictuVM *vm, Table *table, int argc, char **argv) { ObjList *list = newList(vm); push(vm, OBJ_VAL(list)); @@ -627,7 +590,6 @@ Value createSystemModule(DictuVM *vm) { defineNative(vm, &module->values, "sleep", sleepNative); defineNative(vm, &module->values, "exit", exitNative); defineNative(vm, &module->values, "chmod", chmodNative); - defineNative(vm, &module->values, "copyFile", copyFileNative); /** * Define System properties diff --git a/tests/system/copyFile.du b/tests/io/copyFile.du similarity index 87% rename from tests/system/copyFile.du rename to tests/io/copyFile.du index 9ef369aa..60d38836 100644 --- a/tests/system/copyFile.du +++ b/tests/io/copyFile.du @@ -1,13 +1,14 @@ /** * copyFile.du * - * Testing the System.copyFile() function + * Testing the IO.copyFile() function * * copyFile() copies the contents from the source file to the * destination file. */ from UnitTest import UnitTest; +import IO; import Path; import System; @@ -42,11 +43,11 @@ class TestSystemCopyFile < UnitTest { const srcFullPath = Path.join(this.tmpDir, srcFile); const dstFullPath = Path.join(this.tmpDir, dstFile); - const res = System.copyFile(srcFullPath, dstFullPath); + const res = IO.copyFile(srcFullPath, dstFullPath); this.assertNotNil(res); this.assertSuccess(res); } } -TestSystemCopyFile().run(); +TestSystemCopyFile().run(); \ No newline at end of file diff --git a/tests/io/import.du b/tests/io/import.du new file mode 100644 index 00000000..5324db54 --- /dev/null +++ b/tests/io/import.du @@ -0,0 +1,7 @@ +/** + * import.du + * + * General import file for the IO module tests + */ + +import "copyFile.du"; diff --git a/tests/runTests.du b/tests/runTests.du index 6b564f8c..b239da43 100644 --- a/tests/runTests.du +++ b/tests/runTests.du @@ -36,6 +36,7 @@ import "base64/import.du"; import "sqlite/import.du"; import "process/import.du"; import "inspect/import.du"; +import "io/import.du"; import "unittest/import.du"; if (isDefined("HTTP")) { diff --git a/tests/system/import.du b/tests/system/import.du index 49c45b7d..218f88fb 100644 --- a/tests/system/import.du +++ b/tests/system/import.du @@ -5,7 +5,6 @@ */ import "access.du"; -import "copyFile.du"; import "version.du"; import "sleep.du"; import "getCWD.du";