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
)
295 if (__tsearch (new_module
, modules
, module_compare
) == NULL
)
296 /* Something went wrong while inserting the new module. */
306 insert_module (const void *nodep
, VISIT value
, int level
)
308 if (value
== preorder
|| value
== leaf
)
309 __gconv_modules_db
[__gconv_nmodules
++] = *(struct gconv_module
**) nodep
;
313 nothing (void *unused
__attribute__ ((unused
)))
318 /* Read the next configuration file. */
321 read_conf_file (const char *filename
, const char *directory
, size_t dir_len
,
322 void **modules
, size_t *nmodules
)
324 FILE *fp
= fopen (filename
, "r");
329 /* Don't complain if a file is not present or readable, simply silently
334 /* Process the known entries of the file. Comments start with `#' and
335 end with the end of the line. Empty lines are ignored. */
336 while (!feof_unlocked (fp
))
338 char *rp
, *endp
, *word
;
339 ssize_t n
= __getdelim (&line
, &line_len
, '\n', fp
);
341 /* An error occurred. */
345 /* Terminate the line (excluding comments or newline) by an NUL byte
346 to simplify the following code. */
347 endp
= strchr (rp
, '#');
351 if (rp
[n
- 1] == '\n')
354 while (isspace (*rp
))
357 /* If this is an empty line go on with the next one. */
362 while (*rp
!= '\0' && !isspace (*rp
))
365 if (rp
- word
== sizeof ("alias") - 1
366 && memcmp (word
, "alias", sizeof ("alias") - 1) == 0)
368 else if (rp
- word
== sizeof ("module") - 1
369 && memcmp (word
, "module", sizeof ("module") - 1) == 0)
370 add_module (rp
, directory
, dir_len
, modules
, nmodules
, modcounter
++);
372 /* Otherwise ignore the line. */
381 /* Read all configuration files found in the user-specified and the default
384 __gconv_read_conf (void)
386 const char *user_path
= __secure_getenv ("GCONV_PATH");
387 char *gconv_path
, *elem
;
388 void *modules
= NULL
;
390 int save_errno
= errno
;
393 if (user_path
== NULL
)
394 /* No user-defined path. Make a modifiable copy of the default path. */
395 gconv_path
= strdupa (default_gconv_path
);
398 /* Append the default path to the user-defined path. */
399 size_t user_len
= strlen (user_path
);
402 gconv_path
= alloca (user_len
+ 1 + sizeof (default_gconv_path
));
403 tmp
= __mempcpy (gconv_path
, user_path
, user_len
);
405 __mempcpy (tmp
, default_gconv_path
, sizeof (default_gconv_path
));
408 elem
= strtok_r (gconv_path
, ":", &gconv_path
);
412 /* We define a reasonable limit. */
413 # define MAXPATHLEN 4096
415 char real_elem
[MAXPATHLEN
];
417 if (__realpath (elem
, real_elem
) != NULL
)
419 size_t elem_len
= strlen (real_elem
);
420 char *filename
, *tmp
;
422 filename
= alloca (elem_len
+ 1 + sizeof (gconv_conf_filename
));
423 tmp
= __mempcpy (filename
, real_elem
, elem_len
);
425 __mempcpy (tmp
, gconv_conf_filename
, sizeof (gconv_conf_filename
));
427 /* Read the next configuration file. */
428 read_conf_file (filename
, real_elem
, elem_len
, &modules
, &nmodules
);
431 /* Get next element in the path. */
432 elem
= strtok_r (NULL
, ":", &gconv_path
);
435 /* If the configuration files do not contain any valid module specification
436 remember this by setting the pointer to the module array to NULL. */
437 nmodules
+= sizeof (builtin_modules
) / sizeof (builtin_modules
[0]);
439 __gconv_modules_db
= NULL
;
443 (struct gconv_module
**) malloc (nmodules
444 * sizeof (struct gconv_module
));
445 if (__gconv_modules_db
!= NULL
)
449 /* Insert all module entries into the array. */
450 __twalk (modules
, insert_module
);
452 /* No remove the tree data structure. */
453 __tdestroy (modules
, nothing
);
455 /* Finally insert the builtin transformations. */
456 for (cnt
= 0; cnt
< (sizeof (builtin_modules
)
457 / sizeof (struct gconv_module
)); ++cnt
)
458 __gconv_modules_db
[__gconv_nmodules
++] = &builtin_modules
[cnt
];
462 /* Add aliases for builtin conversions. */
463 cnt
= sizeof (builtin_aliases
) / sizeof (builtin_aliases
[0]);
466 char *copy
= strdupa (builtin_aliases
[--cnt
]);
470 /* Restore the error number. */
471 __set_errno (save_errno
);