/*************************************************************************
 *
 *  Authors:
 *  Pasi Ryhänen, 2002/05/23
 *  Harri Pitkänen (hatapitk@cc.jyu.fi), 2005
 *
 *  The Contents of this file are made available subject to the terms of
 *  GNU Lesser General Public License Version 2.1
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *  MA  02110-1301, USA
 *
 ************************************************************************/
 
/*
 * Interface for loading speller/hyphenator functions from a dynamic
 * library. Uses the dlfcn.h functions on Unixes,
 * LoadLibrary/GetProcAddress/etc. on Windows. Expects a macro UNX or
 * WNT to be defined (which seems to be the practise in
 * OpenOffice.org).
 */

 
#include <cstdio>
#ifdef UNX
#include <dlfcn.h>
#endif
#ifdef WNT
#include <windows.h>
#endif


#include "commonfi.hxx"


#ifdef SOIKKO_DEBUG
#define SPDLOG(x) printf x
#else
#define SPDLOG(x) 
#endif

namespace soikko {

static void * open_dl  (const char *file);
static void * get_func (void *handle, const char *name);


static void *
open_dl (const char *file_name)
{
#ifdef WNT
  return (void *)LoadLibrary(file_name);
#endif
#ifdef UNX
  return dlopen(file_name, RTLD_NOW);
#endif
  return NULL;
}


static void *
get_func (void *handle, const char *name)
{
  SPDLOG(("get_func(%s)\n", name));
#ifdef WNT
  return (void *)GetProcAddress((HMODULE)handle, name);
#endif
#ifdef UNX
  return dlsym(handle, name);
#endif
  return NULL;
}


#define LOAD_FUNC(name, func_type, func) \
    dl->func = (func_type *)get_func(dl->handle, (name)); \
    if (dl->func == NULL)  { \
      SPDLOG(("get_func(%s) failed\n", (name))); \
      goto ERROR1; \
    }

int
load_dl (const char *dl_name, tm_dl_t *dl)
{
  int version_num;

  if (dl_name == NULL || dl == NULL)
    return -1;
  
  SPDLOG(("library %s\n", dl_name));
  dl->handle = open_dl(dl_name);
  if (!dl->handle) {
    SPDLOG(("soikko.so:n avaaminen ei onnistunut\n"));
    return -1;
  }

  LOAD_FUNC("Tm_version", version_func_type, version_func);
  version_num = dl->version_func();

  if (version_num >= 0x00020000) {
    SPDLOG(("Tm_version not compatible: %x\n", version_num));
    goto ERROR1;
  } 
    
  LOAD_FUNC("Tm_init",             init_func_type,      init_func);
  LOAD_FUNC("Tm_terminate",   terminate_func_type, terminate_func);
  LOAD_FUNC("Tm_open",             open_func_type,      open_func);
  LOAD_FUNC("Tm_open_hyph",    openhyph_func_type,  openhyph_func);
  LOAD_FUNC("Tm_hyphenate",   hyphenate_func_type, hyphenate_func);
  LOAD_FUNC("Tm_check_buffer",    check_func_type,     check_func);
  LOAD_FUNC("Tm_suggest",       suggest_func_type,   suggest_func);
  LOAD_FUNC("Tm_set_encoding", encoding_func_type,  encoding_func);
  LOAD_FUNC("Tm_set_option",     option_func_type,    option_func);

  return 0;

 ERROR1:
  SPDLOG(("load_dl() failed\n"));
  close_dl(dl);
  return -1;
}


/*
 * Close the library.
 * Returns 0 on success, non-zero on error.
 */
int
close_dl (tm_dl_t *dl)
{
  int ret = 0;
  if (dl == NULL || dl->handle == NULL)
    return 0;

#ifdef WNT
  ret = FreeLibrary((HMODULE)dl->handle) ? 0 : 1;
#endif
#ifdef UNX
  ret =  dlclose(dl->handle);
#endif

  dl->handle = NULL;
  return ret;
}

}
