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