#ifdef HAVE_CONFIG_H
# include <config.h>
#else
# if defined(hpux)
# define HAVE_DL_H
# else
# define HAVE_DLFCN_H
# endif
#endif
#include <stdio.h>
#ifdef HAVE_DL_H
#include <dl.h>
#endif
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
#include <ctype.h>
#include "Xlibint.h"
#include "XlcPublic.h"
#include "XlcPubI.h"
#if defined(_LP64) && defined(__sparcv9)
# define _MACH64_NAME "sparcv9"
#else
# undef _MACH64_NAME
#endif
#ifdef _MACH64_NAME
# define _MACH64_NAME_LEN (sizeof (_MACH64_NAME) - 1)
#endif
#define XI18N_DLREL 2
#define iscomment(ch) ((ch) == '\0' || (ch) == '#')
typedef enum {
XLC_OBJECT,
XIM_OBJECT,
XOM_OBJECT
} XI18NDLType;
typedef struct {
XI18NDLType type;
int locale_name_len;
char *locale_name;
char *dl_name;
char *open;
char *im_register;
char *im_unregister;
int dl_release;
unsigned int refcount;
#if defined(hpux)
shl_t dl_module;
#else
void *dl_module;
#endif
} XI18NObjectsListRec, *XI18NObjectsList;
#define OBJECT_INIT_LEN 8
#define OBJECT_INC_LEN 4
static int lc_len = 0;
static XI18NObjectsListRec *xi18n_objects_list = NULL;
static int lc_count = 0;
static int
parse_line(char *line, char **argv, int argsize)
{
int argc = 0;
char *p = line;
while (argc < argsize) {
while (isspace(*p)) {
++p;
}
if (iscomment(*p)){
break;
}
argv[argc++] = p;
while (!isspace(*p)) {
++p;
}
if (iscomment(*p)) {
break;
}
*p++ = '\0';
}
return argc;
}
static char *
strdup_with_underscore(const char *symbol)
{
char *result;
if ((result = malloc(strlen(symbol) + 2)) == NULL)
return NULL;
result[0] = '_';
strcpy(result + 1, symbol);
return result;
}
#ifndef hpux
static void *
try_both_dlsym (void *handle, char *name)
{
void *ret;
ret = dlsym (handle, name);
if (!ret)
{
name = strdup_with_underscore (name);
if (name)
{
ret = dlsym (handle, name);
free (name);
}
}
return ret;
}
#endif
static void
resolve_object(char *path, const char *lc_name)
{
char filename[BUFSIZ];
FILE *fp;
char buf[BUFSIZ];
if (lc_len == 0) {
lc_len = OBJECT_INIT_LEN;
xi18n_objects_list = (XI18NObjectsList)
Xmalloc(sizeof(XI18NObjectsListRec) * lc_len);
if (!xi18n_objects_list) return;
}
sprintf(filename, "%.*s/%s", BUFSIZ - 12, path, "XI18N_OBJS");
fp = fopen(filename, "r");
if (fp == (FILE *)NULL){
return;
}
while (fgets(buf, BUFSIZ, fp) != NULL){
char *p = buf;
int n;
char *args[6];
while (isspace(*p)){
++p;
}
if (iscomment(*p)){
continue;
}
if (lc_count == lc_len) {
lc_len += OBJECT_INC_LEN;
xi18n_objects_list = (XI18NObjectsList)
Xrealloc(xi18n_objects_list,
sizeof(XI18NObjectsListRec) * lc_len);
if (!xi18n_objects_list) return;
}
n = parse_line(p, args, 6);
if (n == 3 || n == 5) {
if (!strcmp(args[0], "XLC")){
xi18n_objects_list[lc_count].type = XLC_OBJECT;
} else if (!strcmp(args[0], "XOM")){
xi18n_objects_list[lc_count].type = XOM_OBJECT;
} else if (!strcmp(args[0], "XIM")){
xi18n_objects_list[lc_count].type = XIM_OBJECT;
}
xi18n_objects_list[lc_count].dl_name = strdup(args[1]);
xi18n_objects_list[lc_count].open = strdup(args[2]);
xi18n_objects_list[lc_count].dl_release = XI18N_DLREL;
xi18n_objects_list[lc_count].locale_name = strdup(lc_name);
xi18n_objects_list[lc_count].refcount = 0;
xi18n_objects_list[lc_count].dl_module = (void*)NULL;
if (n == 5) {
xi18n_objects_list[lc_count].im_register = strdup(args[3]);
xi18n_objects_list[lc_count].im_unregister = strdup(args[4]);
} else {
xi18n_objects_list[lc_count].im_register = NULL;
xi18n_objects_list[lc_count].im_unregister = NULL;
}
lc_count++;
}
}
fclose(fp);
}
static char*
__lc_path(const char *dl_name, const char *lc_dir)
{
char *path;
size_t len;
if (strstr (dl_name, "../"))
return NULL;
#if defined (_LP64) && defined (_MACH64_NAME)
len = (lc_dir ? strlen(lc_dir) : 0 ) +
(dl_name ? strlen(dl_name) : 0) + _MACH64_NAME_LEN + 10;
path = Xmalloc(len + 1);
if (strchr(dl_name, '/') != NULL) {
char *tmp = strdup(dl_name);
char *dl_dir, *dl_file;
char *slash_p;
slash_p = strchr(tmp, '/');
*slash_p = '\0';
dl_dir = tmp;
dl_file = ++slash_p;
slash_p = strrchr(lc_dir, '/');
*slash_p = '\0';
strcpy(path, lc_dir); strcat(path, "/");
strcat(path, dl_dir); strcat(path, "/");
strcat(path, _MACH64_NAME); strcat(path, "/");
strcat(path, dl_file); strcat(path, ".so.2");
*slash_p = '/';
Xfree(tmp);
} else {
strcpy(path, lc_dir); strcat(path, "/");
strcat(path, _MACH64_NAME); strcat(path, "/");
strcat(path, dl_name); strcat(path, ".so.2");
}
#else
len = (lc_dir ? strlen(lc_dir) : 0 ) +
(dl_name ? strlen(dl_name) : 0) + 10;
#if defined POSTLOCALELIBDIR
len += (strlen(POSTLOCALELIBDIR) + 1);
#endif
path = Xmalloc(len + 1);
if (strchr(dl_name, '/') != NULL) {
char *slash_p;
slash_p = strrchr(lc_dir, '/');
*slash_p = '\0';
strcpy(path, lc_dir); strcat(path, "/");
#if defined POSTLOCALELIBDIR
strcat(path, POSTLOCALELIBDIR); strcat(path, "/");
#endif
strcat(path, dl_name); strcat(path, ".so.2");
*slash_p = '/';
} else {
strcpy(path, lc_dir); strcat(path, "/");
#if defined POSTLOCALELIBDIR
strcat(path, POSTLOCALELIBDIR); strcat(path, "/");
#endif
strcat(path, dl_name); strcat(path, ".so.2");
}
#endif
return path;
}
static Bool
open_object(
XI18NObjectsList object,
char *lc_dir)
{
char *path;
if (object->refcount == 0) {
path = __lc_path(object->dl_name, lc_dir);
if (!path)
return False;
#if defined(hpux)
object->dl_module = shl_load(path, BIND_DEFERRED, 0L);
#else
object->dl_module = dlopen(path, RTLD_LAZY);
#endif
Xfree(path);
if (!object->dl_module)
return False;
}
object->refcount++;
return True;
}
static void *
fetch_symbol(
XI18NObjectsList object,
char *symbol)
{
void *result = NULL;
#if defined(hpux)
int getsyms_cnt, i;
struct shl_symbol *symbols;
#endif
if (symbol == NULL)
return NULL;
#if defined(hpux)
getsyms_cnt = shl_getsymbols(object->dl_module, TYPE_PROCEDURE,
EXPORT_SYMBOLS, malloc, &symbols);
for(i=0; i<getsyms_cnt; i++) {
if(!strcmp(symbols[i].name, symbol)) {
result = symbols[i].value;
break;
}
}
if(getsyms_cnt > 0) {
free(symbols);
}
#else
result = try_both_dlsym(object->dl_module, symbol);
#endif
return result;
}
static void
close_object(XI18NObjectsList object)
{
object->refcount--;
if (object->refcount == 0)
{
#if defined(hpux)
shl_unload(object->dl_module);
#else
dlclose(object->dl_module);
#endif
object->dl_module = NULL;
}
}
typedef XLCd (*dynamicLoadProc)(const char *);
XLCd
_XlcDynamicLoad(const char *lc_name)
{
XLCd lcd = (XLCd)NULL;
dynamicLoadProc lc_loader = (dynamicLoadProc)NULL;
int count;
XI18NObjectsList objects_list;
char lc_dir[BUFSIZE], lc_lib_dir[BUFSIZE];
if (lc_name == NULL) return (XLCd)NULL;
if (_XlcLocaleDirName(lc_dir, BUFSIZE, (char *)lc_name) == (char *)NULL)
return (XLCd)NULL;
if (_XlcLocaleLibDirName(lc_lib_dir, BUFSIZE, (char *)lc_name) == (char*)NULL)
return (XLCd)NULL;
resolve_object(lc_dir, lc_name);
resolve_object(lc_lib_dir, lc_name);
objects_list = xi18n_objects_list;
count = lc_count;
for (; count-- > 0; objects_list++) {
if (objects_list->type != XLC_OBJECT ||
strcmp(objects_list->locale_name, lc_name)) continue;
if (!open_object (objects_list, lc_dir) && \
!open_object (objects_list, lc_lib_dir))
continue;
lc_loader = (dynamicLoadProc)fetch_symbol (objects_list, objects_list->open);
if (!lc_loader) continue;
lcd = (*lc_loader)(lc_name);
if (lcd != (XLCd)NULL) {
break;
}
close_object (objects_list);
}
return (XLCd)lcd;
}
typedef XIM (*dynamicOpenProcp)(XLCd, Display *, XrmDatabase, char *, char *);
static XIM
_XDynamicOpenIM(XLCd lcd, Display *display, XrmDatabase rdb,
char *res_name, char *res_class)
{
XIM im = (XIM)NULL;
char lc_dir[BUFSIZE];
char *lc_name;
dynamicOpenProcp im_openIM = (dynamicOpenProcp)NULL;
int count;
XI18NObjectsList objects_list = xi18n_objects_list;
lc_name = lcd->core->name;
if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return (XIM)0;
count = lc_count;
for (; count-- > 0; objects_list++) {
if (objects_list->type != XIM_OBJECT ||
strcmp(objects_list->locale_name, lc_name)) continue;
if (!open_object (objects_list, lc_dir))
continue;
im_openIM = (dynamicOpenProcp)fetch_symbol(objects_list, objects_list->open);
if (!im_openIM) continue;
im = (*im_openIM)(lcd, display, rdb, res_name, res_class);
if (im != (XIM)NULL) {
break;
}
close_object (objects_list);
}
return (XIM)im;
}
typedef Bool (*dynamicRegisterCBProcp)(
XLCd, Display *, XrmDatabase, char *, char *, XIDProc, XPointer);
static Bool
_XDynamicRegisterIMInstantiateCallback(
XLCd lcd,
Display *display,
XrmDatabase rdb,
char *res_name,
char *res_class,
XIDProc callback,
XPointer client_data)
{
char lc_dir[BUFSIZE];
char *lc_name;
dynamicRegisterCBProcp im_registerIM = (dynamicRegisterCBProcp)NULL;
Bool ret_flag = False;
int count;
XI18NObjectsList objects_list = xi18n_objects_list;
#if defined(hpux)
int getsyms_cnt, i;
struct shl_symbol *symbols;
#endif
lc_name = lcd->core->name;
if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return False;
count = lc_count;
for (; count-- > 0; objects_list++) {
if (objects_list->type != XIM_OBJECT ||
strcmp(objects_list->locale_name, lc_name)) continue;
if (!open_object (objects_list, lc_dir))
continue;
im_registerIM = (dynamicRegisterCBProcp)fetch_symbol(objects_list,
objects_list->im_register);
if (!im_registerIM) continue;
ret_flag = (*im_registerIM)(lcd, display, rdb,
res_name, res_class,
callback, client_data);
if (ret_flag) break;
close_object (objects_list);
}
return (Bool)ret_flag;
}
typedef Bool (*dynamicUnregisterProcp)(
XLCd, Display *, XrmDatabase, char *, char *, XIDProc, XPointer);
static Bool
_XDynamicUnRegisterIMInstantiateCallback(
XLCd lcd,
Display *display,
XrmDatabase rdb,
char *res_name,
char *res_class,
XIDProc callback,
XPointer client_data)
{
char lc_dir[BUFSIZE];
char *lc_name;
dynamicUnregisterProcp im_unregisterIM = (dynamicUnregisterProcp)NULL;
Bool ret_flag = False;
int count;
XI18NObjectsList objects_list = xi18n_objects_list;
#if defined(hpux)
int getsyms_cnt, i;
struct shl_symbol *symbols;
#endif
lc_name = lcd->core->name;
if (_XlcLocaleDirName(lc_dir, BUFSIZE, lc_name) == NULL) return False;
count = lc_count;
for (; count-- > 0; objects_list++) {
if (objects_list->type != XIM_OBJECT ||
strcmp(objects_list->locale_name, lc_name)) continue;
if (!objects_list->refcount)
continue;
im_unregisterIM = (dynamicUnregisterProcp)fetch_symbol(objects_list,
objects_list->im_unregister);
if (!im_unregisterIM) continue;
ret_flag = (*im_unregisterIM)(lcd, display, rdb,
res_name, res_class,
callback, client_data);
if (ret_flag) {
close_object (objects_list);
break;
}
}
return (Bool)ret_flag;
}
Bool
_XInitDynamicIM(XLCd lcd)
{
if(lcd == (XLCd)NULL)
return False;
lcd->methods->open_im = _XDynamicOpenIM;
lcd->methods->register_callback = _XDynamicRegisterIMInstantiateCallback;
lcd->methods->unregister_callback = _XDynamicUnRegisterIMInstantiateCallback;
return True;
}
typedef XOM (*dynamicIOpenProcp)(
XLCd, Display *, XrmDatabase, _Xconst char *, _Xconst char *);
static XOM
_XDynamicOpenOM(XLCd lcd, Display *display, XrmDatabase rdb,
_Xconst char *res_name, _Xconst char *res_class)
{
XOM om = (XOM)NULL;
int count;
char lc_dir[BUFSIZE];
char *lc_name;
dynamicIOpenProcp om_openOM = (dynamicIOpenProcp)NULL;
XI18NObjectsList objects_list = xi18n_objects_list;
#if defined(hpux)
int getsyms_cnt, i;
struct shl_symbol *symbols;
#endif
lc_name = lcd->core->name;
if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return (XOM)0;
count = lc_count;
for (; count-- > 0; objects_list++) {
if (objects_list->type != XOM_OBJECT ||
strcmp(objects_list->locale_name, lc_name)) continue;
if (!open_object (objects_list, lc_dir))
continue;
om_openOM = (dynamicIOpenProcp)fetch_symbol(objects_list, objects_list->open);
if (!om_openOM) continue;
om = (*om_openOM)(lcd, display, rdb, res_name, res_class);
if (om != (XOM)NULL) {
break;
}
close_object(objects_list);
}
return (XOM)om;
}
Bool
_XInitDynamicOM(XLCd lcd)
{
if(lcd == (XLCd)NULL)
return False;
lcd->methods->open_om = _XDynamicOpenOM;
return True;
}