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. */
28 #include <sys/param.h>
30 #include <gconv_int.h>
33 /* This is the default path where we look for module lists. */
34 static const char default_gconv_path
[] = GCONV_PATH
;
36 /* Name of the file containing the module information in the directories
38 static const char gconv_conf_filename
[] = "gconv-modules";
40 /* Filename extension for the modules. */
42 # define MODULE_EXT ".so"
44 static const char gconv_module_ext
[] = MODULE_EXT
;
46 /* We have a few builtin transformations. */
47 static struct gconv_module builtin_modules
[] =
49 #define BUILTIN_TRANSFORMATION(From, ConstPfx, ConstLen, To, Cost, Name, \
50 Fct, Init, End, MinF, MaxF, MinT, MaxT) \
53 from_constpfx: ConstPfx, \
54 from_constpfx_len: ConstLen, \
60 #define BUILTIN_ALIAS(From, To)
62 #include "gconv_builtin.h"
65 #undef BUILTIN_TRANSFORMATION
71 #define BUILTIN_TRANSFORMATION(From, ConstPfx, ConstLen, To, Cost, Name, \
72 Fct, Init, End, MinF, MaxF, MinT, MaxT)
73 #define BUILTIN_ALIAS(From, To) From " " To,
75 #include "gconv_builtin.h"
79 /* Function for searching module. */
81 module_compare (const void *p1
, const void *p2
)
83 struct gconv_module
*s1
= (struct gconv_module
*) p1
;
84 struct gconv_module
*s2
= (struct gconv_module
*) p2
;
87 if (s1
->from_pattern
== NULL
)
89 if (s2
->from_pattern
== NULL
)
90 result
= strcmp (s1
->from_constpfx
, s2
->from_constpfx
);
94 else if (s2
->from_pattern
== NULL
)
97 result
= strcmp (s1
->from_pattern
, s2
->from_pattern
);
100 result
= strcmp (s1
->to_string
, s2
->to_string
);
110 /* We now expect two more string. The strings are normalized
111 (converted to UPPER case) and strored in the alias database. */
112 struct gconv_alias
*new_alias
;
113 char *from
, *to
, *wp
;
115 while (isspace (*rp
))
118 while (*rp
!= '\0' && !isspace (*rp
))
121 /* There is no `to' string on the line. Ignore it. */
125 while (isspace (*rp
))
127 while (*rp
!= '\0' && !isspace (*rp
))
130 /* No `to' string, ignore the line. */
134 new_alias
= (struct gconv_alias
*)
135 malloc (sizeof (struct gconv_alias
) + (wp
- from
));
136 if (new_alias
!= NULL
)
138 new_alias
->fromname
= memcpy ((char *) new_alias
139 + sizeof (struct gconv_alias
),
141 new_alias
->toname
= new_alias
->fromname
+ (to
- from
);
143 if (__tsearch (new_alias
, &__gconv_alias_db
, __gconv_alias_compare
)
145 /* Something went wrong, free this entry. */
151 /* Add new module. */
153 add_module (char *rp
, const char *directory
, size_t dir_len
, void **modules
,
159 3. filename of the module
160 4. an optional cost value
162 struct gconv_module
*new_module
;
163 char *from
, *to
, *module
, *wp
;
169 while (isspace (*rp
))
173 while (*rp
!= '\0' && !isspace (*rp
))
175 if (!isalnum (*rp
) && *rp
!= '-' && *rp
!= '/' && *rp
!= '.'
184 while (isspace (*rp
))
186 while (*rp
!= '\0' && !isspace (*rp
))
193 while (isspace (*rp
));
195 while (*rp
!= '\0' && !isspace (*rp
))
199 /* There is no cost, use one by default. */
205 /* There might be a cost value. */
209 cost
= strtol (rp
, &endp
, 10);
211 /* No useful information. */
215 if (module
[0] == '\0')
216 /* No module name given. */
218 if (module
[0] == '/')
221 /* Increment by one for the slash. */
224 /* See whether we must add the ending. */
226 if (wp
- module
< sizeof (gconv_module_ext
)
227 || memcmp (wp
- sizeof (gconv_module_ext
), gconv_module_ext
,
228 sizeof (gconv_module_ext
)) != 0)
229 /* We must add the module extension. */
230 need_ext
= sizeof (gconv_module_ext
) - 1;
232 /* We've collected all the information, now create an entry. */
237 while (isalnum (from
[const_len
]) || from
[const_len
] == '-'
238 || from
[const_len
] == '/' || from
[const_len
] == '.'
239 || from
[const_len
] == '_')
243 const_len
= to
- from
- 1;
245 new_module
= (struct gconv_module
*) malloc (sizeof (struct gconv_module
)
247 + dir_len
+ need_ext
);
248 if (new_module
!= NULL
)
252 new_module
->from_constpfx
= memcpy ((char *) new_module
253 + sizeof (struct gconv_module
),
256 new_module
->from_pattern
= new_module
->from_constpfx
;
258 new_module
->from_pattern
= NULL
;
260 new_module
->from_constpfx_len
= const_len
;
262 new_module
->from_regex
= NULL
;
264 new_module
->to_string
= memcpy ((char *) new_module
->from_constpfx
265 + (to
- from
), to
, module
- to
);
267 new_module
->cost
= cost
;
269 new_module
->module_name
= (char *) new_module
->to_string
+ (module
- to
);
272 tmp
= (char *) new_module
->module_name
;
275 tmp
= __mempcpy ((char *) new_module
->module_name
,
276 directory
, dir_len
- 1);
280 tmp
= __mempcpy (tmp
, module
, wp
- module
);
283 memcpy (tmp
- 1, gconv_module_ext
, sizeof (gconv_module_ext
));
285 if (__tfind (new_module
, modules
, module_compare
) == NULL
)
286 if (__tsearch (new_module
, modules
, module_compare
) == NULL
)
287 /* Something went wrong while inserting the new module. */
296 insert_module (const void *nodep
, VISIT value
, int level
)
298 if (value
== preorder
|| value
== leaf
)
299 __gconv_modules_db
[__gconv_nmodules
++] = *(struct gconv_module
**) nodep
;
303 nothing (void *unused
__attribute__ ((unused
)))
308 /* Read the next configuration file. */
311 read_conf_file (const char *filename
, const char *directory
, size_t dir_len
,
312 void **modules
, size_t *nmodules
)
314 FILE *fp
= fopen (filename
, "r");
318 /* Don't complain if a file is not present or readable, simply silently
323 /* Process the known entries of the file. Comments start with `#' and
324 end with the end of the line. Empty lines are ignored. */
327 char *rp
, *endp
, *word
;
328 ssize_t n
= __getdelim (&line
, &line_len
, '\n', fp
);
330 /* An error occurred. */
334 /* Terminate the line (excluding comments or newline) by an NUL byte
335 to simplify the following code. */
336 endp
= strchr (rp
, '#');
340 if (rp
[n
- 1] == '\n')
343 while (isspace (*rp
))
346 /* If this is an empty line go on with the next one. */
351 while (*rp
!= '\0' && !isspace (*rp
))
354 if (rp
- word
== sizeof ("alias") - 1
355 && memcmp (word
, "alias", sizeof ("alias") - 1) == 0)
357 else if (rp
- word
== sizeof ("module") - 1
358 && memcmp (word
, "module", sizeof ("module") - 1) == 0)
359 add_module (rp
, directory
, dir_len
, modules
, nmodules
);
361 /* Otherwise ignore the line. */
370 /* Read all configuration files found in the user-specified and the default
374 __gconv_read_conf (void)
376 const char *user_path
= __secure_getenv ("GCONV_PATH");
377 char *gconv_path
, *elem
;
378 void *modules
= NULL
;
380 int save_errno
= errno
;
383 if (user_path
== NULL
)
384 /* No user-defined path. Make a modifiable copy of the default path. */
385 gconv_path
= strdupa (default_gconv_path
);
388 /* Append the default path to the user-defined path. */
389 size_t user_len
= strlen (user_path
);
392 gconv_path
= alloca (user_len
+ 1 + sizeof (default_gconv_path
));
393 tmp
= __mempcpy (gconv_path
, user_path
, user_len
);
395 __mempcpy (tmp
, default_gconv_path
, sizeof (default_gconv_path
));
398 elem
= strtok_r (gconv_path
, ":", &gconv_path
);
402 /* We define a reasonable limit. */
403 # define MAXPATHLEN 4096
405 char real_elem
[MAXPATHLEN
];
407 if (__realpath (elem
, real_elem
) != NULL
)
409 size_t elem_len
= strlen (real_elem
);
410 char *filename
, *tmp
;
412 filename
= alloca (elem_len
+ 1 + sizeof (gconv_conf_filename
));
413 tmp
= __mempcpy (filename
, real_elem
, elem_len
);
415 __mempcpy (tmp
, gconv_conf_filename
, sizeof (gconv_conf_filename
));
417 /* Read the next configuration file. */
418 read_conf_file (filename
, real_elem
, elem_len
, &modules
, &nmodules
);
421 /* Get next element in the path. */
422 elem
= strtok_r (NULL
, ":", &gconv_path
);
425 /* If the configuration files do not contain any valid module specification
426 remember this by setting the pointer to the module array to NULL. */
427 nmodules
+= sizeof (builtin_modules
) / sizeof (builtin_modules
[0]);
429 __gconv_modules_db
= NULL
;
433 (struct gconv_module
**) malloc (nmodules
434 * sizeof (struct gconv_module
));
435 if (__gconv_modules_db
!= NULL
)
439 /* Insert all module entries into the array. */
440 __twalk (modules
, insert_module
);
442 /* No remove the tree data structure. */
443 __tdestroy (modules
, nothing
);
445 /* Finally insert the builtin transformations. */
446 for (cnt
= 0; cnt
< (sizeof (builtin_modules
)
447 / sizeof (struct gconv_module
)); ++cnt
)
448 __gconv_modules_db
[__gconv_nmodules
++] = &builtin_modules
[cnt
];
452 /* Add aliases for builtin conversions. */
453 cnt
= sizeof (builtin_aliases
) / sizeof (builtin_aliases
[0]);
456 char *copy
= strdupa (builtin_aliases
[--cnt
]);
460 /* Restore the error number. */
461 __set_errno (save_errno
);