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