From 15c0985d2e4d7d77302753b3ef3bd82fbf0ec87d Mon Sep 17 00:00:00 2001 From: pikastech Date: Mon, 18 Jul 2022 13:53:39 +0800 Subject: [PATCH] add lseek() function support readline(), readlines(), writelines() for FILEIO --- examples/BuiltIn/file2.py | 9 +++ examples/BuiltIn/file3.py | 4 + package/PikaStdLib/PikaStdData.pyi | 3 + package/PikaStdLib/PikaStdData_FILEIO.c | 74 ++++++++++++++++++ port/linux/package/pikascript/PikaStdData.pyi | 3 + .../PikaStdLib/PikaStdData_FILEIO.c | 75 +++++++++++++++++++ port/linux/test/builtin-test.cpp | 34 +++++++++ src/PikaPlatform.h | 2 +- 8 files changed, 203 insertions(+), 1 deletion(-) create mode 100644 examples/BuiltIn/file2.py create mode 100644 examples/BuiltIn/file3.py diff --git a/examples/BuiltIn/file2.py b/examples/BuiltIn/file2.py new file mode 100644 index 000000000..33a600684 --- /dev/null +++ b/examples/BuiltIn/file2.py @@ -0,0 +1,9 @@ +f = open('test/python/main.py', 'r') + +s = f.readline() +print(s) + +lines = f.readlines() +print(lines) + +f.close() diff --git a/examples/BuiltIn/file3.py b/examples/BuiltIn/file3.py new file mode 100644 index 000000000..76829d8a0 --- /dev/null +++ b/examples/BuiltIn/file3.py @@ -0,0 +1,4 @@ +f = open('test/out/file3.txt', 'w') +seq = ['This is the first line.\n', 'This is the second line.\n', 'This is the third line.\n'] +f.writelines(seq) +f.close() diff --git a/package/PikaStdLib/PikaStdData.pyi b/package/PikaStdLib/PikaStdData.pyi index aacfce77d..f2a6ba09c 100644 --- a/package/PikaStdLib/PikaStdData.pyi +++ b/package/PikaStdLib/PikaStdData.pyi @@ -101,6 +101,9 @@ class FILEIO: def close(self): ... def seek(self, offset: int, *fromwhere) -> int: ... def tell(self) -> int: ... + def readline(self) -> str: ... + def readlines(self) -> List: ... + def writelines(self, lines: List): ... class Utils: diff --git a/package/PikaStdLib/PikaStdData_FILEIO.c b/package/PikaStdLib/PikaStdData_FILEIO.c index 612f69cfe..dbf9dd38a 100644 --- a/package/PikaStdLib/PikaStdData_FILEIO.c +++ b/package/PikaStdLib/PikaStdData_FILEIO.c @@ -1,5 +1,6 @@ #include "PikaStdData_FILEIO.h" #include +#include "PikaStdData_List.h" void PikaStdData_FILEIO_init(PikaObj* self, char* mode, char* path) { if (obj_isArgExist(self, "_f")) { @@ -100,3 +101,76 @@ int PikaStdData_FILEIO_tell(PikaObj* self) { } return __platform_ftell(f); } + +char* PikaStdData_FILEIO_readline(PikaObj* self) { + FILE* f = obj_getPtr(self, "_f"); + if (f == NULL) { + obj_setErrorCode(self, PIKA_RES_ERR_IO); + __platform_printf("Error: can't read line from file\n"); + return NULL; + } + obj_setBytes(self, "_line_buff", NULL, PIKA_LINE_BUFF_SIZE); + char* line_buff = (char*)obj_getBytes(self, "_line_buff"); + while (1) { + char char_buff[2] = {0}; + int n = __platform_fread(char_buff, 1, 1, f); + if (n == 0) { + /* EOF */ + return NULL; + } + if (char_buff[0] == '\n') { + /* end of line */ + strAppend(line_buff, char_buff); + return line_buff; + } + if (strGetSize(line_buff) >= PIKA_LINE_BUFF_SIZE) { + /* line too long */ + obj_setErrorCode(self, PIKA_RES_ERR_IO); + __platform_printf("Error: line too long\n"); + return NULL; + } + strAppend(line_buff, char_buff); + } +} + +PikaObj* PikaStdData_FILEIO_readlines(PikaObj* self) { + FILE* f = obj_getPtr(self, "_f"); + if (f == NULL) { + obj_setErrorCode(self, PIKA_RES_ERR_IO); + __platform_printf("Error: can't read lines from file\n"); + return NULL; + } + PikaObj* line_list = newNormalObj(New_PikaStdData_List); + PikaStdData_List___init__(line_list); + while (1) { + char* line = PikaStdData_FILEIO_readline(self); + if (line == NULL) { + break; + } + Arg* arg_str = arg_setStr(NULL, "", line); + PikaStdData_List_append(line_list, arg_str); + arg_deinit(arg_str); + } + return line_list; +} + +void PikaStdData_FILEIO_writelines(PikaObj* self, PikaObj* lines) { + FILE* f = obj_getPtr(self, "_f"); + if (f == NULL) { + obj_setErrorCode(self, PIKA_RES_ERR_IO); + __platform_printf("Error: can't write lines to file\n"); + return -1; + } + PikaList* list = obj_getPtr(lines, "list"); + if (list == NULL) { + obj_setErrorCode(self, PIKA_RES_ERR_IO); + __platform_printf("Error: can't write lines to file\n"); + return -1; + } + int i; + for (i = 0; i < list_getSize(list); i++) { + PikaObj* line = list_getStr(list, i); + PikaStdData_FILEIO_write(self, line); + } + return 0; +} diff --git a/port/linux/package/pikascript/PikaStdData.pyi b/port/linux/package/pikascript/PikaStdData.pyi index aacfce77d..f2a6ba09c 100644 --- a/port/linux/package/pikascript/PikaStdData.pyi +++ b/port/linux/package/pikascript/PikaStdData.pyi @@ -101,6 +101,9 @@ class FILEIO: def close(self): ... def seek(self, offset: int, *fromwhere) -> int: ... def tell(self) -> int: ... + def readline(self) -> str: ... + def readlines(self) -> List: ... + def writelines(self, lines: List): ... class Utils: diff --git a/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdData_FILEIO.c b/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdData_FILEIO.c index 612f69cfe..650c86f52 100644 --- a/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdData_FILEIO.c +++ b/port/linux/package/pikascript/pikascript-lib/PikaStdLib/PikaStdData_FILEIO.c @@ -1,5 +1,6 @@ #include "PikaStdData_FILEIO.h" #include +#include "PikaStdData_List.h" void PikaStdData_FILEIO_init(PikaObj* self, char* mode, char* path) { if (obj_isArgExist(self, "_f")) { @@ -100,3 +101,77 @@ int PikaStdData_FILEIO_tell(PikaObj* self) { } return __platform_ftell(f); } + +char* PikaStdData_FILEIO_readline(PikaObj* self) { + FILE* f = obj_getPtr(self, "_f"); + if (f == NULL) { + obj_setErrorCode(self, PIKA_RES_ERR_IO); + __platform_printf("Error: can't read line from file\n"); + return NULL; + } + obj_setBytes(self, "_line_buff", NULL, PIKA_LINE_BUFF_SIZE); + char* line_buff = (char*)obj_getBytes(self, "_line_buff"); + while (1) { + char char_buff[2] = {0}; + int n = __platform_fread(char_buff, 1, 1, f); + if (n == 0) { + /* EOF */ + return NULL; + } + if (char_buff[0] == '\n') { + /* end of line */ + strAppend(line_buff, char_buff); + return line_buff; + } + if (strGetSize(line_buff) >= PIKA_LINE_BUFF_SIZE) { + /* line too long */ + obj_setErrorCode(self, PIKA_RES_ERR_IO); + __platform_printf("Error: line too long\n"); + return NULL; + } + strAppend(line_buff, char_buff); + } +} + +PikaObj* PikaStdData_FILEIO_readlines(PikaObj* self) { + FILE* f = obj_getPtr(self, "_f"); + if (f == NULL) { + obj_setErrorCode(self, PIKA_RES_ERR_IO); + __platform_printf("Error: can't read lines from file\n"); + return NULL; + } + PikaObj* line_list = newNormalObj(New_PikaStdData_List); + PikaStdData_List___init__(line_list); + while (1) { + char* line = PikaStdData_FILEIO_readline(self); + if (line == NULL) { + break; + } + Arg* arg_str = arg_setStr(NULL, "", line); + PikaStdData_List_append(line_list, arg_str); + arg_deinit(arg_str); + } + return line_list; +} + +void PikaStdData_FILEIO_writelines(PikaObj* self, PikaObj* lines) { + FILE* f = obj_getPtr(self, "_f"); + if (f == NULL) { + obj_setErrorCode(self, PIKA_RES_ERR_IO); + __platform_printf("Error: can't write lines to file\n"); + return; + } + PikaList* list = obj_getPtr(lines, "list"); + if (list == NULL) { + obj_setErrorCode(self, PIKA_RES_ERR_IO); + __platform_printf("Error: can't write lines to file\n"); + return; + } + for (size_t i = 0; i < list_getSize(list); i++) { + char* line = list_getStr(list, i); + Arg* arg_str = arg_setStr(NULL, "", line); + PikaStdData_FILEIO_write(self, arg_str); + arg_deinit(arg_str); + } + return; +} diff --git a/port/linux/test/builtin-test.cpp b/port/linux/test/builtin-test.cpp index a4df94492..274988943 100644 --- a/port/linux/test/builtin-test.cpp +++ b/port/linux/test/builtin-test.cpp @@ -53,3 +53,37 @@ TEST(builtin, seek) { EXPECT_EQ(pikaMemNow(), 0); } #endif + +#if PIKA_SYNTAX_LEVEL == PIKA_SYNTAX_LEVEL_MAXIMAL +TEST(builtin, file2) { + /* init */ + pikaMemInfo.heapUsedMax = 0; + PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain); + /* run */ + __platform_printf("BEGIN\r\n"); + pikaVM_runSingleFile(pikaMain, "../../examples/BuiltIn/file2.py"); + /* collect */ + char* s = obj_getStr(pikaMain, "s"); + /* assert */ + EXPECT_STREQ(s, "import PikaStdLib\n"); + /* deinit */ + obj_deinit(pikaMain); + EXPECT_EQ(pikaMemNow(), 0); +} +#endif + +#if PIKA_SYNTAX_LEVEL == PIKA_SYNTAX_LEVEL_MAXIMAL +TEST(builtin, file3) { + /* init */ + pikaMemInfo.heapUsedMax = 0; + PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain); + /* run */ + __platform_printf("BEGIN\r\n"); + pikaVM_runSingleFile(pikaMain, "../../examples/BuiltIn/file3.py"); + /* collect */ + /* assert */ + /* deinit */ + obj_deinit(pikaMain); + EXPECT_EQ(pikaMemNow(), 0); +} +#endif \ No newline at end of file diff --git a/src/PikaPlatform.h b/src/PikaPlatform.h index 0d33dc984..3f940db49 100644 --- a/src/PikaPlatform.h +++ b/src/PikaPlatform.h @@ -153,9 +153,9 @@ int __platform_fclose(FILE* stream); size_t __platform_fwrite(const void* ptr, size_t size, size_t n, FILE* stream); size_t __platform_fread(void* ptr, size_t size, size_t n, FILE* stream); int __platform_fseek(FILE* stream, long offset, int whence); +long __platform_ftell(FILE* stream); /* error */ void __platform_error_handle(void); -long __platform_ftell(FILE* stream); #endif