#ifndef SLTDL_H
#define SLTDL_H

#include "sltdl_api.h"
#include "sltdl_compat.h"

#ifdef __cplusplus
extern "C" {
#endif

/**********************************************************************/
/*                                                                    */
/* this header povides projects that depend on ltdl's interfaces the  */
/* most necessary macro definitions, type definitions, and forward    */
/* declarations.                                                      */
/*                                                                    */
/* if your library or utility does not yet use libltdl, then it is    */
/* strongly recommended that you use the various posix interfaces as  */
/* defined in <dlfcn.h>, and accordingly refrain from using libsltdl  */
/* altogether.                                                        */
/*                                                                    */
/**********************************************************************/

/* exclusively support colon as the path element separator */
#define LT_PATHSEP_CHAR ':'

/* modern frameworks only */
#define LT_DLSYM_CONST  const

/* default dlsym vtable, see also: slibtool -dlpreopen self */
#define lt_preloaded_symbols lt__PROGRAM__LTX_preloaded_symbols

enum sltdl_modctl {
	SLTDL_MODCTL_DEBUG,
	SLTDL_MODCTL_PRELOAD_ADD,
	SLTDL_MODCTL_PRELOAD_REMOVE,
	SLTDL_MODCTL_PRELOAD_DEFAULT,
	SLTDL_MODCTL_PRELOAD_RESET,
	SLTDL_MODCTL_CAP,
};

enum sltdl_error {
	SLTDL_ERR_OK,
	SLTDL_ERR_SYSTEM_ERROR,
	SLTDL_ERR_DLFCN_ERROR,
	SLTDL_ERR_SLTDL_ERROR,
	SLTDL_ERR_DLEXIT_REF_COUNT,
	SLTDL_ERR_MODULE_REF_COUNT,
	SLTDL_ERR_MODULE_PTR_INVALID,
	SLTDL_ERR_PATH_INVALID_FIRST_CHAR,
	SLTDL_ERR_PATH_INVALID_SEPARATTOR_CHAR,
	SLTDL_ERR_PATH_INVALID_MARK,
	SLTDL_ERR_PATH_INVALID_LEN,
	SLTDL_ERR_PATH_NO_ENTRY,
	SLTDL_ERR_CANNOT_OPEN,
	SLTDL_ERR_CANNOT_CLOSE,
	SLTDL_ERR_SYMBOL_NOT_FOUND,
	SLTDL_ERR_CAP,
};

/* loader priority */
enum lt_dlpriority {
	LT_DLLOADER_PREPEND,
	LT_DLLOADER_APPEND,
};

typedef enum lt_dlpriority lt_dlloader_priority;

/* binary-compatible type definitions */
typedef void * lt_ptr;
typedef void * lt_module;
typedef void * lt_dlloader;
typedef void * lt_user_data;

struct lt_symdef {
	const char *    name;
	void *          address;
};

typedef struct lt_modctx * lt_dlhandle;
typedef struct lt_modctl * lt_dladvise;
typedef struct lt_symdef   lt_dlsymlist;

typedef void * lt_module_open    (void *, const char *, struct lt_modctx *);
typedef int    lt_module_close   (void *, void *);
typedef void * lt_find_sym       (void *, void *, const char *);
typedef int    lt_dlloader_init  (void *);
typedef int    lt_dlloader_exit  (void *);


struct lt_dlentry {
	const char *       name;
	const char *       sym_prefix;
	lt_module_open *   module_open;
	lt_module_close *  module_close;
	lt_find_sym *      find_sym;
	lt_dlloader_init * dlloader_init;
	lt_dlloader_exit * dlloader_exit;
	lt_user_data       dlloader_data;
	enum lt_dlpriority priority;
};

typedef struct lt_dlentry lt_dlvtable;

/* dlsym vtable */
extern const struct lt_symdef lt__PROGRAM__LTX_preloaded_symbols[];

/* global reference-counting */
lt_api int lt_dlinit(void);
lt_api int lt_dlexit(void);

/* library search path */
lt_api int          lt_dlpathopen(const char *, const char **);
lt_api int          lt_dladdsearchdir(const char *);
lt_api int          lt_dlinsertsearchdir(const char *, const char *);
lt_api int          lt_dlsetsearchpath(const char *);
lt_api const char * lt_dlgetsearchpath(void);
lt_api int          lt_dlforeachfile(const char *,
	                             int(*)(const char *, void *),
	                             void *);

/* module interfaces */
lt_api lt_dlhandle  lt_dlopen(const char *);
lt_api lt_dlhandle  lt_dlopenext(const char *);
lt_api lt_dlhandle  lt_dlopenadvise(const char *, struct lt_modctl *);

lt_api void *       lt_dlsym(lt_dlhandle, const char *);
lt_api int          lt_dlclose(lt_dlhandle);
lt_api const char * lt_dlerror(void);

/* preloaded modules */
lt_api int          lt_dlpreload_modctl(const struct lt_symdef *, enum sltdl_modctl);
lt_api int          lt_dlpreload_default(const struct lt_symdef *);

/* custom loaders */
lt_api int                       lt_dlloader_add(const struct lt_dlentry *);
lt_api const struct lt_dlentry * lt_dlloader_find(const char *);

/* custom errors */
lt_api int          lt_dlseterror (int);

#ifdef __cplusplus
}
#endif

#endif
