1 /* Handle configuration data.
2 Copyright (C) 1997, 1998 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
29 #include <sys/param.h>
31 #include <gconv_int.h>
34 /* This is the default path where we look for module lists. */
35 static const char default_gconv_path[] = GCONV_PATH;
37 /* Name of the file containing the module information in the directories
39 static const char gconv_conf_filename[] = "gconv-modules";
41 /* Filename extension for the modules. */
43 # define MODULE_EXT ".so"
45 static const char gconv_module_ext[] = MODULE_EXT;
47 /* We have a few builtin transformations. */
48 static struct gconv_module builtin_modules[] =
50 #define BUILTIN_TRANSFORMATION(From, ConstPfx, ConstLen, To, Cost, Name, \
51 Fct, Init, End, MinF, MaxF, MinT, MaxT) \
54 from_constpfx: ConstPfx, \
55 from_constpfx_len: ConstLen, \
62 #define BUILTIN_ALIAS(From, To)
64 #include "gconv_builtin.h"
67 #undef BUILTIN_TRANSFORMATION
73 #define BUILTIN_TRANSFORMATION(From, ConstPfx, ConstLen, To, Cost, Name, \
74 Fct, Init, End, MinF, MaxF, MinT, MaxT)
75 #define BUILTIN_ALIAS(From, To) From " " To,
77 #include "gconv_builtin.h"
81 # include <libio/libioP.h>
82 # define __getdelim(line, len, c, fp) _IO_getdelim (line, len, c, fp)
86 /* Function for searching module. */
88 module_compare (const void *p1, const void *p2)
90 struct gconv_module *s1 = (struct gconv_module *) p1;
91 struct gconv_module *s2 = (struct gconv_module *) p2;
94 if (s1->from_pattern == NULL)
96 if (s2->from_pattern == NULL)
97 result = strcmp (s1->from_constpfx, s2->from_constpfx);
101 else if (s2->from_pattern == NULL)
104 result = strcmp (s1->from_pattern, s2->from_pattern);
107 result = strcmp (s1->to_string, s2->to_string);
117 /* We now expect two more string. The strings are normalized
118 (converted to UPPER case) and strored in the alias database. */
119 struct gconv_alias *new_alias;
120 char *from, *to, *wp;
122 while (isspace (*rp))
125 while (*rp != '\0' && !isspace (*rp))
128 /* There is no `to' string on the line. Ignore it. */
132 while (isspace (*rp))
134 while (*rp != '\0' && !isspace (*rp))
137 /* No `to' string, ignore the line. */
141 new_alias = (struct gconv_alias *)
142 malloc (sizeof (struct gconv_alias) + (wp - from));
143 if (new_alias != NULL)
145 new_alias->fromname = memcpy ((char *) new_alias
146 + sizeof (struct gconv_alias),
148 new_alias->toname = new_alias->fromname + (to - from);
150 if (__tsearch (new_alias, &__gconv_alias_db, __gconv_alias_compare)
152 /* Something went wrong, free this entry. */
158 /* Add new module. */
160 add_module (char *rp, const char *directory, size_t dir_len, void **modules,
161 size_t *nmodules, int modcounter)
166 3. filename of the module
167 4. an optional cost value
169 struct gconv_module *new_module;
170 char *from, *to, *module, *wp;
176 while (isspace (*rp))
180 while (*rp != '\0' && !isspace (*rp))
182 if (!isalnum (*rp) && *rp != '-' && *rp != '/' && *rp != '.'
191 while (isspace (*rp))
193 while (*rp != '\0' && !isspace (*rp))
200 while (isspace (*rp));
202 while (*rp != '\0' && !isspace (*rp))
206 /* There is no cost, use one by default. */
212 /* There might be a cost value. */
216 cost_hi = strtol (rp, &endp, 10);
218 /* No useful information. */
222 if (module[0] == '\0')
223 /* No module name given. */
225 if (module[0] == '/')
228 /* Increment by one for the slash. */
231 /* See whether we must add the ending. */
233 if (wp - module < sizeof (gconv_module_ext)
234 || memcmp (wp - sizeof (gconv_module_ext), gconv_module_ext,
235 sizeof (gconv_module_ext)) != 0)
236 /* We must add the module extension. */
237 need_ext = sizeof (gconv_module_ext) - 1;
239 /* We've collected all the information, now create an entry. */
244 while (isalnum (from[const_len]) || from[const_len] == '-'
245 || from[const_len] == '/' || from[const_len] == '.'
246 || from[const_len] == '_')
250 const_len = to - from - 1;
252 new_module = (struct gconv_module *) malloc (sizeof (struct gconv_module)
254 + dir_len + need_ext);
255 if (new_module != NULL)
259 new_module->from_constpfx = memcpy ((char *) new_module
260 + sizeof (struct gconv_module),
263 new_module->from_pattern = new_module->from_constpfx;
265 new_module->from_pattern = NULL;
267 new_module->from_constpfx_len = const_len;
269 new_module->from_regex = NULL;
271 new_module->to_string = memcpy ((char *) new_module->from_constpfx
272 + (to - from), to, module - to);
274 new_module->cost_hi = cost_hi;
275 new_module->cost_lo = modcounter;
277 new_module->module_name = (char *) new_module->to_string + (module - to);
280 tmp = (char *) new_module->module_name;
283 tmp = __mempcpy ((char *) new_module->module_name,
284 directory, dir_len - 1);
288 tmp = __mempcpy (tmp, module, wp - module);
291 memcpy (tmp - 1, gconv_module_ext, sizeof (gconv_module_ext));
293 if (__tfind (new_module, modules, module_compare) == NULL)
294 if (__tsearch (new_module, modules, module_compare) == NULL)
295 /* Something went wrong while inserting the new module. */
304 insert_module (const void *nodep, VISIT value, int level)
306 if (value == preorder || value == leaf)
307 __gconv_modules_db[__gconv_nmodules++] = *(struct gconv_module **) nodep;
311 nothing (void *unused __attribute__ ((unused)))
316 /* Read the next configuration file. */
319 read_conf_file (const char *filename, const char *directory, size_t dir_len,
320 void **modules, size_t *nmodules)
322 FILE *fp = fopen (filename, "r");
327 /* Don't complain if a file is not present or readable, simply silently
332 /* Process the known entries of the file. Comments start with `#' and
333 end with the end of the line. Empty lines are ignored. */
334 while (!feof_unlocked (fp))
336 char *rp, *endp, *word;
337 ssize_t n = __getdelim (&line, &line_len, '\n', fp);
339 /* An error occurred. */
343 /* Terminate the line (excluding comments or newline) by an NUL byte
344 to simplify the following code. */
345 endp = strchr (rp, '#');
349 if (rp[n - 1] == '\n')
352 while (isspace (*rp))
355 /* If this is an empty line go on with the next one. */
360 while (*rp != '\0' && !isspace (*rp))
363 if (rp - word == sizeof ("alias") - 1
364 && memcmp (word, "alias", sizeof ("alias") - 1) == 0)
366 else if (rp - word == sizeof ("module") - 1
367 && memcmp (word, "module", sizeof ("module") - 1) == 0)
368 add_module (rp, directory, dir_len, modules, nmodules, modcounter++);
370 /* Otherwise ignore the line. */
379 /* Read all configuration files found in the user-specified and the default
383 __gconv_read_conf (void)
385 const char *user_path = __secure_getenv ("GCONV_PATH");
386 char *gconv_path, *elem;
387 void *modules = NULL;
389 int save_errno = errno;
392 if (user_path == NULL)
393 /* No user-defined path. Make a modifiable copy of the default path. */
394 gconv_path = strdupa (default_gconv_path);
397 /* Append the default path to the user-defined path. */
398 size_t user_len = strlen (user_path);
401 gconv_path = alloca (user_len + 1 + sizeof (default_gconv_path));
402 tmp = __mempcpy (gconv_path, user_path, user_len);
404 __mempcpy (tmp, default_gconv_path, sizeof (default_gconv_path));
407 elem = strtok_r (gconv_path, ":", &gconv_path);
411 /* We define a reasonable limit. */
412 # define MAXPATHLEN 4096
414 char real_elem[MAXPATHLEN];
416 if (__realpath (elem, real_elem) != NULL)
418 size_t elem_len = strlen (real_elem);
419 char *filename, *tmp;
421 filename = alloca (elem_len + 1 + sizeof (gconv_conf_filename));
422 tmp = __mempcpy (filename, real_elem, elem_len);
424 __mempcpy (tmp, gconv_conf_filename, sizeof (gconv_conf_filename));
426 /* Read the next configuration file. */
427 read_conf_file (filename, real_elem, elem_len, &modules, &nmodules);
430 /* Get next element in the path. */
431 elem = strtok_r (NULL, ":", &gconv_path);
434 /* If the configuration files do not contain any valid module specification
435 remember this by setting the pointer to the module array to NULL. */
436 nmodules += sizeof (builtin_modules) / sizeof (builtin_modules[0]);
438 __gconv_modules_db = NULL;
442 (struct gconv_module **) malloc (nmodules
443 * sizeof (struct gconv_module));
444 if (__gconv_modules_db != NULL)
448 /* Insert all module entries into the array. */
449 __twalk (modules, insert_module);
451 /* No remove the tree data structure. */
452 __tdestroy (modules, nothing);
454 /* Finally insert the builtin transformations. */
455 for (cnt = 0; cnt < (sizeof (builtin_modules)
456 / sizeof (struct gconv_module)); ++cnt)
457 __gconv_modules_db[__gconv_nmodules++] = &builtin_modules[cnt];
461 /* Add aliases for builtin conversions. */
462 cnt = sizeof (builtin_aliases) / sizeof (builtin_aliases[0]);
465 char *copy = strdupa (builtin_aliases[--cnt]);
469 /* Restore the error number. */
470 __set_errno (save_errno);