diff options
Diffstat (limited to 'src/charconv.c')
-rw-r--r-- | src/charconv.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/src/charconv.c b/src/charconv.c new file mode 100644 index 0000000..e869e41 --- /dev/null +++ b/src/charconv.c @@ -0,0 +1,59 @@ +#include "charconv.h" +#include <iconv.h> +#include <langinfo.h> +#include <locale.h> +#include <stdio.h> + +static iconv_t iconv_init_codepage(int codepage) +{ + iconv_t result; + char codepage_name[16]; + snprintf(codepage_name, sizeof(codepage_name), "CP%d", codepage); + result = iconv_open(nl_langinfo(CODESET), codepage_name); + if (result == (iconv_t) - 1) + perror(codepage_name); + return result; +} + +static iconv_t dos_to_local; + +/* + * Initialize conversion from codepage. + * codepage = -1 means default codepage. + * Returns 0 on success, non-zero on failure + */ +static int init_conversion(int codepage) +{ + static int initialized = -1; + if (initialized < 0) { + initialized = 1; + if (codepage < 0) + codepage = DEFAULT_DOS_CODEPAGE; + setlocale(LC_ALL, ""); /* initialize locale */ + dos_to_local = iconv_init_codepage(codepage); + if (dos_to_local == (iconv_t) - 1 && codepage != DEFAULT_DOS_CODEPAGE) { + printf("Trying to set fallback DOS codepage %d\n", + DEFAULT_DOS_CODEPAGE); + dos_to_local = iconv_init_codepage(DEFAULT_DOS_CODEPAGE); + if (dos_to_local == (iconv_t) - 1) + initialized = 0; /* no conversion available */ + } + } + return initialized; +} + +int set_dos_codepage(int codepage) +{ + return init_conversion(codepage); +} + +int dos_char_to_printable(char **p, unsigned char c) +{ + char in[1] = { c }; + char *pin = in; + size_t bytes_in = 1; + size_t bytes_out = 4; + if (!init_conversion(-1)) + return 0; + return iconv(dos_to_local, &pin, &bytes_in, p, &bytes_out) != -1; +} |