paul@354 | 1 | /* Native functions for input/output. |
paul@354 | 2 | |
paul@569 | 3 | Copyright (C) 2016, 2017 Paul Boddie <paul@boddie.org.uk> |
paul@354 | 4 | |
paul@354 | 5 | This program is free software; you can redistribute it and/or modify it under |
paul@354 | 6 | the terms of the GNU General Public License as published by the Free Software |
paul@354 | 7 | Foundation; either version 3 of the License, or (at your option) any later |
paul@354 | 8 | version. |
paul@354 | 9 | |
paul@354 | 10 | This program is distributed in the hope that it will be useful, but WITHOUT |
paul@354 | 11 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
paul@354 | 12 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more |
paul@354 | 13 | details. |
paul@354 | 14 | |
paul@354 | 15 | You should have received a copy of the GNU General Public License along with |
paul@354 | 16 | this program. If not, see <http://www.gnu.org/licenses/>. |
paul@354 | 17 | */ |
paul@354 | 18 | |
paul@354 | 19 | #include <unistd.h> /* read, write */ |
paul@378 | 20 | #include <string.h> /* strcmp, memcpy */ |
paul@354 | 21 | #include <stdio.h> /* fdopen, snprintf */ |
paul@354 | 22 | #include <errno.h> /* errno */ |
paul@354 | 23 | #include "native/common.h" |
paul@354 | 24 | #include "types.h" |
paul@354 | 25 | #include "exceptions.h" |
paul@354 | 26 | #include "ops.h" |
paul@354 | 27 | #include "progconsts.h" |
paul@354 | 28 | #include "progops.h" |
paul@354 | 29 | #include "progtypes.h" |
paul@354 | 30 | #include "main.h" |
paul@354 | 31 | |
paul@354 | 32 | /* Input/output. */ |
paul@354 | 33 | |
paul@664 | 34 | __attr __fn_native_io_fclose(__attr __self, __attr fp) |
paul@354 | 35 | { |
paul@354 | 36 | /* fp interpreted as FILE reference */ |
paul@664 | 37 | FILE *f = (FILE *) fp.datavalue; |
paul@354 | 38 | |
paul@354 | 39 | errno = 0; |
paul@354 | 40 | if (fclose(f)) |
paul@354 | 41 | __raise_io_error(__new_int(errno)); |
paul@354 | 42 | |
paul@354 | 43 | return __builtins___none_None; |
paul@354 | 44 | } |
paul@354 | 45 | |
paul@664 | 46 | __attr __fn_native_io_fflush(__attr __self, __attr fp) |
paul@436 | 47 | { |
paul@436 | 48 | /* fp interpreted as FILE reference */ |
paul@664 | 49 | FILE *f = (FILE *) fp.datavalue; |
paul@436 | 50 | |
paul@436 | 51 | errno = 0; |
paul@436 | 52 | if (fflush(f)) |
paul@436 | 53 | __raise_io_error(__new_int(errno)); |
paul@436 | 54 | |
paul@436 | 55 | return __builtins___none_None; |
paul@436 | 56 | } |
paul@436 | 57 | |
paul@664 | 58 | __attr __fn_native_io_fopen(__attr __self, __attr filename, __attr mode) |
paul@354 | 59 | { |
paul@354 | 60 | /* filename.__data__ interpreted as string */ |
paul@763 | 61 | char *fn = __load_via_object(__VALUE(filename), __data__).strvalue; |
paul@354 | 62 | /* mode.__data__ interpreted as string */ |
paul@763 | 63 | char *s = __load_via_object(__VALUE(mode), __data__).strvalue; |
paul@354 | 64 | FILE *f; |
paul@354 | 65 | __attr attr; |
paul@354 | 66 | |
paul@354 | 67 | errno = 0; |
paul@354 | 68 | f = fopen(fn, s); |
paul@354 | 69 | |
paul@354 | 70 | /* Produce an exception if the operation failed. */ |
paul@354 | 71 | |
paul@354 | 72 | if (f == NULL) |
paul@354 | 73 | __raise_io_error(__new_int(errno)); |
paul@354 | 74 | |
paul@354 | 75 | /* Return the __data__ attribute. */ |
paul@354 | 76 | |
paul@354 | 77 | else |
paul@354 | 78 | { |
paul@354 | 79 | attr.datavalue = (void *) f; |
paul@354 | 80 | return attr; |
paul@354 | 81 | } |
paul@477 | 82 | |
paul@477 | 83 | /* Should never be reached: included to satisfy the compiler. */ |
paul@477 | 84 | |
paul@477 | 85 | return __builtins___none_None; |
paul@354 | 86 | } |
paul@354 | 87 | |
paul@664 | 88 | __attr __fn_native_io_fdopen(__attr __self, __attr fd, __attr mode) |
paul@354 | 89 | { |
paul@758 | 90 | /* fd interpreted as int */ |
paul@763 | 91 | int i = __TOINT(fd); |
paul@354 | 92 | /* mode.__data__ interpreted as string */ |
paul@763 | 93 | char *s = __load_via_object(__VALUE(mode), __data__).strvalue; |
paul@354 | 94 | FILE *f; |
paul@354 | 95 | __attr attr; |
paul@354 | 96 | |
paul@354 | 97 | errno = 0; |
paul@354 | 98 | f = fdopen(i, s); |
paul@354 | 99 | |
paul@354 | 100 | /* Produce an exception if the operation failed. */ |
paul@354 | 101 | |
paul@354 | 102 | if (f == NULL) |
paul@354 | 103 | __raise_io_error(__new_int(errno)); |
paul@354 | 104 | |
paul@354 | 105 | /* Return the __data__ attribute. */ |
paul@354 | 106 | |
paul@354 | 107 | else |
paul@354 | 108 | { |
paul@354 | 109 | attr.datavalue = (void *) f; |
paul@354 | 110 | return attr; |
paul@354 | 111 | } |
paul@477 | 112 | |
paul@477 | 113 | /* Should never be reached: included to satisfy the compiler. */ |
paul@477 | 114 | |
paul@477 | 115 | return __builtins___none_None; |
paul@354 | 116 | } |
paul@354 | 117 | |
paul@664 | 118 | __attr __fn_native_io_fread(__attr __self, __attr fp, __attr size) |
paul@354 | 119 | { |
paul@354 | 120 | /* fp interpreted as FILE reference */ |
paul@664 | 121 | FILE *f = (FILE *) fp.datavalue; |
paul@758 | 122 | /* size interpreted as int */ |
paul@763 | 123 | int to_read = __TOINT(size); |
paul@354 | 124 | char buf[to_read]; |
paul@354 | 125 | size_t have_read; |
paul@354 | 126 | int error; |
paul@354 | 127 | char *s; |
paul@354 | 128 | |
paul@354 | 129 | have_read = fread(buf, sizeof(char), to_read, f); |
paul@354 | 130 | |
paul@354 | 131 | if (have_read != to_read) |
paul@354 | 132 | { |
paul@354 | 133 | if (feof(f) && (have_read == 0)) |
paul@354 | 134 | __raise_eof_error(); |
paul@477 | 135 | else if ((error = ferror(f))) |
paul@354 | 136 | __raise_io_error(__new_int(error)); |
paul@354 | 137 | } |
paul@354 | 138 | |
paul@354 | 139 | /* Reserve space for a new string. */ |
paul@354 | 140 | |
paul@354 | 141 | s = __ALLOCATE(have_read + 1, sizeof(char)); |
paul@378 | 142 | memcpy(s, (char *) buf, have_read); /* does not null terminate but final byte should be zero */ |
paul@583 | 143 | return __new_str(s, have_read); |
paul@354 | 144 | } |
paul@354 | 145 | |
paul@664 | 146 | __attr __fn_native_io_fwrite(__attr __self, __attr fp, __attr str) |
paul@354 | 147 | { |
paul@354 | 148 | /* fp interpreted as FILE reference */ |
paul@664 | 149 | FILE *f = (FILE *) fp.datavalue; |
paul@354 | 150 | /* str.__data__ interpreted as string */ |
paul@763 | 151 | char *s = __load_via_object(__VALUE(str), __data__).strvalue; |
paul@583 | 152 | /* str.__size__ interpreted as int */ |
paul@763 | 153 | int to_write = __TOINT(__load_via_object(__VALUE(str), __size__)); |
paul@354 | 154 | size_t have_written = fwrite(s, sizeof(char), to_write, f); |
paul@354 | 155 | int error; |
paul@354 | 156 | |
paul@354 | 157 | if (have_written != to_write) |
paul@354 | 158 | { |
paul@354 | 159 | if (feof(f)) |
paul@354 | 160 | __raise_eof_error(); |
paul@477 | 161 | else if ((error = ferror(f))) |
paul@354 | 162 | __raise_io_error(__new_int(error)); |
paul@354 | 163 | } |
paul@354 | 164 | |
paul@354 | 165 | return __builtins___none_None; |
paul@354 | 166 | } |
paul@354 | 167 | |
paul@664 | 168 | __attr __fn_native_io_close(__attr __self, __attr fd) |
paul@354 | 169 | { |
paul@758 | 170 | /* fd interpreted as int */ |
paul@763 | 171 | int i = __TOINT(fd); |
paul@354 | 172 | |
paul@354 | 173 | errno = 0; |
paul@354 | 174 | if (close(i) == -1) |
paul@354 | 175 | __raise_io_error(__new_int(errno)); |
paul@354 | 176 | |
paul@354 | 177 | return __builtins___none_None; |
paul@354 | 178 | } |
paul@354 | 179 | |
paul@664 | 180 | __attr __fn_native_io_read(__attr __self, __attr fd, __attr n) |
paul@354 | 181 | { |
paul@758 | 182 | /* fd interpreted as int */ |
paul@763 | 183 | int i = __TOINT(fd); |
paul@758 | 184 | /* n interpreted as int */ |
paul@763 | 185 | int to_read = __TOINT(n); |
paul@354 | 186 | char buf[to_read]; |
paul@354 | 187 | ssize_t have_read; |
paul@354 | 188 | char *s; |
paul@354 | 189 | |
paul@354 | 190 | errno = 0; |
paul@354 | 191 | have_read = read(i, buf, to_read * sizeof(char)); |
paul@354 | 192 | |
paul@354 | 193 | if (have_read == -1) |
paul@354 | 194 | __raise_io_error(__new_int(errno)); |
paul@354 | 195 | |
paul@354 | 196 | /* Reserve space for a new string. */ |
paul@354 | 197 | |
paul@354 | 198 | s = __ALLOCATE(have_read + 1, 1); |
paul@378 | 199 | memcpy(s, (char *) buf, have_read); /* does not null terminate but final byte should be zero */ |
paul@583 | 200 | return __new_str(s, have_read); |
paul@354 | 201 | } |
paul@354 | 202 | |
paul@664 | 203 | __attr __fn_native_io_write(__attr __self, __attr fd, __attr str) |
paul@354 | 204 | { |
paul@758 | 205 | /* fd interpreted as int */ |
paul@763 | 206 | int i = __TOINT(fd); |
paul@354 | 207 | /* str.__data__ interpreted as string */ |
paul@763 | 208 | char *s = __load_via_object(__VALUE(str), __data__).strvalue; |
paul@583 | 209 | /* str.__size__ interpreted as int */ |
paul@763 | 210 | int size = __TOINT(__load_via_object(__VALUE(str), __size__)); |
paul@354 | 211 | ssize_t have_written; |
paul@354 | 212 | |
paul@354 | 213 | errno = 0; |
paul@583 | 214 | have_written = write(i, s, sizeof(char) * size); |
paul@354 | 215 | |
paul@354 | 216 | if (have_written == -1) |
paul@354 | 217 | __raise_io_error(__new_int(errno)); |
paul@354 | 218 | |
paul@354 | 219 | return __new_int(have_written); |
paul@354 | 220 | } |
paul@354 | 221 | |
paul@354 | 222 | /* Module initialisation. */ |
paul@354 | 223 | |
paul@354 | 224 | void __main_native_io() |
paul@354 | 225 | { |
paul@354 | 226 | } |