Freeciv-3.2: /fast/freeciv/nightly/S3_2/utility/fciconv.c Source File

Freeciv-3.2

Loading...
Searching...
No Matches
fciconv.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 2003-2004 - The Freeciv Project
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include <errno.h>
19#include <stdarg.h>
20#include <stdio.h>
21#include <string.h>
22
23#ifdef HAVE_ICONV
24#include <iconv.h>
25#endif
26
27#ifdef HAVE_LANGINFO_CODESET
28#include <langinfo.h>
29#endif
30
31#ifdef HAVE_LIBCHARSET
32#include <libcharset.h>
33#endif
34
35/* utility */
36#include "fciconv.h"
37#include "fcintl.h"
38#include "log.h"
39#include "mem.h"
40#include "support.h"
41
42 static bool is_init = FALSE;
43 static char convert_buffer[4096];
44 static const char *transliteration_string;
45
46#ifdef HAVE_ICONV
47static const char *local_encoding, *data_encoding, *internal_encoding;
48#else /* HAVE_ICONV */
49/* Hack to confuse the compiler into working. */
50# define local_encoding get_local_encoding()
51# define data_encoding get_local_encoding()
52# define internal_encoding get_local_encoding()
53#endif /* HAVE_ICONV */
54
55 static char *saved_from = NULL;
56 static char *saved_to = NULL;
57
58static char *convert_string(const char *text,
59 const char *from,
60 const char *to,
61 char *buf, size_t bufsz)
62 fc__attribute((nonnull (1,2,3)));
63
64/***********************************************************************/
70 void init_character_encodings(const char *my_internal_encoding,
71 bool my_use_transliteration)
72{
73 transliteration_string = "";
74#ifdef HAVE_ICONV
75 if (my_use_transliteration) {
76 transliteration_string = "//TRANSLIT";
77 }
78
79 /* Set the data encoding - first check $FREECIV_DATA_ENCODING,
80 * then fall back to the default. */
81 data_encoding = getenv("FREECIV_DATA_ENCODING");
82 if (!data_encoding) {
83 data_encoding = FC_DEFAULT_DATA_ENCODING;
84 }
85
86 /* Set the local encoding - first check $FREECIV_LOCAL_ENCODING,
87 * then ask the system. */
88 local_encoding = getenv("FREECIV_LOCAL_ENCODING");
89 if (!local_encoding) {
90#ifdef HAVE_LIBCHARSET
91 local_encoding = locale_charset();
92#else /* HAVE_LIBCHARSET */
93#ifdef HAVE_LANGINFO_CODESET
94 local_encoding = nl_langinfo(CODESET);
95#else /* HAVE_LANGINFO_CODESET */
96 local_encoding = "";
97#endif /* HAVE_LANGINFO_CODESET */
98#endif /* HAVE_LIBCHARSET */
99 if (fc_strcasecmp(local_encoding, "ANSI_X3.4-1968") == 0
100 || fc_strcasecmp(local_encoding, "ASCII") == 0
101 || fc_strcasecmp(local_encoding, "US-ASCII") == 0) {
102 /* HACK: use latin1 instead of ascii in typical cases when the
103 * encoding is unconfigured. */
104 local_encoding = "ISO-8859-1";
105 }
106
107 if (fc_strcasecmp(local_encoding, "646") == 0) {
108 /* HACK: On Solaris the encoding always comes up as "646" (ascii),
109 * which iconv doesn't understand. Work around it by using UTF-8
110 * instead. */
111 local_encoding = "UTF-8";
112 }
113 }
114
115 /* Set the internal encoding - first check $FREECIV_INTERNAL_ENCODING,
116 * then check the passed-in default value, then fall back to the local
117 * encoding. */
118 internal_encoding = getenv("FREECIV_INTERNAL_ENCODING");
119 if (!internal_encoding) {
120 internal_encoding = my_internal_encoding;
121
122 if (!internal_encoding) {
123 internal_encoding = local_encoding;
124 }
125 }
126
127#ifdef FREECIV_ENABLE_NLS
128 bind_textdomain_codeset("freeciv-core", internal_encoding);
129#endif
130
131#ifdef FREECIV_DEBUG
132 fprintf(stderr, "Encodings: Data=%s, Local=%s, Internal=%s\n",
133 data_encoding, local_encoding, internal_encoding);
134#endif /* FREECIV_DEBUG */
135
136#else /* HAVE_ICONV */
137 /* log_* may not work at this point. */
138 fprintf(stderr,
139 _("You are running Freeciv without using iconv. Unless\n"
140 "you are using the UTF-8 character set, some characters\n"
141 "may not be displayed properly. You can download iconv\n"
142 "at https://gnu.org/.\n"));
143#endif /* HAVE_ICONV */
144
145 is_init = TRUE;
146}
147
148/***********************************************************************/
151 const char *get_data_encoding(void)
152{
153 fc_assert_ret_val(is_init, NULL);
154 return data_encoding;
155}
156
157/***********************************************************************/
160 const char *get_local_encoding(void)
161{
162#ifdef HAVE_ICONV
163 fc_assert_ret_val(is_init, NULL);
164 return local_encoding;
165#else /* HAVE_ICONV */
166# ifdef HAVE_LIBCHARSET
167 return locale_charset();
168# else /* HAVE_LIBCHARSET */
169# ifdef HAVE_LANGINFO_CODESET
170 return nl_langinfo(CODESET);
171# else /* HAVE_LANGINFO_CODESET */
172 return "";
173# endif /* HAVE_LANGINFO_CODESET */
174# endif /* HAVE_LIBCHARSET */
175#endif /* HAVE_ICONV */
176}
177
178/***********************************************************************/
182 const char *get_internal_encoding(void)
183{
184 fc_assert_ret_val(is_init, NULL);
185 return internal_encoding;
186}
187
188/***********************************************************************/
196 static char *convert_string(const char *text,
197 const char *from,
198 const char *to,
199 char *buf, size_t bufsz)
200{
201#ifdef HAVE_ICONV
202 iconv_t cd = iconv_open(to, from);
203 size_t from_len = strlen(text) + 1, to_len;
204 bool alloc = (buf == NULL);
205
206 if (cd == (iconv_t) (-1)) {
207 /* Do not do potentially recursive call to freeciv logging here,
208 * but use fprintf(stderr) */
209 /* Use the real OS-provided strerror and errno rather than Freeciv's
210 * abstraction, as that wouldn't do the correct thing with third-party
211 * iconv on Windows. */
212
213 if (saved_from == NULL
214 || strcmp(saved_from, from)
215 || strcmp(saved_to, to)) {
216
217 /* TRANS: "Could not convert text from <encoding a> to <encoding b>:"
218 * <externally translated error string>." */
219 fprintf(stderr, _("Could not convert text from %s to %s: %s.\n"),
220 from, to, strerror(errno));
221
222 if (saved_from != NULL) {
223 free(saved_from);
224 free(saved_to);
225 }
226
227 saved_from = fc_strdup(from);
228 saved_to = fc_strdup(to);
229 }
230
231 /* The best we can do? */
232 if (alloc) {
233 return fc_strdup(text);
234 } else {
235 fc_snprintf(buf, bufsz, "%s", text);
236 return buf;
237 }
238 }
239
240 if (alloc) {
241 to_len = from_len;
242 } else {
243 to_len = bufsz;
244 }
245
246 do {
247 size_t flen = from_len, tlen = to_len, res;
248 const char *mytext = text;
249 char *myresult;
250
251 if (alloc) {
252 buf = fc_malloc(to_len);
253 }
254
255 myresult = buf;
256
257 /* Since we may do multiple translations, we may need to reset iconv
258 * in between. */
259 iconv(cd, NULL, NULL, NULL, NULL);
260
261 res = iconv(cd, (ICONV_CONST char **)&mytext, &flen, &myresult, &tlen);
262 if (res == (size_t) (-1)) {
263 if (errno != E2BIG) {
264 /* Invalid input. */
265
266 fprintf(stderr, "Invalid string conversion from %s to %s: %s.\n",
267 from, to, strerror(errno));
268 iconv_close(cd);
269 if (alloc) {
270 free(buf);
271 return fc_strdup(text); /* The best we can do? */
272 } else {
273 fc_snprintf(buf, bufsz, "%s", text);
274 return buf;
275 }
276 }
277 } else {
278 /* Success. */
279 iconv_close(cd);
280
281 /* There may be wasted space here, but there's nothing we can do
282 * about it. */
283 return buf;
284 }
285
286 if (alloc) {
287 /* Not enough space; try again. */
288 buf[to_len - 1] = 0;
289
290 free(buf);
291 to_len *= 2;
292 }
293 } while (alloc);
294
295 return buf;
296#else /* HAVE_ICONV */
297 if (buf) {
298 strncpy(buf, text, bufsz);
299 buf[bufsz - 1] = '\0';
300 return buf;
301 } else {
302 return fc_strdup(text);
303 }
304#endif /* HAVE_ICONV */
305}
306
307#define CONV_FUNC_MALLOC(src, dst) \
308char *src ## _to_ ## dst ## _string_malloc(const char *text) \
309{ \
310 const char *encoding1 = (dst ## _encoding); \
311 char encoding[strlen(encoding1) + strlen(transliteration_string) + 1]; \
312 \
313 fc_snprintf(encoding, sizeof(encoding), \
314 "%s%s", encoding1, transliteration_string); \
315 return convert_string(text, (src ## _encoding), \
316 (encoding), NULL, 0); \
317}
318
319#define CONV_FUNC_BUFFER(src, dst) \
320char *src ## _to_ ## dst ## _string_buffer(const char *text, \
321 char *buf, size_t bufsz) \
322{ \
323 const char *encoding1 = (dst ## _encoding); \
324 char encoding[strlen(encoding1) + strlen(transliteration_string) + 1]; \
325 \
326 fc_snprintf(encoding, sizeof(encoding), \
327 "%s%s", encoding1, transliteration_string); \
328 return convert_string(text, (src ## _encoding), \
329 encoding, buf, bufsz); \
330}
331
332#define CONV_FUNC_STATIC(src, dst) \
333char *src ## _to_ ## dst ## _string_static(const char *text) \
334{ \
335 (src ## _to_ ## dst ## _string_buffer)(text, \
336 convert_buffer, \
337 sizeof(convert_buffer)); \
338 return convert_buffer; \
339}
340
341 CONV_FUNC_MALLOC(data, internal)
342 CONV_FUNC_MALLOC(internal, data)
343 CONV_FUNC_MALLOC(internal, local)
344 CONV_FUNC_MALLOC(local, internal)
345
346 CONV_FUNC_BUFFER(local, internal)
347 CONV_FUNC_BUFFER(internal, local)
348
349 static CONV_FUNC_STATIC(internal, local)
350
351/***********************************************************************/
354void fc_fprintf(FILE *stream, const char *format, ...)
355{
356 va_list ap;
357 char string[4096];
358 const char *output;
359 static bool recursion = FALSE;
360
361 /* The recursion variable is used to prevent a recursive loop. If
362 * an iconv conversion fails, then log_* will be called and an
363 * fc_fprintf will be done. But below we do another iconv conversion
364 * on the error messages, which is of course likely to fail also. */
365 if (recursion) {
366 return;
367 }
368
369 va_start(ap, format);
370 fc_vsnprintf(string, sizeof(string), format, ap);
371 va_end(ap);
372
373 recursion = TRUE;
374 if (is_init) {
375 output = internal_to_local_string_static(string);
376 } else {
377 output = string;
378 }
379 recursion = FALSE;
380
381 fputs(output, stream);
382 fflush(stream);
383}
384
385/***********************************************************************/
395 size_t get_internal_string_length(const char *text)
396{
397 int text2[(strlen(text) + 1)]; /* UCS-4 text */
398 int i;
399 int len = 0;
400
401 convert_string(text, internal_encoding, "UCS-4",
402 (char *)text2, sizeof(text2));
403 for (i = 0; ; i++) {
404 if (text2[i] == 0) {
405 return len;
406 }
407 if (text2[i] != 0x0000FEFF && text2[i] != 0xFFFE0000) {
408 /* Not BOM */
409 len++;
410 }
411 }
412}
413
414/***********************************************************************/
417 void fc_iconv_close(void)
418{
419 if (saved_from != NULL) {
420 free(saved_from);
421 saved_from = NULL;
422 }
423
424 if (saved_to != NULL) {
425 free(saved_to);
426 saved_to = NULL;
427 }
428}
incite_cost
char * incite_cost
Definition comments.c:74
get_internal_string_length
size_t get_internal_string_length(const char *text)
Definition fciconv.c:395
saved_to
static char * saved_to
Definition fciconv.c:56
CONV_FUNC_BUFFER
#define CONV_FUNC_BUFFER(src, dst)
Definition fciconv.c:319
convert_buffer
static char convert_buffer[4096]
Definition fciconv.c:43
saved_from
static char * saved_from
Definition fciconv.c:55
transliteration_string
static const char * transliteration_string
Definition fciconv.c:44
fc_iconv_close
void fc_iconv_close(void)
Definition fciconv.c:417
CONV_FUNC_MALLOC
#define CONV_FUNC_MALLOC(src, dst)
Definition fciconv.c:307
get_data_encoding
const char * get_data_encoding(void)
Definition fciconv.c:151
internal_encoding
#define internal_encoding
Definition fciconv.c:52
is_init
static bool is_init
Definition fciconv.c:42
data_encoding
#define data_encoding
Definition fciconv.c:51
convert_string
static char * convert_string(const char *text, const char *from, const char *to, char *buf, size_t bufsz) fc__attribute((nonnull(1
Definition fciconv.c:196
get_internal_encoding
const char * get_internal_encoding(void)
Definition fciconv.c:182
CONV_FUNC_STATIC
#define CONV_FUNC_STATIC(src, dst)
Definition fciconv.c:332
init_character_encodings
static char void init_character_encodings(const char *my_internal_encoding, bool my_use_transliteration)
Definition fciconv.c:70
local_encoding
#define local_encoding
Definition fciconv.c:50
get_local_encoding
const char * get_local_encoding(void)
Definition fciconv.c:160
fciconv.h
FC_DEFAULT_DATA_ENCODING
#define FC_DEFAULT_DATA_ENCODING
Definition fciconv.h:89
fc_fprintf
void fc_fprintf(FILE *stream, const char *format,...) fc__attribute((__format__(__printf__
fcintl.h
_
#define _(String)
Definition fcintl.h:67
bufsz
static const int bufsz
Definition helpdlg.c:70
log.h
fc_assert_ret_val
#define fc_assert_ret_val(condition, val)
Definition log.h:194
mem.h
fc_strdup
#define fc_strdup(str)
Definition mem.h:43
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
len
int len
Definition packhand.c:127
recursion
static int recursion[AIT_LAST]
Definition srv_log.c:45
fc_snprintf
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:974
fc_strcasecmp
int fc_strcasecmp(const char *str0, const char *str1)
Definition support.c:189
fc_vsnprintf
int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap)
Definition support.c:900
support.h
fc__attribute
#define fc__attribute(x)
Definition support.h:99
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47