XlcDL.c revision dac667f7
1/*
2Copyright 1985, 1986, 1987, 1991, 1998  The Open Group
3
4Permission is hereby granted, free of charge, to any person obtaining a
5copy of this software and associated documentation files (the
6"Software"), to deal in the Software without restriction, including
7without limitation the rights to use, copy, modify, merge, publish,
8distribute, sublicense, and/or sell copies of the Software, and to
9permit persons to whom the Software is furnished to do so, subject to
10the following conditions: The above copyright notice and this
11permission notice shall be included in all copies or substantial
12portions of the Software.
13
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
21EVEN IF ADVISED IN ADVANCE OF THE POSSIBILITY OF SUCH DAMAGES.
22
23
24Except as contained in this notice, the name of The Open Group shall not be
25used in advertising or otherwise to promote the sale, use or other dealings
26in this Software without prior written authorization from The Open Group.
27
28
29X Window System is a trademark of The Open Group
30
31OSF/1, OSF/Motif and Motif are registered trademarks, and OSF, the OSF
32logo, LBX, X Window System, and Xinerama are trademarks of the Open
33Group. All other trademarks and registered trademarks mentioned herein
34are the property of their respective owners. No right, title or
35interest in or to any trademark, service mark, logo or trade name of
36Sun Microsystems, Inc. or its licensors is granted.
37
38*/
39/*
40 * Copyright 2000 Oracle and/or its affiliates. All rights reserved.
41 *
42 * Permission is hereby granted, free of charge, to any person obtaining a
43 * copy of this software and associated documentation files (the "Software"),
44 * to deal in the Software without restriction, including without limitation
45 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
46 * and/or sell copies of the Software, and to permit persons to whom the
47 * Software is furnished to do so, subject to the following conditions:
48 *
49 * The above copyright notice and this permission notice (including the next
50 * paragraph) shall be included in all copies or substantial portions of the
51 * Software.
52 *
53 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
54 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
55 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
56 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
57 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
58 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
59 * DEALINGS IN THE SOFTWARE.
60 */
61
62
63#ifdef HAVE_CONFIG_H
64# include <config.h>
65#else
66# if defined(hpux)
67#  define HAVE_DL_H
68# else
69#  define HAVE_DLFCN_H
70# endif
71#endif
72
73#include <stdio.h>
74
75#ifdef HAVE_DL_H
76#include <dl.h>
77#endif
78
79#ifdef HAVE_DLFCN_H
80#include <dlfcn.h>
81#endif
82
83#include <ctype.h>
84
85#include "Xlibint.h"
86#include "XlcPublic.h"
87#include "XlcPubI.h"
88
89#define XI18N_DLREL		2
90
91#define	iscomment(ch)	((ch) == '\0' || (ch) == '#')
92
93typedef enum {
94  XLC_OBJECT,
95  XIM_OBJECT,
96  XOM_OBJECT
97} XI18NDLType;
98
99typedef struct {
100  XI18NDLType type;
101  int	locale_name_len;
102  char *locale_name;
103  char *dl_name;
104  char *open;
105  char *im_register;
106  char *im_unregister;
107  int dl_release;
108  unsigned int refcount;
109#if defined(hpux)
110  shl_t dl_module;
111#else
112  void *dl_module;
113#endif
114} XI18NObjectsListRec, *XI18NObjectsList;
115
116#define OBJECT_INIT_LEN 8
117#define OBJECT_INC_LEN 4
118static int lc_len = 0;
119static XI18NObjectsListRec *xi18n_objects_list = NULL;
120static int lc_count = 0;
121
122static int
123parse_line(char *line, char **argv, int argsize)
124{
125    int argc = 0;
126    char *p = line;
127
128    while (argc < argsize) {
129	while (isspace(*p)) {
130	    ++p;
131	}
132	if (iscomment(*p)){
133	    break;
134	}
135	argv[argc++] = p;
136	while (!isspace(*p)) {
137	    ++p;
138	}
139	if (iscomment(*p)) {
140	    break;
141	}
142	*p++ = '\0';
143    }
144    return argc;
145}
146
147static char *
148strdup_with_underscore(const char *symbol)
149{
150	char *result;
151
152	if ((result = malloc(strlen(symbol) + 2)) == NULL)
153		return NULL;
154	result[0] = '_';
155	strcpy(result + 1, symbol);
156	return result;
157}
158
159#ifndef hpux
160static void *
161try_both_dlsym (void *handle, char *name)
162{
163    void    *ret;
164
165    ret = dlsym (handle, name);
166    if (!ret)
167    {
168	 name = strdup_with_underscore (name);
169	 if (name)
170	 {
171	     ret = dlsym (handle, name);
172	     free (name);
173	 }
174    }
175    return ret;
176}
177#endif
178
179static void
180resolve_object(char *path, const char *lc_name)
181{
182    char filename[BUFSIZ];
183    FILE *fp;
184    char buf[BUFSIZ];
185
186    if (lc_len == 0) { /* True only for the 1st time */
187      lc_len = OBJECT_INIT_LEN;
188      xi18n_objects_list = Xmalloc(sizeof(XI18NObjectsListRec) * lc_len);
189      if (!xi18n_objects_list) return;
190    }
191    snprintf(filename, sizeof(filename), "%s/%s", path, "XI18N_OBJS");
192    fp = fopen(filename, "r");
193    if (fp == (FILE *)NULL){
194	return;
195    }
196
197    while (fgets(buf, BUFSIZ, fp) != NULL){
198	char *p = buf;
199	int n;
200	char *args[6];
201	while (isspace(*p)){
202	    ++p;
203	}
204	if (iscomment(*p)){
205	    continue;
206	}
207
208	if (lc_count == lc_len) {
209	  int new_len = lc_len + OBJECT_INC_LEN;
210	  XI18NObjectsListRec *tmp = Xrealloc(xi18n_objects_list,
211	      sizeof(XI18NObjectsListRec) * new_len);
212	  if (tmp == NULL)
213	      goto done;
214	  xi18n_objects_list = tmp;
215	  lc_len = new_len;
216	}
217	n = parse_line(p, args, 6);
218
219	if (n == 3 || n == 5) {
220	  if (!strcmp(args[0], "XLC")){
221	    xi18n_objects_list[lc_count].type = XLC_OBJECT;
222	  } else if (!strcmp(args[0], "XOM")){
223	    xi18n_objects_list[lc_count].type = XOM_OBJECT;
224	  } else if (!strcmp(args[0], "XIM")){
225	    xi18n_objects_list[lc_count].type = XIM_OBJECT;
226	  }
227	  xi18n_objects_list[lc_count].dl_name = strdup(args[1]);
228	  xi18n_objects_list[lc_count].open = strdup(args[2]);
229	  xi18n_objects_list[lc_count].dl_release = XI18N_DLREL;
230	  xi18n_objects_list[lc_count].locale_name = strdup(lc_name);
231	  xi18n_objects_list[lc_count].refcount = 0;
232	  xi18n_objects_list[lc_count].dl_module = (void*)NULL;
233	  if (n == 5) {
234	    xi18n_objects_list[lc_count].im_register = strdup(args[3]);
235	    xi18n_objects_list[lc_count].im_unregister = strdup(args[4]);
236	  } else {
237	    xi18n_objects_list[lc_count].im_register = NULL;
238	    xi18n_objects_list[lc_count].im_unregister = NULL;
239	  }
240	  lc_count++;
241	}
242    }
243  done:
244    fclose(fp);
245}
246
247static char*
248__lc_path(const char *dl_name, const char *lc_dir)
249{
250    char *path;
251    size_t len;
252    char *slash_p;
253
254    /*
255     * reject this for possible security issue
256     */
257    if (strstr (dl_name, "../"))
258	return NULL;
259
260    len = (lc_dir ? strlen(lc_dir) : 0 ) +
261	(dl_name ? strlen(dl_name) : 0) + 10;
262#if defined POSTLOCALELIBDIR
263    len += (strlen(POSTLOCALELIBDIR) + 1);
264#endif
265    path = Xmalloc(len + 1);
266
267    if (strchr(dl_name, '/') != NULL) {
268	slash_p = strrchr(lc_dir, '/');
269	*slash_p = '\0';
270    } else
271	slash_p = NULL;
272
273#if defined POSTLOCALELIBDIR
274    snprintf(path, len + 1, "%s/%s/%s.so.2",
275             lc_dir, POSTLOCALELIBDIR, dl_name);
276#else
277    snprintf(path, len + 1, "%s/%s.so.2", lc_dir, dl_name);
278#endif
279
280    if (slash_p != NULL)
281	*slash_p = '/';
282
283    return path;
284}
285
286/* We reference count dlopen() and dlclose() of modules; unfortunately,
287 * since XCloseIM, XCloseOM, XlcClose aren't wrapped, but directly
288 * call the close method of the object, we leak a reference count every
289 * time we open then close a module. Fixing this would require
290 * either creating proxy objects or hooks for close_im/close_om
291 * in XLCd
292 */
293static Bool
294open_object(
295     XI18NObjectsList object,
296     char *lc_dir)
297{
298  char *path;
299
300  if (object->refcount == 0) {
301      path = __lc_path(object->dl_name, lc_dir);
302      if (!path)
303	  return False;
304#if defined(hpux)
305      object->dl_module = shl_load(path, BIND_DEFERRED, 0L);
306#else
307      object->dl_module = dlopen(path, RTLD_LAZY);
308#endif
309      Xfree(path);
310
311      if (!object->dl_module)
312	  return False;
313    }
314
315  object->refcount++;
316  return True;
317}
318
319static void *
320fetch_symbol(
321     XI18NObjectsList object,
322     char *symbol)
323{
324    void *result = NULL;
325#if defined(hpux)
326    int getsyms_cnt, i;
327    struct shl_symbol *symbols;
328#endif
329
330    if (symbol == NULL)
331    	return NULL;
332
333#if defined(hpux)
334    getsyms_cnt = shl_getsymbols(object->dl_module, TYPE_PROCEDURE,
335				 EXPORT_SYMBOLS, malloc, &symbols);
336
337    for(i=0; i<getsyms_cnt; i++) {
338        if(!strcmp(symbols[i].name, symbol)) {
339	    result = symbols[i].value;
340	    break;
341         }
342    }
343
344    if(getsyms_cnt > 0) {
345        free(symbols);
346    }
347#else
348    result = try_both_dlsym(object->dl_module, symbol);
349#endif
350
351    return result;
352}
353
354static void
355close_object(XI18NObjectsList object)
356{
357  object->refcount--;
358  if (object->refcount == 0)
359    {
360#if defined(hpux)
361        shl_unload(object->dl_module);
362#else
363        dlclose(object->dl_module);
364#endif
365        object->dl_module = NULL;
366    }
367}
368
369
370typedef XLCd (*dynamicLoadProc)(const char *);
371
372XLCd
373_XlcDynamicLoad(const char *lc_name)
374{
375    XLCd lcd = (XLCd)NULL;
376    dynamicLoadProc lc_loader = (dynamicLoadProc)NULL;
377    int count;
378    XI18NObjectsList objects_list;
379    char lc_dir[BUFSIZE], lc_lib_dir[BUFSIZE];
380
381    if (lc_name == NULL) return (XLCd)NULL;
382
383    if (_XlcLocaleDirName(lc_dir, BUFSIZE, lc_name) == NULL)
384        return (XLCd)NULL;
385    if (_XlcLocaleLibDirName(lc_lib_dir, BUFSIZE, lc_name) == NULL)
386	return (XLCd)NULL;
387
388    resolve_object(lc_dir, lc_name);
389    resolve_object(lc_lib_dir, lc_name);
390
391    objects_list = xi18n_objects_list;
392    count = lc_count;
393    for (; count-- > 0; objects_list++) {
394        if (objects_list->type != XLC_OBJECT ||
395	    strcmp(objects_list->locale_name, lc_name)) continue;
396	if (!open_object (objects_list, lc_dir) && \
397            !open_object (objects_list, lc_lib_dir))
398	    continue;
399
400	lc_loader = (dynamicLoadProc)fetch_symbol (objects_list, objects_list->open);
401	if (!lc_loader) continue;
402	lcd = (*lc_loader)(lc_name);
403	if (lcd != (XLCd)NULL) {
404	    break;
405	}
406
407	close_object (objects_list);
408    }
409    return (XLCd)lcd;
410}
411
412
413typedef XIM (*dynamicOpenProcp)(XLCd, Display *, XrmDatabase, char *, char *);
414
415static XIM
416_XDynamicOpenIM(XLCd lcd, Display *display, XrmDatabase rdb,
417		char *res_name, char *res_class)
418{
419  XIM im = (XIM)NULL;
420  char lc_dir[BUFSIZE];
421  char *lc_name;
422  dynamicOpenProcp im_openIM = (dynamicOpenProcp)NULL;
423  int count;
424  XI18NObjectsList objects_list = xi18n_objects_list;
425
426  lc_name = lcd->core->name;
427
428  if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return (XIM)0;
429
430  count = lc_count;
431  for (; count-- > 0; objects_list++) {
432    if (objects_list->type != XIM_OBJECT ||
433	strcmp(objects_list->locale_name, lc_name)) continue;
434
435    if (!open_object (objects_list, lc_dir))
436        continue;
437
438    im_openIM = (dynamicOpenProcp)fetch_symbol(objects_list, objects_list->open);
439    if (!im_openIM) continue;
440    im = (*im_openIM)(lcd, display, rdb, res_name, res_class);
441    if (im != (XIM)NULL) {
442        break;
443    }
444
445    close_object (objects_list);
446  }
447  return (XIM)im;
448}
449
450typedef Bool (*dynamicRegisterCBProcp)(
451    XLCd, Display *, XrmDatabase, char *, char *, XIDProc, XPointer);
452
453static Bool
454_XDynamicRegisterIMInstantiateCallback(
455    XLCd	 lcd,
456    Display	*display,
457    XrmDatabase	 rdb,
458    char	*res_name,
459    char        *res_class,
460    XIDProc	 callback,
461    XPointer	 client_data)
462{
463  char lc_dir[BUFSIZE];
464  char *lc_name;
465  dynamicRegisterCBProcp im_registerIM = (dynamicRegisterCBProcp)NULL;
466  Bool ret_flag = False;
467  int count;
468  XI18NObjectsList objects_list = xi18n_objects_list;
469#if defined(hpux)
470  int getsyms_cnt, i;
471  struct shl_symbol *symbols;
472#endif
473
474  lc_name = lcd->core->name;
475
476  if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return False;
477
478  count = lc_count;
479  for (; count-- > 0; objects_list++) {
480    if (objects_list->type != XIM_OBJECT ||
481	strcmp(objects_list->locale_name, lc_name)) continue;
482
483    if (!open_object (objects_list, lc_dir))
484        continue;
485    im_registerIM = (dynamicRegisterCBProcp)fetch_symbol(objects_list,
486					    objects_list->im_register);
487    if (!im_registerIM) continue;
488    ret_flag = (*im_registerIM)(lcd, display, rdb,
489				res_name, res_class,
490				callback, client_data);
491    if (ret_flag) break;
492
493    close_object (objects_list);
494  }
495  return (Bool)ret_flag;
496}
497
498typedef Bool (*dynamicUnregisterProcp)(
499    XLCd, Display *, XrmDatabase, char *, char *, XIDProc, XPointer);
500
501static Bool
502_XDynamicUnRegisterIMInstantiateCallback(
503    XLCd	 lcd,
504    Display	*display,
505    XrmDatabase	 rdb,
506    char	*res_name,
507    char        *res_class,
508    XIDProc	 callback,
509    XPointer	 client_data)
510{
511  char lc_dir[BUFSIZE];
512  const char *lc_name;
513  dynamicUnregisterProcp im_unregisterIM = (dynamicUnregisterProcp)NULL;
514  Bool ret_flag = False;
515  int count;
516  XI18NObjectsList objects_list = xi18n_objects_list;
517#if defined(hpux)
518  int getsyms_cnt, i;
519  struct shl_symbol *symbols;
520#endif
521
522  lc_name = lcd->core->name;
523  if (_XlcLocaleDirName(lc_dir, BUFSIZE, lc_name) == NULL) return False;
524
525  count = lc_count;
526  for (; count-- > 0; objects_list++) {
527    if (objects_list->type != XIM_OBJECT ||
528	strcmp(objects_list->locale_name, lc_name)) continue;
529
530    if (!objects_list->refcount) /* Must already be opened */
531        continue;
532
533    im_unregisterIM = (dynamicUnregisterProcp)fetch_symbol(objects_list,
534					      objects_list->im_unregister);
535
536    if (!im_unregisterIM) continue;
537    ret_flag = (*im_unregisterIM)(lcd, display, rdb,
538				  res_name, res_class,
539				  callback, client_data);
540    if (ret_flag) {
541        close_object (objects_list); /* opened in RegisterIMInstantiateCallback */
542	break;
543    }
544  }
545  return (Bool)ret_flag;
546}
547
548Bool
549_XInitDynamicIM(XLCd lcd)
550{
551    if(lcd == (XLCd)NULL)
552	return False;
553    lcd->methods->open_im = _XDynamicOpenIM;
554    lcd->methods->register_callback = _XDynamicRegisterIMInstantiateCallback;
555    lcd->methods->unregister_callback = _XDynamicUnRegisterIMInstantiateCallback;
556    return True;
557}
558
559
560typedef XOM (*dynamicIOpenProcp)(
561        XLCd, Display *, XrmDatabase, _Xconst char *, _Xconst char *);
562
563static XOM
564_XDynamicOpenOM(XLCd lcd, Display *display, XrmDatabase rdb,
565		_Xconst char *res_name, _Xconst char *res_class)
566{
567  XOM om = (XOM)NULL;
568  int count;
569  char lc_dir[BUFSIZE];
570  char *lc_name;
571  dynamicIOpenProcp om_openOM = (dynamicIOpenProcp)NULL;
572  XI18NObjectsList objects_list = xi18n_objects_list;
573#if defined(hpux)
574  int getsyms_cnt, i;
575  struct shl_symbol *symbols;
576#endif
577
578  lc_name = lcd->core->name;
579
580  if (_XlcLocaleLibDirName(lc_dir, BUFSIZE, lc_name) == NULL) return (XOM)0;
581
582  count = lc_count;
583  for (; count-- > 0; objects_list++) {
584    if (objects_list->type != XOM_OBJECT ||
585	strcmp(objects_list->locale_name, lc_name)) continue;
586    if (!open_object (objects_list, lc_dir))
587        continue;
588
589    om_openOM = (dynamicIOpenProcp)fetch_symbol(objects_list, objects_list->open);
590    if (!om_openOM) continue;
591    om = (*om_openOM)(lcd, display, rdb, res_name, res_class);
592    if (om != (XOM)NULL) {
593        break;
594    }
595    close_object(objects_list);
596  }
597  return (XOM)om;
598}
599
600Bool
601_XInitDynamicOM(XLCd lcd)
602{
603    if(lcd == (XLCd)NULL)
604	return False;
605
606    lcd->methods->open_om = _XDynamicOpenOM;
607
608    return True;
609}
610