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