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