From e971a2571882d3fb7da9c3b6da0d68a4c6bbd487 Mon Sep 17 00:00:00 2001 From: jaeger Date: Mon, 18 Jul 2011 21:43:55 +0000 Subject: [PATCH] Implemented basic file I/O. git-svn-id: svn://kolibrios.org@2006 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/develop/tinypy/modules/kolibri/fs.c | 258 ++++++++++++++++++ .../develop/tinypy/modules/kolibri/init.c | 20 ++ programs/develop/tinypy/tinypy/test.py | 11 +- 3 files changed, 286 insertions(+), 3 deletions(-) create mode 100755 programs/develop/tinypy/modules/kolibri/fs.c create mode 100755 programs/develop/tinypy/modules/kolibri/init.c diff --git a/programs/develop/tinypy/modules/kolibri/fs.c b/programs/develop/tinypy/modules/kolibri/fs.c new file mode 100755 index 0000000000..ce94be5007 --- /dev/null +++ b/programs/develop/tinypy/modules/kolibri/fs.c @@ -0,0 +1,258 @@ +#include +#include "tp.h" + +extern tp_obj tp_fnc(TP,tp_obj v(TP)); +extern tp_obj tp_method(TP,tp_obj self,tp_obj v(TP)); +extern tp_obj tp_number(tp_num v); +extern tp_obj tp_string(char const *v); +extern tp_obj tp_list(TP); +extern tp_obj tp_dict(TP); +extern void _tp_raise(TP,tp_obj); +#define _cdecl __attribute__((cdecl)) +extern int (* _cdecl con_printf)(const char* format,...); + +#define call70(par, st) asm volatile ("int $0x40":"=a"(st):"a"(70), "b"(par)) +#define call70_rw(par, st, cnt) asm volatile ("int $0x40":"=a"(st), "=b"(cnt):"a"(70), "b"(par)) +typedef unsigned int uint32_t; +typedef unsigned char uint8_t; + +typedef struct { + uint32_t subfnc; + uint32_t res1; + uint32_t res2; + uint32_t res3; + uint8_t *data; + uint8_t res4; + char *fn; + }__attribute__((__packed__)) info_params_t; + +typedef struct { + uint32_t subfnc; + uint32_t pos; + uint32_t res1; + uint32_t cnt; + char* data; + uint8_t res2; + char* fn; + } __attribute__((__packed__)) rw_params_t; + +static tp_obj kolibri_close(TP) +{ + tp_obj self = TP_TYPE(TP_DICT); + uint32_t size = tp_get(tp, self, tp_string("size")).number.val; + char *mode = (char *)tp_get(tp, self, tp_string("mode")).string.val; + tp_set(tp, self, tp_string("closed"), tp_True); + return tp_None; +} + +static tp_obj kolibri_read(TP) +{ + uint32_t status, num; + tp_obj self = TP_TYPE(TP_DICT); + uint32_t pos = tp_get(tp, self, tp_string("pos")).number.val; + uint32_t size = tp_get(tp, self, tp_string("size")).number.val; + uint32_t cnt; + char *buf = (char *)malloc(size - pos); + rw_params_t params = {0, pos, 0, size - pos, buf, 0, + (char *)tp_get(tp, self, tp_string("name")).string.val}; + char *mode = (char *)tp_get(tp, self, tp_string("mode")).string.val; + + if (*mode != 'r') + tp_raise(tp_None, "IOError: file not open for reading", tp_None); + + if (!buf) + return tp_None; + call70_rw((¶ms), status, cnt); + buf[cnt] = '\0'; + return tp_string(buf); +} + +#if 0 +static tp_obj kolibri_readline(TP) +{ + return tp_string("Line"); +} + +static tp_obj kolibri_readlines(TP) +{ + tp_obj result = tp_list(tp); + int i; + + for(i=0; i < 5; i++) + tp_add(result, tp_string("Line")); + return result; +} +#endif + +/* Write object to file. + * + * tp TinyPy virtual machine structure. + * + * returns tp_True + */ +static tp_obj kolibri_write(TP) +{ + tp_obj self = TP_TYPE(TP_DICT); + tp_obj obj = TP_OBJ(); /* What to write. */ + char *mode = (char *)tp_get(tp, self, tp_string("mode")).string.val; + uint32_t pos = (uint32_t)tp_get(tp, self, tp_string("pos")).number.val; + uint32_t size = (uint32_t)tp_get(tp, self, tp_string("size")).number.val; + + if (*mode != 'w' && *mode != 'a') + { + tp_raise(tp_None, "IOError: file not open for writing", tp_None); + } + else + { + char *data = (char *)TP_CSTR(obj); + rw_params_t params = {3, pos, 0, strlen(data), data, 0, + (char *)tp_get(tp, self, tp_string("name")).string.val}; + uint32_t status; + uint32_t cnt; + call70_rw((¶ms), status, cnt); + if (status) + { + tp_raise(tp_None, "IOError: writing failed with status %d", status); + } + pos += cnt; + tp_set(tp, self, tp_string("pos"), tp_number(pos)); + if (pos > size) + { + /* If writing has come beyond the file, increase its size. */ + tp_set(tp, self, tp_string("size"), tp_number(pos)); + } + return tp_True; + } +} + +/* Write line list into file. + * + * tp TinyPy virtual machine structure. + * + * returns tp_None. + */ +static tp_obj kolibri_writelines(TP) +{ + tp_obj result = tp_None; + tp_obj self = TP_TYPE(TP_DICT); + tp_obj list = TP_TYPE(TP_LIST); /* What to write. */ + char *mode = (char *)tp_get(tp, self, tp_string("mode")).string.val; + long pos = (long)tp_get(tp, self, tp_string("pos")).number.val; + uint32_t size = (uint32_t)tp_get(tp, self, tp_string("size")).number.val; + + if (*mode != 'w' && *mode != 'a') + { + tp_raise(tp_None, "IOError: file not open for writing", tp_None); + } + else + { + int i; + char *fn = (char *)tp_get(tp, self, tp_string("name")).string.val; + rw_params_t params = {3, 0, 0, 0, NULL, 0, fn}; + + for (i = 0; i < list.list.val->len; i++) + { + char *data = (char *)TP_CSTR(list.list.val->items[i]); + uint32_t status; + uint32_t cnt; + + params.data = data; + params.cnt = strlen(data); + params.pos = pos; + + call70_rw((¶ms), status, cnt); + if (status) + tp_raise(tp_None, "IOError: writing failed with status %d", status); + pos += cnt; + } + tp_set(tp, self, tp_string("pos"), tp_number(pos)); + if (pos > size) + { + /* If writing has come beyond the file, increase its size. */ + tp_set(tp, self, tp_string("size"), tp_number(pos)); + } + return tp_True; + } +} + +/* Get file size. + * + * fn ASCIIZ absolute file path. + */ +long long int kolibri_filesize(const char *fn) +{ + uint8_t data[40]; + uint32_t status; + long long int result; + info_params_t params = {5, 0, 0, 0, data, 0, (char *)fn}; + + call70((¶ms), status); + /* File size is at offset 32. */ + if (status == 0) + result = *(long long*)(&data[32]); + else + result = -status; + return result; +} + + +/* Open file. + * + * tp TinyPy virtual machine structure. + * + * returns file object. + */ +tp_obj kolibri_open(TP) { + tp_obj obj; + char *fn = (char *)(TP_TYPE(TP_STRING).string.val); + tp_obj mode_obj = TP_OBJ(); + long long int size; + long long int pos = 0; + uint32_t status; + info_params_t params = {2, 0, 0, 0, NULL, 0, fn}; + + if (mode_obj.type == TP_NONE) + mode_obj = tp_string("r"); + else if (mode_obj.type != TP_STRING) + tp_raise(tp_None, "ValueError: bad file access mode %s", TP_CSTR(mode_obj)); + switch(mode_obj.string.val[0]) + { + case 'w': + call70((¶ms), status); + if (status) + tp_raise(tp_None, "IOError: cannot open file for writing", tp_None); + size = 0; + break; + case 'a': + pos = size; + break; + case 'r': + break; + default: + tp_raise(tp_None, "ValueError: mode string must begin with 'r', 'w', or 'a'", tp_None); + } + if ((size = kolibri_filesize(fn)) < 0) + tp_raise(tp_None, "IOError: filesize returned %d", tp_number(size)); + obj = tp_dict(tp); + tp_set(tp, obj, tp_string("name"), tp_string(fn)); + tp_set(tp, obj, tp_string("size"), tp_number(size)); + tp_set(tp, obj, tp_string("pos"), tp_number(pos)); + tp_set(tp, obj, tp_string("mode"), mode_obj); +#if 0 + tp_set(tp, obj, tp_string("__doc__"), + tp_string("File object.\nAttributes:\n name: file name\n" + " closed: boolean indicating whether file was closed\n" + "Methods:\n read: read the entire file into string\n" + " readlines: get list of lines\n" + " close: close the file\n" + )); +#endif + tp_set(tp, obj, tp_string("closed"), tp_False); + tp_set(tp, obj, tp_string("close"), tp_method(tp, obj, kolibri_close)); + tp_set(tp, obj, tp_string("read"), tp_method(tp, obj, kolibri_read)); + tp_set(tp, obj, tp_string("write"), tp_method(tp, obj, kolibri_write)); + tp_set(tp, obj, tp_string("writelines"), tp_method(tp, obj, kolibri_writelines)); + return obj; +} + + diff --git a/programs/develop/tinypy/modules/kolibri/init.c b/programs/develop/tinypy/modules/kolibri/init.c new file mode 100755 index 0000000000..6486e84a42 --- /dev/null +++ b/programs/develop/tinypy/modules/kolibri/init.c @@ -0,0 +1,20 @@ +#include "tp.h" + +extern tp_obj kolibri_open(TP); +extern tp_obj tp_dict(TP); +extern tp_obj tp_fnc(TP,tp_obj v(TP)); + +void kolibri_init(TP) +{ + tp_obj kolibri_mod = tp_dict(tp); + + tp_set(tp, kolibri_mod, tp_string("open"), tp_fnc(tp, kolibri_open)); + + /* Bind module attributes. */ + tp_set(tp, kolibri_mod, tp_string("__doc__"), + tp_string("KolibriOS system specific functions.")); + tp_set(tp, kolibri_mod, tp_string("__name__"), tp_string("kolibri")); + tp_set(tp, kolibri_mod, tp_string("__file__"), tp_string(__FILE__)); + /* Bind to tiny modules[] */ + tp_set(tp, tp->modules, tp_string("kolibri"), kolibri_mod); +} diff --git a/programs/develop/tinypy/tinypy/test.py b/programs/develop/tinypy/tinypy/test.py index b67491643b..e48a998697 100644 --- a/programs/develop/tinypy/tinypy/test.py +++ b/programs/develop/tinypy/tinypy/test.py @@ -1,7 +1,12 @@ import kolibri if __name__=="__main__": print("ok!") - f = kolibri.open("/hd0/1/tinypy/test.txt") - print(f.size) - print(f.read()) + f = kolibri.open("/hd0/1/tinypy/test.txt", "a") + l=[] + s="" + for i in range(10): + s = s + 'A' + l.append(s+'\n') + print(l) + f.writelines(l) f.close()