1 /* $NetBSD: citrus_mapper.c,v 1.10 2012/06/08 07:49:42 martin Exp $ */
4 * Copyright (c)2003 Citrus Project,
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/cdefs.h>
30 #if defined(LIBC_SCCS) && !defined(lint)
31 __RCSID("$NetBSD: citrus_mapper.c,v 1.10 2012/06/08 07:49:42 martin Exp $");
32 #endif /* LIBC_SCCS and not lint */
34 #include "namespace.h"
35 #include "reentrant.h"
42 #include <sys/types.h>
44 #include <sys/queue.h>
46 #include "citrus_namespace.h"
47 #include "citrus_types.h"
48 #include "citrus_region.h"
49 #include "citrus_memstream.h"
50 #include "citrus_bcs.h"
51 #include "citrus_mmap.h"
52 #include "citrus_module.h"
53 #include "citrus_hash.h"
54 #include "citrus_mapper.h"
56 #define _CITRUS_MAPPER_DIR "mapper.dir"
58 #define CM_HASH_SIZE 101
59 #define REFCOUNT_PERSISTENT -1
62 static rwlock_t lock
= RWLOCK_INITIALIZER
;
65 struct _citrus_mapper_area
{
66 _CITRUS_HASH_HEAD(, _citrus_mapper
, CM_HASH_SIZE
) ma_cache
;
71 * _citrus_mapper_create_area:
76 _citrus_mapper_create_area(
77 struct _citrus_mapper_area
*__restrict
*__restrict rma
,
78 const char *__restrict area
)
83 struct _citrus_mapper_area
*ma
;
92 snprintf(path
, (size_t)PATH_MAX
, "%s/%s", area
, _CITRUS_MAPPER_DIR
);
94 ret
= stat(path
, &st
);
98 ma
= malloc(sizeof(*ma
));
103 ma
->ma_dir
= strdup(area
);
104 if (ma
->ma_dir
== NULL
) {
109 _CITRUS_HASH_INIT(&ma
->ma_cache
, CM_HASH_SIZE
);
114 rwlock_unlock(&lock
);
121 * lookup_mapper_entry:
122 * lookup mapper.dir entry in the specified directory.
124 * line format of iconv.dir file:
126 * mapper : mapper name.
127 * module : mapper module name.
128 * arg : argument for the module (generally, description file name)
132 lookup_mapper_entry(const char *dir
, const char *mapname
,
133 void *linebuf
, size_t linebufsize
,
134 const char **module
, const char **variable
)
137 struct _memstream ms
;
144 /* create mapper.dir path */
145 snprintf(path
, (size_t)PATH_MAX
, "%s/%s", dir
, _CITRUS_MAPPER_DIR
);
147 /* open read stream */
148 ret
= _map_file(&r
, path
);
152 _memstream_bind(&ms
, &r
);
154 /* search the line matching to the map name */
155 cp
= _memstream_matchline(&ms
, mapname
, &len
, 0);
160 if (!len
|| len
>linebufsize
-1) {
166 /* get module name */
168 cq
= _bcs_skip_nonws_len(cp
, &len
);
169 strlcpy(p
, cp
, (size_t)(cq
-cp
+1));
174 cp
= _bcs_skip_ws_len(cq
, &len
);
175 strlcpy(p
, cp
, len
+1);
186 * simply close a mapper. (without handling hash)
189 mapper_close(struct _citrus_mapper
*cm
)
194 (*cm
->cm_ops
->mo_uninit
)(cm
);
197 _citrus_unload_module(cm
->cm_module
);
205 * simply open a mapper. (without handling hash)
208 mapper_open(struct _citrus_mapper_area
*__restrict ma
,
209 struct _citrus_mapper
* __restrict
* __restrict rcm
,
210 const char * __restrict module
,
211 const char * __restrict variable
)
214 struct _citrus_mapper
*cm
;
215 _citrus_mapper_getops_t getops
;
217 /* initialize mapper handle */
218 cm
= malloc(sizeof(*cm
));
222 cm
->cm_module
= NULL
;
224 cm
->cm_closure
= NULL
;
225 cm
->cm_traits
= NULL
;
230 ret
= _citrus_load_module(&cm
->cm_module
, module
);
235 getops
= (_citrus_mapper_getops_t
)
236 _citrus_find_getops(cm
->cm_module
, module
, "mapper");
241 cm
->cm_ops
= malloc(sizeof(*cm
->cm_ops
));
246 ret
= (*getops
)(cm
->cm_ops
, sizeof(*cm
->cm_ops
),
247 _CITRUS_MAPPER_ABI_VERSION
);
251 if (!cm
->cm_ops
->mo_init
||
252 !cm
->cm_ops
->mo_uninit
||
253 !cm
->cm_ops
->mo_convert
||
254 !cm
->cm_ops
->mo_init_state
) {
259 /* allocate traits structure */
260 cm
->cm_traits
= malloc(sizeof(*cm
->cm_traits
));
261 if (cm
->cm_traits
== NULL
) {
265 /* initialize the mapper */
266 ret
= (*cm
->cm_ops
->mo_init
)(ma
, cm
, ma
->ma_dir
,
267 (const void *)variable
,
269 cm
->cm_traits
, sizeof(*cm
->cm_traits
));
283 * _citrus_mapper_open_direct:
287 _citrus_mapper_open_direct(struct _citrus_mapper_area
*__restrict ma
,
288 struct _citrus_mapper
* __restrict
* __restrict rcm
,
289 const char * __restrict module
,
290 const char * __restrict variable
)
292 return mapper_open(ma
, rcm
, module
, variable
);
299 hash_func(const char *key
)
301 return _string_hash_func(key
, CM_HASH_SIZE
);
308 match_func(struct _citrus_mapper
*cm
, const char *key
)
310 return strcmp(cm
->cm_key
, key
);
314 * _citrus_mapper_open:
315 * open a mapper with looking up "mapper.dir".
318 _citrus_mapper_open(struct _citrus_mapper_area
*__restrict ma
,
319 struct _citrus_mapper
* __restrict
* __restrict rcm
,
320 const char * __restrict mapname
)
323 char linebuf
[PATH_MAX
];
324 const char *module
, *variable
= NULL
;
325 struct _citrus_mapper
*cm
;
328 rwlock_wrlock(&lock
);
330 /* search in the cache */
331 hashval
= hash_func(mapname
);
332 _CITRUS_HASH_SEARCH(&ma
->ma_cache
, cm
, cm_entry
, match_func
, mapname
,
342 /* search mapper entry */
343 ret
= lookup_mapper_entry(ma
->ma_dir
, mapname
, linebuf
,
344 (size_t)PATH_MAX
, &module
, &variable
);
349 ret
= mapper_open(ma
, &cm
, module
, variable
);
352 cm
->cm_key
= strdup(mapname
);
353 if (cm
->cm_key
== NULL
) {
355 rwlock_unlock(&lock
);
360 /* insert to the cache */
362 _CITRUS_HASH_INSERT(&ma
->ma_cache
, cm
, cm_entry
, hashval
);
367 rwlock_unlock(&lock
);
372 * _citrus_mapper_close:
373 * close the specified mapper.
376 _citrus_mapper_close(struct _citrus_mapper
*cm
)
379 rwlock_wrlock(&lock
);
380 if (cm
->cm_refcount
== REFCOUNT_PERSISTENT
)
382 if (cm
->cm_refcount
> 0) {
383 if (--cm
->cm_refcount
> 0)
385 _CITRUS_HASH_REMOVE(cm
, cm_entry
);
388 rwlock_unlock(&lock
);
392 rwlock_unlock(&lock
);
397 * _citrus_mapper_set_persistent:
398 * set persistent count.
401 _citrus_mapper_set_persistent(struct _citrus_mapper
* __restrict cm
)
403 rwlock_wrlock(&lock
);
404 cm
->cm_refcount
= REFCOUNT_PERSISTENT
;
405 rwlock_unlock(&lock
);