~ubuntu-branches/ubuntu/lucid/stfl/lucid

« back to all changes in this revision

Viewing changes to iconv.c

  • Committer: Bazaar Package Importer
  • Author(s): Nico Golde
  • Date: 2007-08-07 13:06:54 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20070807130654-fmvsraotulj0nbri
Tags: 0.15-3
Again added fPIC to CFLAGS. Hopefully all build issues
are fixed now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  STFL - The Structured Terminal Forms Language/Library
 
3
 *  Copyright (C) 2007  Clifford Wolf <clifford@clifford.at>
 
4
 *
 
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.
 
9
 *  
 
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.
 
14
 *  
 
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,
 
18
 *  MA 02110-1301 USA
 
19
 *
 
20
 *  iconv.c: Helper functions for widechar conversion
 
21
 */
 
22
 
 
23
#include "stfl.h"
 
24
 
 
25
#include <string.h>
 
26
#include <stdlib.h>
 
27
#include <wchar.h>
 
28
#include <iconv.h>
 
29
#include <errno.h>
 
30
 
 
31
struct stfl_ipool_entry {
 
32
        void *data;
 
33
        struct stfl_ipool_entry *next;
 
34
};
 
35
 
 
36
struct stfl_ipool {
 
37
        iconv_t to_wc_desc;
 
38
        iconv_t from_wc_desc;
 
39
        char *code;
 
40
        struct stfl_ipool_entry *list;
 
41
};
 
42
 
 
43
struct stfl_ipool *stfl_ipool_create(const char *code)
 
44
{
 
45
        struct stfl_ipool *pool = malloc(sizeof(struct stfl_ipool));
 
46
 
 
47
        pool->to_wc_desc = (iconv_t)(-1);
 
48
        pool->from_wc_desc = (iconv_t)(-1);
 
49
 
 
50
        pool->code = strdup(code);
 
51
        pool->list = 0;
 
52
 
 
53
        return pool;
 
54
}
 
55
 
 
56
void *stfl_ipool_add(struct stfl_ipool *pool, void *data)
 
57
{
 
58
        struct stfl_ipool_entry *entry = malloc(sizeof(struct stfl_ipool_entry));
 
59
 
 
60
        entry->data = data;
 
61
        entry->next = pool->list;
 
62
        pool->list = entry;
 
63
 
 
64
        return data;
 
65
}
 
66
 
 
67
 
 
68
const wchar_t *stfl_ipool_towc(struct stfl_ipool *pool, const char *buf)
 
69
{
 
70
        if (!pool || !buf)
 
71
                return 0;
 
72
 
 
73
        if (!strcmp("WCHAR_T", pool->code))
 
74
                return (wchar_t*)buf;
 
75
 
 
76
        if (pool->to_wc_desc == (iconv_t)(-1))
 
77
                pool->to_wc_desc = iconv_open("WCHAR_T", pool->code);
 
78
 
 
79
        if (pool->to_wc_desc == (iconv_t)(-1))
 
80
                return 0;
 
81
 
 
82
        char *inbuf = (char*)buf;
 
83
        size_t inbytesleft = strlen(buf);
 
84
 
 
85
        int buffer_size = inbytesleft * 2 + 16;
 
86
        int buffer_pos = 0;
 
87
        char *buffer = NULL;
 
88
 
 
89
grow_buffer_retry:;
 
90
        buffer_size += inbytesleft * 2;
 
91
        buffer = realloc(buffer, buffer_size);
 
92
 
 
93
retry_without_growing:;
 
94
        char *outbuf = buffer + buffer_pos;
 
95
        size_t outbytesleft = buffer_size - buffer_pos;
 
96
 
 
97
        iconv(pool->to_wc_desc, NULL, NULL, NULL, NULL);
 
98
        int rc = iconv(pool->to_wc_desc, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
 
99
 
 
100
        buffer_pos = outbuf - buffer;
 
101
 
 
102
        if (rc == -1 && errno == E2BIG)
 
103
                goto grow_buffer_retry;
 
104
 
 
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);
 
111
                inbuf++;
 
112
                inbytesleft--;
 
113
                goto retry_without_growing;
 
114
        }
 
