1 /* $NetBSD: citrus_csmapper.c,v 1.8.12.1 2009/01/04 17:02:18 christos 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.8.12.1 2009/01/04 17:02:18 christos 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)
146 /* r2: norm among pivot and dst */
147 ret
= get32(&r2
, &val32
);
151 /* judge minimum norm */
154 strlcpy(pivot
, buf
, pvlen
);
170 if (*rnorm
== ULONG_MAX
)
176 /* ---------------------------------------------------------------------- */
179 const char *begin
, *end
;
188 parse_line(struct parse_arg
*pa
, struct _region
*r
)
194 len
= _region_size(r
);
195 z1
.begin
= _bcs_skip_ws_len(_region_head(r
), &len
);
198 z1
.end
= _bcs_skip_nonws_len(z1
.begin
, &len
);
201 z2
.begin
= _bcs_skip_ws_len(z1
.end
, &len
);
204 z2
.end
= _bcs_skip_nonws_len(z2
.begin
, &len
);
206 /* z1 : dst name, z2 : norm */
207 snprintf(pa
->dst
, sizeof(pa
->dst
),
208 "%.*s", (int)(z1
.end
-z1
.begin
), z1
.begin
);
209 snprintf(buf
, sizeof(buf
),
210 "%.*s", (int)(z2
.end
-z2
.begin
), z2
.begin
);
211 pa
->norm
= _bcs_strtoul(buf
, NULL
, 0);
217 find_dst(struct parse_arg
*pasrc
, const char *dst
)
220 struct parse_arg padst
;
224 ret
= _lookup_seq_open(&cl
, CS_PIVOT
, _LOOKUP_CASE_IGNORE
);
228 ret
= _lookup_seq_lookup(cl
, pasrc
->dst
, &data
);
230 ret
= parse_line(&padst
, &data
);
233 if (strcmp(dst
, padst
.dst
) == 0) {
234 pasrc
->norm
+= padst
.norm
;
237 ret
= _lookup_seq_next(cl
, NULL
, &data
);
239 _lookup_seq_close(cl
);
245 find_best_pivot_lookup(const char *src
, const char *dst
, char *pivot
,
246 size_t pvlen
, unsigned long *rnorm
)
252 unsigned long norm_min
;
253 char pivot_min
[PATH_MAX
];
255 ret
= _lookup_seq_open(&cl
, CS_PIVOT
, _LOOKUP_CASE_IGNORE
);
259 norm_min
= ULONG_MAX
;
261 /* find pivot code */
262 ret
= _lookup_seq_lookup(cl
, src
, &data
);
264 ret
= parse_line(&pa
, &data
);
267 ret
= find_dst(&pa
, dst
);
270 if (pa
.norm
< norm_min
) {
272 strlcpy(pivot_min
, pa
.dst
, sizeof(pivot_min
));
274 ret
= _lookup_seq_next(cl
, NULL
, &data
);
276 _lookup_seq_close(cl
);
280 if (norm_min
== ULONG_MAX
)
282 strlcpy(pivot
, pivot_min
, pvlen
);
290 find_best_pivot(const char *src
, const char *dst
, char *pivot
, size_t pvlen
,
291 unsigned long *rnorm
)
295 ret
= find_best_pivot_pvdb(src
, dst
, pivot
, pvlen
, rnorm
);
296 if (ret
== NO_SUCH_FILE
)
297 ret
= find_best_pivot_lookup(src
, dst
, pivot
, pvlen
, rnorm
);
303 open_serial_mapper(struct _citrus_mapper_area
*__restrict ma
,
304 struct _citrus_mapper
* __restrict
* __restrict rcm
,
305 const char *src
, const char *pivot
, const char *dst
)
309 snprintf(buf
, sizeof(buf
), "%s/%s,%s/%s", src
, pivot
, pivot
, dst
);
311 return _mapper_open_direct(ma
, rcm
, "mapper_serial", buf
);
314 static struct _citrus_csmapper
*csm_none
= NULL
;
316 get_none(struct _citrus_mapper_area
*__restrict ma
,
317 struct _citrus_csmapper
*__restrict
*__restrict rcsm
)
321 rwlock_wrlock(&lock
);
328 ret
= _mapper_open_direct(ma
, &csm_none
, "mapper_none", "");
331 _mapper_set_persistent(csm_none
);
336 rwlock_unlock(&lock
);
341 _citrus_csmapper_open(struct _citrus_csmapper
* __restrict
* __restrict rcsm
,
342 const char * __restrict src
, const char * __restrict dst
,
343 uint32_t flags
, unsigned long *rnorm
)
346 char buf1
[PATH_MAX
], buf2
[PATH_MAX
], key
[PATH_MAX
], pivot
[PATH_MAX
];
347 const char *realsrc
, *realdst
;
350 norm
= 0; /* XXX gcc */
352 ret
= _citrus_mapper_create_area(&maparea
, _PATH_CSMAPPER
);
356 realsrc
= _lookup_alias(CS_ALIAS
, src
, buf1
, sizeof(buf1
),
357 _LOOKUP_CASE_IGNORE
);
358 realdst
= _lookup_alias(CS_ALIAS
, dst
, buf2
, sizeof(buf2
),
359 _LOOKUP_CASE_IGNORE
);
360 if (!strcmp(realsrc
, realdst
)) {
361 ret
= get_none(maparea
, rcsm
);
362 if (ret
== 0 && rnorm
!= NULL
)
367 snprintf(key
, sizeof(key
), "%s/%s", realsrc
, realdst
);
369 ret
= _mapper_open(maparea
, rcsm
, key
);
375 if (ret
!= ENOENT
|| (flags
& _CSMAPPER_F_PREVENT_PIVOT
)!=0)
378 ret
= find_best_pivot(realsrc
, realdst
, pivot
, sizeof(pivot
), &norm
);
382 ret
= open_serial_mapper(maparea
, rcsm
, realsrc
, pivot
, realdst
);
383 if (ret
== 0 && rnorm
!= NULL
)