1/*	$NetBSD: citrus_ctype.c,v 1.5 2008/06/14 16:01:07 tnozaki Exp $	*/
2
3/*-
4 * Copyright (c)1999, 2000, 2001, 2002 Citrus Project,
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30#if defined(LIBC_SCCS) && !defined(lint)
31__RCSID("$NetBSD: citrus_ctype.c,v 1.5 2008/06/14 16:01:07 tnozaki Exp $");
32#endif /* LIBC_SCCS and not lint */
33
34#include <sys/types.h>
35#include <assert.h>
36#include <errno.h>
37#include <limits.h>
38#include <string.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <unistd.h>
42#include <stddef.h>
43#include <wchar.h>
44#include "citrus_module.h"
45#include "citrus_ctype.h"
46#include "citrus_ctype_fallback.h"
47#include "citrus_none.h"
48#include _CITRUS_DEFAULT_CTYPE_HEADER
49
50_citrus_ctype_rec_t _citrus_ctype_default = {
51	&_CITRUS_DEFAULT_CTYPE_OPS,	/* cc_ops */
52	NULL,				/* cc_closure */
53	NULL				/* cc_module */
54};
55
56#ifdef _I18N_DYNAMIC
57
58static int _initctypemodule(_citrus_ctype_t, char const *, _citrus_module_t,
59			    void *, size_t, size_t);
60
61static int
62_initctypemodule(_citrus_ctype_t cc, char const *modname,
63		 _citrus_module_t handle, void *variable, size_t lenvar,
64		 size_t szpriv)
65{
66	int ret;
67	_citrus_ctype_getops_t getops;
68
69	_DIAGASSERT(cc != NULL);
70
71	cc->cc_module = handle;
72
73	getops = (_citrus_ctype_getops_t)_citrus_find_getops(cc->cc_module,
74							     modname,
75							     "ctype");
76	if (getops == NULL)
77		return (EINVAL);
78
79	cc->cc_ops = (_citrus_ctype_ops_rec_t *)malloc(sizeof(*cc->cc_ops));
80	if (cc->cc_ops == NULL)
81		return (ENOMEM);
82
83	ret = (*getops)(cc->cc_ops, sizeof(*cc->cc_ops),
84			_CITRUS_CTYPE_ABI_VERSION);
85	if (ret)
86		goto bad;
87
88	/* If return ABI version is not expected, fixup it here*/
89	switch (cc->cc_ops->co_abi_version) {
90	case 0x00000001:
91		cc->cc_ops->co_btowc = &_citrus_ctype_btowc_fallback;
92		cc->cc_ops->co_wctob = &_citrus_ctype_wctob_fallback;
93		/* FALLTHROUGH */
94	case 0x00000002:
95		/* FALLTHROUGH */
96	default:
97		break;
98	}
99
100	/* validation check */
101	if (cc->cc_ops->co_init == NULL ||
102	    cc->cc_ops->co_uninit == NULL ||
103	    cc->cc_ops->co_get_mb_cur_max == NULL ||
104	    cc->cc_ops->co_mblen == NULL ||
105	    cc->cc_ops->co_mbrlen == NULL ||
106	    cc->cc_ops->co_mbrtowc == NULL ||
107	    cc->cc_ops->co_mbsinit == NULL ||
108	    cc->cc_ops->co_mbsrtowcs == NULL ||
109	    cc->cc_ops->co_mbstowcs == NULL ||
110	    cc->cc_ops->co_mbtowc == NULL ||
111	    cc->cc_ops->co_wcrtomb == NULL ||
112	    cc->cc_ops->co_wcsrtombs == NULL ||
113	    cc->cc_ops->co_wcstombs == NULL ||
114	    cc->cc_ops->co_wctomb == NULL ||
115	    cc->cc_ops->co_btowc == NULL ||
116	    cc->cc_ops->co_wctob == NULL) {
117		ret = EINVAL;
118		goto bad;
119	}
120
121	/* init and get closure */
122	ret = (*cc->cc_ops->co_init)(
123		&cc->cc_closure, variable, lenvar, szpriv);
124	if (ret)
125		goto bad;
126
127	return (0);
128
129bad:
130	if (cc->cc_ops)
131		free(cc->cc_ops);
132	cc->cc_ops = NULL;
133
134	return (ret);
135}
136
137int
138_citrus_ctype_open(_citrus_ctype_t *rcc,
139		   char const *encname, void *variable, size_t lenvar,
140		   size_t szpriv)
141{
142	int ret;
143	_citrus_module_t handle;
144	_citrus_ctype_t cc;
145
146	_DIAGASSERT(encname != NULL);
147	_DIAGASSERT(!lenvar || variable!=NULL);
148	_DIAGASSERT(rcc != NULL);
149
150	if (!strcmp(encname, _CITRUS_DEFAULT_CTYPE_NAME)) {
151		*rcc = &_citrus_ctype_default;
152		return (0);
153	}
154	ret = _citrus_load_module(&handle, encname);
155	if (ret)
156		return (ret);
157
158	cc = calloc(1, sizeof(*cc));
159	if (!cc) {
160		_citrus_unload_module(handle);
161		return (errno);
162	}
163
164	ret = _initctypemodule(cc, encname, handle, variable, lenvar, szpriv);
165	if (ret) {
166		_citrus_unload_module(cc->cc_module);
167		free(cc);
168		return (ret);
169	}
170
171	*rcc = cc;
172
173	return (0);
174}
175
176void
177_citrus_ctype_close(_citrus_ctype_t cc)
178{
179
180	_DIAGASSERT(cc != NULL);
181
182	if (cc == &_citrus_ctype_default)
183		return;
184	(*cc->cc_ops->co_uninit)(cc->cc_closure);
185	free(cc->cc_ops);
186	_citrus_unload_module(cc->cc_module);
187	free(cc);
188}
189
190#else
191/* !_I18N_DYNAMIC */
192
193int
194/*ARGSUSED*/
195_citrus_ctype_open(_citrus_ctype_t *rcc,
196		   char const *encname, void *variable, size_t lenvar,
197		   size_t szpriv)
198{
199	if (!strcmp(encname, _CITRUS_DEFAULT_CTYPE_NAME)) {
200		*rcc = &_citrus_ctype_default;
201		return (0);
202	}
203	return (EINVAL);
204}
205
206void
207/*ARGSUSED*/
208_citrus_ctype_close(_citrus_ctype_t cc)
209{
210}
211
212#endif
213