From 2c822cca563be548a9e62f9d6368de752fb2654d Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Fri, 20 Jan 2023 00:33:20 +0200 Subject: [PATCH 22/22] Log iconv inability to convert between encodings just once See osdn #46497 Signed-off-by: Marko Lindqvist --- common/fc_interface.c | 2 ++ utility/fciconv.c | 67 ++++++++++++++++++++++++++++++++----------- utility/fciconv.h | 8 ++---- 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/common/fc_interface.c b/common/fc_interface.c index 3819e26bf4..ac970e5973 100644 --- a/common/fc_interface.c +++ b/common/fc_interface.c @@ -16,6 +16,7 @@ #endif /* utility */ +#include "fciconv.h" #include "netfile.h" #include "shared.h" @@ -91,5 +92,6 @@ void libfreeciv_free(void) free_fileinfo_data(); netfile_free(); free_nls(); + fc_iconv_close(); fc_support_free(); } diff --git a/utility/fciconv.c b/utility/fciconv.c index 8ad065f0c6..458419d91a 100644 --- a/utility/fciconv.c +++ b/utility/fciconv.c @@ -52,6 +52,9 @@ static const char *local_encoding, *data_encoding, *internal_encoding; # define internal_encoding get_local_encoding() #endif /* HAVE_ICONV */ +static char *saved_from = NULL; +static char *saved_to = NULL; + /*************************************************************************** Must be called during the initialization phase of server and client to initialize the character encodings to be used. @@ -59,7 +62,7 @@ static const char *local_encoding, *data_encoding, *internal_encoding; Pass an internal encoding of NULL to use the local encoding internally. ***************************************************************************/ void init_character_encodings(const char *my_internal_encoding, - bool my_use_transliteration) + bool my_use_transliteration) { transliteration_string = ""; #ifdef HAVE_ICONV @@ -177,17 +180,17 @@ const char *get_internal_encoding(void) } /*************************************************************************** - Convert the text. Both 'from' and 'to' must be 8-bit charsets. The - result will be put into the buf buffer unless it is NULL, in which case it - will be allocated on demand. + Convert the text. Both 'from' and 'to' must be 8-bit charsets. The result + will be put into the buf buffer unless it is NULL, in which case it will + be allocated on demand. - Don't use this function if you can avoid it. Use one of the + Don't use this function if you can avoid it. Use one of the xxx_to_yyy_string functions. ***************************************************************************/ -char *convert_string(const char *text, - const char *from, - const char *to, - char *buf, size_t bufsz) +static char *convert_string(const char *text, + const char *from, + const char *to, + char *buf, size_t bufsz) { #ifdef HAVE_ICONV iconv_t cd = iconv_open(to, from); @@ -202,12 +205,26 @@ char *convert_string(const char *text, * but use fprintf(stderr) */ /* Use the real OS-provided strerror and errno rather than Freeciv's * abstraction, as that wouldn't do the correct thing with third-party - * iconv on Windows */ + * iconv on Windows. */ + + if (saved_from == NULL + || strcmp(saved_from, from) + || strcmp(saved_to, to)) { + + /* TRANS: "Could not convert text from to :" + * ." */ + fprintf(stderr, _("Could not convert text from %s to %s: %s.\n"), + from, to, strerror(errno)); + + if (saved_from != NULL) { + free(saved_from); + free(saved_to); + } + + saved_from = fc_strdup(from); + saved_to = fc_strdup(to); + } - /* TRANS: "Could not convert text from to :" - * ."*/ - fprintf(stderr, _("Could not convert text from %s to %s: %s.\n"), - from, to, strerror(errno)); /* The best we can do? */ if (alloc) { return fc_strdup(text); @@ -363,12 +380,12 @@ void fc_fprintf(FILE *stream, const char *format, ...) } /**************************************************************************** - Return the length, in *characters*, of the string. This can be used in - place of strlen in some places because it returns the number of characters + Return the length, in *characters*, of the string. This can be used in + place of strlen() in some places because it returns the number of characters not the number of bytes (with multi-byte characters in UTF-8, the two may not be the same). - Use of this function outside of GUI layout code is probably a hack. For + Use of this function outside of GUI layout code is probably a hack. For instance the demographics code uses it, but this should instead pass the data directly to the GUI library for formatting. ****************************************************************************/ @@ -390,3 +407,19 @@ size_t get_internal_string_length(const char *text) } } } + +/*************************************************************************** + Free resources allocated by the iconv system +***************************************************************************/ +void fc_iconv_close(void) +{ + if (saved_from != NULL) { + free(saved_from); + saved_from = NULL; + } + + if (saved_to != NULL) { + free(saved_to); + saved_to = NULL; + } +} diff --git a/utility/fciconv.h b/utility/fciconv.h index 12c4f26ca2..5855ec98a8 100644 --- a/utility/fciconv.h +++ b/utility/fciconv.h @@ -88,7 +88,8 @@ extern "C" { #define FC_DEFAULT_DATA_ENCODING "UTF-8" void init_character_encodings(const char *internal_encoding, - bool use_transliteration); + bool use_transliteration); +void fc_iconv_close(void); const char *get_data_encoding(void); const char *get_local_encoding(void); @@ -108,11 +109,6 @@ char *internal_to_local_string_buffer(const char *text, void fc_fprintf(FILE *stream, const char *format, ...) fc__attribute((__format__ (__printf__, 2, 3))); -char *convert_string(const char *text, - const char *from, - const char *to, - char *buf, size_t bufsz); - size_t get_internal_string_length(const char *text); #ifdef __cplusplus -- 2.39.0