big5.c revision 129334
1254721Semaste/*-
2254721Semaste * Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
3254721Semaste * Copyright (c) 1993
4254721Semaste *	The Regents of the University of California.  All rights reserved.
5254721Semaste *
6254721Semaste * This code is derived from software contributed to Berkeley by
7254721Semaste * Paul Borman at Krystal Technologies.
8254721Semaste *
9254721Semaste * Redistribution and use in source and binary forms, with or without
10254721Semaste * modification, are permitted provided that the following conditions
11254721Semaste * are met:
12254721Semaste * 1. Redistributions of source code must retain the above copyright
13254721Semaste *    notice, this list of conditions and the following disclaimer.
14254721Semaste * 2. Redistributions in binary form must reproduce the above copyright
15254721Semaste *    notice, this list of conditions and the following disclaimer in the
16254721Semaste *    documentation and/or other materials provided with the distribution.
17254721Semaste * 3. All advertising materials mentioning features or use of this software
18254721Semaste *    must display the following acknowledgement:
19254721Semaste *	This product includes software developed by the University of
20254721Semaste *	California, Berkeley and its contributors.
21254721Semaste * 4. Neither the name of the University nor the names of its contributors
22254721Semaste *    may be used to endorse or promote products derived from this software
23254721Semaste *    without specific prior written permission.
24254721Semaste *
25254721Semaste * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26254721Semaste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27254721Semaste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28254721Semaste * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29254721Semaste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30254721Semaste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31254721Semaste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32254721Semaste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33254721Semaste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34254721Semaste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35254721Semaste * SUCH DAMAGE.
36254721Semaste */
37254721Semaste
38254721Semaste#if defined(LIBC_SCCS) && !defined(lint)
39254721Semastestatic char sccsid[] = "@(#)big5.c	8.1 (Berkeley) 6/4/93";
40254721Semaste#endif /* LIBC_SCCS and not lint */
41254721Semaste#include <sys/param.h>
42254721Semaste__FBSDID("$FreeBSD: head/lib/libc/locale/big5.c 129334 2004-05-17 11:16:14Z tjr $");
43254721Semaste
44254721Semaste#include <errno.h>
45254721Semaste#include <runetype.h>
46254721Semaste#include <stdlib.h>
47254721Semaste#include <string.h>
48254721Semaste#include <wchar.h>
49254721Semaste#include "mblocal.h"
50254721Semaste
51254721Semasteint	_BIG5_init(_RuneLocale *);
52254721Semastesize_t	_BIG5_mbrtowc(wchar_t * __restrict, const char * __restrict, size_t,
53254721Semaste	    mbstate_t * __restrict);
54254721Semasteint	_BIG5_mbsinit(const mbstate_t *);
55254721Semastesize_t	_BIG5_wcrtomb(char * __restrict, wchar_t, mbstate_t * __restrict);
56254721Semaste
57254721Semastetypedef struct {
58254721Semaste	wchar_t	ch;
59254721Semaste} _BIG5State;
60254721Semaste
61254721Semasteint
62254721Semaste_BIG5_init(_RuneLocale *rl)
63254721Semaste{
64254721Semaste
65254721Semaste	__mbrtowc = _BIG5_mbrtowc;
66254721Semaste	__wcrtomb = _BIG5_wcrtomb;
67254721Semaste	__mbsinit = _BIG5_mbsinit;
68254721Semaste	_CurrentRuneLocale = rl;
69254721Semaste	__mb_cur_max = 2;
70254721Semaste	return (0);
71254721Semaste}
72254721Semaste
73254721Semasteint
74254721Semaste_BIG5_mbsinit(const mbstate_t *ps)
75254721Semaste{
76254721Semaste
77254721Semaste	return (ps == NULL || ((const _BIG5State *)ps)->ch == 0);
78254721Semaste}
79254721Semaste
80254721Semastestatic __inline int
81254721Semaste_big5_check(u_int c)
82254721Semaste{
83254721Semaste
84254721Semaste	c &= 0xff;
85254721Semaste	return ((c >= 0xa1 && c <= 0xfe) ? 2 : 1);
86254721Semaste}
87254721Semaste
88254721Semastesize_t
89254721Semaste_BIG5_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
90254721Semaste    mbstate_t * __restrict ps)
91263363Semaste{
92263363Semaste	_BIG5State *bs;
93254721Semaste	wchar_t wc;
94254721Semaste	size_t len;
95254721Semaste
96254721Semaste	bs = (_BIG5State *)ps;
97254721Semaste
98254721Semaste	if ((bs->ch & ~0xFF) != 0) {
99254721Semaste		/* Bad conversion state. */
100254721Semaste		errno = EINVAL;
101254721Semaste		return ((size_t)-1);
102254721Semaste	}
103254721Semaste
104254721Semaste	if (s == NULL) {
105254721Semaste		s = "";
106254721Semaste		n = 1;
107254721Semaste		pwc = NULL;
108254721Semaste	}
109254721Semaste
110254721Semaste	if (n == 0)
111254721Semaste		/* Incomplete multibyte sequence */
112254721Semaste		return ((size_t)-2);
113254721Semaste
114254721Semaste	if (bs->ch != 0) {
115254721Semaste		if (*s == '\0') {
116254721Semaste			errno = EILSEQ;
117254721Semaste			return ((size_t)-1);
118254721Semaste		}
119254721Semaste		wc = (bs->ch << 8) | (*s & 0xFF);
120254721Semaste		if (pwc != NULL)
121254721Semaste			*pwc = wc;
122254721Semaste		bs->ch = 0;
123254721Semaste		return (1);
124254721Semaste	}
125254721Semaste
126254721Semaste	len = (size_t)_big5_check(*s);
127254721Semaste	wc = *s++ & 0xff;
128254721Semaste	if (len == 2) {
129254721Semaste		if (n < 2) {
130254721Semaste			/* Incomplete multibyte sequence */
131254721Semaste			bs->ch = wc;
132254721Semaste			return ((size_t)-2);
133254721Semaste		}
134254721Semaste		if (*s == '\0') {
135254721Semaste			errno = EILSEQ;
136254721Semaste			return ((size_t)-1);
137254721Semaste		}
138254721Semaste		wc = (wc << 8) | (*s++ & 0xff);
139254721Semaste		if (pwc != NULL)
140254721Semaste			*pwc = wc;
141254721Semaste                return (2);
142254721Semaste	} else {
143254721Semaste		if (pwc != NULL)
144254721Semaste			*pwc = wc;
145254721Semaste		return (wc == L'\0' ? 0 : 1);
146254721Semaste	}
147254721Semaste}
148254721Semaste
149254721Semastesize_t
150254721Semaste_BIG5_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
151254721Semaste{
152254721Semaste	_BIG5State *bs;
153254721Semaste
154254721Semaste	bs = (_BIG5State *)ps;
155254721Semaste
156254721Semaste	if (bs->ch != 0) {
157254721Semaste		errno = EINVAL;
158254721Semaste		return ((size_t)-1);
159	}
160
161	if (s == NULL)
162		/* Reset to initial shift state (no-op) */
163		return (1);
164	if (wc & 0x8000) {
165		*s++ = (wc >> 8) & 0xff;
166		*s = wc & 0xff;
167		return (2);
168	}
169	*s = wc & 0xff;
170	return (1);
171}
172