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