2 /* $NetBSD: citrus_mapper.c,v 1.10 2012/06/08 07:49:42 martin Exp $ */
5 * SPDX-License-Identifier: BSD-2-Clause
7 * Copyright (c)2003 Citrus Project,
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
33 #include <sys/types.h>
35 #include <sys/queue.h>
44 #include "citrus_namespace.h"
45 #include "citrus_types.h"
46 #include "citrus_region.h"
47 #include "citrus_lock.h"
48 #include "citrus_memstream.h"
49 #include "citrus_bcs.h"
50 #include "citrus_mmap.h"
51 #include "citrus_module.h"
52 #include "citrus_hash.h"
53 #include "citrus_mapper.h"
55 #define _CITRUS_MAPPER_DIR "mapper.dir"
57 #define CM_HASH_SIZE 101
58 #define REFCOUNT_PERSISTENT -1
60 static pthread_rwlock_t cm_lock = PTHREAD_RWLOCK_INITIALIZER;
62 struct _citrus_mapper_area {
63 _CITRUS_HASH_HEAD(, _citrus_mapper, CM_HASH_SIZE) ma_cache;
68 * _citrus_mapper_create_area:
73 _citrus_mapper_create_area(
74 struct _citrus_mapper_area *__restrict *__restrict rma,
75 const char *__restrict area)
77 struct _citrus_mapper_area *ma;
89 snprintf(path, (size_t)PATH_MAX, "%s/%s", area, _CITRUS_MAPPER_DIR);
91 ret = stat(path, &st);
95 ma = malloc(sizeof(*ma));
100 ma->ma_dir = strdup(area);
101 if (ma->ma_dir == NULL) {
106 _CITRUS_HASH_INIT(&ma->ma_cache, CM_HASH_SIZE);
118 * lookup_mapper_entry:
119 * lookup mapper.dir entry in the specified directory.
121 * line format of iconv.dir file:
123 * mapper : mapper name.
124 * module : mapper module name.
125 * arg : argument for the module (generally, description file name)
129 lookup_mapper_entry(const char *dir, const char *mapname, void *linebuf,
130 size_t linebufsize, const char **module, const char **variable)
133 struct _memstream ms;
140 /* create mapper.dir path */
141 snprintf(path, (size_t)PATH_MAX, "%s/%s", dir, _CITRUS_MAPPER_DIR);
143 /* open read stream */
144 ret = _map_file(&r, path);
148 _memstream_bind(&ms, &r);
150 /* search the line matching to the map name */
151 cp = _memstream_matchline(&ms, mapname, &len, 0);
156 if (!len || len > linebufsize - 1) {
162 /* get module name */
164 cq = _bcs_skip_nonws_len(cp, &len);
165 strlcpy(p, cp, (size_t)(cq - cp + 1));
170 cp = _bcs_skip_ws_len(cq, &len);
171 strlcpy(p, cp, len + 1);
182 * simply close a mapper. (without handling hash)
185 mapper_close(struct _citrus_mapper *cm)
190 (*cm->cm_ops->mo_uninit)(cm);
193 _citrus_unload_module(cm->cm_module);
201 * simply open a mapper. (without handling hash)
204 mapper_open(struct _citrus_mapper_area *__restrict ma,
205 struct _citrus_mapper * __restrict * __restrict rcm,
206 const char * __restrict module,
207 const char * __restrict variable)
209 struct _citrus_mapper *cm;
210 _citrus_mapper_getops_t getops;
213 /* initialize mapper handle */
214 cm = malloc(sizeof(*cm));
218 cm->cm_module = NULL;
220 cm->cm_closure = NULL;
221 cm->cm_traits = NULL;
226 ret = _citrus_load_module(&cm->cm_module, module);
231 getops = (_citrus_mapper_getops_t)
232 _citrus_find_getops(cm->cm_module, module, "mapper");
237 cm->cm_ops = malloc(sizeof(*cm->cm_ops));
242 ret = (*getops)(cm->cm_ops);
246 if (!cm->cm_ops->mo_init ||
247 !cm->cm_ops->mo_uninit ||
248 !cm->cm_ops->mo_convert ||
249 !cm->cm_ops->mo_init_state) {
254 /* allocate traits structure */
255 cm->cm_traits = malloc(sizeof(*cm->cm_traits));
256 if (cm->cm_traits == NULL) {
260 /* initialize the mapper */
261 ret = (*cm->cm_ops->mo_init)(ma, cm, ma->ma_dir,
262 (const void *)variable, strlen(variable) + 1,
263 cm->cm_traits, sizeof(*cm->cm_traits));
277 * _citrus_mapper_open_direct:
281 _citrus_mapper_open_direct(struct _citrus_mapper_area *__restrict ma,
282 struct _citrus_mapper * __restrict * __restrict rcm,
283 const char * __restrict module, const char * __restrict variable)
286 return (mapper_open(ma, rcm, module, variable));
293 hash_func(const char *key)
296 return (_string_hash_func(key, CM_HASH_SIZE));
303 match_func(struct _citrus_mapper *cm, const char *key)
306 return (strcmp(cm->cm_key, key));
310 * _citrus_mapper_open:
311 * open a mapper with looking up "mapper.dir".
314 _citrus_mapper_open(struct _citrus_mapper_area *__restrict ma,
315 struct _citrus_mapper * __restrict * __restrict rcm,
316 const char * __restrict mapname)
318 struct _citrus_mapper *cm;
319 char linebuf[PATH_MAX];
320 const char *module, *variable;
327 /* search in the cache */
328 hashval = hash_func(mapname);
329 _CITRUS_HASH_SEARCH(&ma->ma_cache, cm, cm_entry, match_func, mapname,
339 /* search mapper entry */
340 ret = lookup_mapper_entry(ma->ma_dir, mapname, linebuf,
341 (size_t)PATH_MAX, &module, &variable);
347 ret = mapper_open(ma, &cm, module, variable);
351 cm->cm_key = strdup(mapname);
352 if (cm->cm_key == NULL) {
358 /* insert to the cache */
360 _CITRUS_HASH_INSERT(&ma->ma_cache, cm, cm_entry, hashval);
371 * _citrus_mapper_close:
372 * close the specified mapper.
375 _citrus_mapper_close(struct _citrus_mapper *cm)
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);
397 * _citrus_mapper_set_persistent:
398 * set persistent count.
401 _citrus_mapper_set_persistent(struct _citrus_mapper * __restrict cm)
405 cm->cm_refcount = REFCOUNT_PERSISTENT;