1 /* $FreeBSD: head/lib/libc/iconv/citrus_csmapper.c 263986 2014-04-01 10:36:11Z tijl $ */
2 /* $NetBSD: citrus_csmapper.c,v 1.11 2011/11/20 07:43:52 tnozaki Exp $ */
5 * Copyright (c)2003 Citrus Project,
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 #include <sys/endian.h>
32 #include <sys/types.h>
33 #include <sys/queue.h>
43 #include "citrus_namespace.h"
44 #include "citrus_types.h"
45 #include "citrus_bcs.h"
46 #include "citrus_region.h"
47 #include "citrus_lock.h"
48 #include "citrus_memstream.h"
49 #include "citrus_mmap.h"
50 #include "citrus_module.h"
51 #include "citrus_hash.h"
52 #include "citrus_mapper.h"
53 #include "citrus_csmapper.h"
54 #include "citrus_pivot_file.h"
55 #include "citrus_db.h"
56 #include "citrus_db_hash.h"
57 #include "citrus_lookup.h"
59 static struct _citrus_mapper_area
*maparea
= NULL
;
61 static pthread_rwlock_t ma_lock
= PTHREAD_RWLOCK_INITIALIZER
;
63 #define CS_ALIAS _PATH_CSMAPPER "/charset.alias"
64 #define CS_PIVOT _PATH_CSMAPPER "/charset.pivot"
67 /* ---------------------------------------------------------------------- */
70 get32(struct _region
*r
, uint32_t *rval
)
73 if (_region_size(r
) != 4)
76 memcpy(rval
, _region_head(r
), (size_t)4);
77 *rval
= be32toh(*rval
);
83 open_subdb(struct _citrus_db
**subdb
, struct _citrus_db
*db
, const char *src
)
88 ret
= _db_lookup_by_s(db
, src
, &r
, NULL
);
91 ret
= _db_open(subdb
, &r
, _CITRUS_PIVOT_SUB_MAGIC
, _db_hash_std
, NULL
);
99 #define NO_SUCH_FILE EOPNOTSUPP
101 find_best_pivot_pvdb(const char *src
, const char *dst
, char *pivot
,
102 size_t pvlen
, unsigned long *rnorm
)
104 struct _citrus_db
*db1
, *db2
, *db3
;
105 struct _region fr
, r1
, r2
;
111 ret
= _map_file(&fr
, CS_PIVOT
".pvdb");
117 ret
= _db_open(&db1
, &fr
, _CITRUS_PIVOT_MAGIC
, _db_hash_std
, NULL
);
120 ret
= open_subdb(&db2
, db1
, src
);
124 num
= _db_get_num_entries(db2
);
126 for (i
= 0; i
< num
; i
++) {
127 /* iterate each pivot */
128 ret
= _db_get_entry(db2
, i
, &r1
, &r2
);
131 /* r1:pivot name, r2:norm among src and pivot */
132 ret
= get32(&r2
, &val32
);
136 snprintf(buf
, sizeof(buf
), "%.*s",
137 (int)_region_size(&r1
), (char *)_region_head(&r1
));
138 /* buf: pivot name */
139 ret
= open_subdb(&db3
, db1
, buf
);
142 if (_db_lookup_by_s(db3
, dst
, &r2
, NULL
) != 0)
143 /* don't break the loop, test all src/dst pairs. */
145 /* r2: norm among pivot and dst */
146 ret
= get32(&r2
, &val32
);
150 /* judge minimum norm */
153 strlcpy(pivot
, buf
, pvlen
);
169 if (*rnorm
== ULONG_MAX
)
175 /* ---------------------------------------------------------------------- */
178 const char *begin
, *end
;
187 parse_line(struct parse_arg
*pa
, struct _region
*r
)
193 len
= _region_size(r
);
194 z1
.begin
= _bcs_skip_ws_len(_region_head(r
), &len
);
197 z1
.end
= _bcs_skip_nonws_len(z1
.begin
, &len
);
200 z2
.begin
= _bcs_skip_ws_len(z1
.end
, &len
);
203 z2
.end
= _bcs_skip_nonws_len(z2
.begin
, &len
);
205 /* z1 : dst name, z2 : norm */
206 snprintf(pa
->dst
, sizeof(pa
->dst
),
207 "%.*s", (int)(z1
.end
-z1
.begin
), z1
.begin
);
208 snprintf(buf
, sizeof(buf
),
209 "%.*s", (int)(z2
.end
-z2
.begin
), z2
.begin
);
210 pa
->norm
= _bcs_strtoul(buf
, NULL
, 0);
216 find_dst(struct parse_arg
*pasrc
, const char *dst
)
219 struct parse_arg padst
;
223 ret
= _lookup_seq_open(&cl
, CS_PIVOT
, _LOOKUP_CASE_IGNORE
);
227 ret
= _lookup_seq_lookup(cl
, pasrc
->dst
, &data
);
229 ret
= parse_line(&padst
, &data
);
232 if (strcmp(dst
, padst
.dst
) == 0) {
233 pasrc
->norm
+= padst
.norm
;
236 ret
= _lookup_seq_next(cl
, NULL
, &data
);
238 _lookup_seq_close(cl
);
244 find_best_pivot_lookup(const char *src
, const char *dst
, char *pivot
,
245 size_t pvlen
, unsigned long *rnorm
)
250 char pivot_min
[PATH_MAX
];
251 unsigned long norm_min
;
254 ret
= _lookup_seq_open(&cl
, CS_PIVOT
, _LOOKUP_CASE_IGNORE
);
258 norm_min
= ULONG_MAX
;
260 /* find pivot code */
261 ret
= _lookup_seq_lookup(cl
, src
, &data
);
263 ret
= parse_line(&pa
, &data
);
266 ret
= find_dst(&pa
, dst
);
269 if (pa
.norm
< norm_min
) {
271 strlcpy(pivot_min
, pa
.dst
, sizeof(pivot_min
));
273 ret
= _lookup_seq_next(cl
, NULL
, &data
);
275 _lookup_seq_close(cl
);
279 if (norm_min
== ULONG_MAX
)
281 strlcpy(pivot
, pivot_min
, pvlen
);
289 find_best_pivot(const char *src
, const char *dst
, char *pivot
, size_t pvlen
,
290 unsigned long *rnorm
)
294 ret
= find_best_pivot_pvdb(src
, dst
, pivot
, pvlen
, rnorm
);
295 if (ret
== NO_SUCH_FILE
)
296 ret
= find_best_pivot_lookup(src
, dst
, pivot
, pvlen
, rnorm
);
302 open_serial_mapper(struct _citrus_mapper_area
*__restrict ma
,
303 struct _citrus_mapper
* __restrict
* __restrict rcm
,
304 const char *src
, const char *pivot
, const char *dst
)
308 snprintf(buf
, sizeof(buf
), "%s/%s,%s/%s", src
, pivot
, pivot
, dst
);
310 return (_mapper_open_direct(ma
, rcm
, "mapper_serial", buf
));
313 static struct _citrus_csmapper
*csm_none
= NULL
;
315 get_none(struct _citrus_mapper_area
*__restrict ma
,
316 struct _citrus_csmapper
*__restrict
*__restrict rcsm
)
327 ret
= _mapper_open_direct(ma
, &csm_none
, "mapper_none", "");
330 _mapper_set_persistent(csm_none
);
340 _citrus_csmapper_open(struct _citrus_csmapper
* __restrict
* __restrict rcsm
,
341 const char * __restrict src
, const char * __restrict dst
, uint32_t flags
,
342 unsigned long *rnorm
)
344 const char *realsrc
, *realdst
;
345 char buf1
[PATH_MAX
], buf2
[PATH_MAX
], key
[PATH_MAX
], pivot
[PATH_MAX
];
351 ret
= _citrus_mapper_create_area(&maparea
, _PATH_CSMAPPER
);
355 realsrc
= _lookup_alias(CS_ALIAS
, src
, buf1
, sizeof(buf1
),
356 _LOOKUP_CASE_IGNORE
);
357 realdst
= _lookup_alias(CS_ALIAS
, dst
, buf2
, sizeof(buf2
),
358 _LOOKUP_CASE_IGNORE
);
359 if (!strcmp(realsrc
, realdst
)) {
360 ret
= get_none(maparea
, rcsm
);
361 if (ret
== 0 && rnorm
!= NULL
)
366 snprintf(key
, sizeof(key
), "%s/%s", realsrc
, realdst
);
368 ret
= _mapper_open(maparea
, rcsm
, key
);
374 if (ret
!= ENOENT
|| (flags
& _CSMAPPER_F_PREVENT_PIVOT
)!=0)
377 ret
= find_best_pivot(realsrc
, realdst
, pivot
, sizeof(pivot
), &norm
);
381 ret
= open_serial_mapper(maparea
, rcsm
, realsrc
, pivot
, realdst
);
382 if (ret
== 0 && rnorm
!= NULL
)