Lichen

Annotated templates/native/io.c

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