| @@ -188,6 +188,15 @@ namespace · 187 unmodified lines |
| 188 | 188 | throw vm_user_exception{ "Write operation error" }; |
| 189 | 189 | } |
| 190 | 190 | |
| 191 | + big_t seek(const std::ios::seekdir start, const big_t offset) |
| 192 | + { |
| 193 | + if (_stream == nullptr) |
| 194 | + throw vm_user_exception{ "Unable to seek on a fifo file descriptor (e.g. stdin, stdout, stderr)" }; |
| 195 | + |
| 196 | + auto new_offset = _stream->rdbuf()->pubseekoff(static_cast<std::streamoff>(offset), start, _fd_mode); |
| 197 | + return static_cast<big_t>(new_offset); |
| 198 | + } |
| 199 | + |
| 191 | 200 | private: |
| 192 | 201 | const word_t _fd_mode; |
| 193 | 202 | vm_string_t *_fd_path; |
| @@ -218,6 +227,21 @@ namespace · 24 unmodified lines |
| 218 | 227 | |
| 219 | 228 | return om; |
| 220 | 229 | } |
| 230 | + |
| 231 | + std::ios::seekdir convert_to_seekdir(const word_t start) |
| 232 | + { |
| 233 | + switch (start) |
| 234 | + { |
| 235 | + case Sys_SEEKSTART: |
| 236 | + return std::ios::beg; |
| 237 | + case Sys_SEEKRELA: |
| 238 | + return std::ios::cur; |
| 239 | + case Sys_SEEKEND: |
| 240 | + return std::ios::end; |
| 241 | + default: |
| 242 | + throw vm_user_exception{ "Invalid seek mode" }; |
| 243 | + } |
| 244 | + } |
| 221 | 245 | } |
| 222 | 246 | |
| 223 | 247 | void |
| @@ -612,7 +636,6 @@ Sys_read(vm_registers_t &r, vm_t &vm) · 388 unmodified lines |
| 612 | 636 | auto &fp = r.stack.peek_frame()->base<F_Sys_read>(); |
| 613 | 637 | |
| 614 | 638 | const auto buffer = vm_alloc_t::from_allocation<vm_array_t>(fp.buf); |
| 615 | | − assert(buffer->get_element_type()->size_in_bytes == intrinsic_type_desc::type<byte_t>()->size_in_bytes); |
| 616 | 639 | |
| 617 | 640 | auto n = fp.n; |
| 618 | 641 | if (buffer == nullptr || n <= 0) |
| @@ -621,11 +644,16 @@ Sys_read(vm_registers_t &r, vm_t &vm) · 2 unmodified lines |
| 621 | 644 | return; |
| 622 | 645 | } |
| 623 | 646 | |
| 647 | + assert(buffer->get_element_type()->size_in_bytes == intrinsic_type_desc::type<byte_t>()->size_in_bytes); |
| 648 | + |
| 624 | 649 | // [SPEC] Supplying a size greater than the buffer length is |
| 625 | 650 | // equivalent to indicating the entire buffer should be filled. |
| 626 | 651 | n = std::min(n, buffer->get_length()); |
| 627 | 652 | |
| 628 | 653 | auto fd_alloc = vm_alloc_t::from_allocation(fp.fd); |
| 654 | + if (fd_alloc == nullptr) |
| 655 | + throw dereference_nil{ "Read from file descriptor" }; |
| 656 | + |
| 629 | 657 | assert(fd_alloc->alloc_type == T_FD); |
| 630 | 658 | |
| 631 | 659 | auto fd = fd_alloc->get_allocation<vm_fd_t>(); |
| @@ -650,7 +678,16 @@ void · 18 unmodified lines |
| 650 | 678 | Sys_seek(vm_registers_t &r, vm_t &vm) |
| 651 | 679 | { |
| 652 | 680 | auto &fp = r.stack.peek_frame()->base<F_Sys_seek>(); |
| 653 | | − throw vm_system_exception{ "Instruction not implemented" }; |
| 681 | + |
| 682 | + auto fd_alloc = vm_alloc_t::from_allocation(fp.fd); |
| 683 | + if (fd_alloc == nullptr) |
| 684 | + throw dereference_nil{ "Seek in file descriptor" }; |
| 685 | + |
| 686 | + assert(fd_alloc->alloc_type == T_FD); |
| 687 | + auto fd = fd_alloc->get_allocation<vm_fd_t>(); |
| 688 | + |
| 689 | + const auto start = convert_to_seekdir(fp.start); |
| 690 | + *fp.ret = fd->seek(start, fp.off); |
| 654 | 691 | } |
| 655 | 692 | |
| 656 | 693 | void |
| @@ -814,7 +851,19 @@ void · 157 unmodified lines |
| 814 | 851 | Sys_utfbytes(vm_registers_t &r, vm_t &vm) |
| 815 | 852 | { |
| 816 | 853 | auto &fp = r.stack.peek_frame()->base<F_Sys_utfbytes>(); |
| 817 | | − throw vm_system_exception{ "Instruction not implemented" }; |
| 854 | + const auto buffer = vm_alloc_t::from_allocation<vm_array_t>(fp.buf); |
| 855 | + |
| 856 | + const auto n = fp.n; |
| 857 | + if (buffer == nullptr || n > buffer->get_length()) |
| 858 | + throw out_of_range_memory{}; |
| 859 | + |
| 860 | + assert(buffer->get_element_type()->size_in_bytes == intrinsic_type_desc::type<byte_t>()->size_in_bytes); |
| 861 | + |
| 862 | + auto raw_buffer = reinterpret_cast<uint8_t *>(buffer->at(0)); |
| 863 | + |
| 864 | + const auto len = utf8::count_codepoints(raw_buffer, n); |
| 865 | + *fp.ret = static_cast<word_t>(len.byte_count); |
| 866 | + assert(*fp.ret <= n && "Code points should not exceed number of bytes processed"); |
| 818 | 867 | } |
| 819 | 868 | |
| 820 | 869 | void |
| @@ -830,7 +879,6 @@ Sys_write(vm_registers_t &r, vm_t &vm) · 9 unmodified lines |
| 830 | 879 | auto &fp = r.stack.peek_frame()->base<F_Sys_write>(); |
| 831 | 880 | |
| 832 | 881 | const auto buffer = vm_alloc_t::from_allocation<vm_array_t>(fp.buf); |
| 833 | | − assert(buffer->get_element_type()->size_in_bytes == intrinsic_type_desc::type<byte_t>()->size_in_bytes); |
| 834 | 882 | |
| 835 | 883 | auto n = fp.n; |
| 836 | 884 | if (buffer == nullptr || n <= 0) |
| @@ -839,11 +887,16 @@ Sys_write(vm_registers_t &r, vm_t &vm) · 2 unmodified lines |
| 839 | 887 | return; |
| 840 | 888 | } |
| 841 | 889 | |
| 890 | + assert(buffer->get_element_type()->size_in_bytes == intrinsic_type_desc::type<byte_t>()->size_in_bytes); |
| 891 | + |
| 842 | 892 | // [SPEC] Supplying a size greater than the buffer length is |
| 843 | 893 | // equivalent to indicating the entire buffer should be written. |
| 844 | 894 | n = std::min(n, buffer->get_length()); |
| 845 | 895 | |
| 846 | 896 | auto fd_alloc = vm_alloc_t::from_allocation(fp.fd); |
| 897 | + if (fd_alloc == nullptr) |
| 898 | + throw dereference_nil{ "Write to file descriptor" }; |
| 899 | + |
| 847 | 900 | assert(fd_alloc->alloc_type == T_FD); |
| 848 | 901 | |
| 849 | 902 | auto fd = fd_alloc->get_allocation<vm_fd_t>(); |