# HG changeset patch # User Matti Hamalainen # Date 1578760210 -7200 # Node ID b3d46806787d693eddd32f400c4b0f3f6c3d6b1a # Parent 1950bb04a69b6d690cbdc45837559eaf4a8c5d9b Move a number of more or less generic helper functions into a separate sidutil.[ch] module. diff -r 1950bb04a69b -r b3d46806787d Makefile.gen --- a/Makefile.gen Sat Jan 11 14:28:22 2020 +0200 +++ b/Makefile.gen Sat Jan 11 18:30:10 2020 +0200 @@ -10,7 +10,7 @@ THLIBS_OBJ=th_util.o th_string.o th_ioctx.o \ th_file.o th_args.o th_crypto.o th_datastruct.o -SIDINFO_OBJ=sidlib.o sidinfo.o +SIDINFO_OBJ=sidlib.o sidutil.o sidinfo.o SIDINFO_BIN=$(BINPATH)sidinfo$(BINEXT) TARGETS += $(SIDINFO_BIN) diff -r 1950bb04a69b -r b3d46806787d sidinfo.c --- a/sidinfo.c Sat Jan 11 14:28:22 2020 +0200 +++ b/sidinfo.c Sat Jan 11 18:30:10 2020 +0200 @@ -8,27 +8,14 @@ #include "th_file.h" #include "th_datastruct.h" #include "sidlib.h" +#include "sidutil.h" #include #include -#ifdef HAVE_ICONV -# include -#endif // // Some constants // - -// HVSC documents directory -#define SET_HVSC_DOCUMENTS "DOCUMENTS" - -// Songlengths database filename prefix (.md5|.txt appended) -#define SET_SLDB_FILEBASE "Songlengths" - -// STIL database file -#define SET_STILDB_FILENAME "STIL.txt" - - enum { OFMT_QUOTED = 0x0001, @@ -44,15 +31,6 @@ }; -enum -{ - TH_LANG_UTF8, - TH_LANG_ISO88591, - TH_LANG_CP850, - TH_LANG_CP437, -}; - - typedef struct { int cmd; @@ -135,13 +113,7 @@ SIDLibSLDB *sidSLDB = NULL; SIDLibSTILDB *sidSTILDB = NULL; - -BOOL setUseOutConv; -#ifdef HAVE_ICONV -iconv_t setIConvCtx; -#else -int setOutLang; -#endif +SIDUtilChConvCtx setChConv; // Define option arguments @@ -167,47 +139,11 @@ static const int optListN = sizeof(optList) / sizeof(optList[0]); -void argShowLicense(void) -{ - printf("%s - %s\n%s\n", th_prog_name, th_prog_desc, th_prog_author); - printf( - "\n" - "Redistribution and use in source and binary forms, with or without\n" - "modification, are permitted provided that the following conditions\n" - "are met:\n" - "\n" - " 1. Redistributions of source code must retain the above copyright\n" - " notice, this list of conditions and the following disclaimer.\n" - "\n" - " 2. Redistributions in binary form must reproduce the above copyright\n" - " notice, this list of conditions and the following disclaimer in\n" - " the documentation and/or other materials provided with the\n" - " distribution.\n" - "\n" - " 3. The name of the author may not be used to endorse or promote\n" - " products derived from this software without specific prior written\n" - " permission.\n" - "\n" - "THIS SOFTWARE IS PROVIDED BY THE AUTHOR \"AS IS\" AND ANY EXPRESS OR\n" - "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n" - "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n" - "ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\n" - "INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n" - "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n" - "SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n" - "HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n" - "STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n" - "IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n" - "POSSIBILITY OF SUCH DAMAGE.\n" - ); -} - - void argShowHelp(void) { int index, len; - th_print_banner(stdout, th_prog_name, "[options] [sid filename #2 ..]"); + th_print_banner(stdout, th_prog_name, "[options] [file|path #2 ..]"); th_args_help(stdout, optList, optListN, 0); printf( "\n" @@ -281,43 +217,6 @@ } -const char *siStripHVSCPath(const char *filename) -{ - if (setHVSCPath != NULL) - { - const char *hvsc = setHVSCPath, *fptr = filename; - - // Compare until end of string(s) - for (; *hvsc != 0 && *fptr != 0 && *hvsc == *fptr; hvsc++, fptr++); - - // Full match? - if (*hvsc == 0) - return fptr - 1; - } - - return filename; -} - - -char *siCheckHVSCFilePath(const char *filebase, const char *fext) -{ - th_stat_data sdata; - char *npath = th_strdup_printf("%s%c%s%c%s%s", - setHVSCPath, TH_DIR_SEPARATOR_CHR, - SET_HVSC_DOCUMENTS, TH_DIR_SEPARATOR_CHR, - filebase, fext != NULL ? fext : ""); - - if (npath != NULL && - th_stat_path(npath, &sdata) && - (sdata.flags & TH_IS_READABLE) && - (sdata.flags & TH_IS_DIR) == 0) - return npath; - - th_free(npath); - return NULL; -} - - BOOL siStackAddItem(PSFStack *stack, const PSFStackItem *item) { if (stack->items == NULL || stack->nitems + 1 >= stack->nallocated) @@ -396,128 +295,6 @@ } -#ifndef HAVE_ICONV - -static const uint8_t si_lang_iso88591_to_cp850[16*6] = { -0xff, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, 0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, -0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, 0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, -0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, 0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, -0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, 0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, -0x85, 0xa0, 0x83, 0xc6, 0x84, 0x86, 0x91, 0x87, 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, -0xd0, 0xa4, 0x95, 0xa2, 0x93, 0xe4, 0x94, 0xf6, 0x9b, 0x97, 0xa3, 0x96, 0x81, 0xec, 0xe7, 0x98, -}; - -static const uint8_t si_lang_iso88591_to_cp437[16*6] = { -0xff, 0xad, 0x9b, 0x9c, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, -0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, 0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, -0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, -0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, -0x00, 0xa4, 0x95, 0xa2, 0x93, 0x00, 0x94, 0xf6, 0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x98, -}; - -#endif - - -char *siConvertCharset(const char *src) -{ -#ifdef HAVE_ICONV - size_t srcLeft = strlen(src) + 1; - size_t outLeft = srcLeft * 2; - char *srcPtr = (char *) src; - char *outBuf, *outPtr; - - if ((outBuf = outPtr = th_malloc(outLeft + 1)) == NULL) - return NULL; - - while (srcLeft > 0) - { - size_t ret = iconv(setIConvCtx, &srcPtr, &srcLeft, &outPtr, &outLeft); - if (ret == (size_t) -1) - break; - } - -#else - // Fallback conversion of ISO-8859-1 to X - size_t srcSize = strlen(src), outSize, minLeft; - const uint8_t *srcPtr = (const uint8_t *) src; - const uint8_t *tab; - uint8_t *outBuf, *outPtr; - - switch (setOutLang) - { - case TH_LANG_UTF8: - outSize = srcSize * 2; - minLeft = 2; - break; - - default: - outSize = srcSize; - minLeft = 1; - } - - if ((outBuf = outPtr = th_malloc(outSize)) == NULL) - return NULL; - - while (srcSize > 0 && outSize >= minLeft) - { - switch (setOutLang) - { - case TH_LANG_UTF8: - // Not 100% correct really, but close enough - if (*srcPtr < 0x80) - { - *outPtr++ = *srcPtr; - outSize--; - } - else - if (*srcPtr < 0xBF) - { - *outPtr++ = 0xC2; - *outPtr++ = *srcPtr; - outSize -= 2; - } - else - { - *outPtr++ = 0xC3; - *outPtr++ = *srcPtr - 0x40; - outSize -= 2; - } - break; - - case TH_LANG_ISO88591: - *outPtr++ = *srcPtr; - outSize--; - break; - - case TH_LANG_CP850: - case TH_LANG_CP437: - // Not 100% correct either, but close enough - tab = (setOutLang == TH_LANG_CP850) ? si_lang_iso88591_to_cp850 : si_lang_iso88591_to_cp437; - - if (*srcPtr < 0x7f) - *outPtr++ = *srcPtr; - else - if (*srcPtr >= 0xA0) - *outPtr++ = tab[*srcPtr - 0xA0]; - else - *outPtr++ = '?'; - - outSize--; - break; - } - - srcPtr++; - srcSize--; - } - - *outPtr++ = 0; -#endif - - return (char *) outBuf; -} - - static int siItemFormatStrPutInt(th_vprintf_ctx *ctx, th_vprintf_putch vputch, const int value, const int f_radix, int f_flags, int f_width, int f_prec, const BOOL f_unsig, th_vprintf_altfmt_func f_alt) @@ -857,7 +634,7 @@ break; case 10: - argShowLicense(); + sidutil_print_license(); exit(0); break; @@ -1040,9 +817,9 @@ { char *str, *tmp; - if (setUseOutConv && d_str != NULL && convert) + if (d_str != NULL && setChConv.enabled && convert) { - char *tmp2 = siConvertCharset(d_str); + char *tmp2 = sidutil_chconv_convert(&setChConv, d_str); tmp = siEscapeString(tmp2, optEscapeChars); th_free(tmp2); } @@ -1282,7 +1059,9 @@ // Get STIL information, if any if (sidSTILDB != NULL) { - psid->stil = sidlib_stildb_get_node(sidSTILDB, siStripHVSCPath(filename)); + psid->stil = sidlib_stildb_get_node(sidSTILDB, + sidutil_strip_hvsc_path(setHVSCPath, filename)); + if (psid->stil != NULL) psid->stil->lengths = psid->lengths; } @@ -1424,8 +1203,9 @@ int main(int argc, char *argv[]) { - char *setLang = th_strdup(getenv("LANG")); th_ioctx *inFile = NULL; + char *setLang = getenv("LANG"); + int ret; // Get HVSC_BASE env variable if it is set th_pstr_cpy(&setHVSCPath, getenv("HVSC_BASE")); @@ -1439,47 +1219,11 @@ memset(&optFormat, 0, sizeof(optFormat)); - // Get environment language - if (setLang != NULL) + // Initialize character conversion + if ((ret = sidutil_chconv_init(&setChConv, setLang)) != THERR_OK) { - // Get the character encoding part (e.g. "UTF-8" etc.) and - // strip out and lowercase everything (e.g. "utf8") - size_t i; - char *ptr = strchr(setLang, '.'); - ptr = (ptr == NULL) ? setLang : ptr + 1; - - for (i = 0; *ptr; ptr++) - { - if (*ptr != '-') - setLang[i++] = th_tolower(*ptr); - } - setLang[i] = 0; - -#ifdef HAVE_ICONV - // Initialize iconv, check if we have language/charset - setIConvCtx = iconv_open("utf8", "iso88591"); - setUseOutConv = setIConvCtx != (iconv_t) -1; -#else - // Check if we can use our fallback converter - if (strcmp(setLang, "utf8") == 0) - setOutLang = TH_LANG_UTF8; - else - if (strcmp(setLang, "iso88591") == 0 || - strcmp(setLang, "cp819") == 0 || - strcmp(setLang, "latin1") == 0 || - strcmp(setLang, "cp28591") == 0) - setOutLang = TH_LANG_ISO88591; - else - if (strcmp(setLang, "cp850") == 0) - setOutLang = TH_LANG_CP850; - else - if (strcmp(setLang, "cp437") == 0) - setOutLang = TH_LANG_CP437; - else - setOutLang = TH_LANG_ISO88591; - - setUseOutConv = setOutLang != TH_LANG_ISO88591; -#endif + THERR("Could not initialize character set conversion (LANG='%s'): %s\n", + setLang, th_error_str(ret)); } // Parse command line arguments @@ -1488,7 +1232,7 @@ goto out; THMSG(2, "Requested output LANG='%s', use charset conversion=%s\n", - setLang, setUseOutConv ? "yes" : "no"); + setChConv.outLang, setChConv.enabled ? "yes" : "no"); if (optOneLineFieldSep != NULL || (!optFieldOutput && optFormat.nitems > 0)) @@ -1525,20 +1269,18 @@ // If SLDB path is not set, autocheck for .md5 and .txt if (setSLDBPath == NULL) - setSLDBPath = siCheckHVSCFilePath(SET_SLDB_FILEBASE, ".md5"); + setSLDBPath = sidutil_check_hvsc_file(setHVSCPath, SET_SLDB_FILEBASE, ".md5"); if (setSLDBPath == NULL) - setSLDBPath = siCheckHVSCFilePath(SET_SLDB_FILEBASE, ".txt"); + setSLDBPath = sidutil_check_hvsc_file(setHVSCPath, SET_SLDB_FILEBASE, ".txt"); if (setSTILDBPath == NULL) - setSTILDBPath = siCheckHVSCFilePath(SET_STILDB_FILENAME, NULL); + setSTILDBPath = sidutil_check_hvsc_file(setHVSCPath, SET_STILDB_FILENAME, NULL); } if (setSLDBPath != NULL) { // Initialize SLDB - int ret = THERR_OK; - setSLDBNewFormat = th_strrcasecmp(setSLDBPath, ".md5") != NULL; if ((ret = th_io_fopen(&inFile, &th_stdio_io_ops, setSLDBPath, "r")) != THERR_OK) @@ -1584,8 +1326,6 @@ if (setSTILDBPath != NULL) { // Initialize STILDB - int ret = THERR_OK; - if ((ret = th_io_fopen(&inFile, &th_stdio_io_ops, setSTILDBPath, "r")) != THERR_OK) { THERR("Could not open STIL database '%s': %s\n", @@ -1636,12 +1376,7 @@ out: -#ifdef HAVE_ICONV - if (setUseOutConv) - iconv_close(setIConvCtx); -#endif - - th_free(setLang); + sidutil_chconv_close(&setChConv); siClearStack(&optFormat); th_free(setHVSCPath); diff -r 1950bb04a69b -r b3d46806787d sidutil.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sidutil.c Sat Jan 11 18:30:10 2020 +0200 @@ -0,0 +1,280 @@ +/* + * SIDLib common utility functions + * Programmed and designed by Matti 'ccr' Hämäläinen + * (C) Copyright 2014-2020 Tecnic Software productions (TNSP) + */ +#include "sidutil.h" +#include "th_file.h" +#include "th_string.h" +#include "th_datastruct.h" + + +void sidutil_print_license(void) +{ + printf("%s - %s\n%s\n", th_prog_name, th_prog_desc, th_prog_author); + printf( + "\n" + "Redistribution and use in source and binary forms, with or without\n" + "modification, are permitted provided that the following conditions\n" + "are met:\n" + "\n" + " 1. Redistributions of source code must retain the above copyright\n" + " notice, this list of conditions and the following disclaimer.\n" + "\n" + " 2. Redistributions in binary form must reproduce the above copyright\n" + " notice, this list of conditions and the following disclaimer in\n" + " the documentation and/or other materials provided with the\n" + " distribution.\n" + "\n" + " 3. The name of the author may not be used to endorse or promote\n" + " products derived from this software without specific prior written\n" + " permission.\n" + "\n" + "THIS SOFTWARE IS PROVIDED BY THE AUTHOR \"AS IS\" AND ANY EXPRESS OR\n" + "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n" + "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n" + "ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,\n" + "INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n" + "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n" + "SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n" + "HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n" + "STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\n" + "IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n" + "POSSIBILITY OF SUCH DAMAGE.\n" + ); +} + + +const char *sidutil_strip_hvsc_path(const char *hvscPath, const char *filename) +{ + if (hvscPath != NULL) + { + const char *hvsc = hvscPath, *fptr = filename; + + // Compare until end of string(s) + for (; *hvsc != 0 && *fptr != 0 && *hvsc == *fptr; hvsc++, fptr++); + + // Full match? + if (*hvsc == 0) + return fptr - 1; + } + + return filename; +} + + +char *sidutil_check_hvsc_file(const char *hvscPath, const char *filebase, const char *fext) +{ + th_stat_data sdata; + char *npath = th_strdup_printf("%s%c%s%c%s%s", + hvscPath, TH_DIR_SEPARATOR_CHR, + SET_HVSC_DOCUMENTS, TH_DIR_SEPARATOR_CHR, + filebase, fext != NULL ? fext : ""); + + if (npath != NULL && + th_stat_path(npath, &sdata) && + (sdata.flags & TH_IS_READABLE) && + (sdata.flags & TH_IS_DIR) == 0) + return npath; + + th_free(npath); + return NULL; +} + + +#ifndef HAVE_ICONV + +static const uint8_t sidutil_lang_iso88591_to_cp850[16*6] = { +0xff, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, 0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, +0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, 0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, +0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, 0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, +0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, 0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, +0x85, 0xa0, 0x83, 0xc6, 0x84, 0x86, 0x91, 0x87, 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, +0xd0, 0xa4, 0x95, 0xa2, 0x93, 0xe4, 0x94, 0xf6, 0x9b, 0x97, 0xa3, 0x96, 0x81, 0xec, 0xe7, 0x98, +}; + +static const uint8_t sidutil_lang_iso88591_to_cp437[16*6] = { +0xff, 0xad, 0x9b, 0x9c, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, +0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, 0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, +0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, +0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, +0x00, 0xa4, 0x95, 0xa2, 0x93, 0x00, 0x94, 0xf6, 0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x98, +}; + + +static char *sidutil_chconv_internal(SIDUtilChConvCtx *ctx, const char *src) +{ + // Fallback conversion of ISO-8859-1 to X + const uint8_t *srcPtr = (const uint8_t *) src; + const uint8_t *convTable; + size_t outSize, outLen; + char *outBuf, outByte; + + if (src == NULL) + return NULL; + + outSize = strlen(src) + 1; + if ((outBuf = th_malloc(outSize)) == NULL) + return NULL; + + for (outLen = 0; *srcPtr; srcPtr++) + { + switch (ctx->outLangID) + { + case TH_LANG_UTF8: + // Not 100% correct really, but close enough + if (*srcPtr < 0x80) + { + if (!th_strbuf_putch(&outBuf, &outSize, &outLen, *srcPtr)) + goto err; + } + else + if (*srcPtr < 0xBF) + { + if (!th_strbuf_putch(&outBuf, &outSize, &outLen, 0xC2) || + !th_strbuf_putch(&outBuf, &outSize, &outLen, *srcPtr)) + goto err; + } + else + { + if (!th_strbuf_putch(&outBuf, &outSize, &outLen, 0xC3) || + !th_strbuf_putch(&outBuf, &outSize, &outLen, *srcPtr - 0x40)) + goto err; + } + break; + + case TH_LANG_ISO88591: + if (!th_strbuf_putch(&outBuf, &outSize, &outLen, *srcPtr)) + goto err; + break; + + case TH_LANG_CP850: + case TH_LANG_CP437: + // Not 100% correct either, but close enough + convTable = (ctx->outLangID == TH_LANG_CP850) ? + sidutil_lang_iso88591_to_cp850 : sidutil_lang_iso88591_to_cp437; + + if (*srcPtr < 0x7f) + outByte = *srcPtr; + else + if (*srcPtr >= 0xA0) + outByte = convTable[*srcPtr - 0xA0]; + else + outByte = '?'; + + if (!th_strbuf_putch(&outBuf, &outSize, &outLen, outByte)) + goto err; + break; + } + } + + if (!th_strbuf_putch(&outBuf, &outSize, &outLen, *srcPtr)) + goto err; + + return outBuf; + +err: + th_free(outBuf); + return NULL; +} + +#endif + + +// NOTICE! Only call this function IF ctx->enabled == TRUE +char * sidutil_chconv_convert(SIDUtilChConvCtx *ctx, const char *src) +{ +#ifdef HAVE_ICONV + size_t srcLeft = strlen(src) + 1; + size_t outLeft = srcLeft * 2; + char *srcPtr = (char *) src; + char *outBuf, *outPtr; + + if ((outBuf = outPtr = th_malloc(outLeft + 1)) == NULL) + return NULL; + + while (srcLeft > 0) + { + size_t ret = iconv(ctx->iconvCtx, &srcPtr, &srcLeft, &outPtr, &outLeft); + if (ret == (size_t) -1) + break; + } + + return (char *) outBuf; +#else + return sidutil_chconv_internal(ctx, src); +#endif +} + + +int sidutil_chconv_init(SIDUtilChConvCtx *ctx, const char *outLang) +{ + if (ctx == NULL) + return THERR_NULLPTR; + + memset(ctx, 0, sizeof(*ctx)); + + if (outLang != NULL) + { + // Get the character encoding part (e.g. "UTF-8" etc.) and + // strip out and lowercase everything (e.g. "utf8") + size_t i; + char *ptr; + + if ((ctx->outLang = th_strdup(outLang)) == NULL) + return THERR_MALLOC; + + if ((ptr = strchr(ctx->outLang, '.')) == NULL) + ptr = ctx->outLang; + else + ptr++; + + for (i = 0; *ptr; ptr++) + { + if (*ptr != '-') + ctx->outLang[i++] = th_tolower(*ptr); + } + ctx->outLang[i] = 0; + +#ifdef HAVE_ICONV + // Initialize iconv, check if we have language/charset + ctx->iconvCtx = iconv_open(ctx->outLang, "iso88591"); + ctx->enabled = (ctx->iconvCtx != (iconv_t) -1); +#else + // Check if we can use our fallback converter + if (strcmp(ctx->outLang, "utf8") == 0) + ctx->outLangID = TH_LANG_UTF8; + else + if (strcmp(ctx->outLang, "iso88591") == 0 || + strcmp(ctx->outLang, "cp819") == 0 || + strcmp(ctx->outLang, "latin1") == 0 || + strcmp(ctx->outLang, "cp28591") == 0) + ctx->outLangID = TH_LANG_ISO88591; + else + if (strcmp(ctx->outLang, "cp850") == 0) + ctx->outLangID = TH_LANG_CP850; + else + if (strcmp(ctx->outLang, "cp437") == 0) + ctx->outLangID = TH_LANG_CP437; + else + ctx->outLangID = TH_LANG_ISO88591; + + ctx->enabled = ctx->outLangID != TH_LANG_ISO88591; +#endif + } + + return THERR_OK; +} + + +void sidutil_chconv_close(SIDUtilChConvCtx *ctx) +{ +#ifdef HAVE_ICONV + if (ctx->iconvCtx != (iconv_t) -1) + iconv_close(ctx->iconvCtx); +#else +#endif + + th_free(ctx->outLang); +} diff -r 1950bb04a69b -r b3d46806787d sidutil.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sidutil.h Sat Jan 11 18:30:10 2020 +0200 @@ -0,0 +1,74 @@ +/* + * SIDLib common utility functions + * Programmed and designed by Matti 'ccr' Hämäläinen + * (C) Copyright 2014-2020 Tecnic Software productions (TNSP) + */ +#ifndef SIDUTIL_H +#define SIDUTIL_H 1 + +#include "th_util.h" +#ifdef HAVE_ICONV +# include +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +// +// Some constants +// + +// HVSC documents directory +#define SET_HVSC_DOCUMENTS "DOCUMENTS" + +// Songlengths database filename prefix (.md5|.txt appended) +#define SET_SLDB_FILEBASE "Songlengths" + +// STIL database file +#define SET_STILDB_FILENAME "STIL.txt" + + +enum +{ + TH_LANG_UTF8, + TH_LANG_ISO88591, + TH_LANG_CP850, + TH_LANG_CP437, +}; + + +// +// Typedefs +// +typedef struct +{ + BOOL enabled; + char *outLang; +#ifdef HAVE_ICONV + iconv_t iconvCtx; +#else + int outLangID; +#endif +} SIDUtilChConvCtx; + + +// +// Functions +// +void sidutil_print_license(void); +const char * sidutil_strip_hvsc_path(const char *hvscPath, const char *filename); +char * sidutil_check_hvsc_file(const char *hvscPath, const char *filebase, const char *fext); + +char * sidutil_chconv_convert(SIDUtilChConvCtx *ctx, const char *src); + +int sidutil_chconv_init(SIDUtilChConvCtx *ctx, const char *outLang); +void sidutil_chconv_close(SIDUtilChConvCtx *ctx); + + +#ifdef __cplusplus +} +#endif +#endif // SIDUTIL_H