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