Home | History | Annotate | Line # | Download | only in citrus
citrus_esdb.c revision 1.1
      1 /*	$NetBSD: citrus_esdb.c,v 1.1 2003/06/25 09:51:31 tshiozak 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.1 2003/06/25 09:51:31 tshiozak 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 }
     68 
     69 
     70 /*
     71  * conv_esdb:
     72  *	external representation -> local structure.
     73  */
     74 static int
     75 conv_esdb(struct _citrus_esdb *esdb, struct _region *fr)
     76 {
     77 	int ret;
     78 	struct _citrus_db *db;
     79 	u_int32_t version, num_charsets, csid, i, tmp;
     80 	char buf[100];
     81 	const char *str;
     82 
     83 	/* open db */
     84 	ret = _db_open(&db, fr, _CITRUS_ESDB_MAGIC, &_db_hash_std, NULL);
     85 	if (ret)
     86 		goto err0;
     87 
     88 	/* check version */
     89 	ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_VERSION, &version, NULL);
     90 	if (ret)
     91 		goto err1;
     92 	switch (version) {
     93 	case 0x00000001:
     94 		/* current version */
     95 		/* initial version */
     96 		break;
     97 	default:
     98 		ret = EFTYPE;
     99 		goto err1;
    100 	}
    101 
    102 	/* get encoding/variable */
    103 	ret = _db_lookupstr_by_s(db, _CITRUS_ESDB_SYM_ENCODING, &str, NULL);
    104 	if (ret)
    105 		goto err1;
    106 	esdb->db_encname = strdup(str);
    107 	if (esdb->db_encname == NULL) {
    108 		ret = errno;
    109 		goto err1;
    110 	}
    111 
    112 	esdb->db_len_variable = 0;
    113 	esdb->db_variable = NULL;
    114 	ret = _db_lookupstr_by_s(db, _CITRUS_ESDB_SYM_VARIABLE, &str, NULL);
    115 	if (ret==0) {
    116 		esdb->db_len_variable = strlen(str)+1;
    117 		esdb->db_variable = strdup(str);
    118 		if (esdb->db_variable == NULL) {
    119 			ret = errno;
    120 			goto err2;
    121 		}
    122 	} else if (ret != ENOENT)
    123 		goto err2;
    124 
    125 	/* get number of charsets */
    126 	ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_NUM_CHARSETS,
    127 				&num_charsets, NULL);
    128 	if (ret)
    129 		goto err3;
    130 	esdb->db_num_charsets = num_charsets;
    131 
    132 	/* get invalid character */
    133 	ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_INVALID, &tmp, NULL);
    134 	if (ret==0) {
    135 		esdb->db_use_invalid = 1;
    136 		esdb->db_invalid = tmp;
    137 	} else if (ret == ENOENT)
    138 		esdb->db_use_invalid = 0;
    139 	else
    140 		goto err3;
    141 
    142 	/* get charsets */
    143 	esdb->db_charsets = malloc(num_charsets * sizeof(*esdb->db_charsets));
    144 	if (esdb->db_charsets == NULL) {
    145 		ret = errno;
    146 		goto err3;
    147 	}
    148 	for (i=0; i<num_charsets; i++) {
    149 		sprintf(buf, _CITRUS_ESDB_SYM_CSID_PREFIX "%d", i);
    150 		ret = _db_lookup32_by_s(db, buf, &csid, NULL);
    151 		if (ret)
    152 			goto err4;
    153 		esdb->db_charsets[i].ec_csid = csid;
    154 
    155 		sprintf(buf, _CITRUS_ESDB_SYM_CSNAME_PREFIX "%d", i);
    156 		ret = _db_lookupstr_by_s(db, buf, &str, NULL);
    157 		if (ret)
    158 			goto err4;
    159 		esdb->db_charsets[i].ec_csname = strdup(str);
    160 		if (esdb->db_charsets[i].ec_csname == NULL) {
    161 			ret = errno;
    162 			goto err4;
    163 		}
    164 	}
    165 
    166 	_db_close(db);
    167 	return 0;
    168 
    169 err4:
    170 	for (; i>0; i--)
    171 		free(esdb->db_charsets[i-1].ec_csname);
    172 	free(esdb->db_charsets);
    173 err3:
    174 	free(esdb->db_variable);
    175 err2:
    176 	free(esdb->db_encname);
    177 err1:
    178 	_db_close(db);
    179 	if (ret == ENOENT)
    180 		ret = EFTYPE;
    181 err0:
    182 	return ret;
    183 }
    184 
    185 /*
    186  * _citrus_esdb_open:
    187  *	open an ESDB file.
    188  */
    189 int
    190 _citrus_esdb_open(struct _citrus_esdb *db, const char *esname)
    191 {
    192 	int ret;
    193 	const char *realname, *encfile;
    194 	char buf1[PATH_MAX], buf2[PATH_MAX], path[PATH_MAX];
    195 	struct _region fr;
    196 
    197 	_DIAGASSERT(esname != NULL);
    198 
    199 	snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, ESDB_ALIAS);
    200 	realname = _lookup_alias(path, esname, buf1, sizeof(buf1));
    201 
    202 	snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, ESDB_DIR);
    203 	encfile = _lookup_simple(path, realname, buf2, sizeof(buf2));
    204 	if (encfile==NULL)
    205 		return ENOENT;
    206 
    207 	/* open file */
    208 	snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, encfile);
    209 	ret = _map_file(&fr, path);
    210 	if (ret)
    211 		return ret;
    212 
    213 	ret = conv_esdb(db, &fr);
    214 
    215 	_unmap_file(&fr);
    216 
    217 	return ret;
    218 }
    219 
    220 /*
    221  * _citrus_esdb_close:
    222  *	free an ESDB.
    223  */
    224 void
    225 _citrus_esdb_close(struct _citrus_esdb *db)
    226 {
    227 	int i;
    228 
    229 	_DIAGASSERT(db != NULL);
    230 	_DIAGASSERT(db->db_num_charsets == 0 || db->db_charsets != NULL);
    231 
    232 	for (i=0; i<db->db_num_charsets; i++)
    233 		free(db->db_charsets[i].ec_csname);
    234 	db->db_num_charsets = 0;
    235 	free(db->db_charsets); db->db_charsets = NULL;
    236 	free(db->db_encname); db->db_encname = NULL;
    237 	db->db_len_variable = 0;
    238 	free(db->db_variable); db->db_variable = NULL;
    239 }
    240 
    241 /*
    242  * _citrus_esdb_free_list:
    243  *	free the list.
    244  */
    245 void
    246 _citrus_esdb_free_list(char **list, size_t num)
    247 {
    248 	size_t i;
    249 
    250 	for (i=0; i<num; i++)
    251 		free(list[i]);
    252 	free(list);
    253 }
    254 
    255 /*
    256  * _citrus_esdb_get_list:
    257  *	get esdb entries.
    258  */
    259 int
    260 _citrus_esdb_get_list(char ***rlist, size_t *rnum)
    261 {
    262 	int ret;
    263 	struct _region key;
    264 	size_t num;
    265 	struct _citrus_lookup *cla, *cld;
    266 	char **list;
    267 	char buf[PATH_MAX];
    268 
    269 	num = 0;
    270 
    271 	ret = _lookup_seq_open(&cla, _PATH_ESDB "/" ESDB_ALIAS);
    272 	if (ret)
    273 		goto quit0;
    274 
    275 	ret = _lookup_seq_open(&cld, _PATH_ESDB "/" ESDB_DIR);
    276 	if (ret)
    277 		goto quit1;
    278 
    279 	/* count number of entries */
    280 	num = _lookup_get_num_entries(cla) + _lookup_get_num_entries(cld);
    281 
    282 	_lookup_seq_rewind(cla);
    283 	_lookup_seq_rewind(cld);
    284 
    285 	/* allocate list pointer space */
    286 	list = malloc(num * sizeof(char *));
    287 	num=0;
    288 	if (list == NULL) {
    289 		ret = errno;
    290 		goto quit3;
    291 	}
    292 
    293 	/* get alias entries */
    294 	while ((ret = _lookup_seq_next(cla, &key, NULL)) == 0) {
    295 		snprintf(buf, sizeof(buf), "%.*s",
    296 			 (int)_region_size(&key),
    297 			 (const char *)_region_head(&key));
    298 		_bcs_convert_to_lower(buf);
    299 		list[num] = strdup(buf);
    300 		if (list[num] == NULL) {
    301 			ret = errno;
    302 			goto quit3;
    303 		}
    304 		num++;
    305 	}
    306 	if (ret != ENOENT)
    307 		goto quit3;
    308 	/* get dir entries */
    309 	while ((ret = _lookup_seq_next(cld, &key, NULL)) == 0) {
    310 		/* check duplicated entry */
    311 		snprintf(buf, sizeof(buf), "%.*s",
    312 			 (int)_region_size(&key),
    313 			 (const char *)_region_head(&key));
    314 		_bcs_convert_to_lower(buf);
    315 		ret = _lookup_seq_lookup(cla, buf, NULL);
    316 		if (ret) {
    317 			if (ret != ENOENT)
    318 				goto quit3;
    319 			/* not duplicated */
    320 			list[num] = strdup(buf);
    321 			if (list[num] == NULL) {
    322 				ret = errno;
    323 				goto quit3;
    324 			}
    325 			num++;
    326 		}
    327 	}
    328 	if (ret != ENOENT)
    329 		goto quit3;
    330 
    331 	ret = 0;
    332 	list = realloc(list, num*sizeof(char *));
    333 	*rlist = list;
    334 	*rnum = num;
    335 quit3:
    336 	if (ret)
    337 		_citrus_esdb_free_list(list, num);
    338 	_lookup_seq_close(cld);
    339 quit1:
    340 	_lookup_seq_close(cla);
    341 quit0:
    342 	return ret;
    343 }
    344