Home | History | Annotate | Line # | Download | only in citrus
citrus_esdb.c revision 1.2
      1 /*	$NetBSD: citrus_esdb.c,v 1.2 2003/07/16 08:05:27 itojun 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.2 2003/07/16 08:05:27 itojun 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 		snprintf(buf, sizeof(buf),
    150 		    _CITRUS_ESDB_SYM_CSID_PREFIX "%d", i);
    151 		ret = _db_lookup32_by_s(db, buf, &csid, NULL);
    152 		if (ret)
    153 			goto err4;
    154 		esdb->db_charsets[i].ec_csid = csid;
    155 
    156 		snprintf(buf, sizeof(buf),
    157 		    _CITRUS_ESDB_SYM_CSNAME_PREFIX "%d", i);
    158 		ret = _db_lookupstr_by_s(db, buf, &str, NULL);
    159 		if (ret)
    160 			goto err4;
    161 		esdb->db_charsets[i].ec_csname = strdup(str);
    162 		if (esdb->db_charsets[i].ec_csname == NULL) {
    163 			ret = errno;
    164 			goto err4;
    165 		}
    166 	}
    167 
    168 	_db_close(db);
    169 	return 0;
    170 
    171 err4:
    172 	for (; i>0; i--)
    173 		free(esdb->db_charsets[i-1].ec_csname);
    174 	free(esdb->db_charsets);
    175 err3:
    176 	free(esdb->db_variable);
    177 err2:
    178 	free(esdb->db_encname);
    179 err1:
    180 	_db_close(db);
    181 	if (ret == ENOENT)
    182 		ret = EFTYPE;
    183 err0:
    184 	return ret;
    185 }
    186 
    187 /*
    188  * _citrus_esdb_open:
    189  *	open an ESDB file.
    190  */
    191 int
    192 _citrus_esdb_open(struct _citrus_esdb *db, const char *esname)
    193 {
    194 	int ret;
    195 	const char *realname, *encfile;
    196 	char buf1[PATH_MAX], buf2[PATH_MAX], path[PATH_MAX];
    197 	struct _region fr;
    198 
    199 	_DIAGASSERT(esname != NULL);
    200 
    201 	snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, ESDB_ALIAS);
    202 	realname = _lookup_alias(path, esname, buf1, sizeof(buf1));
    203 
    204 	snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, ESDB_DIR);
    205 	encfile = _lookup_simple(path, realname, buf2, sizeof(buf2));
    206 	if (encfile==NULL)
    207 		return ENOENT;
    208 
    209 	/* open file */
    210 	snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, encfile);
    211 	ret = _map_file(&fr, path);
    212 	if (ret)
    213 		return ret;
    214 
    215 	ret = conv_esdb(db, &fr);
    216 
    217 	_unmap_file(&fr);
    218 
    219 	return ret;
    220 }
    221 
    222 /*
    223  * _citrus_esdb_close:
    224  *	free an ESDB.
    225  */
    226 void
    227 _citrus_esdb_close(struct _citrus_esdb *db)
    228 {
    229 	int i;
    230 
    231 	_DIAGASSERT(db != NULL);
    232 	_DIAGASSERT(db->db_num_charsets == 0 || db->db_charsets != NULL);
    233 
    234 	for (i=0; i<db->db_num_charsets; i++)
    235 		free(db->db_charsets[i].ec_csname);
    236 	db->db_num_charsets = 0;
    237 	free(db->db_charsets); db->db_charsets = NULL;
    238 	free(db->db_encname); db->db_encname = NULL;
    239 	db->db_len_variable = 0;
    240 	free(db->db_variable); db->db_variable = NULL;
    241 }
    242 
    243 /*
    244  * _citrus_esdb_free_list:
    245  *	free the list.
    246  */
    247 void
    248 _citrus_esdb_free_list(char **list, size_t num)
    249 {
    250 	size_t i;
    251 
    252 	for (i=0; i<num; i++)
    253 		free(list[i]);
    254 	free(list);
    255 }
    256 
    257 /*
    258  * _citrus_esdb_get_list:
    259  *	get esdb entries.
    260  */
    261 int
    262 _citrus_esdb_get_list(char ***rlist, size_t *rnum)
    263 {
    264 	int ret;
    265 	struct _region key;
    266 	size_t num;
    267 	struct _citrus_lookup *cla, *cld;
    268 	char **list;
    269 	char buf[PATH_MAX];
    270 
    271 	num = 0;
    272 
    273 	ret = _lookup_seq_open(&cla, _PATH_ESDB "/" ESDB_ALIAS);
    274 	if (ret)
    275 		goto quit0;
    276 
    277 	ret = _lookup_seq_open(&cld, _PATH_ESDB "/" ESDB_DIR);
    278 	if (ret)
    279 		goto quit1;
    280 
    281 	/* count number of entries */
    282 	num = _lookup_get_num_entries(cla) + _lookup_get_num_entries(cld);
    283 
    284 	_lookup_seq_rewind(cla);
    285 	_lookup_seq_rewind(cld);
    286 
    287 	/* allocate list pointer space */
    288 	list = malloc(num * sizeof(char *));
    289 	num=0;
    290 	if (list == NULL) {
    291 		ret = errno;
    292 		goto quit3;
    293 	}
    294 
    295 	/* get alias entries */
    296 	while ((ret = _lookup_seq_next(cla, &key, NULL)) == 0) {
    297 		snprintf(buf, sizeof(buf), "%.*s",
    298 			 (int)_region_size(&key),
    299 			 (const char *)_region_head(&key));
    300 		_bcs_convert_to_lower(buf);
    301 		list[num] = strdup(buf);
    302 		if (list[num] == NULL) {
    303 			ret = errno;
    304 			goto quit3;
    305 		}
    306 		num++;
    307 	}
    308 	if (ret != ENOENT)
    309 		goto quit3;
    310 	/* get dir entries */
    311 	while ((ret = _lookup_seq_next(cld, &key, NULL)) == 0) {
    312 		/* check duplicated entry */
    313 		snprintf(buf, sizeof(buf), "%.*s",
    314 			 (int)_region_size(&key),
    315 			 (const char *)_region_head(&key));
    316 		_bcs_convert_to_lower(buf);
    317 		ret = _lookup_seq_lookup(cla, buf, NULL);
    318 		if (ret) {
    319 			if (ret != ENOENT)
    320 				goto quit3;
    321 			/* not duplicated */
    322 			list[num] = strdup(buf);
    323 			if (list[num] == NULL) {
    324 				ret = errno;
    325 				goto quit3;
    326 			}
    327 			num++;
    328 		}
    329 	}
    330 	if (ret != ENOENT)
    331 		goto quit3;
    332 
    333 	ret = 0;
    334 	list = realloc(list, num*sizeof(char *));
    335 	*rlist = list;
    336 	*rnum = num;
    337 quit3:
    338 	if (ret)
    339 		_citrus_esdb_free_list(list, num);
    340 	_lookup_seq_close(cld);
    341 quit1:
    342 	_lookup_seq_close(cla);
    343 quit0:
    344 	return ret;
    345 }
    346