blob: a86e3ded7b0ac33dc58d0b7c7cabc81240dc8639 [file] [log] [blame]
/*
Universal iconv implementation for OS/2.
Andrey Vasilkin, 2016.
*/
#define INCL_DOSMODULEMGR /* Module Manager values */
#define INCL_DOSERRORS /* Error values */
#include <os2.h>
#include "geniconv.h"
//#define DEBUG
#ifdef DEBUG
# include <stdio.h>
# 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 );
}