1 /* This program is free software; you can redistribute it and/or modify *
2 * it under the terms of the GNU General Public License as published by *
3 * the Free Software Foundation; either version 2 of the License, or *
4 * (at your option) any later version. *
6 (C) 2001 by The Genes Development Team
7 Original author: Peter Verthez (Peter.Verthez@advalvas.be)
19 #include "gedcom_internal.h"
22 #define INTERNAL_ENCODING "UTF8"
23 #define ENCODING_CONF_FILE "gedcom.enc"
24 #define GCONV_SEARCH_PATH "GCONV_PATH"
27 static iconv_t cd_to_internal = (iconv_t) -1;
28 static void *encoding_mapping = NULL;
29 static ENCODING the_enc = ONE_BYTE;
36 char* charwidth_string[] = { "1", "2_HILO", "2_LOHI" };
38 int node_compare(const void *node1, const void *node2)
40 return strcmp(((const struct node *) node1)->gedcom_name,
41 ((const struct node *) node2)->gedcom_name);
44 void add_encoding(char *gedcom_n, char* charwidth, char *iconv_n)
47 struct node *nodeptr = (struct node *) malloc(sizeof *nodeptr);
48 nodeptr->gedcom_name = (char *) malloc(strlen(gedcom_n)
49 + strlen(charwidth) + 3);
50 nodeptr->iconv_name = (char *) malloc(strlen(iconv_n) + 1);
51 /* sprintf is safe here (malloc'ed before) */
52 sprintf(nodeptr->gedcom_name, "%s(%s)", gedcom_n, charwidth);
53 strcpy(nodeptr->iconv_name, iconv_n);
54 datum = tsearch(nodeptr, &encoding_mapping, node_compare);
55 if ((datum == NULL) || (*datum != nodeptr)) {
56 gedcom_warning("Duplicate entry found for encoding '%s', ignoring",
61 char* get_encoding(char* gedcom_n, ENCODING enc)
64 struct node search_node;
66 buffer = (char*)malloc(strlen(gedcom_n) + strlen(charwidth_string[enc]) + 3);
67 /* sprintf is safe here (malloc'ed before) */
68 sprintf(buffer, "%s(%s)", gedcom_n, charwidth_string[enc]);
69 search_node.gedcom_name = buffer;
70 datum = tfind(&search_node, &encoding_mapping, node_compare);
73 gedcom_error("No encoding found for '%s'", gedcom_n);
77 return ((const struct node *) *datum)->iconv_name;
83 if (encoding_mapping == NULL) {
85 char buffer[MAXBUF + 1];
86 char gedcom_n[MAXBUF + 1];
87 char charwidth[MAXBUF + 1];
88 char iconv_n[MAXBUF + 1];
91 /* Add gedcom data directory to gconv search path */
92 gconv_path = getenv(GCONV_SEARCH_PATH);
93 if (gconv_path == NULL || strstr(gconv_path, PKGDATADIR) == NULL) {
95 if (gconv_path == NULL) {
96 new_gconv_path = (char *)malloc(strlen(GCONV_SEARCH_PATH)
99 sprintf(new_gconv_path, "%s=%s", GCONV_SEARCH_PATH, PKGDATADIR);
102 new_gconv_path = (char *)malloc(strlen(GCONV_SEARCH_PATH)
106 sprintf(new_gconv_path, "%s=%s:%s",
107 GCONV_SEARCH_PATH, gconv_path, PKGDATADIR);
109 if (putenv(new_gconv_path) != 0) {
110 gedcom_warning("Failed updating environment variable %s",
113 printf("%s\n", new_gconv_path);
116 /* Open gedcom configuration file and read */
117 in = fopen(ENCODING_CONF_FILE, "r");
120 sprintf(path, "%s/%s", PKGDATADIR, ENCODING_CONF_FILE);
121 in = fopen(path, "r");
124 gedcom_warning("Could not open encoding configuration file '%s'",
128 while (fgets(buffer, sizeof(buffer), in) != NULL) {
129 if (buffer[strlen(buffer) - 1] != '\n') {
130 gedcom_error("Line too long in encoding configuration file '%s'",
134 else if ((buffer[0] != '#') && (strcmp(buffer, "\n") != 0)) {
135 if (sscanf(buffer, "%s %s %s", gedcom_n, charwidth, iconv_n) == 3) {
136 add_encoding(gedcom_n, charwidth, iconv_n);
139 gedcom_error("Missing data in encoding configuration file '%s'",
150 void set_encoding_width(ENCODING enc)
155 static char conv_buf[MAXGEDCLINELEN * 2];
156 static size_t conv_buf_size;
158 int open_conv_to_internal(char* fromcode)
160 char *encoding = get_encoding(fromcode, the_enc);
161 if (cd_to_internal != (iconv_t) -1)
162 iconv_close(cd_to_internal);
163 if (encoding == NULL) {
164 cd_to_internal = (iconv_t) -1;
167 memset(conv_buf, 0, sizeof(conv_buf));
169 cd_to_internal = iconv_open(INTERNAL_ENCODING, encoding);
170 if (cd_to_internal == (iconv_t) -1) {
171 gedcom_error("Error opening conversion context for encoding %s: %s",
172 encoding, strerror(errno));
175 return (cd_to_internal != (iconv_t) -1);
178 void close_conv_to_internal()
180 iconv_close(cd_to_internal);
181 cd_to_internal = (iconv_t) -1;
184 char* to_internal(char* str, size_t len,
185 char* output_buffer, size_t out_len)
187 size_t outsize = out_len;
188 char *wrptr = output_buffer;
189 char *rdptr = conv_buf;
190 /* set up input buffer (concatenate to what was left previous time) */
191 /* can't use strcpy, because possible null bytes from unicode */
192 memcpy(conv_buf + conv_buf_size, str, len);
193 conv_buf_size += len;
194 /* set up output buffer (empty it) */
195 memset(output_buffer, 0, out_len);
196 /* do the conversion */
197 iconv(cd_to_internal, &rdptr, &conv_buf_size, &wrptr, &outsize);
198 /* then shift what is left over to the head of the input buffer */
199 memmove(conv_buf, rdptr, conv_buf_size);
200 memset(conv_buf + conv_buf_size, 0, sizeof(conv_buf) - conv_buf_size);
201 return output_buffer;