Lichen

templates/native/iconv.c

934:2989aab1b4f7
10 months ago Paul Boddie Renamed the utf8string class to unicode, eliminating the unicode function. This means that the simple case of merely returning an object if it is already a Unicode object no longer occurs when using the unicode callable, but such behaviour might be better supported with more general customised instantiation functionality.
     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     __Raise(__new_posix_iconv_IncompleteSequenceError(__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, value, arg));    44 #endif /* __HAVE_posix_iconv_InvalidSequenceError */    45 }    46     47 /* Character set conversion. */    48     49 __attr __fn_native_iconv_iconv(__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 __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 __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 __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 }