/* Transliteration using the locale's data. Copyright (C) 2000 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 2000. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C 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 the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include #include #include #include #include #include #include #include "gconv_int.h" #include "localeinfo.h" int __gconv_transliterate (struct __gconv_step *step, struct __gconv_step_data *step_data, void *trans_data __attribute__ ((unused)), const unsigned char *inbufstart, const unsigned char **inbufp, const unsigned char *inbufend, unsigned char **outbufstart, size_t *irreversible) { return 0; } /* Structure to represent results of found (or not) transliteration modules. */ struct known_trans { /* This structure must remain the first member. */ struct trans_struct info; char *fname; void *handle; int open_count; }; /* Tree with results of previous calls to __gconv_translit_find. */ static void *search_tree; /* We modify global data. */ __LOCK_INIT(static, lock); /* Compare two transliteration entries. */ static int trans_compare (const void *p1, const void *p2) { const struct known_trans *s1 = (const struct known_trans *) p1; const struct known_trans *s2 = (const struct known_trans *) p2; return strcmp (s1->info.name, s2->info.name); } /* Open (maybe reopen) the module named in the struct. Get the function and data structure pointers we need. */ static int open_translit (struct known_trans *trans) { __gconv_trans_query_fct queryfct; trans->handle = __libc_dlopen (trans->fname); if (trans->handle == NULL) /* Not available. */ return 1; /* Find the required symbol. */ queryfct = __libc_dlsym (trans->handle, "gconv_trans_context"); if (queryfct == NULL) { /* We cannot live with that. */ close_and_out: __libc_dlclose (trans->handle); trans->handle = NULL; return 1; } /* Get the context. */ if (queryfct (trans->info.name, &trans->info.csnames, &trans->info.ncsnames) != 0) goto close_and_out; /* Of course we also have to have the actual function. */ trans->info.trans_fct = __libc_dlsym (trans->handle, "gconv_trans"); if (trans->info.trans_fct == NULL) goto close_and_out; /* Now the optional functions. */ trans->info.trans_init_fct = __libc_dlsym (trans->handle, "gconv_trans_init"); trans->info.trans_context_fct = __libc_dlsym (trans->handle, "gconv_trans_context"); trans->info.trans_end_fct = __libc_dlsym (trans->handle, "gconv_trans_end"); trans->open_count = 1; return 0; } int internal_function __gconv_translit_find (struct trans_struct *trans) { struct known_trans **found; const struct path_elem *runp; int res = 1; /* We have to have a name. */ assert (trans->name != NULL); /* Acquire the lock. */ #ifdef HAVE_DD_LOCK __lock_acquire(lock); #endif /* See whether we know this module already. */ found = tfind (trans, &search_tree, trans_compare); if (found != NULL) { /* Is this module available? */ if ((*found)->handle != NULL) { /* Maybe we have to reopen the file. */ if ((*found)->handle != (void *) -1) /* The object is not unloaded. */ res = 0; else if (open_translit (*found) == 0) { /* Copy the data. */ *trans = (*found)->info; (*found)->open_count++; res = 0; } } } else { size_t name_len = strlen (trans->name) + 1; int need_so = 0; struct known_trans *newp; /* We have to continue looking for the module. */ if (__gconv_path_elem == NULL) __gconv_get_path (); /* See whether we have to append .so. */ if (name_len <= 4 || memcmp (&trans->name[name_len - 4], ".so", 3) != 0) need_so = 1; /* Create a new entry. */ newp = (struct known_trans *) malloc (sizeof (struct known_trans) + (__gconv_max_path_elem_len + name_len + 3) + name_len); if (newp != NULL) { char *cp; /* Clear the struct. */ memset (newp, '\0', sizeof (struct known_trans)); /* Store a copy of the module name. */ newp->info.name = cp = (char *) (newp + 1); cp = memcpy (cp, trans->name, name_len); cp += name_len; newp->fname = cp; /* Search in all the directories. */ for (runp = __gconv_path_elem; runp->name != NULL; ++runp) { strcpy ((char *) newp->fname, runp->name); while(newp->fname != '\0') newp->fname++; cp = memcpy (newp->fname, trans->name, name_len); cp += name_len; if (need_so) memcpy (cp, ".so", sizeof (".so")); if (open_translit (newp) == 0) { /* We found a module. */ res = 0; break; } } if (res) newp->fname = NULL; /* In any case we'll add the entry to our search tree. */ if (tsearch (newp, &search_tree, trans_compare) == NULL) { /* Yickes, this should not happen. Unload the object. */ res = 1; /* XXX unload here. */ } } } #ifdef HAVE_DD_LOCK __lock_release(lock); #endif return res; }