1 /* $NetBSD: citrus_csmapper.c,v 1.8 2008/02/09 14:56:20 junyoung Exp $ */
2 /* $DragonFly: src/lib/libc/citrus/citrus_csmapper.c,v 1.2 2008/04/10 10:21:01 hasso 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 "namespace.h"
31 #include <sys/types.h>
32 #include <sys/endian.h>
33 #include <sys/queue.h>
42 #include "un-namespace.h"
44 #include "libc_private.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"
61 static pthread_mutex_t lock
= PTHREAD_MUTEX_INITIALIZER
;
62 static struct _citrus_mapper_area
*maparea
= NULL
;
64 #define CS_ALIAS _PATH_CSMAPPER "/charset.alias"
65 #define CS_PIVOT _PATH_CSMAPPER "/charset.pivot"
68 /* ---------------------------------------------------------------------- */
71 get32(struct _region
*r
, uint32_t *rval
)
73 if (_region_size(r
) != 4)
76 memcpy(rval
, _region_head(r
), 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
)
105 struct _region fr
, r1
, r2
;
106 struct _citrus_db
*db1
, *db2
, *db3
;
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)
144 /* r2: norm among pivot and dst */
145 ret
= get32(&r2
, &val32
);
149 /* judge minimum norm */
152 strlcpy(pivot
, buf
, pvlen
);
168 if (*rnorm
== ULONG_MAX
)
174 /* ---------------------------------------------------------------------- */
177 const char *begin
, *end
;
186 parse_line(struct parse_arg
*pa
, struct _region
*r
)
192 len
= _region_size(r
);
193 z1
.begin
= _bcs_skip_ws_len(_region_head(r
), &len
);
196 z1
.end
= _bcs_skip_nonws_len(z1
.begin
, &len
);
199 z2
.begin
= _bcs_skip_ws_len(z1
.end
, &len
);
202 z2
.end
= _bcs_skip_nonws_len(z2
.begin
, &len
);
204 /* z1 : dst name, z2 : norm */
205 snprintf(pa
->dst
, sizeof(pa
->dst
),
206 "%.*s", (int)(z1
.end
-z1
.begin
), z1
.begin
);
207 snprintf(buf
, sizeof(buf
),
208 "%.*s", (int)(z2
.end
-z2
.begin
), z2
.begin
);
209 pa
->norm
= strtoul(buf
, NULL
, 0);
215 find_dst(struct parse_arg
*pasrc
, const char *dst
)
218 struct parse_arg padst
;
222 ret
= _lookup_seq_open(&cl
, CS_PIVOT
, _LOOKUP_CASE_IGNORE
);
226 ret
= _lookup_seq_lookup(cl
, pasrc
->dst
, &data
);
228 ret
= parse_line(&padst
, &data
);
231 if (strcmp(dst
, padst
.dst
) == 0) {
232 pasrc
->norm
+= padst
.norm
;
235 ret
= _lookup_seq_next(cl
, NULL
, &data
);
237 _lookup_seq_close(cl
);
243 find_best_pivot_lookup(const char *src
, const char *dst
, char *pivot
,
244 size_t pvlen
, unsigned long *rnorm
)
250 unsigned long norm_min
;
251 char pivot_min
[PATH_MAX
];
253 ret
= _lookup_seq_open(&cl
, CS_PIVOT
, _LOOKUP_CASE_IGNORE
);
257 norm_min
= ULONG_MAX
;
259 /* find pivot code */
260 ret
= _lookup_seq_lookup(cl
, src
, &data
);
262 ret
= parse_line(&pa
, &data
);
265 ret
= find_dst(&pa
, dst
);
268 if (pa
.norm
< norm_min
) {
270 strlcpy(pivot_min
, pa
.dst
, sizeof(pivot_min
));
272 ret
= _lookup_seq_next(cl
, NULL
, &data
);
274 _lookup_seq_close(cl
);
278 if (norm_min
== ULONG_MAX
)
280 strlcpy(pivot
, pivot_min
, pvlen
);
288 find_best_pivot(const char *src
, const char *dst
, char *pivot
, size_t pvlen
,
289 unsigned long *rnorm
)
293 ret
= find_best_pivot_pvdb(src
, dst
, pivot
, pvlen
, rnorm
);
294 if (ret
== NO_SUCH_FILE
)
295 ret
= find_best_pivot_lookup(src
, dst
, pivot
, pvlen
, rnorm
);
301 open_serial_mapper(struct _citrus_mapper_area
*__restrict ma
,
302 struct _citrus_mapper
* __restrict
* __restrict rcm
,
303 const char *src
, const char *pivot
, const char *dst
)
307 snprintf(buf
, sizeof(buf
), "%s/%s,%s/%s", src
, pivot
, pivot
, dst
);
309 return _mapper_open_direct(ma
, rcm
, "mapper_serial", buf
);
312 static struct _citrus_csmapper
*csm_none
= NULL
;
314 get_none(struct _citrus_mapper_area
*__restrict ma
,
315 struct _citrus_csmapper
*__restrict
*__restrict rcsm
)
320 _pthread_mutex_lock(&lock
);
328 ret
= _mapper_open_direct(ma
, &csm_none
, "mapper_none", "");
331 _mapper_set_persistent(csm_none
);
337 _pthread_mutex_unlock(&lock
);
343 _citrus_csmapper_open(struct _citrus_csmapper
* __restrict
* __restrict rcsm
,
344 const char * __restrict src
, const char * __restrict dst
,
345 uint32_t flags
, unsigned long *rnorm
)
348 char buf1
[PATH_MAX
], buf2
[PATH_MAX
], key
[PATH_MAX
], pivot
[PATH_MAX
];
349 const char *realsrc
, *realdst
;
352 norm
= 0; /* XXX gcc */
354 ret
= _citrus_mapper_create_area(&maparea
, _PATH_CSMAPPER
);
358 realsrc
= _lookup_alias(CS_ALIAS
, src
, buf1
, sizeof(buf1
),
359 _LOOKUP_CASE_IGNORE
);
360 realdst
= _lookup_alias(CS_ALIAS
, dst
, buf2
, sizeof(buf2
),
361 _LOOKUP_CASE_IGNORE
);
362 if (!strcmp(realsrc
, realdst
)) {
363 ret
= get_none(maparea
, rcsm
);
364 if (ret
== 0 && rnorm
!= NULL
)
369 snprintf(key
, sizeof(key
), "%s/%s", realsrc
, realdst
);
371 ret
= _mapper_open(maparea
, rcsm
, key
);
377 if (ret
!= ENOENT
|| (flags
& _CSMAPPER_F_PREVENT_PIVOT
)!=0)
380 ret
= find_best_pivot(realsrc
, realdst
, pivot
, sizeof(pivot
), &norm
);
384 ret
= open_serial_mapper(maparea
, rcsm
, realsrc
, pivot
, realdst
);
385 if (ret
== 0 && rnorm
!= NULL
)