Lichen

templates/native/iconv.c

1022:582d834d392d
14 months ago Paul Boddie Merged changes from the value-replacement branch. value-replacement-for-wrapper
     1 /* Native functions for character set conversion.     2      3 Copyright (C) 2016, 2017, 2021, 2023 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     __Raise(__new_posix_iconv_IncompleteSequenceError(__NULL, __NULL, value, arg));    37 #endif /* __HAVE_posix_iconv_IncompleteSequenceError */    38 }    39     40 static void __raise_invalid_sequence_error(__attr value, __attr arg)    41 {    42 #ifdef __HAVE_posix_iconv_InvalidSequenceError    43     __Raise(__new_posix_iconv_InvalidSequenceError(__NULL, __NULL, value, arg));    44 #endif /* __HAVE_posix_iconv_InvalidSequenceError */    45 }    46     47 /* Character set conversion. */    48     49 __attr __fn_native_iconv_iconv(__attr __result, __attr __self, __attr cd, __attr state)    50 {    51     /* cd interpreted as iconv_t */    52     iconv_t c = (iconv_t) cd.datavalue;    53     /* state.__data__ interpreted as list */    54     __fragment *f = __load_via_object(__VALUE(state), __data__).seqvalue;    55     56     /* Obtain the string, start position, and remaining bytes from the state. */    57     58     char *inbuf = __load_via_object(__VALUE(f->attrs[0]), __data__).strvalue;    59     __int start = __TOINT(f->attrs[1]);    60     __int remaining = __TOINT(f->attrs[2]);    61     62     /* Allocate a string for the output buffer using the remaining input size    63        as a guide. */    64     65     size_t outbufsize = remaining < OUTBUFSIZE_MIN ? OUTBUFSIZE_MIN : remaining;    66     size_t outbytesleft = outbufsize;    67     size_t inbytesleft = remaining;    68     69     char buf[outbytesleft];    70     char *outbuf = buf, *outbufstart = outbuf, *resultbuf;    71     size_t result, outbytestotal;    72     73     /* Convert from the start point. */    74     75     inbuf += start;    76     77     errno = 0;    78     result = iconv(c, &inbuf, &inbytesleft, &outbuf, &outbytesleft);    79     80     /* Return any string. */    81     82     if ((result != -1) || (errno == E2BIG) || (errno == EINVAL))    83     {    84         outbytestotal = outbufsize - outbytesleft;    85         resultbuf = __ALLOCATE(outbytestotal + 1, sizeof(char));    86         memcpy(resultbuf, outbufstart, outbytestotal);    87     88         /* Mutate the state to indicate the next input buffer position. */    89     90         f->attrs[1] = __new_int(start + remaining - inbytesleft);    91         f->attrs[2] = __new_int(inbytesleft);    92     93         /* Incomplete sequence: raise the string in an OSError instead. */    94     95         if (errno == EINVAL)    96             __raise_incomplete_sequence_error(__new_int(errno), __new_str(resultbuf, outbytestotal));    97     98         return __new_str(resultbuf, outbytestotal);    99     }   100    101     /* Invalid sequence. */   102    103     if (errno == EILSEQ)   104     {   105         resultbuf = __ALLOCATE(inbytesleft + 1, sizeof(char));   106         memcpy(resultbuf, inbuf, inbytesleft);   107         __raise_invalid_sequence_error(__new_int(errno), __new_str(resultbuf, inbytesleft));   108     }   109    110     /* General failure. */   111    112     else   113         __raise_os_error(__new_int(errno), __builtins___none_None);   114    115     /* Should never be reached: included to satisfy the compiler. */   116    117     return __builtins___none_None;   118 }   119    120 __attr __fn_native_iconv_iconv_close(__attr __result, __attr __self, __attr cd)   121 {   122     /* cd interpreted as iconv_t */   123     iconv_t c = (iconv_t) cd.datavalue;   124    125     errno = 0;   126    127     if (iconv_close(c) == -1)   128         __raise_os_error(__new_int(errno), __builtins___none_None);   129    130     return __builtins___none_None;   131 }   132    133 __attr __fn_native_iconv_iconv_open(__attr __result, __attr __self, __attr tocode, __attr fromcode)   134 {   135     /* tocode.__data__ interpreted as string */   136     char *t = __load_via_object(__VALUE(tocode), __data__).strvalue;   137     /* fromcode.__data__ interpreted as string */   138     char *f = __load_via_object(__VALUE(fromcode), __data__).strvalue;   139     iconv_t result;   140     __attr attr;   141    142     errno = 0;   143     result = iconv_open(t, f);   144    145     if (result == (iconv_t) -1)   146         __raise_os_error(__new_int(errno), __builtins___none_None);   147    148     /* Return the descriptor as an opaque value. */   149    150     attr.datavalue = (void *) result;   151     return attr;   152 }   153    154 __attr __fn_native_iconv_iconv_reset(__attr __result, __attr __self, __attr cd)   155 {   156     /* cd interpreted as iconv_t */   157     iconv_t c = (iconv_t) cd.datavalue;   158    159     iconv(c, NULL, NULL, NULL, NULL);   160     return __builtins___none_None;   161 }   162    163 /* Module initialisation. */   164    165 void __main_native_iconv()   166 {   167 }