1 /* $NetBSD: citrus_csmapper.c,v 1.11 2011/11/20 07:43:52 tnozaki 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_csmapper.c,v 1.11 2011/11/20 07:43:52 tnozaki Exp $");
32 #endif /* LIBC_SCCS and not lint */
34 #include "namespace.h"
35 #include "reentrant.h"
43 #include <sys/types.h>
44 #include <sys/queue.h>
46 #include "citrus_namespace.h"
47 #include "citrus_types.h"
48 #include "citrus_bcs.h"
49 #include "citrus_region.h"
50 #include "citrus_memstream.h"
51 #include "citrus_mmap.h"
52 #include "citrus_module.h"
53 #include "citrus_hash.h"
54 #include "citrus_mapper.h"
55 #include "citrus_csmapper.h"
56 #include "citrus_pivot_file.h"
57 #include "citrus_db.h"
58 #include "citrus_db_hash.h"
59 #include "citrus_lookup.h"
62 static rwlock_t lock
= RWLOCK_INITIALIZER
;
64 static struct _citrus_mapper_area
*maparea
= NULL
;
66 #define CS_ALIAS _PATH_CSMAPPER "/charset.alias"
67 #define CS_PIVOT _PATH_CSMAPPER "/charset.pivot"
70 /* ---------------------------------------------------------------------- */
73 get32(struct _region
*r
, uint32_t *rval
)
75 if (_region_size(r
) != 4)
78 memcpy(rval
, _region_head(r
), (size_t)4);
79 *rval
= be32toh(*rval
);
85 open_subdb(struct _citrus_db
**subdb
, struct _citrus_db
*db
, const char *src
)
90 ret
= _db_lookup_by_s(db
, src
, &r
, NULL
);
93 ret
= _db_open(subdb
, &r
, _CITRUS_PIVOT_SUB_MAGIC
, _db_hash_std
, NULL
);
101 #define NO_SUCH_FILE EOPNOTSUPP
103 find_best_pivot_pvdb(const char *src
, const char *dst
, char *pivot
,
104 size_t pvlen
, unsigned long *rnorm
)
107 struct _region fr
, r1
, r2
;
108 struct _citrus_db
*db1
, *db2
, *db3
;
113 ret
= _map_file(&fr
, CS_PIVOT
".pvdb");
119 ret
= _db_open(&db1
, &fr
, _CITRUS_PIVOT_MAGIC
, _db_hash_std
, NULL
);
122 ret
= open_subdb(&db2
, db1
, src
);
126 num
= _db_get_num_entries(db2
);
128 for (i
= 0; i
< num
; i
++) {
129 /* iterate each pivot */
130 ret
= _db_get_entry(db2
, i
, &r1
, &r2
);
133 /* r1:pivot name, r2:norm among src and pivot */
134 ret
= get32(&r2
, &val32
);
138 snprintf(buf
, sizeof(buf
), "%.*s",
139 (int)_region_size(&r1
), (char *)_region_head(&r1
));
140 /* buf: pivot name */
141 ret
= open_subdb(&db3
, db1
, buf
);
144 if (_db_lookup_by_s(db3
, dst
, &r2
, NULL
) != 0)
145 /* don't break the loop, test all src/dst pairs. */
147 /* r2: norm among pivot and dst */
148 ret
= get32(&r2
, &val32
);
152 /* judge minimum norm */
155 strlcpy(pivot
, buf
, pvlen
);
171 if (*rnorm
== ULONG_MAX
)
177 /* ---------------------------------------------------------------------- */
180 const char *begin
, *end
;
189 parse_line(struct parse_arg
*pa
, struct _region
*r
)
195 len
= _region_size(r
);
196 z1
.begin
= _bcs_skip_ws_len(_region_head(r
), &len
);
199 z1
.end
= _bcs_skip_nonws_len(z1
.begin
, &len
);
202 z2
.begin
= _bcs_skip_ws_len(z1
.end
, &len
);
205 z2
.end
= _bcs_skip_nonws_len(z2
.begin
, &len
);
207 /* z1 : dst name, z2 : norm */
208 snprintf(pa
->dst
, sizeof(pa
->dst
),
209 "%.*s", (int)(z1
.end
-z1
.begin
), z1
.begin
);
210 snprintf(buf
, sizeof(buf
),
211 "%.*s", (int)(z2
.end
-z2
.begin
), z2
.begin
);
212 pa
->norm
= _bcs_strtoul(buf
, NULL
, 0);
218 find_dst(struct parse_arg
*pasrc
, const char *dst
)
221 struct parse_arg padst
;
225 ret
= _lookup_seq_open(&cl
, CS_PIVOT
, _LOOKUP_CASE_IGNORE
);
229 ret
= _lookup_seq_lookup(cl
, pasrc
->dst
, &data
);
231 ret
= parse_line(&padst
, &data
);
234 if (strcmp(dst
, padst
.dst
) == 0) {
235 pasrc
->norm
+= padst
.norm
;
238 ret
= _lookup_seq_next(cl
, NULL
, &data
);
240 _lookup_seq_close(cl
);
246 find_best_pivot_lookup(const char *src
, const char *dst
, char *pivot
,
247 size_t pvlen
, unsigned long *rnorm
)
253 unsigned long norm_min
;
254 char pivot_min
[PATH_MAX
];
256 ret
= _lookup_seq_open(&cl
, CS_PIVOT
, _LOOKUP_CASE_IGNORE
);
260 norm_min
= ULONG_MAX
;
262 /* find pivot code */
263 ret
= _lookup_seq_lookup(cl
, src
, &data
);
265 ret
= parse_line(&pa
, &data
);
268 ret
= find_dst(&pa
, dst
);
271 if (pa
.norm
< norm_min
) {
273 strlcpy(pivot_min
, pa
.dst
, sizeof(pivot_min
));
275 ret
= _lookup_seq_next(cl
, NULL
, &data
);
277 _lookup_seq_close(cl
);
281 if (norm_min
== ULONG_MAX
)
283 strlcpy(pivot
, pivot_min
, pvlen
);
291 find_best_pivot(const char *src
, const char *dst
, char *pivot
, size_t pvlen
,
292 unsigned long *rnorm
)
296 ret
= find_best_pivot_pvdb(src
, dst
, pivot
, pvlen
, rnorm
);
297 if (ret
== NO_SUCH_FILE
)
298 ret
= find_best_pivot_lookup(src
, dst
, pivot
, pvlen
, rnorm
);
304 open_serial_mapper(struct _citrus_mapper_area
*__restrict ma
,
305 struct _citrus_mapper
* __restrict
* __restrict rcm
,
306 const char *src
, const char *pivot
, const char *dst
)
310 snprintf(buf
, sizeof(buf
), "%s/%s,%s/%s", src
, pivot
, pivot
, dst
);
312 return _mapper_open_direct(ma
, rcm
, "mapper_serial", buf
);
315 static struct _citrus_csmapper
*csm_none
= NULL
;
317 get_none(struct _citrus_mapper_area
*__restrict ma
,
318 struct _citrus_csmapper
*__restrict
*__restrict rcsm
)
322 rwlock_wrlock(&lock
);
329 ret
= _mapper_open_direct(ma
, &csm_none
, "mapper_none", "");
332 _mapper_set_persistent(csm_none
);
337 rwlock_unlock(&lock
);
342 _citrus_csmapper_open(struct _citrus_csmapper
* __restrict
* __restrict rcsm
,
343 const char * __restrict src
, const char * __restrict dst
,
344 uint32_t flags
, unsigned long *rnorm
)
347 char buf1
[PATH_MAX
], buf2
[PATH_MAX
], key
[PATH_MAX
], pivot
[PATH_MAX
];
348 const char *realsrc
, *realdst
;
351 norm
= 0; /* XXX gcc */
353 ret
= _citrus_mapper_create_area(&maparea
, _PATH_CSMAPPER
);
357 realsrc
= _lookup_alias(CS_ALIAS
, src
, buf1
, sizeof(buf1
),
358 _LOOKUP_CASE_IGNORE
);
359 realdst
= _lookup_alias(CS_ALIAS
, dst
, buf2
, sizeof(buf2
),
360 _LOOKUP_CASE_IGNORE
);
361 if (!strcmp(realsrc
, realdst
)) {
362 ret
= get_none(maparea
, rcsm
);
363 if (ret
== 0 && rnorm
!= NULL
)
368 snprintf(key
, sizeof(key
), "%s/%s", realsrc
, realdst
);
370 ret
= _mapper_open(maparea
, rcsm
, key
);
376 if (ret
!= ENOENT
|| (flags
& _CSMAPPER_F_PREVENT_PIVOT
)!=0)
379 ret
= find_best_pivot(realsrc
, realdst
, pivot
, sizeof(pivot
), &norm
);
383 ret
= open_serial_mapper(maparea
, rcsm
, realsrc
, pivot
, realdst
);
384 if (ret
== 0 && rnorm
!= NULL
)