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@664 | 60 | /* filename interpreted as string */ |
paul@664 | 61 | char *fn = __load_via_object(filename.value, __data__).strvalue; |
paul@664 | 62 | /* mode interpreted as string */ |
paul@664 | 63 | char *s = __load_via_object(mode.value, __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@664 | 90 | /* fd interpreted as int */ |
paul@664 | 91 | int i = __load_via_object(fd.value, __data__).intvalue; |
paul@664 | 92 | /* mode interpreted as string */ |
paul@664 | 93 | char *s = __load_via_object(mode.value, __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@664 | 122 | /* size interpreted as int */ |
paul@664 | 123 | int to_read = __load_via_object(size.value, __data__).intvalue; |
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@664 | 150 | /* str interpreted as string */ |
paul@664 | 151 | char *s = __load_via_object(str.value, __data__).strvalue; |
paul@668 | 152 | int to_write = __load_via_object(str.value, __size__).intvalue; |
paul@354 | 153 | size_t have_written = fwrite(s, sizeof(char), to_write, f); |
paul@354 | 154 | int error; |
paul@354 | 155 | |
paul@354 | 156 | if (have_written != to_write) |
paul@354 | 157 | { |
paul@354 | 158 | if (feof(f)) |
paul@354 | 159 | __raise_eof_error(); |
paul@477 | 160 | else if ((error = ferror(f))) |
paul@354 | 161 | __raise_io_error(__new_int(error)); |
paul@354 | 162 | } |
paul@354 | 163 | |
paul@354 | 164 | return __builtins___none_None; |
paul@354 | 165 | } |
paul@354 | 166 | |
paul@664 | 167 | __attr __fn_native_io_close(__attr __self, __attr fd) |
paul@354 | 168 | { |
paul@664 | 169 | /* fd interpreted as int */ |
paul@664 | 170 | int i = __load_via_object(fd.value, __data__).intvalue; |
paul@354 | 171 | |
paul@354 | 172 | errno = 0; |
paul@354 | 173 | if (close(i) == -1) |
paul@354 | 174 | __raise_io_error(__new_int(errno)); |
paul@354 | 175 | |
paul@354 | 176 | return __builtins___none_None; |
paul@354 | 177 | } |
paul@354 | 178 | |
paul@664 | 179 | __attr __fn_native_io_read(__attr __self, __attr fd, __attr n) |
paul@354 | 180 | { |
paul@664 | 181 | /* fd interpreted as int */ |
paul@664 | 182 | int i = __load_via_object(fd.value, __data__).intvalue; |
paul@664 | 183 | /* n interpreted as int */ |
paul@664 | 184 | int to_read = __load_via_object(n.value, __data__).intvalue; |
paul@354 | 185 | char buf[to_read]; |
paul@354 | 186 | ssize_t have_read; |
paul@354 | 187 | char *s; |
paul@354 | 188 | |
paul@354 | 189 | errno = 0; |
paul@354 | 190 | have_read = read(i, buf, to_read * sizeof(char)); |
paul@354 | 191 | |
paul@354 | 192 | if (have_read == -1) |
paul@354 | 193 | __raise_io_error(__new_int(errno)); |
paul@354 | 194 | |
paul@354 | 195 | /* Reserve space for a new string. */ |
paul@354 | 196 | |
paul@354 | 197 | s = __ALLOCATE(have_read + 1, 1); |
paul@378 | 198 | memcpy(s, (char *) buf, have_read); /* does not null terminate but final byte should be zero */ |
paul@583 | 199 | return __new_str(s, have_read); |
paul@354 | 200 | } |
paul@354 | 201 | |
paul@664 | 202 | __attr __fn_native_io_write(__attr __self, __attr fd, __attr str) |
paul@354 | 203 | { |
paul@664 | 204 | /* fd interpreted as int */ |
paul@664 | 205 | int i = __load_via_object(fd.value, __data__).intvalue; |
paul@664 | 206 | /* str interpreted as string */ |
paul@664 | 207 | char *s = __load_via_object(str.value, __data__).strvalue; |
paul@664 | 208 | int size = __load_via_object(str.value, __size__).intvalue; |
paul@354 | 209 | ssize_t have_written; |
paul@354 | 210 | |
paul@354 | 211 | errno = 0; |
paul@583 | 212 | have_written = write(i, s, sizeof(char) * size); |
paul@354 | 213 | |
paul@354 | 214 | if (have_written == -1) |
paul@354 | 215 | __raise_io_error(__new_int(errno)); |
paul@354 | 216 | |
paul@354 | 217 | return __new_int(have_written); |
paul@354 | 218 | } |
paul@354 | 219 | |
paul@354 | 220 | /* Module initialisation. */ |
paul@354 | 221 | |
paul@354 | 222 | void __main_native_io() |
paul@354 | 223 | { |
paul@354 | 224 | } |