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