2
* STFL - The Structured Terminal Forms Language/Library
3
* Copyright (C) 2007 Clifford Wolf <clifford@clifford.at>
5
* This library is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU Lesser General Public
7
* License as published by the Free Software Foundation; either
8
* version 3 of the License, or (at your option) any later version.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
* Lesser General Public License for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License along with this library; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
* iconv.c: Helper functions for widechar conversion
31
struct stfl_ipool_entry {
33
struct stfl_ipool_entry *next;
40
struct stfl_ipool_entry *list;
43
struct stfl_ipool *stfl_ipool_create(const char *code)
45
struct stfl_ipool *pool = malloc(sizeof(struct stfl_ipool));
47
pool->to_wc_desc = (iconv_t)(-1);
48
pool->from_wc_desc = (iconv_t)(-1);
50
pool->code = strdup(code);
56
void *stfl_ipool_add(struct stfl_ipool *pool, void *data)
58
struct stfl_ipool_entry *entry = malloc(sizeof(struct stfl_ipool_entry));
61
entry->next = pool->list;
68
const wchar_t *stfl_ipool_towc(struct stfl_ipool *pool, const char *buf)
73
if (!strcmp("WCHAR_T", pool->code))
76
if (pool->to_wc_desc == (iconv_t)(-1))
77
pool->to_wc_desc = iconv_open("WCHAR_T", pool->code);
79
if (pool->to_wc_desc == (iconv_t)(-1))
82
char *inbuf = (char*)buf;
83
size_t inbytesleft = strlen(buf);
85
int buffer_size = inbytesleft * 2 + 16;
90
buffer_size += inbytesleft * 2;
91
buffer = realloc(buffer, buffer_size);
93
retry_without_growing:;
94
char *outbuf = buffer + buffer_pos;
95
size_t outbytesleft = buffer_size - buffer_pos;
97
iconv(pool->to_wc_desc, NULL, NULL, NULL, NULL);
98
int rc = iconv(pool->to_wc_desc, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
100
buffer_pos = outbuf - buffer;
102
if (rc == -1 && errno == E2BIG)
103
goto grow_buffer_retry;
105
if (rc == -1 && (errno == EILSEQ || errno == EINVAL)) {
106
// just copy this char as it is (e.g. when input is broken utf-8 with some latin1 chars)
107
if (outbytesleft < sizeof(wchar_t))
108
goto grow_buffer_retry;
109
*((wchar_t*)outbuf) = *(unsigned char*)inbuf;
110
buffer_pos += sizeof(wchar_t);
113
goto retry_without_growing;
121
if (outbytesleft < sizeof(wchar_t))
122
buffer = realloc(buffer, buffer_size+sizeof(wchar_t));
123
*((wchar_t*)outbuf) = 0;
125
return stfl_ipool_add(pool, buffer);
128
const char *stfl_ipool_fromwc(struct stfl_ipool *pool, const wchar_t *buf)
133
if (!strcmp("WCHAR_T", pool->code))
136
if (pool->from_wc_desc == (iconv_t)(-1))
137
pool->from_wc_desc = iconv_open(pool->code, "WCHAR_T");
139
if (pool->from_wc_desc == (iconv_t)(-1))
142
char *inbuf = (char*)buf;
143
size_t inbytesleft = wcslen(buf)*sizeof(wchar_t);
145
int buffer_size = inbytesleft + 16;
150
buffer_size += inbytesleft;
151
buffer = realloc(buffer, buffer_size);
153
retry_without_growing:;
154
char *outbuf = buffer + buffer_pos;
155
size_t outbytesleft = buffer_size - buffer_pos;
157
iconv(pool->from_wc_desc, NULL, NULL, NULL, NULL);
158
int rc = iconv(pool->from_wc_desc, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
160
buffer_pos = outbuf - buffer;
162
if (rc == -1 && errno == E2BIG)
163
goto grow_buffer_retry;
165
if (rc == -1 && (errno == EILSEQ || errno == EINVAL)) {
166
// just copy a '?' to the output stream
167
if (outbytesleft < 1)
168
goto grow_buffer_retry;
171
inbuf += sizeof(wchar_t);
172
inbytesleft -= sizeof(wchar_t);
173
goto retry_without_growing;
181
if (outbytesleft < 1)
182
buffer = realloc(buffer, buffer_size+1);
185
return stfl_ipool_add(pool, buffer);
188
void stfl_ipool_flush(struct stfl_ipool *pool)
193
struct stfl_ipool_entry *l;
197
pool->list = l->next;
203
void stfl_ipool_destroy(struct stfl_ipool *pool)
208
stfl_ipool_flush(pool);
211
if (pool->to_wc_desc != (iconv_t)(-1))
212
iconv_close(pool->to_wc_desc);
214
if (pool->from_wc_desc != (iconv_t)(-1))
215
iconv_close(pool->from_wc_desc);