Lichen

templates/native.c

347:17317598efd2
2016-12-08 Paul Boddie Added support for fopen and opening files. Moved common stream functionality into the __builtins__.file module. Moved common type checking functionality into the __builtins__.types module.
     1 /* Native functions.     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 <stdlib.h> /* abs, exit */    20 #include <unistd.h> /* read, write */    21 #include <limits.h> /* INT_MAX, INT_MIN */    22 #include <math.h>   /* ceil, log10, pow */    23 #include <string.h> /* strcmp, strncpy, strlen */    24 #include <stdio.h>  /* fdopen, snprintf */    25 #include <errno.h>  /* errno */    26 #include "types.h"    27 #include "exceptions.h"    28 #include "ops.h"    29 #include "progconsts.h"    30 #include "progops.h"    31 #include "progtypes.h"    32 #include "main.h"    33     34 /* Utility functions. */    35     36 static __attr __new_int(int i)    37 {    38     /* Create a new integer and mutate the __data__ attribute. */    39     __attr attr = __new(&__InstanceTable___builtins___int_int, &__builtins___int_int, sizeof(__obj___builtins___int_int));    40     attr.value->attrs[__pos___data__].intvalue = i;    41     return attr;    42 }    43     44 static __attr __new_str(char *s)    45 {    46     /* Create a new string and mutate the __data__ attribute. */    47     __attr attr = __new(&__InstanceTable___builtins___str_string, &__builtins___str_string, sizeof(__obj___builtins___str_string));    48     attr.value->attrs[__pos___data__].strvalue = s;    49     return attr;    50 }    51     52 static __attr __new_list(__fragment *f)    53 {    54     /* Create a new list and mutate the __data__ attribute. */    55     __attr attr = __new(&__InstanceTable___builtins___list_list, &__builtins___list_list, sizeof(__obj___builtins___list_list));    56     attr.value->attrs[__pos___data__].seqvalue = f;    57     return attr;    58 }    59     60 static __fragment *__fragment_append(__fragment *data, __attr * const value)    61 {    62     __fragment *newdata = data;    63     unsigned int size = data->size, capacity = data->capacity;    64     unsigned int n;    65     66     /* Re-allocate the fragment if the capacity has been reached. */    67     if (size >= capacity)    68     {    69         /* NOTE: Consider various restrictions on capacity increases. */    70         n = capacity ? capacity * 2 : 1;    71         newdata = (__fragment *) __REALLOCATE(data, __FRAGMENT_SIZE(n));    72         newdata->capacity = n;    73     }    74     75     /* Insert the new element and increment the list size. */    76     newdata->attrs[size] = *value;    77     newdata->size = size + 1;    78     79     return newdata;    80 }    81     82 /* Environment support. */    83     84 __attr __fn_native__exit(__attr __args[])    85 {    86     __attr * const status = &__args[1];    87     88     exit(__load_via_object(status->value, __pos___data__).intvalue);    89     return __builtins___none_None;    90 }    91     92 __attr __fn_native__get_argv(__attr __args[])    93 {    94     __attr * const status = &__args[1];    95     96     /* NOTE: To be written. */    97     return __builtins___none_None;    98 }    99    100 __attr __fn_native__get_path(__attr __args[])   101 {   102     __attr * const status = &__args[1];   103    104     /* NOTE: To be written. */   105     return __builtins___none_None;   106 }   107    108 /* Identity testing. */   109    110 __attr __fn_native__is(__attr __args[])   111 {   112     __attr * const x = &__args[1];   113     __attr * const y = &__args[2];   114    115     return x->value == y->value ? __builtins___boolean_True : __builtins___boolean_False;   116 }   117    118 __attr __fn_native__is_not(__attr __args[])   119 {   120     __attr * const x = &__args[1];   121     __attr * const y = &__args[2];   122    123     return x->value != y->value ? __builtins___boolean_True : __builtins___boolean_False;   124 }   125    126 /* Limit definition. */   127    128 __attr __fn_native__get_maxint(__attr __args[])   129 {   130     __attr * const status = &__args[1];   131    132     return __new_int(INT_MAX);   133 }   134    135 __attr __fn_native__get_minint(__attr __args[])   136 {   137     __attr * const status = &__args[1];   138    139     return __new_int(INT_MIN);   140 }   141    142 /* Integer operations. */   143    144 __attr __fn_native__int_add(__attr __args[])   145 {   146     __attr * const _data = &__args[1];   147     __attr * const other = &__args[2];   148     /* _data and other interpreted as int */   149     int i = _data->intvalue;   150     int j = other->intvalue;   151    152     /* Test for overflow. */   153     if (((i > 0) && (j > 0) && (i > INT_MAX - j)) ||   154         ((i < 0) && (j < 0) && (i < INT_MIN - j)))   155    156         __raise_overflow_error();   157    158     /* Return the new integer. */   159     return __new_int(i + j);   160 }   161    162 __attr __fn_native__int_sub(__attr __args[])   163 {   164     __attr * const _data = &__args[1];   165     __attr * const other = &__args[2];   166     /* _data and other interpreted as int */   167     int i = _data->intvalue;   168     int j = other->intvalue;   169    170     /* Test for overflow. */   171     if (((i < 0) && (j > 0) && (i < INT_MIN + j)) ||   172         ((i > 0) && (j < 0) && (i > INT_MAX + j)))   173    174         __raise_overflow_error();   175    176     /* Return the new integer. */   177     return __new_int(i - j);   178 }   179    180 __attr __fn_native__int_mul(__attr __args[])   181 {   182     __attr * const _data = &__args[1];   183     __attr * const other = &__args[2];   184     /* _data and other interpreted as int */   185     int i = _data->intvalue;   186     int j = other->intvalue;   187    188     /* Test for overflow. */   189     if (((i > 0) && (j > 0) && (i > INT_MAX / j)) ||   190         ((i < 0) && (j < 0) && (i > INT_MAX / j)) ||   191         ((i < 0) && (j > 0) && (i < INT_MIN / j)) ||   192         ((i > 0) && (j < 0) && (j < INT_MIN / i)))   193    194         __raise_overflow_error();   195    196     /* Return the new integer. */   197     return __new_int(i * j);   198 }   199    200 __attr __fn_native__int_div(__attr __args[])   201 {   202     __attr * const _data = &__args[1];   203     __attr * const other = &__args[2];   204     /* _data and other interpreted as int */   205     int i = _data->intvalue;   206     int j = other->intvalue;   207    208     /* Test for division by zero or overflow. */   209     if (j == 0)   210         __raise_zero_division_error();   211     else if ((j == -1) && (i == INT_MIN))   212         __raise_overflow_error();   213    214     /* Return the new integer. */   215     return __new_int(i / j);   216 }   217    218 __attr __fn_native__int_mod(__attr __args[])   219 {   220     __attr * const _data = &__args[1];   221     __attr * const other = &__args[2];   222     /* _data and other interpreted as int */   223     int i = _data->intvalue;   224     int j = other->intvalue;   225    226     /* Test for division by zero or overflow. */   227     if (j == 0)   228         __raise_zero_division_error();   229     else if ((j == -1) && (i == INT_MIN))   230         __raise_overflow_error();   231    232     /* Return the new integer. */   233     return __new_int(i % j);   234 }   235    236 __attr __fn_native__int_neg(__attr __args[])   237 {   238     __attr * const _data = &__args[1];   239     /* _data interpreted as int */   240     int i = _data->intvalue;   241    242     /* Test for overflow. */   243     if (i == INT_MIN)   244         __raise_overflow_error();   245    246     /* Return the new integer. */   247     return __new_int(-i);   248 }   249    250 __attr __fn_native__int_pow(__attr __args[])   251 {   252     __attr * const _data = &__args[1];   253     __attr * const other = &__args[2];   254     /* _data and other interpreted as int */   255     int i = _data->intvalue;   256     int j = other->intvalue;   257     int k;   258    259     errno = 0;   260     k = (int) pow(i, j);   261    262     /* Test for overflow. */   263    264     if (errno == ERANGE)   265         __raise_overflow_error();   266    267     /* Return the new integer. */   268     return __new_int(k);   269 }   270    271 __attr __fn_native__int_and(__attr __args[])   272 {   273     __attr * const _data = &__args[1];   274     __attr * const other = &__args[2];   275     /* _data and other interpreted as int */   276     int i = _data->intvalue;   277     int j = other->intvalue;   278    279     /* Return the new integer. */   280     /* NOTE: No overflow test applied. */   281     return __new_int(i & j);   282 }   283    284 __attr __fn_native__int_not(__attr __args[])   285 {   286     __attr * const _data = &__args[1];   287     /* _data interpreted as int */   288     int i = _data->intvalue;   289    290     /* Return the new integer. */   291     return __new_int(~i);   292 }   293    294 __attr __fn_native__int_or(__attr __args[])   295 {   296     __attr * const _data = &__args[1];   297     __attr * const other = &__args[2];   298     /* _data and other interpreted as int */   299     int i = _data->intvalue;   300     int j = other->intvalue;   301    302     /* Return the new integer. */   303     /* NOTE: No overflow test applied. */   304     return __new_int(i | j);   305 }   306    307 __attr __fn_native__int_xor(__attr __args[])   308 {   309     __attr * const _data = &__args[1];   310     __attr * const other = &__args[2];   311     /* _data and other interpreted as int */   312     int i = _data->intvalue;   313     int j = other->intvalue;   314    315     /* Return the new integer. */   316     /* NOTE: No overflow test applied. */   317     return __new_int(i ^ j);   318 }   319    320 __attr __fn_native__int_lt(__attr __args[])   321 {   322     __attr * const _data = &__args[1];   323     __attr * const other = &__args[2];   324     /* _data and other interpreted as int */   325     int i = _data->intvalue;   326     int j = other->intvalue;   327    328     /* Return a boolean result. */   329     return i < j ? __builtins___boolean_True : __builtins___boolean_False;   330 }   331    332 __attr __fn_native__int_gt(__attr __args[])   333 {   334     __attr * const _data = &__args[1];   335     __attr * const other = &__args[2];   336     /* _data and other interpreted as int */   337     int i = _data->intvalue;   338     int j = other->intvalue;   339    340     /* Return a boolean result. */   341     return i > j ? __builtins___boolean_True : __builtins___boolean_False;   342 }   343    344 __attr __fn_native__int_eq(__attr __args[])   345 {   346     __attr * const _data = &__args[1];   347     __attr * const other = &__args[2];   348     /* _data and other interpreted as int */   349     int i = _data->intvalue;   350     int j = other->intvalue;   351    352     /* Return a boolean result. */   353     return i == j ? __builtins___boolean_True : __builtins___boolean_False;   354 }   355    356 __attr __fn_native__int_ne(__attr __args[])   357 {   358     __attr * const _data = &__args[1];   359     __attr * const other = &__args[2];   360     /* _data and other interpreted as int */   361     int i = _data->intvalue;   362     int j = other->intvalue;   363    364     /* Return a boolean result. */   365     return i != j ? __builtins___boolean_True : __builtins___boolean_False;   366 }   367    368 __attr __fn_native__int_str(__attr __args[])   369 {   370     __attr * const _data = &__args[1];   371     /* _data interpreted as int */   372     int i = _data->intvalue;   373     /* Employ a buffer big enough to fit the largest integer plus an extra   374        character, a minus sign, and the null terminator. */   375     unsigned int n = (int) log10(INT_MAX) + 3;   376     char *s = (char *) __ALLOCATE(n, sizeof(char));   377    378     snprintf(s, n, "%d", i);   379    380     /* Return a new string. */   381     return __new_str(s);   382 }   383    384 /* String operations. */   385    386 __attr __fn_native__str_add(__attr __args[])   387 {   388     __attr * const _data = &__args[1];   389     __attr * const other = &__args[2];   390     /* _data, other interpreted as string */   391     char *s = _data->strvalue;   392     char *o = other->strvalue;   393     int n = strlen(s) + strlen(o) + 1;   394     char *r = (char *) __ALLOCATE(n, sizeof(char));   395    396     strncpy(r, s, n);   397     strncpy(r + strlen(s), o, n - strlen(s)); /* should null terminate */   398    399     /* Return a new string. */   400     return __new_str(r);   401 }   402    403 __attr __fn_native__str_lt(__attr __args[])   404 {   405     __attr * const _data = &__args[1];   406     __attr * const other = &__args[2];   407     /* _data, other interpreted as string */   408     char *s = _data->strvalue;   409     char *o = other->strvalue;   410    411     /* NOTE: Using simple byte-level string operations. */   412     return strcmp(s, o) < 0 ? __builtins___boolean_True : __builtins___boolean_False;   413 }   414    415 __attr __fn_native__str_gt(__attr __args[])   416 {   417     __attr * const _data = &__args[1];   418     __attr * const other = &__args[2];   419     /* _data, other interpreted as string */   420     char *s = _data->strvalue;   421     char *o = other->strvalue;   422    423     /* NOTE: Using simple byte-level string operations. */   424     return strcmp(s, o) > 0 ? __builtins___boolean_True : __builtins___boolean_False;   425 }   426    427 __attr __fn_native__str_eq(__attr __args[])   428 {   429     __attr * const _data = &__args[1];   430     __attr * const other = &__args[2];   431     /* _data, other interpreted as string */   432     char *s = _data->strvalue;   433     char *o = other->strvalue;   434    435     /* NOTE: Using simple byte-level string operations. */   436     return strcmp(s, o) == 0 ? __builtins___boolean_True : __builtins___boolean_False;   437 }   438    439 __attr __fn_native__str_len(__attr __args[])   440 {   441     __attr * const _data = &__args[1];   442     /* _data interpreted as string */   443     char *s = _data->strvalue;   444    445     /* Return the new integer. */   446     return __new_int(strlen(s));   447 }   448    449 __attr __fn_native__str_nonempty(__attr __args[])   450 {   451     __attr * const _data = &__args[1];   452     /* _data interpreted as string */   453     char *s = _data->strvalue;   454    455     return strlen(s) ? __builtins___boolean_True : __builtins___boolean_False;   456 }   457    458 __attr __fn_native__str_ord(__attr __args[])   459 {   460     __attr * const _data = &__args[1];   461     /* _data interpreted as string */   462     char *s = _data->strvalue;   463    464     return __new_int((unsigned int) s[0]);   465 }   466    467 __attr __fn_native__str_substr(__attr __args[])   468 {   469     __attr * const _data = &__args[1];   470     __attr * const start = &__args[2];   471     __attr * const size = &__args[3];   472     /* _data interpreted as string */   473     char *s = _data->strvalue, *sub;   474     /* start.__data__ interpreted as int */   475     int i = __load_via_object(start->value, __pos___data__).intvalue;   476     /* size.__data__ interpreted as int */   477     int l = __load_via_object(size->value, __pos___data__).intvalue;   478    479     /* Reserve space for a new string. */   480     sub = (char *) __ALLOCATE(l + 1, sizeof(char));   481     strncpy(sub, s + i, l); /* does not null terminate but final byte should be zero */   482     return __new_str(sub);   483 }   484    485 /* List operations. */   486    487 __attr __fn_native__list_init(__attr __args[])   488 {   489     __attr * const size = &__args[1];   490     /* size.__data__ interpreted as int */   491     unsigned int n = __load_via_object(size->value, __pos___data__).intvalue;   492     __attr attr = {0, .seqvalue=__new_fragment(n)};   493    494     /* Return the __data__ attribute. */   495     return attr;   496 }   497    498 __attr __fn_native__list_setsize(__attr __args[])   499 {   500     __attr * const _data = &__args[1];   501     __attr * const size = &__args[2];   502     /* _data interpreted as list */   503     __fragment *data = _data->seqvalue;   504     /* size.__data__ interpreted as int */   505     unsigned int n = __load_via_object(size->value, __pos___data__).intvalue;   506    507     data->size = n;   508     return __builtins___none_None;   509 }   510    511 __attr __fn_native__list_append(__attr __args[])   512 {   513     __attr * const self = &__args[1];   514     __attr * const value = &__args[2];   515     /* self.__data__ interpreted as list */   516     __fragment *data = __load_via_object(self->value, __pos___data__).seqvalue;   517     __fragment *newdata = __fragment_append(data, value);   518    519     /* Replace the __data__ attribute if appropriate. */   520     if (newdata != data)   521         __store_via_object(self->value, __pos___data__, ((__attr) {0, .seqvalue=newdata}));   522     return __builtins___none_None;   523 }   524    525 __attr __fn_native__list_concat(__attr __args[])   526 {   527     __attr * const self = &__args[1];   528     __attr * const other = &__args[2];   529     /* self.__data__, other interpreted as list */   530     __fragment *data = __load_via_object(self->value, __pos___data__).seqvalue;   531     __fragment *other_data = other->seqvalue;   532     __fragment *newdata = data;   533     unsigned int size = data->size, capacity = data->capacity;   534     unsigned int other_size = other_data->size;   535     unsigned int i, j, n;   536    537     /* Re-allocate the fragment if the capacity has been reached. */   538     if (size + other_size >= capacity)   539     {   540         n = size + other_size;   541         newdata = (__fragment *) __REALLOCATE(data, __FRAGMENT_SIZE(n));   542         newdata->capacity = n;   543     }   544    545     /* Copy the elements from the other list and increment the list size. */   546     for (i = size, j = 0; j < other_size; i++, j++)   547         newdata->attrs[i] = other_data->attrs[j];   548     newdata->size = n;   549    550     /* Replace the __data__ attribute if appropriate. */   551     if (newdata != data)   552         __store_via_object(self->value, __pos___data__, ((__attr) {0, .seqvalue=newdata}));   553     return __builtins___none_None;   554 }   555    556 __attr __fn_native__list_len(__attr __args[])   557 {   558     __attr * const _data = &__args[1];   559     /* _data interpreted as fragment */   560     unsigned int size = _data->seqvalue->size;   561    562     /* Return the new integer. */   563     return __new_int(size);   564 }   565    566 __attr __fn_native__list_nonempty(__attr __args[])   567 {   568     __attr * const _data = &__args[1];   569    570     return _data->seqvalue->size ? __builtins___boolean_True : __builtins___boolean_False;   571 }   572    573 __attr __fn_native__list_element(__attr __args[])   574 {   575     __attr * const _data = &__args[1];   576     __attr * const index = &__args[2];   577     /* _data interpreted as fragment */   578     __attr *elements = _data->seqvalue->attrs;   579     /* index.__data__ interpreted as int */   580     int i = __load_via_object(index->value, __pos___data__).intvalue;   581    582     return elements[i];   583 }   584    585 __attr __fn_native__list_setelement(__attr __args[])   586 {   587     __attr * const _data = &__args[1];   588     __attr * const index = &__args[2];   589     __attr * const value = &__args[3];   590     /* _data interpreted as fragment */   591     __attr *elements = _data->seqvalue->attrs;   592     /* index.__data__ interpreted as int */   593     int i = __load_via_object(index->value, __pos___data__).intvalue;   594    595     /* Set the element. */   596     elements[i] = *value;   597     return __builtins___none_None;   598 }   599    600 /* Buffer operations. */   601    602 __attr __fn_native__buffer_str(__attr __args[])   603 {   604     __attr * const _data = &__args[1];   605     /* _data interpreted as buffer */   606     __fragment *data = _data->seqvalue;   607     unsigned int size = 0, i, j, n;   608     char *s, *o;   609    610     /* Calculate the size of the string. */   611     for (i = 0; i < data->size; i++)   612         size += strlen(__load_via_object(data->attrs[i].value, __pos___data__).strvalue);   613    614     /* Reserve space for a new string. */   615     s = (char *) __ALLOCATE(size + 1, sizeof(char));   616    617     /* Build a single string from the buffer contents. */   618     for (i = 0, j = 0; i < data->size; i++)   619     {   620         o = __load_via_object(data->attrs[i].value, __pos___data__).strvalue;   621         n = strlen(o);   622         strncpy(s + j, o, n); /* does not null terminate but final byte should be zero */   623         j += n;   624     }   625    626     /* Return a new string. */   627     return __new_str(s);   628 }   629    630 /* Method binding. */   631    632 __attr __fn_native__get_using(__attr __args[])   633 {   634     __attr * const callable = &__args[1];   635     __attr * const instance = &__args[2];   636    637     return __replace_context(instance->value, *callable);   638 }   639    640 /* Introspection. */   641    642 __attr __fn_native__object_getattr(__attr __args[])   643 {   644     __attr * const obj = &__args[1];   645     __attr * const name = &__args[2];   646     __attr * const _default = &__args[3];   647    648     /* NOTE: To be written. */   649     return __builtins___none_None;   650 }   651    652 static int __issubclass(__ref obj, __attr cls)   653 {   654     return (__HASATTR(obj, __TYPEPOS(cls.value), __TYPECODE(cls.value)));   655 }   656    657 __attr __fn_native__isinstance(__attr __args[])   658 {   659     __attr * const obj = &__args[1];   660     __attr * const cls = &__args[2];   661    662     /* cls must be a class. */   663     if (__is_instance(obj->value) && __issubclass(__get_class(obj->value), *cls))   664         return __builtins___boolean_True;   665     else   666         return __builtins___boolean_False;   667 }   668    669 __attr __fn_native__issubclass(__attr __args[])   670 {   671     __attr * const obj = &__args[1];   672     __attr * const cls = &__args[2];   673    674     /* obj and cls must be classes. */   675     if (__issubclass(obj->value, *cls))   676         return __builtins___boolean_True;   677     else   678         return __builtins___boolean_False;   679 }   680    681 /* Input/output. */   682    683 __attr __fn_native__fopen(__attr __args[])   684 {   685     __attr * const filename = &__args[1];   686     __attr * const mode = &__args[2];   687     /* filename.__data__ interpreted as string */   688     char *fn = __load_via_object(filename->value, __pos___data__).strvalue;   689     /* mode.__data__ interpreted as string */   690     char *s = __load_via_object(mode->value, __pos___data__).strvalue;   691     FILE *f;   692     __attr attr;   693    694     errno = 0;   695     f = fopen(fn, s);   696    697     /* Produce an exception if the operation failed. */   698    699     if (f == NULL)   700         __raise_io_error(__new_int(errno));   701    702     /* Return the __data__ attribute. */   703    704     else   705     {   706         attr.context = 0;   707         attr.datavalue = (void *) f;   708         return attr;   709     }   710 }   711    712 __attr __fn_native__fdopen(__attr __args[])   713 {   714     __attr * const fd = &__args[1];   715     __attr * const mode = &__args[2];   716     /* fd.__data__ interpreted as int */   717     int i = __load_via_object(fd->value, __pos___data__).intvalue;   718     /* mode.__data__ interpreted as string */   719     char *s = __load_via_object(mode->value, __pos___data__).strvalue;   720     FILE *f;   721     __attr attr;   722    723     errno = 0;   724     f = fdopen(i, s);   725    726     /* Produce an exception if the operation failed. */   727    728     if (f == NULL)   729         __raise_io_error(__new_int(errno));   730    731     /* Return the __data__ attribute. */   732    733     else   734     {   735         attr.context = 0;   736         attr.datavalue = (void *) f;   737         return attr;   738     }   739 }   740    741 __attr __fn_native__fread(__attr __args[])   742 {   743     __attr * const fp = &__args[1];   744     __attr * const size = &__args[2];   745     /* fp interpreted as FILE reference */   746     FILE *f = (FILE *) fp->datavalue;   747     /* size.__data__ interpreted as int */   748     int to_read = __load_via_object(size->value, __pos___data__).intvalue;   749     char buf[to_read];   750     size_t have_read;   751     int error;   752     char *s;   753    754     have_read = fread(buf, sizeof(char), to_read, f);   755    756     if (have_read != to_read)   757     {   758         if (feof(f) && (have_read == 0))   759             __raise_eof_error();   760         else if (error = ferror(f))   761             __raise_io_error(__new_int(error));   762     }   763    764     /* Reserve space for a new string. */   765    766     s = __ALLOCATE(have_read + 1, sizeof(char));   767     strncpy(s, (char *) buf, have_read); /* does not null terminate but final byte should be zero */   768     return __new_str(s);   769 }   770    771 __attr __fn_native__fwrite(__attr __args[])   772 {   773     __attr * const fp = &__args[1];   774     __attr * const str = &__args[2];   775     /* fp interpreted as FILE reference */   776     FILE *f = (FILE *) fp->datavalue;   777     /* str.__data__ interpreted as string */   778     char *s = __load_via_object(str->value, __pos___data__).strvalue;   779     size_t to_write = strlen(s);   780     size_t have_written = fwrite(s, sizeof(char), to_write, f);   781     int error;   782    783     if (have_written != to_write)   784     {   785         if (feof(f))   786             __raise_eof_error();   787         else if (error = ferror(f))   788             __raise_io_error(__new_int(error));   789     }   790    791     return __builtins___none_None;   792 }   793    794 __attr __fn_native__read(__attr __args[])   795 {   796     __attr * const fd = &__args[1];   797     __attr * const n = &__args[2];   798     /* fd.__data__ interpreted as int */   799     int i = __load_via_object(fd->value, __pos___data__).intvalue;   800     /* n.__data__ interpreted as int */   801     int to_read = __load_via_object(n->value, __pos___data__).intvalue;   802     char buf[to_read];   803     ssize_t have_read;   804     char *s;   805    806     errno = 0;   807     have_read = read(i, buf, to_read * sizeof(char));   808    809     if (have_read == -1)   810         __raise_io_error(__new_int(errno));   811     else   812     {   813         /* Reserve space for a new string. */   814    815         s = __ALLOCATE(have_read + 1, 1);   816         strncpy(s, (char *) buf, have_read); /* does not null terminate but final byte should be zero */   817         return __new_str(s);   818     }   819 }   820    821 __attr __fn_native__write(__attr __args[])   822 {   823     __attr * const fd = &__args[1];   824     __attr * const str = &__args[2];   825     /* fd.__data__ interpreted as int */   826     int i = __load_via_object(fd->value, __pos___data__).intvalue;   827     /* str.__data__ interpreted as string */   828     char *s = __load_via_object(str->value, __pos___data__).strvalue;   829    830     write(i, s, sizeof(char) * strlen(s));   831     return __builtins___none_None;   832 }   833    834 /* Module initialisation. */   835    836 void __main_native()   837 {   838 }