Lichen

templates/native/iconv.c

750:44ea0968a550
2017-03-20 Paul Boddie Added the context identity to the AttrResult string representation.
     1 /* Native functions for character set conversion.     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 <iconv.h> /* iconv, iconv_close, iconv_open */    20 #include <string.h> /* memcpy */    21 #include <errno.h> /* errno */    22 #include "native/common.h"    23 #include "types.h"    24 #include "exceptions.h"    25 #include "ops.h"    26 #include "progconsts.h"    27 #include "progops.h"    28 #include "progtypes.h"    29 #include "main.h"    30     31 static const size_t OUTBUFSIZE_MIN = 16;    32     33 static void __raise_incomplete_sequence_error(__attr value, __attr arg)    34 {    35 #ifdef __HAVE_posix_iconv_IncompleteSequenceError    36     __attr args[3] = {__NULL, value, arg};    37     __attr exc = __new_posix_iconv_IncompleteSequenceError(args);    38     __Raise(exc);    39 #endif /* __HAVE_posix_iconv_IncompleteSequenceError */    40 }    41     42 static void __raise_invalid_sequence_error(__attr value, __attr arg)    43 {    44 #ifdef __HAVE_posix_iconv_InvalidSequenceError    45     __attr args[3] = {__NULL, value, arg};    46     __attr exc = __new_posix_iconv_InvalidSequenceError(args);    47     __Raise(exc);    48 #endif /* __HAVE_posix_iconv_InvalidSequenceError */    49 }    50     51 /* Character set conversion. */    52     53 __attr __fn_native_iconv_iconv(__attr __args[])    54 {    55     __attr * const cd = &__args[1];    56     __attr * const state = &__args[2];    57     /* cd interpreted as iconv_t */    58     iconv_t c = (iconv_t) cd->datavalue;    59     /* state.__data__ interpreted as list */    60     __fragment *f = __load_via_object(state->value, __data__).seqvalue;    61     62     /* Obtain the string, start position, and remaining bytes from the state. */    63     64     char *inbuf = __load_via_object(f->attrs[0].value, __data__).strvalue;    65     int start = __load_via_object(f->attrs[1].value, __data__).intvalue;    66     int remaining = __load_via_object(f->attrs[2].value, __data__).intvalue;    67     68     /* Allocate a string for the output buffer using the remaining input size    69        as a guide. */    70     71     size_t outbufsize = remaining < OUTBUFSIZE_MIN ? OUTBUFSIZE_MIN : remaining;    72     size_t outbytesleft = outbufsize;    73     size_t inbytesleft = remaining;    74     75     char buf[outbytesleft];    76     char *outbuf = buf, *outbufstart = outbuf, *resultbuf;    77     size_t result, outbytestotal;    78     79     /* Convert from the start point. */    80     81     inbuf += start;    82     83     errno = 0;    84     result = iconv(c, &inbuf, &inbytesleft, &outbuf, &outbytesleft);    85     86     /* Return any string. */    87     88     if ((result != -1) || (errno == E2BIG) || (errno == EINVAL))    89     {    90         outbytestotal = outbufsize - outbytesleft;    91         resultbuf = __ALLOCATE(outbytestotal + 1, sizeof(char));    92         memcpy(resultbuf, outbufstart, outbytestotal);    93     94         /* Mutate the state to indicate the next input buffer position. */    95     96         f->attrs[1] = __new_int(start + remaining - inbytesleft);    97         f->attrs[2] = __new_int(inbytesleft);    98     99         /* Incomplete sequence: raise the string in an OSError instead. */   100    101         if (errno == EINVAL)   102             __raise_incomplete_sequence_error(__new_int(errno), __new_str(resultbuf, outbytestotal));   103    104         return __new_str(resultbuf, outbytestotal);   105     }   106    107     /* Invalid sequence. */   108    109     if (errno == EILSEQ)   110     {   111         resultbuf = __ALLOCATE(inbytesleft + 1, sizeof(char));   112         memcpy(resultbuf, inbuf, inbytesleft);   113         __raise_invalid_sequence_error(__new_int(errno), __new_str(resultbuf, inbytesleft));   114     }   115    116     /* General failure. */   117    118     else   119         __raise_os_error(__new_int(errno), __builtins___none_None);   120    121     /* Should never be reached: included to satisfy the compiler. */   122    123     return __builtins___none_None;   124 }   125    126 __attr __fn_native_iconv_iconv_close(__attr __args[])   127 {   128     __attr * const cd = &__args[1];   129     /* cd interpreted as iconv_t */   130     iconv_t c = (iconv_t) cd->datavalue;   131    132     errno = 0;   133    134     if (iconv_close(c) == -1)   135         __raise_os_error(__new_int(errno), __builtins___none_None);   136    137     return __builtins___none_None;   138 }   139    140 __attr __fn_native_iconv_iconv_open(__attr __args[])   141 {   142     __attr * const tocode = &__args[1];   143     __attr * const fromcode = &__args[2];   144     /* tocode.__data__ interpreted as string */   145     char *t = __load_via_object(tocode->value, __data__).strvalue;   146     /* fromcode.__data__ interpreted as string */   147     char *f = __load_via_object(fromcode->value, __data__).strvalue;   148     iconv_t result;   149     __attr attr;   150    151     errno = 0;   152     result = iconv_open(t, f);   153    154     if (result == (iconv_t) -1)   155         __raise_os_error(__new_int(errno), __builtins___none_None);   156    157     /* Return the descriptor as an opaque value. */   158    159     attr.datavalue = (void *) result;   160     return attr;   161 }   162    163 __attr __fn_native_iconv_iconv_reset(__attr __args[])   164 {   165     __attr * const cd = &__args[1];   166     /* cd interpreted as iconv_t */   167     iconv_t c = (iconv_t) cd->datavalue;   168    169     iconv(c, NULL, NULL, NULL, NULL);   170     return __builtins___none_None;   171 }   172    173 /* Module initialisation. */   174    175 void __main_native_iconv()   176 {   177 }