Lichen

templates/native/io.c

940:6ddce984649b
2021-10-30 Paul Boddie Fixed expected result in comment.
     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 }