1 /* Native functions for character set conversion. 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 <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 /* Character set conversion. */ 34 35 __attr __fn_native_iconv_iconv(__attr __args[]) 36 { 37 __attr * const cd = &__args[1]; 38 __attr * const instr = &__args[2]; 39 __attr * const state = &__args[3]; 40 /* cd interpreted as iconv_t */ 41 iconv_t c = (iconv_t) cd->datavalue; 42 /* instr.__data__ interpreted as string */ 43 char *inbuf = __load_via_object(instr->value, __pos___data__).strvalue; 44 /* state.__data__ interpreted as list */ 45 __fragment *f = __load_via_object(state->value, __pos___data__).seqvalue; 46 47 /* Obtain the start position from the state. */ 48 49 int start = __load_via_object(f->attrs[0].value, __pos___data__).intvalue; 50 int remaining = __load_via_object(f->attrs[1].value, __pos___data__).intvalue; 51 52 /* Allocate a string for the output buffer using the remaining input size 53 as a guide. */ 54 55 size_t outbufsize = remaining < OUTBUFSIZE_MIN ? OUTBUFSIZE_MIN : remaining; 56 size_t outbytesleft = outbufsize; 57 size_t inbytesleft = remaining; 58 59 char buf[outbytesleft]; 60 char *outbuf = buf, *outbufstart = outbuf, *resultbuf; 61 size_t result, outbytestotal; 62 63 /* Convert from the start point. */ 64 65 inbuf += start; 66 67 errno = 0; 68 result = iconv(c, &inbuf, &inbytesleft, &outbuf, &outbytesleft); 69 70 /* Return any string. */ 71 72 if ((result != -1) || (errno == E2BIG)) 73 { 74 outbytestotal = outbufsize - outbytesleft; 75 resultbuf = __ALLOCATE(outbytestotal + 1, sizeof(char)); 76 memcpy(resultbuf, outbufstart, outbytestotal); 77 78 /* Mutate the state to indicate the next input buffer position. */ 79 80 f->attrs[0] = __new_int(start + remaining - inbytesleft); 81 f->attrs[1] = __new_int(inbytesleft); 82 return __new_str(resultbuf, outbytestotal); 83 } 84 85 /* Invalid sequence. */ 86 87 if (errno == EILSEQ) 88 { 89 resultbuf = __ALLOCATE(inbytesleft + 1, sizeof(char)); 90 memcpy(resultbuf, inbuf, inbytesleft); 91 __raise_os_error(__new_int(errno), __new_str(resultbuf, inbytesleft)); 92 } 93 94 /* Incomplete sequence. */ 95 96 else if (errno == EINVAL) 97 { 98 resultbuf = __ALLOCATE(inbytesleft + 1, sizeof(char)); 99 memcpy(resultbuf, inbuf, inbytesleft); 100 __raise_os_error(__new_int(errno), __new_str(resultbuf, inbytesleft)); 101 } 102 103 /* General failure. */ 104 105 else 106 __raise_os_error(__new_int(errno), __builtins___none_None); 107 } 108 109 __attr __fn_native_iconv_iconv_close(__attr __args[]) 110 { 111 __attr * const cd = &__args[1]; 112 /* cd interpreted as iconv_t */ 113 iconv_t c = (iconv_t) cd->datavalue; 114 115 errno = 0; 116 117 if (iconv_close(c) == -1) 118 __raise_os_error(__new_int(errno), __builtins___none_None); 119 120 return __builtins___none_None; 121 } 122 123 __attr __fn_native_iconv_iconv_open(__attr __args[]) 124 { 125 __attr * const tocode = &__args[1]; 126 __attr * const fromcode = &__args[2]; 127 /* tocode.__data__ interpreted as string */ 128 char *t = __load_via_object(tocode->value, __pos___data__).strvalue; 129 /* fromcode.__data__ interpreted as string */ 130 char *f = __load_via_object(fromcode->value, __pos___data__).strvalue; 131 iconv_t result; 132 __attr attr; 133 134 errno = 0; 135 result = iconv_open(t, f); 136 137 if (result == (iconv_t) -1) 138 __raise_os_error(__new_int(errno), __builtins___none_None); 139 140 /* Return the descriptor as an opaque value. */ 141 142 attr.context = 0; 143 attr.datavalue = (void *) result; 144 return attr; 145 } 146 147 /* Module initialisation. */ 148 149 void __main_native_iconv() 150 { 151 }