115
 
 
116
        if (rc == -1) {
 
117
                free(buffer);
 
118
                return 0;
 
119
        }
 
120
 
 
121
        if (outbytesleft < sizeof(wchar_t))
 
122
                buffer = realloc(buffer, buffer_size+sizeof(wchar_t));
 
123
        *((wchar_t*)outbuf) = 0;
 
124
 
 
125
        return stfl_ipool_add(pool, buffer);
 
126
}
 
127
 
 
128
const char *stfl_ipool_fromwc(struct stfl_ipool *pool, const wchar_t *buf)
 
129
{
 
130
        if (!pool || !buf)
 
131
                return 0;
 
132
 
 
133
        if (!strcmp("WCHAR_T", pool->code))
 
134
                return (char*)buf;
 
135
 
 
136
        if (pool->from_wc_desc == (iconv_t)(-1))
 
137
                pool->from_wc_desc = iconv_open(pool->code, "WCHAR_T");
 
138
 
 
139
        if (pool->from_wc_desc == (iconv_t)(-1))
 
140
                return 0;
 
141
 
 
142
        char *inbuf = (char*)buf;
 
143
        size_t inbytesleft = wcslen(buf)*sizeof(wchar_t);
 
144
 
 
145
        int buffer_size = inbytesleft + 16;
 
146
        int buffer_pos = 0;
 
147
        char *buffer = NULL;
 
148
 
 
149
grow_buffer_retry:;
 
150
        buffer_size += inbytesleft;
 
151
        buffer = realloc(buffer, buffer_size);
 
152
 
 
153
retry_without_growing:;
 
154
        char *outbuf = buffer + buffer_pos;
 
155
        size_t outbytesleft = buffer_size - buffer_pos;
 
156
 
 
157
        iconv(pool->from_wc_desc, NULL, NULL, NULL, NULL);
 
158
        int rc = iconv(pool->from_wc_desc, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
 
159
 
 
160
        buffer_pos = outbuf - buffer;
 
161
 
 
162
        if (rc == -1 && errno == E2BIG)
 
163
                goto grow_buffer_retry;
 
164
 
 
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;
 
169
                *outbuf = '?';
 
170
                buffer_pos++;
 
171
                inbuf += sizeof(wchar_t);
 
172
                inbytesleft -= sizeof(wchar_t);
 
173
                goto retry_without_growing;
 
174
        }
 
175
 
 
176
        if (rc == -1) {
 
177
                free(buffer);
 
178
                return 0;
 
179
        }
 
180
 
 
181
        if (outbytesleft < 1)
 
182
                buffer = realloc(buffer, buffer_size+1);
 
183
        *outbuf = 0;
 
184
 
 
185
        return stfl_ipool_add(pool, buffer);
 
186
}
 
187
 
 
188
void stfl_ipool_flush(struct stfl_ipool *pool)
 
189
{
 
190
        if (!pool)
 
191
                return;
 
192
 
 
193
        struct stfl_ipool_entry *l;
 
194
 
 
195
        while (pool->list) {
 
196
                l = pool->list;
 
197
                pool->list = l->next;
 
198
                free(l->data);
 
199
                free(l);
 
200
        }
 
201
}
 
202
 
 
203
void stfl_ipool_destroy(struct stfl_ipool *pool)
 
204
{
 
205
        if (!pool)
 
206
                return;
 
207
 
 
208
        stfl_ipool_flush(pool);
 
209
        free(pool->code);
 
210
 
 
211
        if (pool->to_wc_desc != (iconv_t)(-1))
 
212
                iconv_close(pool->to_wc_desc);
 
213
 
 
214
        if (pool->from_wc_desc != (iconv_t)(-1))
 
215
                iconv_close(pool->from_wc_desc);
 
216
 
 
217
        free(pool);
 
218
}
 
219