paul@354 | 1 | /* Native functions for input/output. |
paul@354 | 2 | |
paul@354 | 3 | Copyright (C) 2016 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@354 | 20 | #include <string.h> /* strcmp, strncpy, strlen */ |
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@354 | 34 | __attr __fn_native_io_fclose(__attr __args[]) |
paul@354 | 35 | { |
paul@354 | 36 | __attr * const fp = &__args[1]; |
paul@354 | 37 | /* fp interpreted as FILE reference */ |
paul@354 | 38 | FILE *f = (FILE *) fp->datavalue; |
paul@354 | 39 | |
paul@354 | 40 | errno = 0; |
paul@354 | 41 | if (fclose(f)) |
paul@354 | 42 | __raise_io_error(__new_int(errno)); |
paul@354 | 43 | |
paul@354 | 44 | return __builtins___none_None; |
paul@354 | 45 | } |
paul@354 | 46 | |
paul@354 | 47 | __attr __fn_native_io_fopen(__attr __args[]) |
paul@354 | 48 | { |
paul@354 | 49 | __attr * const filename = &__args[1]; |
paul@354 | 50 | __attr * const mode = &__args[2]; |
paul@354 | 51 | /* filename.__data__ interpreted as string */ |
paul@354 | 52 | char *fn = __load_via_object(filename->value, __pos___data__).strvalue; |
paul@354 | 53 | /* mode.__data__ interpreted as string */ |
paul@354 | 54 | char *s = __load_via_object(mode->value, __pos___data__).strvalue; |
paul@354 | 55 | FILE *f; |
paul@354 | 56 | __attr attr; |
paul@354 | 57 | |
paul@354 | 58 | errno = 0; |
paul@354 | 59 | f = fopen(fn, s); |
paul@354 | 60 | |
paul@354 | 61 | /* Produce an exception if the operation failed. */ |
paul@354 | 62 | |
paul@354 | 63 | if (f == NULL) |
paul@354 | 64 | __raise_io_error(__new_int(errno)); |
paul@354 | 65 | |
paul@354 | 66 | /* Return the __data__ attribute. */ |
paul@354 | 67 | |
paul@354 | 68 | else |
paul@354 | 69 | { |
paul@354 | 70 | attr.context = 0; |
paul@354 | 71 | attr.datavalue = (void *) f; |
paul@354 | 72 | return attr; |
paul@354 | 73 | } |
paul@354 | 74 | } |
paul@354 | 75 | |
paul@354 | 76 | __attr __fn_native_io_fdopen(__attr __args[]) |
paul@354 | 77 | { |
paul@354 | 78 | __attr * const fd = &__args[1]; |
paul@354 | 79 | __attr * const mode = &__args[2]; |
paul@354 | 80 | /* fd.__data__ interpreted as int */ |
paul@354 | 81 | int i = __load_via_object(fd->value, __pos___data__).intvalue; |
paul@354 | 82 | /* mode.__data__ interpreted as string */ |
paul@354 | 83 | char *s = __load_via_object(mode->value, __pos___data__).strvalue; |
paul@354 | 84 | FILE *f; |
paul@354 | 85 | __attr attr; |
paul@354 | 86 | |
paul@354 | 87 | errno = 0; |
paul@354 | 88 | f = fdopen(i, s); |
paul@354 | 89 | |
paul@354 | 90 | /* Produce an exception if the operation failed. */ |
paul@354 | 91 | |
paul@354 | 92 | if (f == NULL) |
paul@354 | 93 | __raise_io_error(__new_int(errno)); |
paul@354 | 94 | |
paul@354 | 95 | /* Return the __data__ attribute. */ |
paul@354 | 96 | |
paul@354 | 97 | else |
paul@354 | 98 | { |
paul@354 | 99 | attr.context = 0; |
paul@354 | 100 | attr.datavalue = (void *) f; |
paul@354 | 101 | return attr; |
paul@354 | 102 | } |
paul@354 | 103 | } |
paul@354 | 104 | |
paul@354 | 105 | __attr __fn_native_io_fread(__attr __args[]) |
paul@354 | 106 | { |
paul@354 | 107 | __attr * const fp = &__args[1]; |
paul@354 | 108 | __attr * const size = &__args[2]; |
paul@354 | 109 | /* fp interpreted as FILE reference */ |
paul@354 | 110 | FILE *f = (FILE *) fp->datavalue; |
paul@354 | 111 | /* size.__data__ interpreted as int */ |
paul@354 | 112 | int to_read = __load_via_object(size->value, __pos___data__).intvalue; |
paul@354 | 113 | char buf[to_read]; |
paul@354 | 114 | size_t have_read; |
paul@354 | 115 | int error; |
paul@354 | 116 | char *s; |
paul@354 | 117 | |
paul@354 | 118 | have_read = fread(buf, sizeof(char), to_read, f); |
paul@354 | 119 | |
paul@354 | 120 | if (have_read != to_read) |
paul@354 | 121 | { |
paul@354 | 122 | if (feof(f) && (have_read == 0)) |
paul@354 | 123 | __raise_eof_error(); |
paul@354 | 124 | else if (error = ferror(f)) |
paul@354 | 125 | __raise_io_error(__new_int(error)); |
paul@354 | 126 | } |
paul@354 | 127 | |
paul@354 | 128 | /* Reserve space for a new string. */ |
paul@354 | 129 | |
paul@354 | 130 | s = __ALLOCATE(have_read + 1, sizeof(char)); |
paul@354 | 131 | strncpy(s, (char *) buf, have_read); /* does not null terminate but final byte should be zero */ |
paul@354 | 132 | return __new_str(s); |
paul@354 | 133 | } |
paul@354 | 134 | |
paul@354 | 135 | __attr __fn_native_io_fwrite(__attr __args[]) |
paul@354 | 136 | { |
paul@354 | 137 | __attr * const fp = &__args[1]; |
paul@354 | 138 | __attr * const str = &__args[2]; |
paul@354 | 139 | /* fp interpreted as FILE reference */ |
paul@354 | 140 | FILE *f = (FILE *) fp->datavalue; |
paul@354 | 141 | /* str.__data__ interpreted as string */ |
paul@354 | 142 | char *s = __load_via_object(str->value, __pos___data__).strvalue; |
paul@354 | 143 | size_t to_write = strlen(s); |
paul@354 | 144 | size_t have_written = fwrite(s, sizeof(char), to_write, f); |
paul@354 | 145 | int error; |
paul@354 | 146 | |
paul@354 | 147 | if (have_written != to_write) |
paul@354 | 148 | { |
paul@354 | 149 | if (feof(f)) |
paul@354 | 150 | __raise_eof_error(); |
paul@354 | 151 | else if (error = ferror(f)) |
paul@354 | 152 | __raise_io_error(__new_int(error)); |
paul@354 | 153 | } |
paul@354 | 154 | |
paul@354 | 155 | return __builtins___none_None; |
paul@354 | 156 | } |
paul@354 | 157 | |
paul@354 | 158 | __attr __fn_native_io_close(__attr __args[]) |
paul@354 | 159 | { |
paul@354 | 160 | __attr * const fd = &__args[1]; |
paul@354 | 161 | /* fd.__data__ interpreted as int */ |
paul@354 | 162 | int i = __load_via_object(fd->value, __pos___data__).intvalue; |
paul@354 | 163 | |
paul@354 | 164 | errno = 0; |
paul@354 | 165 | if (close(i) == -1) |
paul@354 | 166 | __raise_io_error(__new_int(errno)); |
paul@354 | 167 | |
paul@354 | 168 | return __builtins___none_None; |
paul@354 | 169 | } |
paul@354 | 170 | |
paul@354 | 171 | __attr __fn_native_io_read(__attr __args[]) |
paul@354 | 172 | { |
paul@354 | 173 | __attr * const fd = &__args[1]; |
paul@354 | 174 | __attr * const n = &__args[2]; |
paul@354 | 175 | /* fd.__data__ interpreted as int */ |
paul@354 | 176 | int i = __load_via_object(fd->value, __pos___data__).intvalue; |
paul@354 | 177 | /* n.__data__ interpreted as int */ |
paul@354 | 178 | int to_read = __load_via_object(n->value, __pos___data__).intvalue; |
paul@354 | 179 | char buf[to_read]; |
paul@354 | 180 | ssize_t have_read; |
paul@354 | 181 | char *s; |
paul@354 | 182 | |
paul@354 | 183 | errno = 0; |
paul@354 | 184 | have_read = read(i, buf, to_read * sizeof(char)); |
paul@354 | 185 | |
paul@354 | 186 | if (have_read == -1) |
paul@354 | 187 | __raise_io_error(__new_int(errno)); |
paul@354 | 188 | |
paul@354 | 189 | /* Reserve space for a new string. */ |
paul@354 | 190 | |
paul@354 | 191 | s = __ALLOCATE(have_read + 1, 1); |
paul@354 | 192 | strncpy(s, (char *) buf, have_read); /* does not null terminate but final byte should be zero */ |
paul@354 | 193 | return __new_str(s); |
paul@354 | 194 | } |
paul@354 | 195 | |
paul@354 | 196 | __attr __fn_native_io_write(__attr __args[]) |
paul@354 | 197 | { |
paul@354 | 198 | __attr * const fd = &__args[1]; |
paul@354 | 199 | __attr * const str = &__args[2]; |
paul@354 | 200 | /* fd.__data__ interpreted as int */ |
paul@354 | 201 | int i = __load_via_object(fd->value, __pos___data__).intvalue; |
paul@354 | 202 | /* str.__data__ interpreted as string */ |
paul@354 | 203 | char *s = __load_via_object(str->value, __pos___data__).strvalue; |
paul@354 | 204 | ssize_t have_written; |
paul@354 | 205 | |
paul@354 | 206 | errno = 0; |
paul@354 | 207 | have_written = write(i, s, sizeof(char) * strlen(s)); |
paul@354 | 208 | |
paul@354 | 209 | if (have_written == -1) |
paul@354 | 210 | __raise_io_error(__new_int(errno)); |
paul@354 | 211 | |
paul@354 | 212 | return __new_int(have_written); |
paul@354 | 213 | } |
paul@354 | 214 | |
paul@354 | 215 | /* Module initialisation. */ |
paul@354 | 216 | |
paul@354 | 217 | void __main_native_io() |
paul@354 | 218 | { |
paul@354 | 219 | } |