#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; }