/* Universal iconv implementation for OS/2. Andrey Vasilkin, 2016. */ #define INCL_DOSMODULEMGR /* Module Manager values */ #define INCL_DOSERRORS /* Error values */ #include #include "geniconv.h" //#define DEBUG #ifdef DEBUG # include # define debug(s,...) printf(__func__"(): "##s"\n" ,##__VA_ARGS__) #else # define debug(s,...) #endif // Exports from os2iconv.c. extern iconv_t _System os2_iconv_open(const char* tocode, const char* fromcode); extern size_t _System os2_iconv(iconv_t cd, char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft); extern int _System os2_iconv_close(iconv_t cd); // Functions pointers types. typedef iconv_t _System (*FNICONV_OPEN)(const char* tocode, const char* fromcode); typedef size_t _System (*FNICONV)(iconv_t cd, char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft); typedef int _System (*FNICONV_CLOSE)(iconv_t cd); // Used DLL module handle. static HMODULE hmIconv = NULLHANDLE; // Functions pointers. static FNICONV_OPEN fn_iconv_open = NULL; static FNICONV fn_iconv = NULL; static FNICONV_CLOSE fn_iconv_close = NULL; static BOOL _loadDLL(PSZ pszName, PSZ pszIconvOpen, PSZ pszIconv, PSZ pszIconvClose) { ULONG ulRC; CHAR acError[256]; ulRC = DosLoadModule( acError, sizeof(acError), pszName, &hmIconv ); if ( ulRC != NO_ERROR ) { debug( "DLL not loaded: %s", &acError ); return FALSE; } do { ulRC = DosQueryProcAddr( hmIconv, 0, pszIconvOpen, (PFN *)&fn_iconv_open ); if ( ulRC != NO_ERROR ) { debug( "Error: cannot find entry %s in %s", pszIconvOpen, pszName ); break; } ulRC = DosQueryProcAddr( hmIconv, 0, pszIconv, (PFN *)&fn_iconv ); if ( ulRC != NO_ERROR ) { debug( "Error: cannot find entry %s in %s", pszIconv, pszName ); break; } ulRC = DosQueryProcAddr( hmIconv, 0, pszIconvClose, (PFN *)&fn_iconv_close ); if ( ulRC != NO_ERROR ) { debug( "Error: cannot find entry %s in %s", pszIconvClose, pszName ); break; } debug( "DLL %s used", pszName ); return TRUE; } while( FALSE ); DosFreeModule( hmIconv ); hmIconv = NULLHANDLE; return FALSE; } static void _init() { if ( fn_iconv_open != NULL ) // Already was initialized. return; // Try to load kiconv.dll, iconv2.dll or iconv.dll. if ( !_loadDLL( "KICONV", "_libiconv_open", "_libiconv", "_libiconv_close" ) && !_loadDLL( "ICONV2", "_libiconv_open", "_libiconv", "_libiconv_close" ) && !_loadDLL( "ICONV", "_iconv_open", "_iconv", "_iconv_close" ) ) { // No one DLL was loaded - use OS/2 conversion objects API. debug( "Uni*() API used" ); fn_iconv_open = os2_iconv_open; fn_iconv = os2_iconv; fn_iconv_close = os2_iconv_close; } } // Public routines. // ---------------- // Non-standard function for iconv to unload the used dynamic library. void libiconv_clean() { if ( hmIconv != NULLHANDLE ) { DosFreeModule( hmIconv ); hmIconv = NULLHANDLE; fn_iconv_open = NULL; fn_iconv = NULL; fn_iconv_close = NULL; } } iconv_t libiconv_open(const char* tocode, const char* fromcode) { _init(); return fn_iconv_open( tocode, fromcode ); } size_t libiconv(iconv_t cd, char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft) { return fn_iconv( cd, inbuf, inbytesleft, outbuf, outbytesleft ); } int libiconv_close(iconv_t cd) { return fn_iconv_close( cd ); }