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