big5.c revision 129117
151974Smsmith/*-
265245Smsmith * Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
365245Smsmith * Copyright (c) 1993
451974Smsmith *	The Regents of the University of California.  All rights reserved.
551974Smsmith *
651974Smsmith * This code is derived from software contributed to Berkeley by
751974Smsmith * Paul Borman at Krystal Technologies.
851974Smsmith *
951974Smsmith * Redistribution and use in source and binary forms, with or without
1051974Smsmith * modification, are permitted provided that the following conditions
1151974Smsmith * are met:
1251974Smsmith * 1. Redistributions of source code must retain the above copyright
1351974Smsmith *    notice, this list of conditions and the following disclaimer.
1451974Smsmith * 2. Redistributions in binary form must reproduce the above copyright
1551974Smsmith *    notice, this list of conditions and the following disclaimer in the
1651974Smsmith *    documentation and/or other materials provided with the distribution.
1751974Smsmith * 3. All advertising materials mentioning features or use of this software
1851974Smsmith *    must display the following acknowledgement:
1951974Smsmith *	This product includes software developed by the University of
2051974Smsmith *	California, Berkeley and its contributors.
2151974Smsmith * 4. Neither the name of the University nor the names of its contributors
2251974Smsmith *    may be used to endorse or promote products derived from this software
2351974Smsmith *    without specific prior written permission.
2451974Smsmith *
2551974Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2651974Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27106225Semoore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28106225Semoore * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29106225Semoore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30106225Semoore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31106225Semoore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32106225Semoore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33106225Semoore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34106225Semoore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35106225Semoore * SUCH DAMAGE.
36106225Semoore */
37106225Semoore
38106225Semoore#if defined(LIBC_SCCS) && !defined(lint)
39105419Semoorestatic char sccsid[] = "@(#)big5.c	8.1 (Berkeley) 6/4/93";
40106225Semoore#endif /* LIBC_SCCS and not lint */
41105419Semoore#include <sys/param.h>
42105419Semoore__FBSDID("$FreeBSD: head/lib/libc/locale/big5.c 129117 2004-05-11 14:08:22Z tjr $");
43106225Semoore
44106225Semoore#include <errno.h>
45106225Semoore#include <runetype.h>
46106225Semoore#include <stdlib.h>
47106225Semoore#include <string.h>
48106225Semoore#include <wchar.h>
49106225Semoore
50106225Semooreextern size_t (*__mbrtowc)(wchar_t * __restrict, const char * __restrict,
51106225Semoore    size_t, mbstate_t * __restrict);
52106225Semooreextern int (*__mbsinit)(const mbstate_t *);
53106225Semooreextern size_t (*__wcrtomb)(char * __restrict, wchar_t, mbstate_t * __restrict);
54105419Semoore
55106225Semooreint	_BIG5_init(_RuneLocale *);
5651974Smsmithsize_t	_BIG5_mbrtowc(wchar_t * __restrict, const char * __restrict, size_t,
5751974Smsmith	    mbstate_t * __restrict);
5851974Smsmithint	_BIG5_mbsinit(const mbstate_t *);
5965245Smsmithsize_t	_BIG5_wcrtomb(char * __restrict, wchar_t, mbstate_t * __restrict);
60112946Sphk
61140340Sscottltypedef struct {
62140340Sscottl	int	count;
6365245Smsmith	u_char	bytes[2];
6451974Smsmith} _BIG5State;
6565245Smsmith
6687599Sobrienint
6787599Sobrien_BIG5_init(_RuneLocale *rl)
6865245Smsmith{
6965245Smsmith
7065245Smsmith	__mbrtowc = _BIG5_mbrtowc;
7165245Smsmith	__wcrtomb = _BIG5_wcrtomb;
7287599Sobrien	__mbsinit = _BIG5_mbsinit;
7351974Smsmith	_CurrentRuneLocale = rl;
7451974Smsmith	__mb_cur_max = 2;
7551974Smsmith	return (0);
7651974Smsmith}
7751974Smsmith
7851974Smsmithint
7951974Smsmith_BIG5_mbsinit(const mbstate_t *ps)
8051974Smsmith{
8151974Smsmith
8251974Smsmith	return (ps == NULL || ((const _BIG5State *)ps)->count == 0);
8351974Smsmith}
8451974Smsmith
8551974Smsmithstatic __inline int
8651974Smsmith_big5_check(u_int c)
8751974Smsmith{
8851974Smsmith
8951974Smsmith	c &= 0xff;
9051974Smsmith	return ((c >= 0xa1 && c <= 0xfe) ? 2 : 1);
9151974Smsmith}
9265245Smsmith
9365245Smsmithsize_t
9465245Smsmith_BIG5_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
9565245Smsmith    mbstate_t * __restrict ps)
9665245Smsmith{
9765245Smsmith	_BIG5State *bs;
9865245Smsmith	wchar_t wc;
9965245Smsmith	int i, len, ocount;
10051974Smsmith	size_t ncopy;
10165245Smsmith
10265245Smsmith	bs = (_BIG5State *)ps;
10351974Smsmith
10451974Smsmith	if (bs->count < 0 || bs->count > sizeof(bs->bytes)) {
10551974Smsmith		errno = EINVAL;
10651974Smsmith		return ((size_t)-1);
10751974Smsmith	}
10860938Sjake
10951974Smsmith	if (s == NULL) {
11051974Smsmith		s = "";
11151974Smsmith		n = 1;
11265245Smsmith		pwc = NULL;
11351974Smsmith	}
11451974Smsmith
11551974Smsmith	ncopy = MIN(MIN(n, MB_CUR_MAX), sizeof(bs->bytes) - bs->count);
11651974Smsmith	memcpy(bs->bytes + bs->count, s, ncopy);
11765245Smsmith	ocount = bs->count;
11865245Smsmith	bs->count += ncopy;
11965245Smsmith	s = (char *)bs->bytes;
12065245Smsmith	n = bs->count;
12165245Smsmith
12265245Smsmith	if (n == 0 || (size_t)(len = _big5_check(*s)) > n)
12351974Smsmith		/* Incomplete multibyte sequence */
12465245Smsmith		return ((size_t)-2);
12565245Smsmith	if (n == 2 && s[1] == '\0') {
12651974Smsmith		errno = EILSEQ;
12751974Smsmith		return ((size_t)-1);
12851974Smsmith	}
12951974Smsmith	wc = 0;
13051974Smsmith	i = len;
13165245Smsmith	while (i-- > 0)
13265245Smsmith		wc = (wc << 8) | (unsigned char)*s++;
13365245Smsmith	if (pwc != NULL)
13465245Smsmith		*pwc = wc;
13565245Smsmith	bs->count = 0;
13651974Smsmith	return (wc == L'\0' ? 0 : len - ocount);
137105419Semoore}
13851974Smsmith
13951974Smsmithsize_t
14065245Smsmith_BIG5_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
14165245Smsmith{
14265245Smsmith	_BIG5State *bs;
14365245Smsmith
14465245Smsmith	bs = (_BIG5State *)ps;
14565245Smsmith
14665245Smsmith	if (bs->count != 0) {
14765245Smsmith		errno = EINVAL;
14865245Smsmith		return ((size_t)-1);
14965245Smsmith	}
15065245Smsmith
15165245Smsmith	if (s == NULL)
15251974Smsmith		/* Reset to initial shift state (no-op) */
15351974Smsmith		return (1);
15451974Smsmith	if (wc & 0x8000) {
15551974Smsmith		*s++ = (wc >> 8) & 0xff;
15651974Smsmith		*s = wc & 0xff;
15751974Smsmith		return (2);
15851974Smsmith	}
15951974Smsmith	*s = wc & 0xff;
16051974Smsmith	return (1);
16151974Smsmith}
16251974Smsmith