xref: /dragonfly/lib/libc/citrus/citrus_esdb.c (revision 6bd457ed)
1 /*	$NetBSD: src/lib/libc/citrus/citrus_esdb.c,v 1.4 2004/07/21 14:16:34 tshiozak Exp $	*/
2 /*	$DragonFly: src/lib/libc/citrus/citrus_esdb.c,v 1.1 2005/03/11 23:33:53 joerg Exp $ */
3 
4 
5 /*-
6  * Copyright (c)2003 Citrus Project,
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <assert.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <limits.h>
37 #include <paths.h>
38 #include <sys/types.h>
39 
40 #include "citrus_namespace.h"
41 #include "citrus_types.h"
42 #include "citrus_bcs.h"
43 #include "citrus_region.h"
44 #include "citrus_memstream.h"
45 #include "citrus_mmap.h"
46 #include "citrus_lookup.h"
47 #include "citrus_db.h"
48 #include "citrus_db_hash.h"
49 #include "citrus_esdb.h"
50 #include "citrus_esdb_file.h"
51 
52 #define ESDB_DIR	"esdb.dir"
53 #define ESDB_ALIAS	"esdb.alias"
54 
55 /*
56  * _citrus_esdb_alias:
57  *	resolve encoding scheme name aliases.
58  */
59 const char *
60 _citrus_esdb_alias(const char *esname, char *buf, size_t bufsize)
61 {
62 	return _lookup_alias(_PATH_ESDB "/" ESDB_ALIAS, esname, buf, bufsize,
63 			     _LOOKUP_CASE_IGNORE);
64 }
65 
66 
67 /*
68  * conv_esdb:
69  *	external representation -> local structure.
70  */
71 static int
72 conv_esdb(struct _citrus_esdb *esdb, struct _region *fr)
73 {
74 	int ret;
75 	struct _citrus_db *db;
76 	uint32_t version, num_charsets, csid, i, tmp;
77 	char buf[100];
78 	const char *str;
79 
80 	/* open db */
81 	ret = _db_open(&db, fr, _CITRUS_ESDB_MAGIC, &_db_hash_std, NULL);
82 	if (ret)
83 		goto err0;
84 
85 	/* check version */
86 	ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_VERSION, &version, NULL);
87 	if (ret)
88 		goto err1;
89 	switch (version) {
90 	case 0x00000001:
91 		/* current version */
92 		/* initial version */
93 		break;
94 	default:
95 		ret = EFTYPE;
96 		goto err1;
97 	}
98 
99 	/* get encoding/variable */
100 	ret = _db_lookupstr_by_s(db, _CITRUS_ESDB_SYM_ENCODING, &str, NULL);
101 	if (ret)
102 		goto err1;
103 	esdb->db_encname = strdup(str);
104 	if (esdb->db_encname == NULL) {
105 		ret = errno;
106 		goto err1;
107 	}
108 
109 	esdb->db_len_variable = 0;
110 	esdb->db_variable = NULL;
111 	ret = _db_lookupstr_by_s(db, _CITRUS_ESDB_SYM_VARIABLE, &str, NULL);
112 	if (ret == 0) {
113 		esdb->db_len_variable = strlen(str)+1;
114 		esdb->db_variable = strdup(str);
115 		if (esdb->db_variable == NULL) {
116 			ret = errno;
117 			goto err2;
118 		}
119 	} else if (ret != ENOENT)
120 		goto err2;
121 
122 	/* get number of charsets */
123 	ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_NUM_CHARSETS,
124 				&num_charsets, NULL);
125 	if (ret)
126 		goto err3;
127 	esdb->db_num_charsets = num_charsets;
128 
129 	/* get invalid character */
130 	ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_INVALID, &tmp, NULL);
131 	if (ret == 0) {
132 		esdb->db_use_invalid = 1;
133 		esdb->db_invalid = tmp;
134 	} else if (ret == ENOENT)
135 		esdb->db_use_invalid = 0;
136 	else
137 		goto err3;
138 
139 	/* get charsets */
140 	esdb->db_charsets = malloc(num_charsets * sizeof(*esdb->db_charsets));
141 	if (esdb->db_charsets == NULL) {
142 		ret = errno;
143 		goto err3;
144 	}
145 	for (i = 0; i < num_charsets; i++) {
146 		snprintf(buf, sizeof(buf),
147 		    _CITRUS_ESDB_SYM_CSID_PREFIX "%d", i);
148 		ret = _db_lookup32_by_s(db, buf, &csid, NULL);
149 		if (ret)
150 			goto err4;
151 		esdb->db_charsets[i].ec_csid = csid;
152 
153 		snprintf(buf, sizeof(buf),
154 		    _CITRUS_ESDB_SYM_CSNAME_PREFIX "%d", i);
155 		ret = _db_lookupstr_by_s(db, buf, &str, NULL);
156 		if (ret)
157 			goto err4;
158 		esdb->db_charsets[i].ec_csname = strdup(str);
159 		if (esdb->db_charsets[i].ec_csname == NULL) {
160 			ret = errno;
161 			goto err4;
162 		}
163 	}
164 
165 	_db_close(db);
166 	return 0;
167 
168 err4:
169 	for (; i > 0; i--)
170 		free(esdb->db_charsets[i - 1].ec_csname);
171 	free(esdb->db_charsets);
172 err3:
173 	free(esdb->db_variable);
174 err2:
175 	free(esdb->db_encname);
176 err1:
177 	_db_close(db);
178 	if (ret == ENOENT)
179 		ret = EFTYPE;
180 err0:
181 	return ret;
182 }
183 
184 /*
185  * _citrus_esdb_open:
186  *	open an ESDB file.
187  */
188 int
189 _citrus_esdb_open(struct _citrus_esdb *db, const char *esname)
190 {
191 	int ret;
192 	const char *realname, *encfile;
193 	char buf1[PATH_MAX], buf2[PATH_MAX], path[PATH_MAX];
194 	struct _region fr;
195 
196 	_DIAGASSERT(esname != NULL);
197 
198 	snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, ESDB_ALIAS);
199 	realname = _lookup_alias(path, esname, buf1, sizeof(buf1),
200 				 _LOOKUP_CASE_IGNORE);
201 
202 	snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, ESDB_DIR);
203 	encfile = _lookup_simple(path, realname, buf2, sizeof(buf2),
204 				 _LOOKUP_CASE_IGNORE);
205 	if (encfile==NULL)
206 		return ENOENT;
207 
208 	/* open file */
209 	snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, encfile);
210 	ret = _map_file(&fr, path);
211 	if (ret)
212 		return ret;
213 
214 	ret = conv_esdb(db, &fr);
215 
216 	_unmap_file(&fr);
217 
218 	return ret;
219 }
220 
221 /*
222  * _citrus_esdb_close:
223  *	free an ESDB.
224  */
225 void
226 _citrus_esdb_close(struct _citrus_esdb *db)
227 {
228 	int i;
229 
230 	_DIAGASSERT(db != NULL);
231 	_DIAGASSERT(db->db_num_charsets == 0 || db->db_charsets != NULL);
232 
233 	for (i = 0; i < db->db_num_charsets; i++)
234 		free(db->db_charsets[i].ec_csname);
235 	db->db_num_charsets = 0;
236 	free(db->db_charsets); db->db_charsets = NULL;
237 	free(db->db_encname); db->db_encname = NULL;
238 	db->db_len_variable = 0;
239 	free(db->db_variable); db->db_variable = NULL;
240 }
241 
242 /*
243  * _citrus_esdb_free_list:
244  *	free the list.
245  */
246 void
247 _citrus_esdb_free_list(char **list, size_t num)
248 {
249 	size_t i;
250 
251 	for (i = 0; i < num; i++)
252 		free(list[i]);
253 	free(list);
254 }
255 
256 /*
257  * _citrus_esdb_get_list:
258  *	get esdb entries.
259  */
260 int
261 _citrus_esdb_get_list(char ***rlist, size_t *rnum)
262 {
263 	int ret;
264 	struct _region key;
265 	size_t num;
266 	struct _citrus_lookup *cla, *cld;
267 	char **list, **q;
268 	char buf[PATH_MAX];
269 
270 	num = 0;
271 
272 	ret = _lookup_seq_open(&cla, _PATH_ESDB "/" ESDB_ALIAS,
273 			       _LOOKUP_CASE_IGNORE);
274 	if (ret)
275 		goto quit0;
276 
277 	ret = _lookup_seq_open(&cld, _PATH_ESDB "/" ESDB_DIR,
278 			       _LOOKUP_CASE_IGNORE);
279 	if (ret)
280 		goto quit1;
281 
282 	/* count number of entries */
283 	num = _lookup_get_num_entries(cla) + _lookup_get_num_entries(cld);
284 
285 	_lookup_seq_rewind(cla);
286 	_lookup_seq_rewind(cld);
287 
288 	/* allocate list pointer space */
289 	list = malloc(num * sizeof(char *));
290 	num = 0;
291 	if (list == NULL) {
292 		ret = errno;
293 		goto quit3;
294 	}
295 
296 	/* get alias entries */
297 	while ((ret = _lookup_seq_next(cla, &key, NULL)) == 0) {
298 		snprintf(buf, sizeof(buf), "%.*s",
299 			 (int)_region_size(&key),
300 			 (const char *)_region_head(&key));
301 		_bcs_convert_to_lower(buf);
302 		list[num] = strdup(buf);
303 		if (list[num] == NULL) {
304 			ret = errno;
305 			goto quit3;
306 		}
307 		num++;
308 	}
309 	if (ret != ENOENT)
310 		goto quit3;
311 	/* get dir entries */
312 	while ((ret = _lookup_seq_next(cld, &key, NULL)) == 0) {
313 		/* check duplicated entry */
314 		snprintf(buf, sizeof(buf), "%.*s",
315 			 (int)_region_size(&key),
316 			 (const char *)_region_head(&key));
317 		_bcs_convert_to_lower(buf);
318 		ret = _lookup_seq_lookup(cla, buf, NULL);
319 		if (ret) {
320 			if (ret != ENOENT)
321 				goto quit3;
322 			/* not duplicated */
323 			list[num] = strdup(buf);
324 			if (list[num] == NULL) {
325 				ret = errno;
326 				goto quit3;
327 			}
328 			num++;
329 		}
330 	}
331 	if (ret != ENOENT)
332 		goto quit3;
333 
334 	ret = 0;
335 	q = realloc(list, num * sizeof(char *));
336 	if (!q) {
337 		ret = ENOMEM;
338 		goto quit3;
339 	}
340 	list = q;
341 	*rlist = list;
342 	*rnum = num;
343 quit3:
344 	if (ret)
345 		_citrus_esdb_free_list(list, num);
346 	_lookup_seq_close(cld);
347 quit1:
348 	_lookup_seq_close(cla);
349 quit0:
350 	return ret;
351 }
352