diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index 52bd80e5a..9eff06b1c 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -496,18 +496,30 @@ Q(monotonic) // file QSTRs Q(file) -Q(tell) -Q(seek) + Q(close) Q(closed) -Q(fileno) Q(flush) Q(isatty) Q(readable) Q(readline) +Q(readlines) Q(seekable) -Q(write) +Q(tell) Q(writable) +Q(writelines) + +Q(fileno) +Q(seek) +Q(truncate) + +Q(write) + +Q(read) + +Q(name) +Q(mode) + Q(SEEK_SET) Q(SEEK_CUR) Q(SEEK_END) diff --git a/python/port/mod/ion/file.cpp b/python/port/mod/ion/file.cpp index 79a80a934..bf72e0bab 100644 --- a/python/port/mod/ion/file.cpp +++ b/python/port/mod/ion/file.cpp @@ -41,6 +41,22 @@ const mp_obj_fun_builtin_var_t file_readline_obj = { {(mp_fun_var_t)file_readline} }; +STATIC mp_obj_t file_readlines(size_t n_args, const mp_obj_t* args); + +const mp_obj_fun_builtin_var_t file_readlines_obj = { + {&mp_type_fun_builtin_var}, + MP_OBJ_FUN_MAKE_SIG(1, 2, false), + {(mp_fun_var_t)file_readlines} +}; + +STATIC mp_obj_t file_truncate(size_t n_args, const mp_obj_t* args); + +const mp_obj_fun_builtin_var_t file_truncate_obj = { + {&mp_type_fun_builtin_var}, + MP_OBJ_FUN_MAKE_SIG(1, 2, false), + {(mp_fun_var_t)file_truncate} +}; + STATIC mp_obj_t file_read(size_t n_args, const mp_obj_t* args); const mp_obj_fun_builtin_var_t file_read_obj = { @@ -56,6 +72,13 @@ const mp_obj_fun_builtin_fixed_t file_write_obj = { {(mp_fun_0_t)file_write} }; +STATIC mp_obj_t file_writelines(mp_obj_t o_in, mp_obj_t o_lines); + +const mp_obj_fun_builtin_fixed_t file_writelines_obj = { + {&mp_type_fun_builtin_2}, + {(mp_fun_0_t)file_writelines} +}; + STATIC mp_obj_t file_seekable(mp_obj_t o_in); const mp_obj_fun_builtin_fixed_t file_seekable_obj = { @@ -164,6 +187,7 @@ typedef struct _file_obj_t { mp_obj_base_t base; mp_obj_t name; + mp_obj_t mode_repr; file_mode_t open_mode; bool edit_mode; @@ -214,58 +238,85 @@ STATIC mp_obj_t file___iter__(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) { } STATIC void file_attr(mp_obj_t self_in, qstr attribute, mp_obj_t *destination) { - destination[1] = self_in; file_obj_t *self = (file_obj_t*) MP_OBJ_TO_PTR(self_in); - if (destination[0] == nullptr) { - switch(attribute) { - case MP_QSTR_closed: - destination[0] = mp_obj_new_bool(self->closed); - break; - case MP_QSTR___enter__: - destination[0] = (mp_obj_t) MP_ROM_PTR(&file___enter___obj); - break; - case MP_QSTR___exit__: - destination[0] = (mp_obj_t) MP_ROM_PTR(&file___exit___obj); - break; - case MP_QSTR_close: - destination[0] = (mp_obj_t) MP_ROM_PTR(&file_close_obj); - break; - case MP_QSTR_tell: - destination[0] = (mp_obj_t) MP_ROM_PTR(&file_tell_obj); - break; - case MP_QSTR_seek: - destination[0] = (mp_obj_t) MP_ROM_PTR(&file_seek_obj); - break; - case MP_QSTR_seekable: - destination[0] = (mp_obj_t) MP_ROM_PTR(&file_seekable_obj); - break; - case MP_QSTR_fileno: - destination[0] = (mp_obj_t) MP_ROM_PTR(&file_fileno_obj); - break; - case MP_QSTR_flush: - destination[0] = (mp_obj_t) MP_ROM_PTR(&file_flush_obj); - break; - case MP_QSTR_isatty: - destination[0] = (mp_obj_t) MP_ROM_PTR(&file_isatty_obj); - break; - case MP_QSTR_readable: - destination[0] = (mp_obj_t) MP_ROM_PTR(&file_readable_obj); - break; - case MP_QSTR_read: - destination[0] = (mp_obj_t) MP_ROM_PTR(&file_read_obj); - break; - case MP_QSTR_readline: - destination[0] = (mp_obj_t) MP_ROM_PTR(&file_readline_obj); - break; - case MP_QSTR_write: - destination[0] = (mp_obj_t) MP_ROM_PTR(&file_write_obj); - break; - default: - break; - } + switch(attribute) { + case MP_QSTR_closed: + destination[0] = mp_obj_new_bool(self->closed); + break; + case MP_QSTR_name: + destination[0] = (mp_obj_t) self->name; + break; + case MP_QSTR_mode: + destination[0] = (mp_obj_t) self->mode_repr; + break; + case MP_QSTR___enter__: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file___enter___obj); + destination[1] = self_in; + break; + case MP_QSTR___exit__: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file___exit___obj); + destination[1] = self_in; + break; + case MP_QSTR_close: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file_close_obj); + destination[1] = self_in; + break; + case MP_QSTR_tell: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file_tell_obj); + destination[1] = self_in; + break; + case MP_QSTR_seek: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file_seek_obj); + destination[1] = self_in; + break; + case MP_QSTR_seekable: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file_seekable_obj); + destination[1] = self_in; + break; + case MP_QSTR_fileno: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file_fileno_obj); + destination[1] = self_in; + break; + case MP_QSTR_flush: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file_flush_obj); + destination[1] = self_in; + break; + case MP_QSTR_isatty: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file_isatty_obj); + destination[1] = self_in; + break; + case MP_QSTR_readable: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file_readable_obj); + destination[1] = self_in; + break; + case MP_QSTR_read: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file_read_obj); + destination[1] = self_in; + break; + case MP_QSTR_readline: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file_readline_obj); + destination[1] = self_in; + break; + case MP_QSTR_readlines: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file_readlines_obj); + destination[1] = self_in; + break; + case MP_QSTR_write: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file_write_obj); + destination[1] = self_in; + break; + case MP_QSTR_writelines: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file_writelines_obj); + destination[1] = self_in; + break; + case MP_QSTR_truncate: + destination[0] = (mp_obj_t) MP_ROM_PTR(&file_truncate_obj); + destination[1] = self_in; + break; + default: + break; } - } STATIC void file_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { @@ -274,38 +325,7 @@ STATIC void file_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ size_t l; const char* file_name = mp_obj_str_get_data(self->name, &l); - - uint8_t offset = 0; - char file_mode[4] = {0, 0, 0, 0}; - - switch(self->open_mode) { - case READ: - file_mode[0] = 'r'; - break; - case WRITE: - file_mode[0] = 'w'; - break; - case APPEND: - file_mode[0] = 'a'; - break; - case CREATE: - file_mode[0] = 'x'; - break; - } - - if (self->edit_mode) { - file_mode[1] = '+'; - offset = 1; - } - - switch(self->binary_mode) { - case TEXT: - file_mode[1 + offset] = 't'; - break; - case BINARY: - file_mode[1 + offset] = 'b'; - break; - } + const char* file_mode = mp_obj_str_get_data(self->mode_repr, &l); mp_print_str(print, "edit_mode) { + file_mode[1] = '+'; + offset = 1; + } + + switch(file->binary_mode) { + case TEXT: + file_mode[1 + offset] = 't'; + break; + case BINARY: + file_mode[1 + offset] = 'b'; + break; + } + + file->mode_repr = mp_obj_new_str(file_mode, 2 + offset); + + return MP_OBJ_FROM_PTR(file); } @@ -686,7 +743,7 @@ STATIC mp_obj_t file_write(mp_obj_t o_in, mp_obj_t o_s) { size_t avaliable_size = Ion::Storage::sharedStorage()->putAvailableSpaceAtEndOfRecord(file->record); // Check if there is enough space left - if (file->position + len + 1 > avaliable_size) { + if (file->position + len > avaliable_size) { Ion::Storage::sharedStorage()->getAvailableSpaceFromEndOfRecord(file->record, avaliable_size - previous_size); mp_raise_OSError(28); } @@ -709,6 +766,16 @@ STATIC mp_obj_t file_write(mp_obj_t o_in, mp_obj_t o_s) { return mp_obj_new_int(len); } +STATIC mp_obj_t file_writelines(mp_obj_t o_in, mp_obj_t o_lines) { + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(o_lines, &iter_buf); + mp_obj_t item; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + file_write(o_in, item); + } + return mp_const_none; +} + STATIC mp_obj_t __file_read_backend(file_obj_t* file, mp_int_t size, bool with_line_sep) { if (file->location == RAM) { size_t file_size = file->record.value().size; @@ -778,7 +845,11 @@ STATIC mp_obj_t file_read(size_t n_args, const mp_obj_t* args) { return mp_obj_new_str("", 0); if (file->binary_mode == BINARY) return mp_const_empty_bytes; + } else { + return ret; } + + return mp_const_none; } STATIC mp_obj_t file_readline(size_t n_args, const mp_obj_t* args) { @@ -806,13 +877,124 @@ STATIC mp_obj_t file_readline(size_t n_args, const mp_obj_t* args) { size = mp_obj_get_int(args[1]); } - mp_obj_t ret = __file_read_backend(file, size, false); + mp_obj_t ret = __file_read_backend(file, size, true); if (ret == mp_const_none) { if (file->binary_mode == TEXT) return mp_obj_new_str("", 0); if (file->binary_mode == BINARY) return mp_const_empty_bytes; + } else { + return ret; } + + return mp_const_none; +} + +STATIC mp_obj_t file_readlines(size_t n_args, const mp_obj_t* args) { + mp_arg_check_num(n_args, 0, 1, 2, false); + + if(!mp_obj_is_type(args[0], &file_type)) { + mp_raise_TypeError("self must be a file!"); + } + + file_obj_t *file = (file_obj_t*) MP_OBJ_TO_PTR(args[0]); + + check_closed(file); + + if (file->open_mode != READ && file->edit_mode != true) { + mp_raise_OSError(1); + } + + mp_int_t hint = -1; + + if (n_args > 1) { + if (!mp_obj_is_integer(args[1])) { + mp_raise_ValueError("hint must be an int!"); + } + + hint = mp_obj_get_int(args[1]); + } + + mp_obj_t list = mp_obj_new_list(0, NULL); + + if (hint <= 0) { + mp_obj_t ret = __file_read_backend(file, -1, true); + while(ret != mp_const_none) { + mp_obj_list_append(list, ret); + ret = __file_read_backend(file, -1, true); + } + } else { + mp_int_t curr_len = 0; + + mp_obj_t ret = __file_read_backend(file, -1, true); + while(ret != mp_const_none && curr_len <= hint) { + mp_obj_list_append(list, ret); + size_t l = 0; + mp_obj_str_get_data(ret, &l); + curr_len += l; + ret = __file_read_backend(file, -1, true); + } + } + + return list; +} + +STATIC mp_obj_t file_truncate(size_t n_args, const mp_obj_t* args) { + mp_arg_check_num(n_args, 0, 1, 2, false); + + if(!mp_obj_is_type(args[0], &file_type)) { + mp_raise_TypeError("self must be a file!"); + } + + file_obj_t *file = (file_obj_t*) MP_OBJ_TO_PTR(args[0]); + + check_closed(file); + + if (file->open_mode == READ && file->edit_mode != true) { + mp_raise_OSError(1); + } + + if(!mp_obj_is_integer(args[1]) && args[1] != mp_const_none) { + mp_raise_TypeError("size must be an integer!"); + } + + mp_int_t temp_new_end = file->position; + + if (args[1] != mp_const_none) { + temp_new_end = mp_obj_get_int(args[1]); + } + + if (temp_new_end < 0) { + mp_raise_OSError(22); + } + + size_t new_end = (size_t) temp_new_end; + + if (file->location == RAM) { + size_t previous_size = file->record.value().size; + + // Claim avaliable space. + size_t avaliable_size = Ion::Storage::sharedStorage()->putAvailableSpaceAtEndOfRecord(file->record); + + // Check if there is enough space left + if (new_end > avaliable_size) { + Ion::Storage::sharedStorage()->getAvailableSpaceFromEndOfRecord(file->record, avaliable_size - previous_size); + mp_raise_OSError(28); + } + + // Check if new_end is higher than file end + // If yes, fill space between there with 0x00 + if (new_end > previous_size) { + memset((uint8_t*)(file->record.value().buffer) + new_end, 0x00, new_end - previous_size); + } + + // Set new size + Ion::Storage::sharedStorage()->getAvailableSpaceFromEndOfRecord(file->record, file->record.value().size - new_end); + + return mp_obj_new_int(new_end); + } + + return mp_const_none; }