1/*	$NetBSD: citrus_stdenc.c,v 1.3 2005/10/29 18:02:04 tshiozak Exp $	*/
2
3/*-
4 * Copyright (c)2003 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_stdenc.c,v 1.3 2005/10/29 18:02:04 tshiozak Exp $");
32#endif /* LIBC_SCCS and not lint */
33
34#include "namespace.h"
35#include <assert.h>
36#include <errno.h>
37#include <stdlib.h>
38#include <string.h>
39
40#include "citrus_namespace.h"
41#include "citrus_types.h"
42#include "citrus_module.h"
43#include "citrus_stdenc.h"
44#include "citrus_none.h"
45
46struct _citrus_stdenc _citrus_stdenc_default = {
47	&_citrus_NONE_stdenc_ops,	/* ce_ops */
48	NULL,				/* ce_closure */
49	NULL,				/* ce_module */
50	&_citrus_NONE_stdenc_traits,	/* ce_traits */
51};
52
53#ifdef _I18N_DYNAMIC
54
55static int
56/*ARGSUSED*/
57get_state_desc_default(struct _citrus_stdenc * __restrict ce,
58		       void * __restrict ps,
59		       int id,
60		       struct _citrus_stdenc_state_desc * __restrict d)
61{
62	return EOPNOTSUPP;
63}
64
65int
66_citrus_stdenc_open(struct _citrus_stdenc * __restrict * __restrict rce,
67		    char const * __restrict encname,
68		    const void * __restrict variable, size_t lenvar)
69{
70	int ret;
71	_citrus_module_t handle;
72	struct _citrus_stdenc *ce;
73	_citrus_stdenc_getops_t getops;
74
75	_DIAGASSERT(encname != NULL);
76	_DIAGASSERT(!lenvar || variable!=NULL);
77	_DIAGASSERT(rce != NULL);
78
79	if (!strcmp(encname, _CITRUS_DEFAULT_STDENC_NAME)) {
80		*rce = &_citrus_stdenc_default;
81		return (0);
82	}
83	ce = malloc(sizeof(*ce));
84	if (ce==NULL) {
85		ret = errno;
86		goto bad;
87	}
88	ce->ce_ops = NULL;
89	ce->ce_closure = NULL;
90	ce->ce_module = NULL;
91	ce->ce_traits = NULL;
92
93	ret = _citrus_load_module(&handle, encname);
94	if (ret)
95		goto bad;
96
97	ce->ce_module = handle;
98
99	getops =
100	    (_citrus_stdenc_getops_t)_citrus_find_getops(ce->ce_module,
101							 encname, "stdenc");
102	if (getops == NULL) {
103		ret = EINVAL;
104		goto bad;
105	}
106
107	ce->ce_ops = (struct _citrus_stdenc_ops *)malloc(sizeof(*ce->ce_ops));
108	if (ce->ce_ops == NULL) {
109		ret = errno;
110		goto bad;
111	}
112
113	ret = (*getops)(ce->ce_ops, sizeof(*ce->ce_ops),
114			_CITRUS_STDENC_ABI_VERSION);
115	if (ret)
116		goto bad;
117
118	/* If return ABI version is not expected, should fixup it */
119	if (ce->ce_ops->eo_abi_version < 0x00000002) {
120		ce->ce_ops->eo_get_state_desc = &get_state_desc_default;
121	}
122
123	/* validation check */
124	if (ce->ce_ops->eo_init == NULL ||
125	    ce->ce_ops->eo_uninit == NULL ||
126	    ce->ce_ops->eo_init_state == NULL ||
127	    ce->ce_ops->eo_mbtocs == NULL ||
128	    ce->ce_ops->eo_cstomb == NULL ||
129	    ce->ce_ops->eo_mbtowc == NULL ||
130	    ce->ce_ops->eo_wctomb == NULL ||
131	    ce->ce_ops->eo_get_state_desc == NULL) {
132		ret = EINVAL;
133		goto bad;
134	}
135
136	/* allocate traits */
137	ce->ce_traits = malloc(sizeof(*ce->ce_traits));
138	if (ce->ce_traits == NULL) {
139		ret = errno;
140		goto bad;
141	}
142	/* init and get closure */
143	ret = (*ce->ce_ops->eo_init)(ce, variable, lenvar, ce->ce_traits);
144	if (ret)
145		goto bad;
146
147	*rce = ce;
148
149	return (0);
150
151bad:
152	_citrus_stdenc_close(ce);
153	return (ret);
154}
155
156void
157_citrus_stdenc_close(struct _citrus_stdenc *ce)
158{
159
160	_DIAGASSERT(ce != NULL);
161
162	if (ce == &_citrus_stdenc_default)
163		return;
164
165	if (ce->ce_module) {
166		if (ce->ce_ops) {
167			if (ce->ce_closure && ce->ce_ops->eo_uninit)
168				(*ce->ce_ops->eo_uninit)(ce);
169			free(ce->ce_ops);
170		}
171		free(ce->ce_traits);
172		_citrus_unload_module(ce->ce_module);
173	}
174	free(ce);
175}
176
177#else
178/* !_I18N_DYNAMIC */
179
180int
181/*ARGSUSED*/
182_citrus_stdenc_open(struct _citrus_stdenc * __restrict * __restrict rce,
183		    char const * __restrict encname,
184		    const void * __restrict variable, size_t lenvar)
185{
186	if (!strcmp(encname, _CITRUS_DEFAULT_STDENC_NAME)) {
187		*rce = &_citrus_stdenc_default;
188		return (0);
189	}
190	return (EINVAL);
191}
192
193void
194/*ARGSUSED*/
195_citrus_stdenc_close(struct _citrus_stdenc *ce)
196{
197}
198
199#endif
200