1bdcf3f2bSJohn Marino /* $FreeBSD: head/lib/libiconv_modules/HZ/citrus_hz.c 281550 2015-04-15 09:09:20Z tijl $ */
20d5acd74SJohn Marino /* $NetBSD: citrus_hz.c,v 1.2 2008/06/14 16:01:07 tnozaki Exp $ */
30d5acd74SJohn Marino
40d5acd74SJohn Marino /*-
50d5acd74SJohn Marino * Copyright (c)2004, 2006 Citrus Project,
60d5acd74SJohn Marino * All rights reserved.
70d5acd74SJohn Marino *
80d5acd74SJohn Marino * Redistribution and use in source and binary forms, with or without
90d5acd74SJohn Marino * modification, are permitted provided that the following conditions
100d5acd74SJohn Marino * are met:
110d5acd74SJohn Marino * 1. Redistributions of source code must retain the above copyright
120d5acd74SJohn Marino * notice, this list of conditions and the following disclaimer.
130d5acd74SJohn Marino * 2. Redistributions in binary form must reproduce the above copyright
140d5acd74SJohn Marino * notice, this list of conditions and the following disclaimer in the
150d5acd74SJohn Marino * documentation and/or other materials provided with the distribution.
160d5acd74SJohn Marino *
170d5acd74SJohn Marino * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
180d5acd74SJohn Marino * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190d5acd74SJohn Marino * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200d5acd74SJohn Marino * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
210d5acd74SJohn Marino * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
220d5acd74SJohn Marino * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
230d5acd74SJohn Marino * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
240d5acd74SJohn Marino * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
250d5acd74SJohn Marino * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
260d5acd74SJohn Marino * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
270d5acd74SJohn Marino * SUCH DAMAGE.
280d5acd74SJohn Marino *
290d5acd74SJohn Marino */
300d5acd74SJohn Marino
310d5acd74SJohn Marino #include <sys/cdefs.h>
320d5acd74SJohn Marino #include <sys/queue.h>
330d5acd74SJohn Marino #include <sys/types.h>
340d5acd74SJohn Marino
350d5acd74SJohn Marino #include <assert.h>
360d5acd74SJohn Marino #include <errno.h>
370d5acd74SJohn Marino #include <limits.h>
380d5acd74SJohn Marino #include <stddef.h>
390d5acd74SJohn Marino #include <stdint.h>
400d5acd74SJohn Marino #include <stdlib.h>
410d5acd74SJohn Marino #include <string.h>
420d5acd74SJohn Marino #include <wchar.h>
430d5acd74SJohn Marino
440d5acd74SJohn Marino #include "citrus_namespace.h"
450d5acd74SJohn Marino #include "citrus_types.h"
460d5acd74SJohn Marino #include "citrus_bcs.h"
470d5acd74SJohn Marino #include "citrus_module.h"
480d5acd74SJohn Marino #include "citrus_stdenc.h"
490d5acd74SJohn Marino
500d5acd74SJohn Marino #include "citrus_hz.h"
510d5acd74SJohn Marino #include "citrus_prop.h"
520d5acd74SJohn Marino
530d5acd74SJohn Marino /*
540d5acd74SJohn Marino * wchar_t mapping:
550d5acd74SJohn Marino *
560d5acd74SJohn Marino * CTRL/ASCII 00000000 00000000 00000000 gxxxxxxx
570d5acd74SJohn Marino * GB2312 00000000 00000000 0xxxxxxx gxxxxxxx
580d5acd74SJohn Marino * 94/96*n (~M) 0mmmmmmm 0xxxxxxx 0xxxxxxx gxxxxxxx
590d5acd74SJohn Marino */
600d5acd74SJohn Marino
610d5acd74SJohn Marino #define ESCAPE_CHAR '~'
620d5acd74SJohn Marino
630d5acd74SJohn Marino typedef enum {
640d5acd74SJohn Marino CTRL = 0, ASCII = 1, GB2312 = 2, CS94 = 3, CS96 = 4
650d5acd74SJohn Marino } charset_t;
660d5acd74SJohn Marino
670d5acd74SJohn Marino typedef struct {
680d5acd74SJohn Marino int start;
690db70a6aSJohn Marino int end;
700d5acd74SJohn Marino int width;
710d5acd74SJohn Marino } range_t;
720d5acd74SJohn Marino
730d5acd74SJohn Marino static const range_t ranges[] = {
740d5acd74SJohn Marino #define RANGE(start, end) { start, end, (end - start) + 1 }
750d5acd74SJohn Marino /* CTRL */ RANGE(0x00, 0x1F),
760d5acd74SJohn Marino /* ASCII */ RANGE(0x20, 0x7F),
770d5acd74SJohn Marino /* GB2312 */ RANGE(0x21, 0x7E),
780d5acd74SJohn Marino /* CS94 */ RANGE(0x21, 0x7E),
790d5acd74SJohn Marino /* CS96 */ RANGE(0x20, 0x7F),
800d5acd74SJohn Marino #undef RANGE
810d5acd74SJohn Marino };
820d5acd74SJohn Marino
830d5acd74SJohn Marino typedef struct escape_t escape_t;
840d5acd74SJohn Marino typedef struct {
850d5acd74SJohn Marino charset_t charset;
860d5acd74SJohn Marino escape_t *escape;
870d5acd74SJohn Marino ssize_t length;
880d5acd74SJohn Marino #define ROWCOL_MAX 3
890d5acd74SJohn Marino } graphic_t;
900d5acd74SJohn Marino
910d5acd74SJohn Marino typedef TAILQ_HEAD(escape_list, escape_t) escape_list;
920d5acd74SJohn Marino struct escape_t {
930d5acd74SJohn Marino TAILQ_ENTRY(escape_t) entry;
940d5acd74SJohn Marino escape_list *set;
950d5acd74SJohn Marino graphic_t *left;
960d5acd74SJohn Marino graphic_t *right;
970d5acd74SJohn Marino int ch;
980d5acd74SJohn Marino };
990d5acd74SJohn Marino
1000d5acd74SJohn Marino #define GL(escape) ((escape)->left)
1010d5acd74SJohn Marino #define GR(escape) ((escape)->right)
1020d5acd74SJohn Marino #define SET(escape) ((escape)->set)
1030d5acd74SJohn Marino #define ESC(escape) ((escape)->ch)
1040d5acd74SJohn Marino #define INIT(escape) (TAILQ_FIRST(SET(escape)))
1050d5acd74SJohn Marino
1060d5acd74SJohn Marino static __inline escape_t *
find_escape(escape_list * set,int ch)1070d5acd74SJohn Marino find_escape(escape_list *set, int ch)
1080d5acd74SJohn Marino {
1090d5acd74SJohn Marino escape_t *escape;
1100d5acd74SJohn Marino
1110d5acd74SJohn Marino TAILQ_FOREACH(escape, set, entry) {
1120d5acd74SJohn Marino if (ESC(escape) == ch)
1130d5acd74SJohn Marino break;
1140d5acd74SJohn Marino }
1150d5acd74SJohn Marino
1160d5acd74SJohn Marino return (escape);
1170d5acd74SJohn Marino }
1180d5acd74SJohn Marino
1190d5acd74SJohn Marino typedef struct {
1200d5acd74SJohn Marino escape_list e0;
1210d5acd74SJohn Marino escape_list e1;
1220d5acd74SJohn Marino graphic_t *ascii;
1230d5acd74SJohn Marino graphic_t *gb2312;
1240d5acd74SJohn Marino } _HZEncodingInfo;
1250d5acd74SJohn Marino
1260d5acd74SJohn Marino #define E0SET(ei) (&(ei)->e0)
1270d5acd74SJohn Marino #define E1SET(ei) (&(ei)->e1)
1280d5acd74SJohn Marino #define INIT0(ei) (TAILQ_FIRST(E0SET(ei)))
1290d5acd74SJohn Marino #define INIT1(ei) (TAILQ_FIRST(E1SET(ei)))
1300d5acd74SJohn Marino
1310d5acd74SJohn Marino typedef struct {
1320d5acd74SJohn Marino escape_t *inuse;
1330d5acd74SJohn Marino int chlen;
1340d5acd74SJohn Marino char ch[ROWCOL_MAX];
1350d5acd74SJohn Marino } _HZState;
1360d5acd74SJohn Marino
1370d5acd74SJohn Marino #define _CEI_TO_EI(_cei_) (&(_cei_)->ei)
1380d5acd74SJohn Marino #define _CEI_TO_STATE(_cei_, _func_) (_cei_)->states.s_##_func_
1390d5acd74SJohn Marino
1400d5acd74SJohn Marino #define _FUNCNAME(m) _citrus_HZ_##m
1410d5acd74SJohn Marino #define _ENCODING_INFO _HZEncodingInfo
1420d5acd74SJohn Marino #define _ENCODING_STATE _HZState
1430d5acd74SJohn Marino #define _ENCODING_MB_CUR_MAX(_ei_) MB_LEN_MAX
1440d5acd74SJohn Marino #define _ENCODING_IS_STATE_DEPENDENT 1
1450d5acd74SJohn Marino #define _STATE_NEEDS_EXPLICIT_INIT(_ps_) ((_ps_)->inuse == NULL)
1460d5acd74SJohn Marino
1470d5acd74SJohn Marino static __inline void
_citrus_HZ_init_state(_HZEncodingInfo * __restrict ei,_HZState * __restrict psenc)1480d5acd74SJohn Marino _citrus_HZ_init_state(_HZEncodingInfo * __restrict ei,
1490d5acd74SJohn Marino _HZState * __restrict psenc)
1500d5acd74SJohn Marino {
1510d5acd74SJohn Marino
1520d5acd74SJohn Marino psenc->chlen = 0;
1530d5acd74SJohn Marino psenc->inuse = INIT0(ei);
1540d5acd74SJohn Marino }
1550d5acd74SJohn Marino
156*71ea2de5SJohn Marino #if 0
1570d5acd74SJohn Marino static __inline void
1580d5acd74SJohn Marino /*ARGSUSED*/
1590d5acd74SJohn Marino _citrus_HZ_pack_state(_HZEncodingInfo * __restrict ei __unused,
1600d5acd74SJohn Marino void *__restrict pspriv, const _HZState * __restrict psenc)
1610d5acd74SJohn Marino {
1620d5acd74SJohn Marino
1630d5acd74SJohn Marino memcpy(pspriv, (const void *)psenc, sizeof(*psenc));
1640d5acd74SJohn Marino }
1650d5acd74SJohn Marino
1660d5acd74SJohn Marino static __inline void
1670d5acd74SJohn Marino /*ARGSUSED*/
1680d5acd74SJohn Marino _citrus_HZ_unpack_state(_HZEncodingInfo * __restrict ei __unused,
1690d5acd74SJohn Marino _HZState * __restrict psenc, const void * __restrict pspriv)
1700d5acd74SJohn Marino {
1710d5acd74SJohn Marino
1720d5acd74SJohn Marino memcpy((void *)psenc, pspriv, sizeof(*psenc));
1730d5acd74SJohn Marino }
174*71ea2de5SJohn Marino #endif
1750d5acd74SJohn Marino
1760d5acd74SJohn Marino 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)1770d5acd74SJohn Marino _citrus_HZ_mbrtowc_priv(_HZEncodingInfo * __restrict ei,
1780db70a6aSJohn Marino wchar_t * __restrict pwc, char ** __restrict s, size_t n,
1790d5acd74SJohn Marino _HZState * __restrict psenc, size_t * __restrict nresult)
1800d5acd74SJohn Marino {
1810d5acd74SJohn Marino escape_t *candidate, *init;
1820d5acd74SJohn Marino graphic_t *graphic;
1830d5acd74SJohn Marino const range_t *range;
1840db70a6aSJohn Marino char *s0;
1850d5acd74SJohn Marino wchar_t wc;
1860d5acd74SJohn Marino int bit, ch, head, len, tail;
1870d5acd74SJohn Marino
1880d5acd74SJohn Marino if (*s == NULL) {
1890d5acd74SJohn Marino _citrus_HZ_init_state(ei, psenc);
1900d5acd74SJohn Marino *nresult = 1;
1910d5acd74SJohn Marino return (0);
1920d5acd74SJohn Marino }
1930d5acd74SJohn Marino s0 = *s;
1940d5acd74SJohn Marino if (psenc->chlen < 0 || psenc->inuse == NULL)
1950d5acd74SJohn Marino return (EINVAL);
1960d5acd74SJohn Marino
1970d5acd74SJohn Marino wc = (wchar_t)0;
1980d5acd74SJohn Marino bit = head = tail = 0;
1990d5acd74SJohn Marino graphic = NULL;
2000d5acd74SJohn Marino for (len = 0; len <= MB_LEN_MAX;) {
2010d5acd74SJohn Marino if (psenc->chlen == tail) {
2020d5acd74SJohn Marino if (n-- < 1) {
2030d5acd74SJohn Marino *s = s0;
2040d5acd74SJohn Marino *nresult = (size_t)-2;
2050d5acd74SJohn Marino return (0);
2060d5acd74SJohn Marino }
2070d5acd74SJohn Marino psenc->ch[psenc->chlen++] = *s0++;
2080d5acd74SJohn Marino ++len;
2090d5acd74SJohn Marino }
2100d5acd74SJohn Marino ch = (unsigned char)psenc->ch[tail++];
2110d5acd74SJohn Marino if (tail == 1) {
2120d5acd74SJohn Marino if ((ch & ~0x80) <= 0x1F) {
2130d5acd74SJohn Marino if (psenc->inuse != INIT0(ei))
2140d5acd74SJohn Marino break;
2150d5acd74SJohn Marino wc = (wchar_t)ch;
2160d5acd74SJohn Marino goto done;
2170d5acd74SJohn Marino }
2180d5acd74SJohn Marino if (ch & 0x80) {
2190d5acd74SJohn Marino graphic = GR(psenc->inuse);
2200d5acd74SJohn Marino bit = 0x80;
2210d5acd74SJohn Marino ch &= ~0x80;
2220d5acd74SJohn Marino } else {
2230d5acd74SJohn Marino graphic = GL(psenc->inuse);
2240d5acd74SJohn Marino if (ch == ESCAPE_CHAR)
2250d5acd74SJohn Marino continue;
2260d5acd74SJohn Marino bit = 0x0;
2270d5acd74SJohn Marino }
2280d5acd74SJohn Marino if (graphic == NULL)
2290d5acd74SJohn Marino break;
2300d5acd74SJohn Marino } else if (tail == 2 && psenc->ch[0] == ESCAPE_CHAR) {
2310d5acd74SJohn Marino if (tail < psenc->chlen)
2320d5acd74SJohn Marino return (EINVAL);
2330d5acd74SJohn Marino if (ch == ESCAPE_CHAR) {
2340d5acd74SJohn Marino ++head;
2350d5acd74SJohn Marino } else if (ch == '\n') {
2360d5acd74SJohn Marino if (psenc->inuse != INIT0(ei))
2370d5acd74SJohn Marino break;
2380d5acd74SJohn Marino tail = psenc->chlen = 0;
2390d5acd74SJohn Marino continue;
2400d5acd74SJohn Marino } else {
2410d5acd74SJohn Marino candidate = NULL;
2420d5acd74SJohn Marino init = INIT0(ei);
2430d5acd74SJohn Marino if (psenc->inuse == init) {
2440d5acd74SJohn Marino init = INIT1(ei);
2450d5acd74SJohn Marino } else if (INIT(psenc->inuse) == init) {
2460d5acd74SJohn Marino if (ESC(init) != ch)
2470d5acd74SJohn Marino break;
2480d5acd74SJohn Marino candidate = init;
2490d5acd74SJohn Marino }
2500d5acd74SJohn Marino if (candidate == NULL) {
2510d5acd74SJohn Marino candidate = find_escape(
2520d5acd74SJohn Marino SET(psenc->inuse), ch);
2530d5acd74SJohn Marino if (candidate == NULL) {
2540d5acd74SJohn Marino if (init == NULL ||
2550d5acd74SJohn Marino ESC(init) != ch)
2560d5acd74SJohn Marino break;
2570d5acd74SJohn Marino candidate = init;
2580d5acd74SJohn Marino }
2590d5acd74SJohn Marino }
2600d5acd74SJohn Marino psenc->inuse = candidate;
2610d5acd74SJohn Marino tail = psenc->chlen = 0;
2620d5acd74SJohn Marino continue;
2630d5acd74SJohn Marino }
2640d5acd74SJohn Marino } else if (ch & 0x80) {
2650d5acd74SJohn Marino if (graphic != GR(psenc->inuse))
2660d5acd74SJohn Marino break;
2670d5acd74SJohn Marino ch &= ~0x80;
2680d5acd74SJohn Marino } else {
2690d5acd74SJohn Marino if (graphic != GL(psenc->inuse))
2700d5acd74SJohn Marino break;
2710d5acd74SJohn Marino }
2720d5acd74SJohn Marino range = &ranges[(size_t)graphic->charset];
2730d5acd74SJohn Marino if (range->start > ch || range->end < ch)
2740d5acd74SJohn Marino break;
2750d5acd74SJohn Marino wc <<= 8;
2760d5acd74SJohn Marino wc |= ch;
2770d5acd74SJohn Marino if (graphic->length == (tail - head)) {
2780d5acd74SJohn Marino if (graphic->charset > GB2312)
2790d5acd74SJohn Marino bit |= ESC(psenc->inuse) << 24;
2800d5acd74SJohn Marino wc |= bit;
2810d5acd74SJohn Marino goto done;
2820d5acd74SJohn Marino }
2830d5acd74SJohn Marino }
2840d5acd74SJohn Marino *nresult = (size_t)-1;
2850d5acd74SJohn Marino return (EILSEQ);
2860d5acd74SJohn Marino done:
2870d5acd74SJohn Marino if (tail < psenc->chlen)
2880d5acd74SJohn Marino return (EINVAL);
2890d5acd74SJohn Marino *s = s0;
2900d5acd74SJohn Marino if (pwc != NULL)
2910d5acd74SJohn Marino *pwc = wc;
2920d5acd74SJohn Marino psenc->chlen = 0;
2930d5acd74SJohn Marino *nresult = (wc == 0) ? 0 : len;
2940d5acd74SJohn Marino
2950d5acd74SJohn Marino return (0);
2960d5acd74SJohn Marino }
2970d5acd74SJohn Marino
2980d5acd74SJohn Marino 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)2990d5acd74SJohn Marino _citrus_HZ_wcrtomb_priv(_HZEncodingInfo * __restrict ei,
3000d5acd74SJohn Marino char * __restrict s, size_t n, wchar_t wc,
3010d5acd74SJohn Marino _HZState * __restrict psenc, size_t * __restrict nresult)
3020d5acd74SJohn Marino {
3030d5acd74SJohn Marino escape_t *candidate, *init;
3040d5acd74SJohn Marino graphic_t *graphic;
3050d5acd74SJohn Marino const range_t *range;
3060d5acd74SJohn Marino size_t len;
3070d5acd74SJohn Marino int bit, ch;
3080d5acd74SJohn Marino
3090d5acd74SJohn Marino if (psenc->chlen != 0 || psenc->inuse == NULL)
3100d5acd74SJohn Marino return (EINVAL);
3110d5acd74SJohn Marino if (wc & 0x80) {
3120d5acd74SJohn Marino bit = 0x80;
3130d5acd74SJohn Marino wc &= ~0x80;
3140d5acd74SJohn Marino } else {
3150d5acd74SJohn Marino bit = 0x0;
3160d5acd74SJohn Marino }
3170d5acd74SJohn Marino if ((uint32_t)wc <= 0x1F) {
3180d5acd74SJohn Marino candidate = INIT0(ei);
3190d5acd74SJohn Marino graphic = (bit == 0) ? candidate->left : candidate->right;
3200d5acd74SJohn Marino if (graphic == NULL)
3210d5acd74SJohn Marino goto ilseq;
3220d5acd74SJohn Marino range = &ranges[(size_t)CTRL];
3230d5acd74SJohn Marino len = 1;
3240d5acd74SJohn Marino } else if ((uint32_t)wc <= 0x7F) {
3250d5acd74SJohn Marino graphic = ei->ascii;
3260d5acd74SJohn Marino if (graphic == NULL)
3270d5acd74SJohn Marino goto ilseq;
3280d5acd74SJohn Marino candidate = graphic->escape;
3290d5acd74SJohn Marino range = &ranges[(size_t)graphic->charset];
3300d5acd74SJohn Marino len = graphic->length;
3310d5acd74SJohn Marino } else if ((uint32_t)wc <= 0x7F7F) {
3320d5acd74SJohn Marino graphic = ei->gb2312;
3330d5acd74SJohn Marino if (graphic == NULL)
3340d5acd74SJohn Marino goto ilseq;
3350d5acd74SJohn Marino candidate = graphic->escape;
3360d5acd74SJohn Marino range = &ranges[(size_t)graphic->charset];
3370d5acd74SJohn Marino len = graphic->length;
3380d5acd74SJohn Marino } else {
3390d5acd74SJohn Marino ch = (wc >> 24) & 0xFF;
3400d5acd74SJohn Marino candidate = find_escape(E0SET(ei), ch);
3410d5acd74SJohn Marino if (candidate == NULL) {
3420d5acd74SJohn Marino candidate = find_escape(E1SET(ei), ch);
3430d5acd74SJohn Marino if (candidate == NULL)
3440d5acd74SJohn Marino goto ilseq;
3450d5acd74SJohn Marino }
3460d5acd74SJohn Marino wc &= ~0xFF000000;
3470d5acd74SJohn Marino graphic = (bit == 0) ? candidate->left : candidate->right;
3480d5acd74SJohn Marino if (graphic == NULL)
3490d5acd74SJohn Marino goto ilseq;
3500d5acd74SJohn Marino range = &ranges[(size_t)graphic->charset];
3510d5acd74SJohn Marino len = graphic->length;
3520d5acd74SJohn Marino }
3530d5acd74SJohn Marino if (psenc->inuse != candidate) {
3540d5acd74SJohn Marino init = INIT0(ei);
3550d5acd74SJohn Marino if (SET(psenc->inuse) == SET(candidate)) {
3560d5acd74SJohn Marino if (INIT(psenc->inuse) != init ||
3570d5acd74SJohn Marino psenc->inuse == init || candidate == init)
3580d5acd74SJohn Marino init = NULL;
3590d5acd74SJohn Marino } else if (candidate == (init = INIT(candidate))) {
3600d5acd74SJohn Marino init = NULL;
3610d5acd74SJohn Marino }
3620d5acd74SJohn Marino if (init != NULL) {
3630d5acd74SJohn Marino if (n < 2)
3640d5acd74SJohn Marino return (E2BIG);
3650d5acd74SJohn Marino n -= 2;
3660d5acd74SJohn Marino psenc->ch[psenc->chlen++] = ESCAPE_CHAR;
3670d5acd74SJohn Marino psenc->ch[psenc->chlen++] = ESC(init);
3680d5acd74SJohn Marino }
3690d5acd74SJohn Marino if (n < 2)
3700d5acd74SJohn Marino return (E2BIG);
3710d5acd74SJohn Marino n -= 2;
3720d5acd74SJohn Marino psenc->ch[psenc->chlen++] = ESCAPE_CHAR;
3730d5acd74SJohn Marino psenc->ch[psenc->chlen++] = ESC(candidate);
3740d5acd74SJohn Marino psenc->inuse = candidate;
3750d5acd74SJohn Marino }
3760d5acd74SJohn Marino if (n < len)
3770d5acd74SJohn Marino return (E2BIG);
3780d5acd74SJohn Marino while (len-- > 0) {
3790d5acd74SJohn Marino ch = (wc >> (len * 8)) & 0xFF;
3800d5acd74SJohn Marino if (range->start > ch || range->end < ch)
3810d5acd74SJohn Marino goto ilseq;
3820d5acd74SJohn Marino psenc->ch[psenc->chlen++] = ch | bit;
3830d5acd74SJohn Marino }
3840d5acd74SJohn Marino memcpy(s, psenc->ch, psenc->chlen);
3850d5acd74SJohn Marino *nresult = psenc->chlen;
3860d5acd74SJohn Marino psenc->chlen = 0;
3870d5acd74SJohn Marino
3880d5acd74SJohn Marino return (0);
3890d5acd74SJohn Marino
3900d5acd74SJohn Marino ilseq:
3910d5acd74SJohn Marino *nresult = (size_t)-1;
3920d5acd74SJohn Marino return (EILSEQ);
3930d5acd74SJohn Marino }
3940d5acd74SJohn Marino
3950d5acd74SJohn Marino static __inline int
_citrus_HZ_put_state_reset(_HZEncodingInfo * __restrict ei,char * __restrict s,size_t n,_HZState * __restrict psenc,size_t * __restrict nresult)3960d5acd74SJohn Marino _citrus_HZ_put_state_reset(_HZEncodingInfo * __restrict ei,
3970d5acd74SJohn Marino char * __restrict s, size_t n, _HZState * __restrict psenc,
3980d5acd74SJohn Marino size_t * __restrict nresult)
3990d5acd74SJohn Marino {
4000d5acd74SJohn Marino escape_t *candidate;
4010d5acd74SJohn Marino
4020d5acd74SJohn Marino if (psenc->chlen != 0 || psenc->inuse == NULL)
4030d5acd74SJohn Marino return (EINVAL);
4040d5acd74SJohn Marino candidate = INIT0(ei);
4050d5acd74SJohn Marino if (psenc->inuse != candidate) {
4060d5acd74SJohn Marino if (n < 2)
4070d5acd74SJohn Marino return (E2BIG);
4080d5acd74SJohn Marino n -= 2;
4090d5acd74SJohn Marino psenc->ch[psenc->chlen++] = ESCAPE_CHAR;
4100d5acd74SJohn Marino psenc->ch[psenc->chlen++] = ESC(candidate);
4110d5acd74SJohn Marino }
4120d5acd74SJohn Marino if (n < 1)
4130d5acd74SJohn Marino return (E2BIG);
4140d5acd74SJohn Marino if (psenc->chlen > 0)
4150d5acd74SJohn Marino memcpy(s, psenc->ch, psenc->chlen);
4160d5acd74SJohn Marino *nresult = psenc->chlen;
4170d5acd74SJohn Marino _citrus_HZ_init_state(ei, psenc);
4180d5acd74SJohn Marino
4190d5acd74SJohn Marino return (0);
4200d5acd74SJohn Marino }
4210d5acd74SJohn Marino
4220d5acd74SJohn Marino static __inline int
_citrus_HZ_stdenc_get_state_desc_generic(_HZEncodingInfo * __restrict ei,_HZState * __restrict psenc,int * __restrict rstate)4230d5acd74SJohn Marino _citrus_HZ_stdenc_get_state_desc_generic(_HZEncodingInfo * __restrict ei,
4240d5acd74SJohn Marino _HZState * __restrict psenc, int * __restrict rstate)
4250d5acd74SJohn Marino {
4260d5acd74SJohn Marino
4270d5acd74SJohn Marino if (psenc->chlen < 0 || psenc->inuse == NULL)
4280d5acd74SJohn Marino return (EINVAL);
4290d5acd74SJohn Marino *rstate = (psenc->chlen == 0)
4300d5acd74SJohn Marino ? ((psenc->inuse == INIT0(ei))
4310d5acd74SJohn Marino ? _STDENC_SDGEN_INITIAL
4320d5acd74SJohn Marino : _STDENC_SDGEN_STABLE)
4330d5acd74SJohn Marino : ((psenc->ch[0] == ESCAPE_CHAR)
4340d5acd74SJohn Marino ? _STDENC_SDGEN_INCOMPLETE_SHIFT
4350d5acd74SJohn Marino : _STDENC_SDGEN_INCOMPLETE_CHAR);
4360d5acd74SJohn Marino
4370d5acd74SJohn Marino return (0);
4380d5acd74SJohn Marino }
4390d5acd74SJohn Marino
4400d5acd74SJohn Marino static __inline int
4410d5acd74SJohn Marino /*ARGSUSED*/
_citrus_HZ_stdenc_wctocs(_HZEncodingInfo * __restrict ei __unused,_csid_t * __restrict csid,_index_t * __restrict idx,wchar_t wc)4420d5acd74SJohn Marino _citrus_HZ_stdenc_wctocs(_HZEncodingInfo * __restrict ei __unused,
4430d5acd74SJohn Marino _csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc)
4440d5acd74SJohn Marino {
4450d5acd74SJohn Marino int bit;
4460d5acd74SJohn Marino
4470d5acd74SJohn Marino if (wc & 0x80) {
4480d5acd74SJohn Marino bit = 0x80;
4490d5acd74SJohn Marino wc &= ~0x80;
4500d5acd74SJohn Marino } else
4510d5acd74SJohn Marino bit = 0x0;
4520d5acd74SJohn Marino if ((uint32_t)wc <= 0x7F) {
4530d5acd74SJohn Marino *csid = (_csid_t)bit;
4540d5acd74SJohn Marino *idx = (_index_t)wc;
4550d5acd74SJohn Marino } else if ((uint32_t)wc <= 0x7F7F) {
4560d5acd74SJohn Marino *csid = (_csid_t)(bit | 0x8000);
4570d5acd74SJohn Marino *idx = (_index_t)wc;
4580d5acd74SJohn Marino } else {
4590d5acd74SJohn Marino *csid = (_index_t)(wc & ~0x00FFFF7F);
4600d5acd74SJohn Marino *idx = (_csid_t)(wc & 0x00FFFF7F);
4610d5acd74SJohn Marino }
4620d5acd74SJohn Marino
4630d5acd74SJohn Marino return (0);
4640d5acd74SJohn Marino }
4650d5acd74SJohn Marino
4660d5acd74SJohn Marino static __inline int
4670d5acd74SJohn Marino /*ARGSUSED*/
_citrus_HZ_stdenc_cstowc(_HZEncodingInfo * __restrict ei __unused,wchar_t * __restrict wc,_csid_t csid,_index_t idx)4680d5acd74SJohn Marino _citrus_HZ_stdenc_cstowc(_HZEncodingInfo * __restrict ei __unused,
4690d5acd74SJohn Marino wchar_t * __restrict wc, _csid_t csid, _index_t idx)
4700d5acd74SJohn Marino {
4710d5acd74SJohn Marino
4720d5acd74SJohn Marino *wc = (wchar_t)idx;
4730d5acd74SJohn Marino switch (csid) {
4740d5acd74SJohn Marino case 0x80:
4750d5acd74SJohn Marino case 0x8080:
4760d5acd74SJohn Marino *wc |= (wchar_t)0x80;
4770d5acd74SJohn Marino /*FALLTHROUGH*/
4780d5acd74SJohn Marino case 0x0:
4790d5acd74SJohn Marino case 0x8000:
4800d5acd74SJohn Marino break;
4810d5acd74SJohn Marino default:
4820d5acd74SJohn Marino *wc |= (wchar_t)csid;
4830d5acd74SJohn Marino }
4840d5acd74SJohn Marino
4850d5acd74SJohn Marino return (0);
4860d5acd74SJohn Marino }
4870d5acd74SJohn Marino
4880d5acd74SJohn Marino static void
_citrus_HZ_encoding_module_uninit(_HZEncodingInfo * ei)4890d5acd74SJohn Marino _citrus_HZ_encoding_module_uninit(_HZEncodingInfo *ei)
4900d5acd74SJohn Marino {
4910d5acd74SJohn Marino escape_t *escape;
4920d5acd74SJohn Marino
4930d5acd74SJohn Marino while ((escape = TAILQ_FIRST(E0SET(ei))) != NULL) {
4940d5acd74SJohn Marino TAILQ_REMOVE(E0SET(ei), escape, entry);
4950d5acd74SJohn Marino free(GL(escape));
4960d5acd74SJohn Marino free(GR(escape));
4970d5acd74SJohn Marino free(escape);
4980d5acd74SJohn Marino }
4990d5acd74SJohn Marino while ((escape = TAILQ_FIRST(E1SET(ei))) != NULL) {
5000d5acd74SJohn Marino TAILQ_REMOVE(E1SET(ei), escape, entry);
5010d5acd74SJohn Marino free(GL(escape));
5020d5acd74SJohn Marino free(GR(escape));
5030d5acd74SJohn Marino free(escape);
5040d5acd74SJohn Marino }
5050d5acd74SJohn Marino }
5060d5acd74SJohn Marino
5070d5acd74SJohn Marino static int
_citrus_HZ_parse_char(void * context,const char * name __unused,const char * s)508bdcf3f2bSJohn Marino _citrus_HZ_parse_char(void *context, const char *name __unused, const char *s)
5090d5acd74SJohn Marino {
5100d5acd74SJohn Marino escape_t *escape;
5110d5acd74SJohn Marino void **p;
5120d5acd74SJohn Marino
513bdcf3f2bSJohn Marino p = (void **)context;
5140d5acd74SJohn Marino escape = (escape_t *)p[0];
5150d5acd74SJohn Marino if (escape->ch != '\0')
5160d5acd74SJohn Marino return (EINVAL);
5170d5acd74SJohn Marino escape->ch = *s++;
5180d5acd74SJohn Marino if (escape->ch == ESCAPE_CHAR || *s != '\0')
5190d5acd74SJohn Marino return (EINVAL);
5200d5acd74SJohn Marino
5210d5acd74SJohn Marino return (0);
5220d5acd74SJohn Marino }
5230d5acd74SJohn Marino
5240d5acd74SJohn Marino static int
_citrus_HZ_parse_graphic(void * context,const char * name,const char * s)525bdcf3f2bSJohn Marino _citrus_HZ_parse_graphic(void *context, const char *name, const char *s)
5260d5acd74SJohn Marino {
5270d5acd74SJohn Marino _HZEncodingInfo *ei;
5280d5acd74SJohn Marino escape_t *escape;
5290d5acd74SJohn Marino graphic_t *graphic;
5300d5acd74SJohn Marino void **p;
5310d5acd74SJohn Marino
532bdcf3f2bSJohn Marino p = (void **)context;
5330d5acd74SJohn Marino escape = (escape_t *)p[0];
5340d5acd74SJohn Marino ei = (_HZEncodingInfo *)p[1];
5350db70a6aSJohn Marino graphic = calloc(1, sizeof(*graphic));
5360d5acd74SJohn Marino if (graphic == NULL)
5370d5acd74SJohn Marino return (ENOMEM);
5380d5acd74SJohn Marino if (strcmp("GL", name) == 0) {
5390d5acd74SJohn Marino if (GL(escape) != NULL)
5400d5acd74SJohn Marino goto release;
5410d5acd74SJohn Marino GL(escape) = graphic;
5420d5acd74SJohn Marino } else if (strcmp("GR", name) == 0) {
5430d5acd74SJohn Marino if (GR(escape) != NULL)
5440d5acd74SJohn Marino goto release;
5450d5acd74SJohn Marino GR(escape) = graphic;
5460d5acd74SJohn Marino } else {
5470d5acd74SJohn Marino release:
5480d5acd74SJohn Marino free(graphic);
5490d5acd74SJohn Marino return (EINVAL);
5500d5acd74SJohn Marino }
5510d5acd74SJohn Marino graphic->escape = escape;
5520d5acd74SJohn Marino if (_bcs_strncasecmp("ASCII", s, 5) == 0) {
5530d5acd74SJohn Marino if (s[5] != '\0')
5540d5acd74SJohn Marino return (EINVAL);
5550d5acd74SJohn Marino graphic->charset = ASCII;
5560d5acd74SJohn Marino graphic->length = 1;
5570d5acd74SJohn Marino ei->ascii = graphic;
5580d5acd74SJohn Marino return (0);
5590d5acd74SJohn Marino } else if (_bcs_strncasecmp("GB2312", s, 6) == 0) {
5600d5acd74SJohn Marino if (s[6] != '\0')
5610d5acd74SJohn Marino return (EINVAL);
5620d5acd74SJohn Marino graphic->charset = GB2312;
5630d5acd74SJohn Marino graphic->length = 2;
5640d5acd74SJohn Marino ei->gb2312 = graphic;
5650d5acd74SJohn Marino return (0);
5660d5acd74SJohn Marino } else if (strncmp("94*", s, 3) == 0)
5670d5acd74SJohn Marino graphic->charset = CS94;
5680d5acd74SJohn Marino else if (strncmp("96*", s, 3) == 0)
5690d5acd74SJohn Marino graphic->charset = CS96;
5700d5acd74SJohn Marino else
5710d5acd74SJohn Marino return (EINVAL);
5720d5acd74SJohn Marino s += 3;
5730d5acd74SJohn Marino switch(*s) {
5740d5acd74SJohn Marino case '1': case '2': case '3':
5750d5acd74SJohn Marino graphic->length = (size_t)(*s - '0');
5760d5acd74SJohn Marino if (*++s == '\0')
5770d5acd74SJohn Marino break;
5780d5acd74SJohn Marino /*FALLTHROUGH*/
5790d5acd74SJohn Marino default:
5800d5acd74SJohn Marino return (EINVAL);
5810d5acd74SJohn Marino }
5820d5acd74SJohn Marino return (0);
5830d5acd74SJohn Marino }
5840d5acd74SJohn Marino
5850d5acd74SJohn Marino static const _citrus_prop_hint_t escape_hints[] = {
5860d5acd74SJohn Marino _CITRUS_PROP_HINT_STR("CH", &_citrus_HZ_parse_char),
5870d5acd74SJohn Marino _CITRUS_PROP_HINT_STR("GL", &_citrus_HZ_parse_graphic),
5880d5acd74SJohn Marino _CITRUS_PROP_HINT_STR("GR", &_citrus_HZ_parse_graphic),
5890d5acd74SJohn Marino _CITRUS_PROP_HINT_END
5900d5acd74SJohn Marino };
5910d5acd74SJohn Marino
5920d5acd74SJohn Marino static int
_citrus_HZ_parse_escape(void * context,const char * name,const char * s)593bdcf3f2bSJohn Marino _citrus_HZ_parse_escape(void *context, const char *name, const char *s)
5940d5acd74SJohn Marino {
5950d5acd74SJohn Marino _HZEncodingInfo *ei;
5960d5acd74SJohn Marino escape_t *escape;
5970d5acd74SJohn Marino void *p[2];
5980d5acd74SJohn Marino
599bdcf3f2bSJohn Marino ei = (_HZEncodingInfo *)context;
6000db70a6aSJohn Marino escape = calloc(1, sizeof(*escape));
6010d5acd74SJohn Marino if (escape == NULL)
6020d5acd74SJohn Marino return (EINVAL);
6030d5acd74SJohn Marino if (strcmp("0", name) == 0) {
6040d5acd74SJohn Marino escape->set = E0SET(ei);
6050d5acd74SJohn Marino TAILQ_INSERT_TAIL(E0SET(ei), escape, entry);
6060d5acd74SJohn Marino } else if (strcmp("1", name) == 0) {
6070d5acd74SJohn Marino escape->set = E1SET(ei);
6080d5acd74SJohn Marino TAILQ_INSERT_TAIL(E1SET(ei), escape, entry);
6090d5acd74SJohn Marino } else {
6100d5acd74SJohn Marino free(escape);
6110d5acd74SJohn Marino return (EINVAL);
6120d5acd74SJohn Marino }
6130d5acd74SJohn Marino p[0] = (void *)escape;
6140d5acd74SJohn Marino p[1] = (void *)ei;
6150d5acd74SJohn Marino return (_citrus_prop_parse_variable(
6160d5acd74SJohn Marino escape_hints, (void *)&p[0], s, strlen(s)));
6170d5acd74SJohn Marino }
6180d5acd74SJohn Marino
6190d5acd74SJohn Marino static const _citrus_prop_hint_t root_hints[] = {
6200d5acd74SJohn Marino _CITRUS_PROP_HINT_STR("0", &_citrus_HZ_parse_escape),
6210d5acd74SJohn Marino _CITRUS_PROP_HINT_STR("1", &_citrus_HZ_parse_escape),
6220d5acd74SJohn Marino _CITRUS_PROP_HINT_END
6230d5acd74SJohn Marino };
6240d5acd74SJohn Marino
6250d5acd74SJohn Marino static int
_citrus_HZ_encoding_module_init(_HZEncodingInfo * __restrict ei,const void * __restrict var,size_t lenvar)6260d5acd74SJohn Marino _citrus_HZ_encoding_module_init(_HZEncodingInfo * __restrict ei,
6270d5acd74SJohn Marino const void * __restrict var, size_t lenvar)
6280d5acd74SJohn Marino {
6290d5acd74SJohn Marino int errnum;
6300d5acd74SJohn Marino
6310d5acd74SJohn Marino memset(ei, 0, sizeof(*ei));
6320d5acd74SJohn Marino TAILQ_INIT(E0SET(ei));
6330d5acd74SJohn Marino TAILQ_INIT(E1SET(ei));
6340d5acd74SJohn Marino errnum = _citrus_prop_parse_variable(
6350d5acd74SJohn Marino root_hints, (void *)ei, var, lenvar);
6360d5acd74SJohn Marino if (errnum != 0)
6370d5acd74SJohn Marino _citrus_HZ_encoding_module_uninit(ei);
6380d5acd74SJohn Marino return (errnum);
6390d5acd74SJohn Marino }
6400d5acd74SJohn Marino
6410d5acd74SJohn Marino /* ----------------------------------------------------------------------
6420d5acd74SJohn Marino * public interface for stdenc
6430d5acd74SJohn Marino */
6440d5acd74SJohn Marino
6450d5acd74SJohn Marino _CITRUS_STDENC_DECLS(HZ);
6460d5acd74SJohn Marino _CITRUS_STDENC_DEF_OPS(HZ);
6470d5acd74SJohn Marino
6480d5acd74SJohn Marino #include "citrus_stdenc_template.h"
649