citrus_hz.c revision 1.1 1 1.1 tnozaki /* $NetBSD: citrus_hz.c,v 1.1 2006/11/22 23:38:27 tnozaki Exp $ */
2 1.1 tnozaki
3 1.1 tnozaki /*-
4 1.1 tnozaki * Copyright (c)2004, 2006 Citrus Project,
5 1.1 tnozaki * All rights reserved.
6 1.1 tnozaki *
7 1.1 tnozaki * Redistribution and use in source and binary forms, with or without
8 1.1 tnozaki * modification, are permitted provided that the following conditions
9 1.1 tnozaki * are met:
10 1.1 tnozaki * 1. Redistributions of source code must retain the above copyright
11 1.1 tnozaki * notice, this list of conditions and the following disclaimer.
12 1.1 tnozaki * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 tnozaki * notice, this list of conditions and the following disclaimer in the
14 1.1 tnozaki * documentation and/or other materials provided with the distribution.
15 1.1 tnozaki *
16 1.1 tnozaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 1.1 tnozaki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 1.1 tnozaki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 1.1 tnozaki * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 1.1 tnozaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 1.1 tnozaki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 1.1 tnozaki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 1.1 tnozaki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 1.1 tnozaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 tnozaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 tnozaki * SUCH DAMAGE.
27 1.1 tnozaki *
28 1.1 tnozaki */
29 1.1 tnozaki
30 1.1 tnozaki #include <sys/cdefs.h>
31 1.1 tnozaki #if defined(LIBC_SCCS) && !defined(lint)
32 1.1 tnozaki __RCSID("$NetBSD: citrus_hz.c,v 1.1 2006/11/22 23:38:27 tnozaki Exp $");
33 1.1 tnozaki #endif /* LIBC_SCCS and not lint */
34 1.1 tnozaki
35 1.1 tnozaki #include <sys/queue.h>
36 1.1 tnozaki #include <sys/types.h>
37 1.1 tnozaki #include <assert.h>
38 1.1 tnozaki #include <errno.h>
39 1.1 tnozaki #include <string.h>
40 1.1 tnozaki #include <stdint.h>
41 1.1 tnozaki #include <stdlib.h>
42 1.1 tnozaki #include <stddef.h>
43 1.1 tnozaki #include <locale.h>
44 1.1 tnozaki #include <limits.h>
45 1.1 tnozaki #include <wchar.h>
46 1.1 tnozaki
47 1.1 tnozaki #include "citrus_namespace.h"
48 1.1 tnozaki #include "citrus_types.h"
49 1.1 tnozaki #include "citrus_bcs.h"
50 1.1 tnozaki #include "citrus_module.h"
51 1.1 tnozaki #include "citrus_ctype.h"
52 1.1 tnozaki #include "citrus_stdenc.h"
53 1.1 tnozaki
54 1.1 tnozaki #include "citrus_hz.h"
55 1.1 tnozaki #include "citrus_prop.h"
56 1.1 tnozaki
57 1.1 tnozaki /*
58 1.1 tnozaki * wchar_t mapping:
59 1.1 tnozaki *
60 1.1 tnozaki * CTRL/ASCII 00000000 00000000 00000000 gxxxxxxx
61 1.1 tnozaki * GB2312 00000000 00000000 0xxxxxxx gxxxxxxx
62 1.1 tnozaki * 94/96*n (~M) 0mmmmmmm 0xxxxxxx 0xxxxxxx gxxxxxxx
63 1.1 tnozaki */
64 1.1 tnozaki
65 1.1 tnozaki #define ESCAPE_CHAR '~'
66 1.1 tnozaki
67 1.1 tnozaki typedef enum {
68 1.1 tnozaki CTRL = 0, ASCII = 1, GB2312 = 2, CS94 = 3, CS96 = 4
69 1.1 tnozaki } charset_t;
70 1.1 tnozaki
71 1.1 tnozaki typedef struct {
72 1.1 tnozaki int start, end, width;
73 1.1 tnozaki } range_t;
74 1.1 tnozaki
75 1.1 tnozaki static const range_t ranges[] = {
76 1.1 tnozaki #define RANGE(start, end) { start, end, (end - start) + 1 }
77 1.1 tnozaki /* CTRL */ RANGE(0x00, 0x1F),
78 1.1 tnozaki /* ASCII */ RANGE(0x20, 0x7F),
79 1.1 tnozaki /* GB2312 */ RANGE(0x21, 0x7E),
80 1.1 tnozaki /* CS94 */ RANGE(0x21, 0x7E),
81 1.1 tnozaki /* CS96 */ RANGE(0x20, 0x7F),
82 1.1 tnozaki #undef RANGE
83 1.1 tnozaki };
84 1.1 tnozaki
85 1.1 tnozaki typedef struct escape_t escape_t;
86 1.1 tnozaki typedef struct {
87 1.1 tnozaki charset_t charset;
88 1.1 tnozaki size_t length;
89 1.1 tnozaki #define ROWCOL_MAX 3
90 1.1 tnozaki escape_t *escape;
91 1.1 tnozaki } graphic_t;
92 1.1 tnozaki
93 1.1 tnozaki typedef TAILQ_HEAD(escape_list, escape_t) escape_list;
94 1.1 tnozaki struct escape_t {
95 1.1 tnozaki TAILQ_ENTRY(escape_t) entry;
96 1.1 tnozaki int ch;
97 1.1 tnozaki graphic_t *left, *right;
98 1.1 tnozaki escape_list *set;
99 1.1 tnozaki };
100 1.1 tnozaki
101 1.1 tnozaki #define GL(escape) ((escape)->left)
102 1.1 tnozaki #define GR(escape) ((escape)->right)
103 1.1 tnozaki #define SET(escape) ((escape)->set)
104 1.1 tnozaki #define ESC(escape) ((escape)->ch)
105 1.1 tnozaki #define INIT(escape) (TAILQ_FIRST(SET(escape)))
106 1.1 tnozaki
107 1.1 tnozaki static __inline escape_t *
108 1.1 tnozaki find_escape(escape_list *set, int ch)
109 1.1 tnozaki {
110 1.1 tnozaki escape_t *escape;
111 1.1 tnozaki
112 1.1 tnozaki _DIAGASSERT(set != NULL);
113 1.1 tnozaki
114 1.1 tnozaki TAILQ_FOREACH(escape, set, entry) {
115 1.1 tnozaki if (ESC(escape) == ch)
116 1.1 tnozaki break;
117 1.1 tnozaki }
118 1.1 tnozaki
119 1.1 tnozaki return escape;
120 1.1 tnozaki }
121 1.1 tnozaki
122 1.1 tnozaki typedef struct {
123 1.1 tnozaki escape_list e0, e1;
124 1.1 tnozaki graphic_t *ascii, *gb2312;
125 1.1 tnozaki } _HZEncodingInfo;
126 1.1 tnozaki
127 1.1 tnozaki #define E0SET(ei) (&(ei)->e0)
128 1.1 tnozaki #define E1SET(ei) (&(ei)->e1)
129 1.1 tnozaki #define INIT0(ei) (TAILQ_FIRST(E0SET(ei)))
130 1.1 tnozaki #define INIT1(ei) (TAILQ_FIRST(E1SET(ei)))
131 1.1 tnozaki
132 1.1 tnozaki typedef struct {
133 1.1 tnozaki int chlen;
134 1.1 tnozaki char ch[ROWCOL_MAX];
135 1.1 tnozaki escape_t *inuse;
136 1.1 tnozaki } _HZState;
137 1.1 tnozaki
138 1.1 tnozaki typedef struct {
139 1.1 tnozaki _HZEncodingInfo ei;
140 1.1 tnozaki struct {
141 1.1 tnozaki /* for future multi-locale facility */
142 1.1 tnozaki _HZState s_mblen;
143 1.1 tnozaki _HZState s_mbrlen;
144 1.1 tnozaki _HZState s_mbrtowc;
145 1.1 tnozaki _HZState s_mbtowc;
146 1.1 tnozaki _HZState s_mbsrtowcs;
147 1.1 tnozaki _HZState s_wcrtomb;
148 1.1 tnozaki _HZState s_wcsrtombs;
149 1.1 tnozaki _HZState s_wctomb;
150 1.1 tnozaki } states;
151 1.1 tnozaki } _HZCTypeInfo;
152 1.1 tnozaki
153 1.1 tnozaki #define _CEI_TO_EI(_cei_) (&(_cei_)->ei)
154 1.1 tnozaki #define _CEI_TO_STATE(_cei_, _func_) (_cei_)->states.s_##_func_
155 1.1 tnozaki
156 1.1 tnozaki #define _FUNCNAME(m) _citrus_HZ_##m
157 1.1 tnozaki #define _ENCODING_INFO _HZEncodingInfo
158 1.1 tnozaki #define _CTYPE_INFO _HZCTypeInfo
159 1.1 tnozaki #define _ENCODING_STATE _HZState
160 1.1 tnozaki #define _ENCODING_MB_CUR_MAX(_ei_) MB_LEN_MAX
161 1.1 tnozaki #define _ENCODING_IS_STATE_DEPENDENT 1
162 1.1 tnozaki #define _STATE_NEEDS_EXPLICIT_INIT(_ps_) ((_ps_)->inuse == NULL)
163 1.1 tnozaki
164 1.1 tnozaki static __inline void
165 1.1 tnozaki _citrus_HZ_init_state(_HZEncodingInfo * __restrict ei,
166 1.1 tnozaki _HZState * __restrict psenc)
167 1.1 tnozaki {
168 1.1 tnozaki _DIAGASSERT(ei != NULL);
169 1.1 tnozaki _DIAGASSERT(psenc != NULL);
170 1.1 tnozaki
171 1.1 tnozaki psenc->chlen = 0;
172 1.1 tnozaki psenc->inuse = INIT0(ei);
173 1.1 tnozaki }
174 1.1 tnozaki
175 1.1 tnozaki static __inline void
176 1.1 tnozaki /*ARGSUSED*/
177 1.1 tnozaki _citrus_HZ_pack_state(_HZEncodingInfo * __restrict ei,
178 1.1 tnozaki void *__restrict pspriv, const _HZState * __restrict psenc)
179 1.1 tnozaki {
180 1.1 tnozaki /* ei may be unused */
181 1.1 tnozaki _DIAGASSERT(pspriv != NULL);
182 1.1 tnozaki _DIAGASSERT(psenc != NULL);
183 1.1 tnozaki
184 1.1 tnozaki memcpy(pspriv, (const void *)psenc, sizeof(*psenc));
185 1.1 tnozaki }
186 1.1 tnozaki
187 1.1 tnozaki static __inline void
188 1.1 tnozaki /*ARGSUSED*/
189 1.1 tnozaki _citrus_HZ_unpack_state(_HZEncodingInfo * __restrict ei,
190 1.1 tnozaki _HZState * __restrict psenc, const void * __restrict pspriv)
191 1.1 tnozaki {
192 1.1 tnozaki /* ei may be unused */
193 1.1 tnozaki _DIAGASSERT(psenc != NULL);
194 1.1 tnozaki _DIAGASSERT(pspriv != NULL);
195 1.1 tnozaki
196 1.1 tnozaki memcpy((void *)psenc, pspriv, sizeof(*psenc));
197 1.1 tnozaki }
198 1.1 tnozaki
199 1.1 tnozaki static int
200 1.1 tnozaki _citrus_HZ_mbrtowc_priv(_HZEncodingInfo * __restrict ei,
201 1.1 tnozaki wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
202 1.1 tnozaki _HZState * __restrict psenc, size_t * __restrict nresult)
203 1.1 tnozaki {
204 1.1 tnozaki const char *s0;
205 1.1 tnozaki wchar_t wc;
206 1.1 tnozaki int bit, head, tail, len, ch;
207 1.1 tnozaki graphic_t *graphic;
208 1.1 tnozaki escape_t *candidate, *init;
209 1.1 tnozaki const range_t *range;
210 1.1 tnozaki
211 1.1 tnozaki _DIAGASSERT(ei != NULL);
212 1.1 tnozaki /* pwc may be null */
213 1.1 tnozaki _DIAGASSERT(s != NULL);
214 1.1 tnozaki _DIAGASSERT(psenc != NULL);
215 1.1 tnozaki _DIAGASSERT(nresult != NULL);
216 1.1 tnozaki
217 1.1 tnozaki if (*s == NULL) {
218 1.1 tnozaki _citrus_HZ_init_state(ei, psenc);
219 1.1 tnozaki *nresult = 1;
220 1.1 tnozaki return 0;
221 1.1 tnozaki }
222 1.1 tnozaki s0 = *s;
223 1.1 tnozaki if (psenc->chlen < 0 || psenc->inuse == NULL)
224 1.1 tnozaki return EINVAL;
225 1.1 tnozaki
226 1.1 tnozaki wc = (wchar_t)0;
227 1.1 tnozaki bit = head = tail = 0;
228 1.1 tnozaki graphic = NULL;
229 1.1 tnozaki for (len = 0; len <= MB_LEN_MAX; /**/) {
230 1.1 tnozaki if (psenc->chlen == tail) {
231 1.1 tnozaki if (n-- < 1) {
232 1.1 tnozaki *s = s0;
233 1.1 tnozaki *nresult = (size_t)-2;
234 1.1 tnozaki return 0;
235 1.1 tnozaki }
236 1.1 tnozaki psenc->ch[psenc->chlen++] = *s0++;
237 1.1 tnozaki ++len;
238 1.1 tnozaki }
239 1.1 tnozaki ch = (unsigned char)psenc->ch[tail++];
240 1.1 tnozaki if (tail == 1) {
241 1.1 tnozaki if ((ch & ~0x80) <= 0x1F) {
242 1.1 tnozaki if (psenc->inuse != INIT0(ei))
243 1.1 tnozaki break;
244 1.1 tnozaki wc = (wchar_t)ch;
245 1.1 tnozaki goto done;
246 1.1 tnozaki }
247 1.1 tnozaki if (ch & 0x80) {
248 1.1 tnozaki graphic = GR(psenc->inuse);
249 1.1 tnozaki bit = 0x80;
250 1.1 tnozaki ch &= ~0x80;
251 1.1 tnozaki } else {
252 1.1 tnozaki graphic = GL(psenc->inuse);
253 1.1 tnozaki if (ch == ESCAPE_CHAR)
254 1.1 tnozaki continue;
255 1.1 tnozaki bit = 0x0;
256 1.1 tnozaki }
257 1.1 tnozaki if (graphic == NULL)
258 1.1 tnozaki break;
259 1.1 tnozaki } else if (tail == 2 && psenc->ch[0] == ESCAPE_CHAR) {
260 1.1 tnozaki if (tail < psenc->chlen)
261 1.1 tnozaki return EINVAL;
262 1.1 tnozaki if (ch == ESCAPE_CHAR) {
263 1.1 tnozaki ++head;
264 1.1 tnozaki } else if (ch == '\n') {
265 1.1 tnozaki if (psenc->inuse != INIT0(ei))
266 1.1 tnozaki break;
267 1.1 tnozaki tail = psenc->chlen = 0;
268 1.1 tnozaki continue;
269 1.1 tnozaki } else {
270 1.1 tnozaki candidate = NULL;
271 1.1 tnozaki init = INIT0(ei);
272 1.1 tnozaki _DIAGASSERT(init != NULL);
273 1.1 tnozaki if (psenc->inuse == init) {
274 1.1 tnozaki init = INIT1(ei);
275 1.1 tnozaki } else if (INIT(psenc->inuse) == init) {
276 1.1 tnozaki if (ESC(init) != ch)
277 1.1 tnozaki break;
278 1.1 tnozaki candidate = init;
279 1.1 tnozaki }
280 1.1 tnozaki if (candidate == NULL) {
281 1.1 tnozaki candidate = find_escape(
282 1.1 tnozaki SET(psenc->inuse), ch);
283 1.1 tnozaki if (candidate == NULL) {
284 1.1 tnozaki if (init == NULL ||
285 1.1 tnozaki ESC(init) != ch)
286 1.1 tnozaki break;
287 1.1 tnozaki candidate = init;
288 1.1 tnozaki }
289 1.1 tnozaki }
290 1.1 tnozaki psenc->inuse = candidate;
291 1.1 tnozaki tail = psenc->chlen = 0;
292 1.1 tnozaki continue;
293 1.1 tnozaki }
294 1.1 tnozaki } else if (ch & 0x80) {
295 1.1 tnozaki if (graphic != GR(psenc->inuse))
296 1.1 tnozaki break;
297 1.1 tnozaki ch &= ~0x80;
298 1.1 tnozaki } else {
299 1.1 tnozaki if (graphic != GL(psenc->inuse))
300 1.1 tnozaki break;
301 1.1 tnozaki }
302 1.1 tnozaki _DIAGASSERT(graphic != NULL);
303 1.1 tnozaki range = &ranges[(size_t)graphic->charset];
304 1.1 tnozaki if (range->start > ch || range->end < ch)
305 1.1 tnozaki break;
306 1.1 tnozaki wc <<= 8;
307 1.1 tnozaki wc |= ch;
308 1.1 tnozaki if (graphic->length == (tail - head)) {
309 1.1 tnozaki if (graphic->charset > GB2312)
310 1.1 tnozaki bit |= ESC(psenc->inuse) << 24;
311 1.1 tnozaki wc |= bit;
312 1.1 tnozaki goto done;
313 1.1 tnozaki }
314 1.1 tnozaki }
315 1.1 tnozaki *nresult = (size_t)-1;
316 1.1 tnozaki return EILSEQ;
317 1.1 tnozaki done:
318 1.1 tnozaki if (tail < psenc->chlen)
319 1.1 tnozaki return EINVAL;
320 1.1 tnozaki *s = s0;
321 1.1 tnozaki if (pwc != NULL)
322 1.1 tnozaki *pwc = wc;
323 1.1 tnozaki psenc->chlen = 0;
324 1.1 tnozaki *nresult = (wc == 0) ? 0 : len;
325 1.1 tnozaki
326 1.1 tnozaki return 0;
327 1.1 tnozaki }
328 1.1 tnozaki
329 1.1 tnozaki static int
330 1.1 tnozaki _citrus_HZ_wcrtomb_priv(_HZEncodingInfo * __restrict ei,
331 1.1 tnozaki char * __restrict s, size_t n, wchar_t wc,
332 1.1 tnozaki _HZState * __restrict psenc, size_t * __restrict nresult)
333 1.1 tnozaki {
334 1.1 tnozaki int bit, ch;
335 1.1 tnozaki escape_t *candidate, *init;
336 1.1 tnozaki graphic_t *graphic;
337 1.1 tnozaki size_t len;
338 1.1 tnozaki const range_t *range;
339 1.1 tnozaki
340 1.1 tnozaki _DIAGASSERT(ei != NULL);
341 1.1 tnozaki _DIAGASSERT(s != NULL);
342 1.1 tnozaki _DIAGASSERT(psenc != NULL);
343 1.1 tnozaki _DIAGASSERT(nresult != NULL);
344 1.1 tnozaki
345 1.1 tnozaki if (psenc->chlen != 0 || psenc->inuse == NULL)
346 1.1 tnozaki return EINVAL;
347 1.1 tnozaki if (wc & 0x80) {
348 1.1 tnozaki bit = 0x80;
349 1.1 tnozaki wc &= ~0x80;
350 1.1 tnozaki } else {
351 1.1 tnozaki bit = 0x0;
352 1.1 tnozaki }
353 1.1 tnozaki if ((uint32_t)wc <= 0x1F) {
354 1.1 tnozaki candidate = INIT0(ei);
355 1.1 tnozaki graphic = (bit == 0)
356 1.1 tnozaki ? candidate->left : candidate->right;
357 1.1 tnozaki if (graphic == NULL)
358 1.1 tnozaki goto ilseq;
359 1.1 tnozaki range = &ranges[(size_t)CTRL];
360 1.1 tnozaki len = 1;
361 1.1 tnozaki } else if ((uint32_t)wc <= 0x7F) {
362 1.1 tnozaki graphic = ei->ascii;
363 1.1 tnozaki if (graphic == NULL)
364 1.1 tnozaki goto ilseq;
365 1.1 tnozaki candidate = graphic->escape;
366 1.1 tnozaki range = &ranges[(size_t)graphic->charset];
367 1.1 tnozaki len = graphic->length;
368 1.1 tnozaki } else if ((uint32_t)wc <= 0x7F7F) {
369 1.1 tnozaki graphic = ei->gb2312;
370 1.1 tnozaki if (graphic == NULL)
371 1.1 tnozaki goto ilseq;
372 1.1 tnozaki candidate = graphic->escape;
373 1.1 tnozaki range = &ranges[(size_t)graphic->charset];
374 1.1 tnozaki len = graphic->length;
375 1.1 tnozaki } else {
376 1.1 tnozaki ch = (wc >> 24) & 0xFF;
377 1.1 tnozaki candidate = find_escape(E0SET(ei), ch);
378 1.1 tnozaki if (candidate == NULL) {
379 1.1 tnozaki candidate = find_escape(E1SET(ei), ch);
380 1.1 tnozaki if (candidate == NULL)
381 1.1 tnozaki goto ilseq;
382 1.1 tnozaki }
383 1.1 tnozaki wc &= ~0xFF000000;
384 1.1 tnozaki graphic = (bit == 0)
385 1.1 tnozaki ? candidate->left : candidate->right;
386 1.1 tnozaki if (graphic == NULL)
387 1.1 tnozaki goto ilseq;
388 1.1 tnozaki range = &ranges[(size_t)graphic->charset];
389 1.1 tnozaki len = graphic->length;
390 1.1 tnozaki }
391 1.1 tnozaki if (psenc->inuse != candidate) {
392 1.1 tnozaki init = INIT0(ei);
393 1.1 tnozaki if (SET(psenc->inuse) == SET(candidate)) {
394 1.1 tnozaki if (INIT(psenc->inuse) != init ||
395 1.1 tnozaki psenc->inuse == init || candidate == init)
396 1.1 tnozaki init = NULL;
397 1.1 tnozaki } else if (candidate == (init = INIT(candidate))) {
398 1.1 tnozaki init = NULL;
399 1.1 tnozaki }
400 1.1 tnozaki if (init != NULL) {
401 1.1 tnozaki if (n < 2)
402 1.1 tnozaki return E2BIG;
403 1.1 tnozaki n -= 2;
404 1.1 tnozaki psenc->ch[psenc->chlen++] = ESCAPE_CHAR;
405 1.1 tnozaki psenc->ch[psenc->chlen++] = ESC(init);
406 1.1 tnozaki }
407 1.1 tnozaki if (n < 2)
408 1.1 tnozaki return E2BIG;
409 1.1 tnozaki n -= 2;
410 1.1 tnozaki psenc->ch[psenc->chlen++] = ESCAPE_CHAR;
411 1.1 tnozaki psenc->ch[psenc->chlen++] = ESC(candidate);
412 1.1 tnozaki psenc->inuse = candidate;
413 1.1 tnozaki }
414 1.1 tnozaki if (n < len)
415 1.1 tnozaki return E2BIG;
416 1.1 tnozaki while (len-- > 0) {
417 1.1 tnozaki ch = (wc >> (len * 8)) & 0xFF;
418 1.1 tnozaki if (range->start > ch || range->end < ch)
419 1.1 tnozaki goto ilseq;
420 1.1 tnozaki psenc->ch[psenc->chlen++] = ch | bit;
421 1.1 tnozaki }
422 1.1 tnozaki memcpy(s, psenc->ch, psenc->chlen);
423 1.1 tnozaki *nresult = psenc->chlen;
424 1.1 tnozaki psenc->chlen = 0;
425 1.1 tnozaki
426 1.1 tnozaki return 0;
427 1.1 tnozaki
428 1.1 tnozaki ilseq:
429 1.1 tnozaki *nresult = (size_t)-1;
430 1.1 tnozaki return EILSEQ;
431 1.1 tnozaki }
432 1.1 tnozaki
433 1.1 tnozaki static __inline int
434 1.1 tnozaki _citrus_HZ_put_state_reset(_HZEncodingInfo * __restrict ei,
435 1.1 tnozaki char * __restrict s, size_t n, _HZState * __restrict psenc,
436 1.1 tnozaki size_t * __restrict nresult)
437 1.1 tnozaki {
438 1.1 tnozaki escape_t *candidate;
439 1.1 tnozaki
440 1.1 tnozaki _DIAGASSERT(ei != NULL);
441 1.1 tnozaki _DIAGASSERT(s != NULL);
442 1.1 tnozaki _DIAGASSERT(psenc != NULL);
443 1.1 tnozaki _DIAGASSERT(nresult != NULL);
444 1.1 tnozaki
445 1.1 tnozaki if (psenc->chlen != 0 || psenc->inuse == NULL)
446 1.1 tnozaki return EINVAL;
447 1.1 tnozaki candidate = INIT0(ei);
448 1.1 tnozaki if (psenc->inuse != candidate) {
449 1.1 tnozaki if (n < 2)
450 1.1 tnozaki return E2BIG;
451 1.1 tnozaki n -= 2;
452 1.1 tnozaki psenc->ch[psenc->chlen++] = ESCAPE_CHAR;
453 1.1 tnozaki psenc->ch[psenc->chlen++] = ESC(candidate);
454 1.1 tnozaki }
455 1.1 tnozaki if (n < 1)
456 1.1 tnozaki return E2BIG;
457 1.1 tnozaki if (psenc->chlen > 0)
458 1.1 tnozaki memcpy(s, psenc->ch, psenc->chlen);
459 1.1 tnozaki *nresult = psenc->chlen;
460 1.1 tnozaki _citrus_HZ_init_state(ei, psenc);
461 1.1 tnozaki
462 1.1 tnozaki return 0;
463 1.1 tnozaki }
464 1.1 tnozaki
465 1.1 tnozaki static __inline int
466 1.1 tnozaki _citrus_HZ_stdenc_get_state_desc_generic(_HZEncodingInfo * __restrict ei,
467 1.1 tnozaki _HZState * __restrict psenc, int * __restrict rstate)
468 1.1 tnozaki {
469 1.1 tnozaki _DIAGASSERT(ei != NULL);
470 1.1 tnozaki _DIAGASSERT(psenc != NULL);
471 1.1 tnozaki _DIAGASSERT(rstate != NULL);
472 1.1 tnozaki
473 1.1 tnozaki if (psenc->chlen < 0 || psenc->inuse == NULL)
474 1.1 tnozaki return EINVAL;
475 1.1 tnozaki *rstate = (psenc->chlen == 0)
476 1.1 tnozaki ? ((psenc->inuse == INIT0(ei))
477 1.1 tnozaki ? _STDENC_SDGEN_INITIAL
478 1.1 tnozaki : _STDENC_SDGEN_STABLE)
479 1.1 tnozaki : ((psenc->ch[0] == ESCAPE_CHAR)
480 1.1 tnozaki ? _STDENC_SDGEN_INCOMPLETE_SHIFT
481 1.1 tnozaki : _STDENC_SDGEN_INCOMPLETE_CHAR);
482 1.1 tnozaki
483 1.1 tnozaki return 0;
484 1.1 tnozaki }
485 1.1 tnozaki
486 1.1 tnozaki static __inline int
487 1.1 tnozaki /*ARGSUSED*/
488 1.1 tnozaki _citrus_HZ_stdenc_wctocs(_HZEncodingInfo * __restrict ei,
489 1.1 tnozaki _csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc)
490 1.1 tnozaki {
491 1.1 tnozaki int bit;
492 1.1 tnozaki
493 1.1 tnozaki _DIAGASSERT(csid != NULL);
494 1.1 tnozaki _DIAGASSERT(idx != NULL);
495 1.1 tnozaki
496 1.1 tnozaki if (wc & 0x80) {
497 1.1 tnozaki bit = 0x80;
498 1.1 tnozaki wc &= ~0x80;
499 1.1 tnozaki } else {
500 1.1 tnozaki bit = 0x0;
501 1.1 tnozaki }
502 1.1 tnozaki if ((uint32_t)wc <= 0x7F) {
503 1.1 tnozaki *csid = (_csid_t)bit;
504 1.1 tnozaki *idx = (_index_t)wc;
505 1.1 tnozaki } else if ((uint32_t)wc <= 0x7F7F) {
506 1.1 tnozaki *csid = (_csid_t)(bit | 0x8000);
507 1.1 tnozaki *idx = (_index_t)wc;
508 1.1 tnozaki } else {
509 1.1 tnozaki *csid = (_index_t)(wc & ~0x00FFFF7F);
510 1.1 tnozaki *idx = (_csid_t)(wc & 0x00FFFF7F);
511 1.1 tnozaki }
512 1.1 tnozaki
513 1.1 tnozaki return 0;
514 1.1 tnozaki }
515 1.1 tnozaki
516 1.1 tnozaki static __inline int
517 1.1 tnozaki /*ARGSUSED*/
518 1.1 tnozaki _citrus_HZ_stdenc_cstowc(_HZEncodingInfo * __restrict ei,
519 1.1 tnozaki wchar_t * __restrict wc, _csid_t csid, _index_t idx)
520 1.1 tnozaki {
521 1.1 tnozaki _DIAGASSERT(ei != NULL);
522 1.1 tnozaki _DIAGASSERT(wc != NULL);
523 1.1 tnozaki
524 1.1 tnozaki *wc = (wchar_t)idx;
525 1.1 tnozaki switch (csid) {
526 1.1 tnozaki case 0x80:
527 1.1 tnozaki case 0x8080:
528 1.1 tnozaki *wc |= (wchar_t)0x80;
529 1.1 tnozaki /*FALLTHROUGH*/
530 1.1 tnozaki case 0x0:
531 1.1 tnozaki case 0x8000:
532 1.1 tnozaki break;
533 1.1 tnozaki default:
534 1.1 tnozaki *wc |= (wchar_t)csid;
535 1.1 tnozaki }
536 1.1 tnozaki
537 1.1 tnozaki return 0;
538 1.1 tnozaki }
539 1.1 tnozaki
540 1.1 tnozaki static void
541 1.1 tnozaki _citrus_HZ_encoding_module_uninit(_HZEncodingInfo *ei)
542 1.1 tnozaki {
543 1.1 tnozaki escape_t *escape;
544 1.1 tnozaki
545 1.1 tnozaki _DIAGASSERT(ei != NULL);
546 1.1 tnozaki while ((escape = TAILQ_FIRST(E0SET(ei))) != NULL) {
547 1.1 tnozaki TAILQ_REMOVE(E0SET(ei), escape, entry);
548 1.1 tnozaki free(GL(escape));
549 1.1 tnozaki free(GR(escape));
550 1.1 tnozaki free(escape);
551 1.1 tnozaki }
552 1.1 tnozaki while ((escape = TAILQ_FIRST(E1SET(ei))) != NULL) {
553 1.1 tnozaki TAILQ_REMOVE(E1SET(ei), escape, entry);
554 1.1 tnozaki free(GL(escape));
555 1.1 tnozaki free(GR(escape));
556 1.1 tnozaki free(escape);
557 1.1 tnozaki }
558 1.1 tnozaki }
559 1.1 tnozaki
560 1.1 tnozaki static int
561 1.1 tnozaki _citrus_HZ_parse_char(void **context, const char *name, const char *s)
562 1.1 tnozaki {
563 1.1 tnozaki void **p;
564 1.1 tnozaki escape_t *escape;
565 1.1 tnozaki
566 1.1 tnozaki _DIAGASSERT(context != NULL && *context != NULL);
567 1.1 tnozaki _DIAGASSERT(name != NULL);
568 1.1 tnozaki _DIAGASSERT(s != NULL);
569 1.1 tnozaki
570 1.1 tnozaki p = (void **)*context;
571 1.1 tnozaki escape = (escape_t *)p[0];
572 1.1 tnozaki if (escape->ch != '\0')
573 1.1 tnozaki return EINVAL;
574 1.1 tnozaki escape->ch = *s++;
575 1.1 tnozaki if (escape->ch == ESCAPE_CHAR || *s != '\0')
576 1.1 tnozaki return EINVAL;
577 1.1 tnozaki
578 1.1 tnozaki return 0;
579 1.1 tnozaki }
580 1.1 tnozaki
581 1.1 tnozaki static int
582 1.1 tnozaki _citrus_HZ_parse_graphic(void **context, const char *name, const char *s)
583 1.1 tnozaki {
584 1.1 tnozaki void **p;
585 1.1 tnozaki _HZEncodingInfo *ei;
586 1.1 tnozaki escape_t *escape;
587 1.1 tnozaki graphic_t *graphic;
588 1.1 tnozaki
589 1.1 tnozaki _DIAGASSERT(context != NULL && *context != NULL);
590 1.1 tnozaki _DIAGASSERT(name != NULL);
591 1.1 tnozaki _DIAGASSERT(s != NULL);
592 1.1 tnozaki
593 1.1 tnozaki p = (void **)*context;
594 1.1 tnozaki escape = (escape_t *)p[0];
595 1.1 tnozaki ei = (_HZEncodingInfo *)p[1];
596 1.1 tnozaki graphic = malloc(sizeof(*graphic));
597 1.1 tnozaki if (graphic == NULL)
598 1.1 tnozaki return ENOMEM;
599 1.1 tnozaki memset(graphic, 0, sizeof(*graphic));
600 1.1 tnozaki if (strcmp("GL", name) == 0) {
601 1.1 tnozaki if (GL(escape) != NULL)
602 1.1 tnozaki goto release;
603 1.1 tnozaki GL(escape) = graphic;
604 1.1 tnozaki } else if (strcmp("GR", name) == 0) {
605 1.1 tnozaki if (GR(escape) != NULL)
606 1.1 tnozaki goto release;
607 1.1 tnozaki GR(escape) = graphic;
608 1.1 tnozaki } else {
609 1.1 tnozaki release:
610 1.1 tnozaki free(graphic);
611 1.1 tnozaki return EINVAL;
612 1.1 tnozaki }
613 1.1 tnozaki graphic->escape = escape;
614 1.1 tnozaki if (_bcs_strncasecmp("ASCII", s, 5) == 0) {
615 1.1 tnozaki if (s[5] != '\0')
616 1.1 tnozaki return EINVAL;
617 1.1 tnozaki graphic->charset = ASCII;
618 1.1 tnozaki graphic->length = 1;
619 1.1 tnozaki ei->ascii = graphic;
620 1.1 tnozaki return 0;
621 1.1 tnozaki } else if (_bcs_strncasecmp("GB2312", s, 6) == 0) {
622 1.1 tnozaki if (s[6] != '\0')
623 1.1 tnozaki return EINVAL;
624 1.1 tnozaki graphic->charset = GB2312;
625 1.1 tnozaki graphic->length = 2;
626 1.1 tnozaki ei->gb2312 = graphic;
627 1.1 tnozaki return 0;
628 1.1 tnozaki } else if (strncmp("94*", s, 3) == 0) {
629 1.1 tnozaki graphic->charset = CS94;
630 1.1 tnozaki } else if (strncmp("96*", s, 3) == 0) {
631 1.1 tnozaki graphic->charset = CS96;
632 1.1 tnozaki } else {
633 1.1 tnozaki return EINVAL;
634 1.1 tnozaki }
635 1.1 tnozaki s += 3;
636 1.1 tnozaki switch(*s) {
637 1.1 tnozaki case '1': case '2': case '3':
638 1.1 tnozaki graphic->length = (size_t)(*s - '0');
639 1.1 tnozaki if (*++s == '\0')
640 1.1 tnozaki break;
641 1.1 tnozaki /*FALLTHROUGH*/
642 1.1 tnozaki default:
643 1.1 tnozaki return EINVAL;
644 1.1 tnozaki }
645 1.1 tnozaki return 0;
646 1.1 tnozaki }
647 1.1 tnozaki
648 1.1 tnozaki static const _citrus_prop_hint_t escape_hints[] = {
649 1.1 tnozaki _CITRUS_PROP_HINT_STR("CH", &_citrus_HZ_parse_char),
650 1.1 tnozaki _CITRUS_PROP_HINT_STR("GL", &_citrus_HZ_parse_graphic),
651 1.1 tnozaki _CITRUS_PROP_HINT_STR("GR", &_citrus_HZ_parse_graphic),
652 1.1 tnozaki _CITRUS_PROP_HINT_END
653 1.1 tnozaki };
654 1.1 tnozaki
655 1.1 tnozaki static int
656 1.1 tnozaki _citrus_HZ_parse_escape(void **context, const char *name, const char *s)
657 1.1 tnozaki {
658 1.1 tnozaki _HZEncodingInfo *ei;
659 1.1 tnozaki escape_t *escape;
660 1.1 tnozaki void *p[2];
661 1.1 tnozaki
662 1.1 tnozaki _DIAGASSERT(context != NULL);
663 1.1 tnozaki _DIAGASSERT(name != NULL);
664 1.1 tnozaki _DIAGASSERT(s != NULL);
665 1.1 tnozaki
666 1.1 tnozaki ei = (_HZEncodingInfo *)*context;
667 1.1 tnozaki escape = malloc(sizeof(*escape));
668 1.1 tnozaki if (escape == NULL)
669 1.1 tnozaki return EINVAL;
670 1.1 tnozaki memset(escape, 0, sizeof(*escape));
671 1.1 tnozaki if (strcmp("0", name) == 0) {
672 1.1 tnozaki escape->set = E0SET(ei);
673 1.1 tnozaki TAILQ_INSERT_TAIL(E0SET(ei), escape, entry);
674 1.1 tnozaki } else if (strcmp("1", name) == 0) {
675 1.1 tnozaki escape->set = E1SET(ei);
676 1.1 tnozaki TAILQ_INSERT_TAIL(E1SET(ei), escape, entry);
677 1.1 tnozaki } else {
678 1.1 tnozaki free(escape);
679 1.1 tnozaki return EINVAL;
680 1.1 tnozaki }
681 1.1 tnozaki p[0] = (void *)escape;
682 1.1 tnozaki p[1] = (void *)ei;
683 1.1 tnozaki return _citrus_prop_parse_variable(
684 1.1 tnozaki escape_hints, (void *)&p[0], s, strlen(s));
685 1.1 tnozaki }
686 1.1 tnozaki
687 1.1 tnozaki static const _citrus_prop_hint_t root_hints[] = {
688 1.1 tnozaki _CITRUS_PROP_HINT_STR("0", &_citrus_HZ_parse_escape),
689 1.1 tnozaki _CITRUS_PROP_HINT_STR("1", &_citrus_HZ_parse_escape),
690 1.1 tnozaki _CITRUS_PROP_HINT_END
691 1.1 tnozaki };
692 1.1 tnozaki
693 1.1 tnozaki static int
694 1.1 tnozaki _citrus_HZ_encoding_module_init(_HZEncodingInfo * __restrict ei,
695 1.1 tnozaki const void * __restrict var, size_t lenvar)
696 1.1 tnozaki {
697 1.1 tnozaki int errnum;
698 1.1 tnozaki
699 1.1 tnozaki _DIAGASSERT(ei != NULL);
700 1.1 tnozaki
701 1.1 tnozaki memset(ei, 0, sizeof(*ei));
702 1.1 tnozaki TAILQ_INIT(E0SET(ei));
703 1.1 tnozaki TAILQ_INIT(E1SET(ei));
704 1.1 tnozaki errnum = _citrus_prop_parse_variable(
705 1.1 tnozaki root_hints, (void *)ei, var, lenvar);
706 1.1 tnozaki if (errnum != 0)
707 1.1 tnozaki _citrus_HZ_encoding_module_uninit(ei);
708 1.1 tnozaki return errnum;
709 1.1 tnozaki }
710 1.1 tnozaki
711 1.1 tnozaki /* ----------------------------------------------------------------------
712 1.1 tnozaki * public interface for ctype
713 1.1 tnozaki */
714 1.1 tnozaki
715 1.1 tnozaki _CITRUS_CTYPE_DECLS(HZ);
716 1.1 tnozaki _CITRUS_CTYPE_DEF_OPS(HZ);
717 1.1 tnozaki
718 1.1 tnozaki #include "citrus_ctype_template.h"
719 1.1 tnozaki
720 1.1 tnozaki /* ----------------------------------------------------------------------
721 1.1 tnozaki * public interface for stdenc
722 1.1 tnozaki */
723 1.1 tnozaki
724 1.1 tnozaki _CITRUS_STDENC_DECLS(HZ);
725 1.1 tnozaki _CITRUS_STDENC_DEF_OPS(HZ);
726 1.1 tnozaki
727 1.1 tnozaki #include "citrus_stdenc_template.h"
728